Auto merge of #154384 - JonathanBrouwer:rollup-Wou9g2B, r=JonathanBrouwer

Rollup of 22 pull requests

Successful merges:

 - rust-lang/rust#153049 (Add `-Zsanitize=kernel-hwaddress`)
 - rust-lang/rust#153702 (Add macro matcher for `guard` fragment specifier)
 - rust-lang/rust#154200 (debuginfo: emit DW_TAG_call_site entries)
 - rust-lang/rust#154263 (interpret: when passing an argument fails, point at that argument)
 - rust-lang/rust#154269 (miri recursive validation: only check one layer deep)
 - rust-lang/rust#154313 (Init `self_decl` with a correct visibility)
 - rust-lang/rust#154344 (Update LLVM to 22.1.2)
 - rust-lang/rust#154348 (re-enable enzyme/autodiff builds on dist-aarch64-apple)
 - rust-lang/rust#154351 (Overhaul `Erasable` impls)
 - rust-lang/rust#154363 (delegation: fix zero-args nested delegation ICE)
 - rust-lang/rust#154364 (delegation: don't propagate synthetic params, remove lifetime hacks)
 - rust-lang/rust#151148 (Add functions to `GrowableBitSet`)
 - rust-lang/rust#154090 (Move tests in the statics category)
 - rust-lang/rust#154112 (some `tests/ui/macros` cleanup)
 - rust-lang/rust#154131 (begin `tests/ui/structs-enums` cleanup)
 - rust-lang/rust#154216 (unstably mark `NonNull::with_exposed_provenance` as const)
 - rust-lang/rust#154230 (Moved and rename issue-50411 to tests/ui/mir/inliner-double-elaborate)
 - rust-lang/rust#154233 (Move ui/issues tests to relevant subdirectories)
 - rust-lang/rust#154288 (Fix typo in doc comment for `char::to_titlecase`)
 - rust-lang/rust#154355 (delegation: add const type ICE test)
 - rust-lang/rust#154358 (install-template.sh: Optimize by using Bourne shell builtins.)
 - rust-lang/rust#154360 (fromrangeiter-overflow-checks: accept optional `signext` for argument)
This commit is contained in:
bors
2026-03-25 20:01:44 +00:00
243 changed files with 1890 additions and 1782 deletions
+14 -2
View File
@@ -938,7 +938,7 @@ pub enum PatKind {
Never,
/// A guard pattern (e.g., `x if guard(x)`).
Guard(Box<Pat>, Box<Expr>),
Guard(Box<Pat>, Box<Guard>),
/// Parentheses in patterns used for grouping (i.e., `(PAT)`).
Paren(Box<Pat>),
@@ -1346,7 +1346,7 @@ pub struct Arm {
/// Match arm pattern, e.g. `10` in `match foo { 10 => {}, _ => {} }`.
pub pat: Box<Pat>,
/// Match arm guard, e.g. `n > 10` in `match foo { n if n > 10 => {}, _ => {} }`.
pub guard: Option<Box<Expr>>,
pub guard: Option<Box<Guard>>,
/// Match arm body. Omitted if the pattern is a never pattern.
pub body: Option<Box<Expr>>,
pub span: Span,
@@ -3954,6 +3954,18 @@ impl ConstBlockItem {
pub const IDENT: Ident = Ident { name: kw::Underscore, span: DUMMY_SP };
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct Guard {
pub cond: Expr,
pub span_with_leading_if: Span,
}
impl Guard {
pub fn span(&self) -> Span {
self.cond.span
}
}
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum ItemKind {
+5
View File
@@ -94,6 +94,7 @@ pub enum MetaVarKind {
},
Path,
Vis,
Guard,
TT,
}
@@ -114,6 +115,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
MetaVarKind::Meta { .. } => sym::meta,
MetaVarKind::Path => sym::path,
MetaVarKind::Vis => sym::vis,
MetaVarKind::Guard => sym::guard,
MetaVarKind::TT => sym::tt,
};
write!(f, "{sym}")
@@ -1124,6 +1126,7 @@ pub enum NonterminalKind {
Meta,
Path,
Vis,
Guard,
TT,
}
@@ -1161,6 +1164,7 @@ pub fn from_symbol(
sym::meta => NonterminalKind::Meta,
sym::path => NonterminalKind::Path,
sym::vis => NonterminalKind::Vis,
sym::guard => NonterminalKind::Guard,
sym::tt => NonterminalKind::TT,
_ => return None,
})
@@ -1182,6 +1186,7 @@ fn symbol(self) -> Symbol {
NonterminalKind::Meta => sym::meta,
NonterminalKind::Path => sym::path,
NonterminalKind::Vis => sym::vis,
NonterminalKind::Guard => sym::guard,
NonterminalKind::TT => sym::tt,
}
}
+1
View File
@@ -442,6 +442,7 @@ pub fn ctxt(&self) -> Option<FnCtxt> {
FormatArguments,
FormatPlaceholder,
GenericParamKind,
Guard,
Impl,
ImplPolarity,
Inline,
@@ -432,6 +432,17 @@ fn lower_delegation_body(
args.push(arg);
}
// If we have no params in signature function but user still wrote some code in
// delegation body, then add this code as first arg, eventually an error will be shown,
// also nested delegations may need to access information about this code (#154332),
// so it is better to leave this code as opposed to bodies of extern functions,
// which are completely erased from existence.
if param_count == 0
&& let Some(block) = block
{
args.push(this.lower_target_expr(&block));
}
let final_expr = this.finalize_body_lowering(delegation, args, generics, span);
(this.arena.alloc_from_iter(parameters), final_expr)
@@ -337,7 +337,6 @@ fn uplift_delegation_generic_params(
// HACK: for now we generate predicates such that all lifetimes are early bound,
// we can not not generate early-bound lifetimes, but we can't know which of them
// are late-bound at this level of compilation.
// FIXME(fn_delegation): proper support for late bound lifetimes.
let predicates =
self.arena.alloc_from_iter(params.iter().filter_map(|p| {
p.is_lifetime().then(|| self.generate_lifetime_predicate(p, span))
@@ -391,7 +390,7 @@ fn create_generics_args_from_params(
self.arena.alloc(hir::GenericArgs {
args: self.arena.alloc_from_iter(params.iter().filter_map(|p| {
// Skip self generic arg, we do not need to propagate it.
if p.name.ident().name == kw::SelfUpper {
if p.name.ident().name == kw::SelfUpper || p.is_impl_trait() {
return None;
}
+2 -2
View File
@@ -640,7 +640,7 @@ fn wrap_in_try_constructor(
fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
let pat = self.lower_pat(&arm.pat);
let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond));
let guard = arm.guard.as_ref().map(|guard| self.lower_expr(&guard.cond));
let hir_id = self.next_id();
let span = self.lower_span(arm.span);
self.lower_attrs(hir_id, &arm.attrs, arm.span, Target::Arm);
@@ -663,7 +663,7 @@ fn lower_arm(&mut self, arm: &Arm) -> hir::Arm<'hir> {
} else if let Some(body) = &arm.body {
self.dcx().emit_err(NeverPatternWithBody { span: body.span });
} else if let Some(g) = &arm.guard {
self.dcx().emit_err(NeverPatternWithGuard { span: g.span });
self.dcx().emit_err(NeverPatternWithGuard { span: g.span() });
}
// We add a fake `loop {}` arm body so that it typecks to `!`. The mir lowering of never
+5 -2
View File
@@ -133,8 +133,11 @@ fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
self.lower_range_end(end, e2.is_some()),
);
}
PatKind::Guard(inner, cond) => {
break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond));
PatKind::Guard(inner, guard) => {
break hir::PatKind::Guard(
self.lower_pat(inner),
self.lower_expr(&guard.cond),
);
}
PatKind::Slice(pats) => break self.lower_pat_slice(pats),
PatKind::Rest => {
@@ -1943,12 +1943,12 @@ fn print_pat(&mut self, pat: &ast::Pat) {
self.print_expr(e, FixupContext::default());
}
}
PatKind::Guard(subpat, condition) => {
PatKind::Guard(subpat, guard) => {
self.popen();
self.print_pat(subpat);
self.space();
self.word_space("if");
self.print_expr(condition, FixupContext::default());
self.print_expr(&guard.cond, FixupContext::default());
self.pclose();
}
PatKind::Slice(elts) => {
@@ -891,9 +891,9 @@ fn print_arm(&mut self, arm: &ast::Arm) {
self.print_outer_attributes(&arm.attrs);
self.print_pat(&arm.pat);
self.space();
if let Some(e) = &arm.guard {
if let Some(guard) = &arm.guard {
self.word_space("if");
self.print_expr(e, FixupContext::default());
self.print_expr(&guard.cond, FixupContext::default());
self.space();
}
@@ -582,6 +582,7 @@ impl<S: Stage> SingleAttributeParser<S> for SanitizeParser {
r#"kernel_address = "on|off""#,
r#"cfi = "on|off""#,
r#"hwaddress = "on|off""#,
r#"kernel_hwaddress = "on|off""#,
r#"kcfi = "on|off""#,
r#"memory = "on|off""#,
r#"memtag = "on|off""#,
@@ -648,7 +649,9 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
Some(sym::memtag) => apply(SanitizerSet::MEMTAG),
Some(sym::shadow_call_stack) => apply(SanitizerSet::SHADOWCALLSTACK),
Some(sym::thread) => apply(SanitizerSet::THREAD),
Some(sym::hwaddress) => apply(SanitizerSet::HWADDRESS),
Some(sym::hwaddress) | Some(sym::kernel_hwaddress) => {
apply(SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS)
}
Some(sym::realtime) => match value.value_as_str() {
Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking),
Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking),
@@ -673,6 +676,7 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<Attrib
sym::shadow_call_stack,
sym::thread,
sym::hwaddress,
sym::kernel_hwaddress,
sym::realtime,
],
);
@@ -120,7 +120,8 @@ pub(crate) fn sanitize_attrs<'ll, 'tcx>(
if enabled.contains(SanitizerSet::THREAD) {
attrs.push(llvm::AttributeKind::SanitizeThread.create_attr(cx.llcx));
}
if enabled.contains(SanitizerSet::HWADDRESS) {
if enabled.contains(SanitizerSet::HWADDRESS) || enabled.contains(SanitizerSet::KERNELHWADDRESS)
{
attrs.push(llvm::AttributeKind::SanitizeHWAddress.create_attr(cx.llcx));
}
if enabled.contains(SanitizerSet::SHADOWCALLSTACK) {
@@ -644,6 +644,10 @@ pub(crate) unsafe fn llvm_optimize(
sanitize_kernel_address_recover: config
.sanitizer_recover
.contains(SanitizerSet::KERNELADDRESS),
sanitize_kernel_hwaddress: config.sanitizer.contains(SanitizerSet::KERNELHWADDRESS),
sanitize_kernel_hwaddress_recover: config
.sanitizer_recover
.contains(SanitizerSet::KERNELHWADDRESS),
})
} else {
None
+6 -2
View File
@@ -210,10 +210,14 @@ pub(crate) fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
}
pub(crate) fn set_variable_sanitizer_attrs(llval: &Value, attrs: &CodegenFnAttrs) {
if attrs.sanitizers.disabled.contains(SanitizerSet::ADDRESS) {
if attrs.sanitizers.disabled.contains(SanitizerSet::ADDRESS)
|| attrs.sanitizers.disabled.contains(SanitizerSet::KERNELADDRESS)
{
unsafe { llvm::LLVMRustSetNoSanitizeAddress(llval) };
}
if attrs.sanitizers.disabled.contains(SanitizerSet::HWADDRESS) {
if attrs.sanitizers.disabled.contains(SanitizerSet::HWADDRESS)
|| attrs.sanitizers.disabled.contains(SanitizerSet::KERNELHWADDRESS)
{
unsafe { llvm::LLVMRustSetNoSanitizeHWAddress(llval) };
}
}
@@ -471,7 +471,7 @@ fn dbg_scope_fn(
// FIXME(eddyb) does this need to be separate from `loc.line` for some reason?
let scope_line = loc.line;
let mut flags = DIFlags::FlagPrototyped;
let mut flags = DIFlags::FlagPrototyped | DIFlags::FlagAllCallsDescribed;
if fn_abi.ret.layout.is_uninhabited() {
flags |= DIFlags::FlagNoReturn;
@@ -494,6 +494,9 @@ fn dbg_scope_fn(
// LLVM LTO can't unify type definitions when a child DIE is a full subprogram definition.
// When we use this `decl` below, the subprogram definition gets created at the CU level
// with a DW_AT_specification pointing back to the type's declaration.
// FlagAllCallsDescribed cannot appear on the method declaration DIE
// because it has no body, which LLVM's verifier rejects.
let decl_flags = flags & !DIFlags::FlagAllCallsDescribed;
let decl = is_method.then(|| unsafe {
llvm::LLVMRustDIBuilderCreateMethod(
DIB(self),
@@ -505,7 +508,7 @@ fn dbg_scope_fn(
file_metadata,
loc.line,
function_type_metadata,
flags,
decl_flags,
spflags & !DISPFlags::SPFlagDefinition,
template_parameters,
)
@@ -464,6 +464,8 @@ pub(crate) struct SanitizerOptions {
pub sanitize_hwaddress_recover: bool,
pub sanitize_kernel_address: bool,
pub sanitize_kernel_address_recover: bool,
pub sanitize_kernel_hwaddress: bool,
pub sanitize_kernel_hwaddress_recover: bool,
}
/// LLVMRustRelocModel
@@ -779,6 +781,7 @@ pub(crate) struct DIFlags: u32 {
const FlagNonTrivial = (1 << 26);
const FlagBigEndian = (1 << 27);
const FlagLittleEndian = (1 << 28);
const FlagAllCallsDescribed = (1 << 29);
}
}
@@ -88,7 +88,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
&ret.clone().into(),
ReturnContinuation::Stop { cleanup: false },
)?;
ecx.storage_live_for_always_live_locals()?;
ecx.push_stack_frame_done()?;
// The main interpreter loop.
while ecx.step()? {
+139 -147
View File
@@ -404,166 +404,158 @@ pub fn init_stack_frame(
// Push the "raw" frame -- this leaves locals uninitialized.
self.push_stack_frame_raw(instance, body, destination, cont)?;
let preamble_span = self.frame().loc.unwrap_right(); // the span used for preamble errors
// If an error is raised here, pop the frame again to get an accurate backtrace.
// To this end, we wrap it all in a `try` block.
let res: InterpResult<'tcx> = try {
trace!(
"caller ABI: {:#?}, args: {:#?}",
caller_fn_abi,
args.iter()
.map(|arg| (
arg.layout().ty,
match arg {
FnArg::Copy(op) => format!("copy({op:?})"),
FnArg::InPlace(mplace) => format!("in-place({mplace:?})"),
}
))
.collect::<Vec<_>>()
);
trace!(
"spread_arg: {:?}, locals: {:#?}",
body.spread_arg,
body.args_iter()
.map(|local| (
local,
self.layout_of_local(self.frame(), local, None).unwrap().ty,
))
.collect::<Vec<_>>()
);
// In principle, we have two iterators: Where the arguments come from, and where
// they go to.
// The "where they come from" part is easy, we expect the caller to do any special handling
// that might be required here (e.g. for untupling).
// If `with_caller_location` is set we pretend there is an extra argument (that
// we will not pass; our `caller_location` intrinsic implementation walks the stack instead).
assert_eq!(
args.len() + if with_caller_location { 1 } else { 0 },
caller_fn_abi.args.len(),
"mismatch between caller ABI and caller arguments",
);
let mut caller_args = args
.iter()
.zip(caller_fn_abi.args.iter())
.filter(|arg_and_abi| !arg_and_abi.1.is_ignore());
// Now we have to spread them out across the callee's locals,
// taking into account the `spread_arg`. If we could write
// this is a single iterator (that handles `spread_arg`), then
// `pass_argument` would be the loop body. It takes care to
// not advance `caller_iter` for ignored arguments.
let mut callee_args_abis = callee_fn_abi.args.iter().enumerate();
// Determine whether there is a special VaList argument. This is always the
// last argument, and since arguments start at index 1 that's `arg_count`.
let va_list_arg =
callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count));
for local in body.args_iter() {
// Construct the destination place for this argument. At this point all
// locals are still dead, so we cannot construct a `PlaceTy`.
let dest = mir::Place::from(local);
// `layout_of_local` does more than just the instantiation we need to get the
// type, but the result gets cached so this avoids calling the instantiation
// query *again* the next time this local is accessed.
let ty = self.layout_of_local(self.frame(), local, None)?.ty;
if Some(local) == va_list_arg {
// This is the last callee-side argument of a variadic function.
// This argument is a VaList holding the remaining caller-side arguments.
self.storage_live(local)?;
let place = self.eval_place(dest)?;
let mplace = self.force_allocation(&place)?;
// Consume the remaining arguments by putting them into the variable argument
// list.
let varargs = self.allocate_varargs(
&mut caller_args,
// "Ignored" arguments aren't actually passed, so the callee should also
// ignore them. (`pass_argument` does this for regular arguments.)
(&mut callee_args_abis).filter(|(_, abi)| !abi.is_ignore()),
)?;
// When the frame is dropped, these variable arguments are deallocated.
self.frame_mut().va_list = varargs.clone();
let key = self.va_list_ptr(varargs.into());
// Zero the VaList, so it is fully initialized.
self.write_bytes_ptr(
mplace.ptr(),
(0..mplace.layout.size.bytes()).map(|_| 0u8),
)?;
// Store the "key" pointer in the right field.
let key_mplace = self.va_list_key_field(&mplace)?;
self.write_pointer(key, &key_mplace)?;
} else if Some(local) == body.spread_arg {
// Make the local live once, then fill in the value field by field.
self.storage_live(local)?;
// Must be a tuple
let ty::Tuple(fields) = ty.kind() else {
span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}")
};
for (i, field_ty) in fields.iter().enumerate() {
let dest = dest.project_deeper(
&[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)],
*self.tcx,
);
let (idx, callee_abi) = callee_args_abis.next().unwrap();
self.pass_argument(
&mut caller_args,
callee_abi,
idx,
&dest,
field_ty,
/* already_live */ true,
)?;
trace!(
"caller ABI: {:#?}, args: {:#?}",
caller_fn_abi,
args.iter()
.map(|arg| (
arg.layout().ty,
match arg {
FnArg::Copy(op) => format!("copy({op:?})"),
FnArg::InPlace(mplace) => format!("in-place({mplace:?})"),
}
} else {
// Normal argument. Cannot mark it as live yet, it might be unsized!
))
.collect::<Vec<_>>()
);
trace!(
"spread_arg: {:?}, locals: {:#?}",
body.spread_arg,
body.args_iter()
.map(|local| (local, self.layout_of_local(self.frame(), local, None).unwrap().ty,))
.collect::<Vec<_>>()
);
// In principle, we have two iterators: Where the arguments come from, and where
// they go to.
// The "where they come from" part is easy, we expect the caller to do any special handling
// that might be required here (e.g. for untupling).
// If `with_caller_location` is set we pretend there is an extra argument (that
// we will not pass; our `caller_location` intrinsic implementation walks the stack instead).
assert_eq!(
args.len() + if with_caller_location { 1 } else { 0 },
caller_fn_abi.args.len(),
"mismatch between caller ABI and caller arguments",
);
let mut caller_args = args
.iter()
.zip(caller_fn_abi.args.iter())
.filter(|arg_and_abi| !arg_and_abi.1.is_ignore());
// Now we have to spread them out across the callee's locals,
// taking into account the `spread_arg`. If we could write
// this is a single iterator (that handles `spread_arg`), then
// `pass_argument` would be the loop body. It takes care to
// not advance `caller_iter` for ignored arguments.
let mut callee_args_abis = callee_fn_abi.args.iter().enumerate();
// Determine whether there is a special VaList argument. This is always the
// last argument, and since arguments start at index 1 that's `arg_count`.
let va_list_arg = callee_fn_abi.c_variadic.then(|| mir::Local::from_usize(body.arg_count));
for local in body.args_iter() {
// Update the span that we show in case of an error to point to this argument.
self.frame_mut().loc = Right(body.local_decls[local].source_info.span);
// Construct the destination place for this argument. At this point all
// locals are still dead, so we cannot construct a `PlaceTy`.
let dest = mir::Place::from(local);
// `layout_of_local` does more than just the instantiation we need to get the
// type, but the result gets cached so this avoids calling the instantiation
// query *again* the next time this local is accessed.
let ty = self.layout_of_local(self.frame(), local, None)?.ty;
if Some(local) == va_list_arg {
// This is the last callee-side argument of a variadic function.
// This argument is a VaList holding the remaining caller-side arguments.
self.storage_live(local)?;
let place = self.eval_place(dest)?;
let mplace = self.force_allocation(&place)?;
// Consume the remaining arguments by putting them into the variable argument
// list.
let varargs = self.allocate_varargs(
&mut caller_args,
// "Ignored" arguments aren't actually passed, so the callee should also
// ignore them. (`pass_argument` does this for regular arguments.)
(&mut callee_args_abis).filter(|(_, abi)| !abi.is_ignore()),
)?;
// When the frame is dropped, these variable arguments are deallocated.
self.frame_mut().va_list = varargs.clone();
let key = self.va_list_ptr(varargs.into());
// Zero the VaList, so it is fully initialized.
self.write_bytes_ptr(mplace.ptr(), (0..mplace.layout.size.bytes()).map(|_| 0u8))?;
// Store the "key" pointer in the right field.
let key_mplace = self.va_list_key_field(&mplace)?;
self.write_pointer(key, &key_mplace)?;
} else if Some(local) == body.spread_arg {
// Make the local live once, then fill in the value field by field.
self.storage_live(local)?;
// Must be a tuple
let ty::Tuple(fields) = ty.kind() else {
span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}")
};
for (i, field_ty) in fields.iter().enumerate() {
let dest = dest.project_deeper(
&[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)],
*self.tcx,
);
let (idx, callee_abi) = callee_args_abis.next().unwrap();
self.pass_argument(
&mut caller_args,
callee_abi,
idx,
&dest,
ty,
/* already_live */ false,
field_ty,
/* already_live */ true,
)?;
}
} else {
// Normal argument. Cannot mark it as live yet, it might be unsized!
let (idx, callee_abi) = callee_args_abis.next().unwrap();
self.pass_argument(
&mut caller_args,
callee_abi,
idx,
&dest,
ty,
/* already_live */ false,
)?;
}
// If the callee needs a caller location, pretend we consume one more argument from the ABI.
if instance.def.requires_caller_location(*self.tcx) {
callee_args_abis.next().unwrap();
}
// Now we should have no more caller args or callee arg ABIs.
assert!(
callee_args_abis.next().is_none(),
"mismatch between callee ABI and callee body arguments"
);
if caller_args.next().is_some() {
throw_ub_format!("calling a function with more arguments than it expected");
}
// Don't forget to check the return type!
if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
throw_ub!(AbiMismatchReturn {
caller_ty: caller_fn_abi.ret.layout.ty,
callee_ty: callee_fn_abi.ret.layout.ty
});
}
}
// Protect return place for in-place return value passing.
// We only need to protect anything if this is actually an in-memory place.
if let Some(mplace) = destination_mplace {
M::protect_in_place_function_argument(self, &mplace)?;
}
// Don't forget to check the return type!
self.frame_mut().loc = Right(body.local_decls[mir::RETURN_PLACE].source_info.span);
if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
throw_ub!(AbiMismatchReturn {
caller_ty: caller_fn_abi.ret.layout.ty,
callee_ty: callee_fn_abi.ret.layout.ty
});
}
// Protect return place for in-place return value passing.
// We only need to protect anything if this is actually an in-memory place.
if let Some(mplace) = destination_mplace {
M::protect_in_place_function_argument(self, &mplace)?;
}
// Don't forget to mark "initially live" locals as live.
self.storage_live_for_always_live_locals()?;
};
res.inspect_err_kind(|_| {
// Don't show the incomplete stack frame in the error stacktrace.
self.stack_mut().pop();
})
// For the final checks, use same span as preamble since it is unclear what else to do.
self.frame_mut().loc = Right(preamble_span);
// If the callee needs a caller location, pretend we consume one more argument from the ABI.
if instance.def.requires_caller_location(*self.tcx) {
callee_args_abis.next().unwrap();
}
// Now we should have no more caller args or callee arg ABIs.
assert!(
callee_args_abis.next().is_none(),
"mismatch between callee ABI and callee body arguments"
);
if caller_args.next().is_some() {
throw_ub_format!("calling a function with more arguments than it expected");
}
// Done!
self.push_stack_frame_done()
}
/// Initiate a call to this function -- pushing the stack frame and initializing the arguments.
@@ -381,7 +381,7 @@ pub(crate) fn push_stack_frame_raw(
let locals = IndexVec::from_elem(dead_local, &body.local_decls);
let pre_frame = Frame {
body,
loc: Right(body.span), // Span used for errors caused during preamble.
loc: Right(self.tcx.def_span(body.source.def_id())), // Span used for errors caused during preamble.
return_cont,
return_place: return_place.clone(),
locals,
@@ -408,7 +408,6 @@ pub(crate) fn push_stack_frame_raw(
// Finish things up.
M::after_stack_push(self)?;
self.frame_mut().loc = Left(mir::Location::START);
// `tracing_separate_thread` is used to instruct the tracing_chrome [tracing::Layer] in Miri
// to put the "frame" span on a separate trace thread/line than other spans, to make the
// visualization in <https://ui.perfetto.dev> easier to interpret. It is set to a value of
@@ -466,9 +465,11 @@ pub(super) fn cleanup_stack_frame(
}
}
/// In the current stack frame, mark all locals as live that are not arguments and don't have
/// `Storage*` annotations (this includes the return place).
pub(crate) fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tcx> {
/// Call this after `push_stack_frame_raw` and when all the other setup that needs to be done
/// is completed.
pub(crate) fn push_stack_frame_done(&mut self) -> InterpResult<'tcx> {
// Mark all locals as live that are not arguments and don't have `Storage*` annotations
// (this includes the return place, but not the arguments).
self.storage_live(mir::RETURN_PLACE)?;
let body = self.body();
@@ -478,6 +479,10 @@ pub(crate) fn storage_live_for_always_live_locals(&mut self) -> InterpResult<'tc
self.storage_live(local)?;
}
}
// Get ready to execute the first instruction in the stack frame.
self.frame_mut().loc = Left(mir::Location::START);
interp_ok(())
}
@@ -1532,6 +1532,7 @@ fn visit_value(&mut self, val: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'t
}
impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
/// The internal core entry point for all validation operations.
fn validate_operand_internal(
&mut self,
val: &PlaceTy<'tcx, M::Provenance>,
@@ -1539,6 +1540,7 @@ fn validate_operand_internal(
ref_tracking: Option<&mut RefTracking<MPlaceTy<'tcx, M::Provenance>, Path<'tcx>>>,
ctfe_mode: Option<CtfeValidationMode>,
reset_provenance_and_padding: bool,
start_in_may_dangle: bool,
) -> InterpResult<'tcx> {
trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty);
@@ -1556,7 +1558,7 @@ fn validate_operand_internal(
ecx,
reset_provenance_and_padding,
data_bytes: reset_padding.then_some(RangeSet(Vec::new())),
may_dangle: false,
may_dangle: start_in_may_dangle,
};
v.visit_value(val)?;
v.reset_padding(val)?;
@@ -1599,6 +1601,7 @@ pub(crate) fn const_validate_operand(
Some(ref_tracking),
Some(ctfe_mode),
/*reset_provenance*/ false,
/*start_in_may_dangle*/ false,
)
}
@@ -1629,6 +1632,7 @@ pub fn validate_operand(
None,
None,
reset_provenance_and_padding,
/*start_in_may_dangle*/ false,
);
}
// Do a recursive check.
@@ -1639,15 +1643,19 @@ pub fn validate_operand(
Some(&mut ref_tracking),
None,
reset_provenance_and_padding,
/*start_in_may_dangle*/ false,
)?;
while let Some((mplace, path)) = ref_tracking.todo.pop() {
// Things behind reference do *not* have the provenance reset.
// Things behind reference do *not* have the provenance reset. In fact
// we treat the entire thing as being inside MaybeDangling, i.e., references
// do not have to be dereferenceable.
self.validate_operand_internal(
&mplace.into(),
path,
Some(&mut ref_tracking),
None, // no further recursion
None,
/*reset_provenance_and_padding*/ false,
/*start_in_may_dangle*/ true,
)?;
}
interp_ok(())
-1
View File
@@ -5,7 +5,6 @@
#![feature(never_type)]
#![feature(slice_ptr_get)]
#![feature(trait_alias)]
#![feature(try_blocks)]
#![feature(unqualified_local_imports)]
#![feature(yeet_expr)]
#![warn(unqualified_local_imports)]
+48 -10
View File
@@ -724,7 +724,7 @@ pub fn compile_declarative_macro(
let args = p.parse_token_tree();
check_args_parens(sess, sym::attr, &args);
let args = parse_one_tt(args, RulePart::Pattern, sess, node_id, features, edition);
check_emission(check_lhs(sess, node_id, &args));
check_emission(check_lhs(sess, features, node_id, &args));
if let Some(guar) = check_no_eof(sess, &p, "expected macro attr body") {
return dummy_syn_ext(guar);
}
@@ -773,7 +773,7 @@ pub fn compile_declarative_macro(
};
let lhs_tt = p.parse_token_tree();
let lhs_tt = parse_one_tt(lhs_tt, RulePart::Pattern, sess, node_id, features, edition);
check_emission(check_lhs(sess, node_id, &lhs_tt));
check_emission(check_lhs(sess, features, node_id, &lhs_tt));
if let Err(e) = p.expect(exp!(FatArrow)) {
return dummy_syn_ext(e.emit());
}
@@ -870,21 +870,27 @@ fn check_args_empty(sess: &Session, args: &tokenstream::TokenTree) -> Result<(),
}
}
fn check_lhs(sess: &Session, node_id: NodeId, lhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed> {
let e1 = check_lhs_nt_follows(sess, node_id, lhs);
fn check_lhs(
sess: &Session,
features: &Features,
node_id: NodeId,
lhs: &mbe::TokenTree,
) -> Result<(), ErrorGuaranteed> {
let e1 = check_lhs_nt_follows(sess, features, node_id, lhs);
let e2 = check_lhs_no_empty_seq(sess, slice::from_ref(lhs));
e1.and(e2)
}
fn check_lhs_nt_follows(
sess: &Session,
features: &Features,
node_id: NodeId,
lhs: &mbe::TokenTree,
) -> Result<(), ErrorGuaranteed> {
// lhs is going to be like TokenTree::Delimited(...), where the
// entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens.
if let mbe::TokenTree::Delimited(.., delimited) = lhs {
check_matcher(sess, node_id, &delimited.tts)
check_matcher(sess, features, node_id, &delimited.tts)
} else {
let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
Err(sess.dcx().span_err(lhs.span(), msg))
@@ -989,12 +995,13 @@ fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed
fn check_matcher(
sess: &Session,
features: &Features,
node_id: NodeId,
matcher: &[mbe::TokenTree],
) -> Result<(), ErrorGuaranteed> {
let first_sets = FirstSets::new(matcher);
let empty_suffix = TokenSet::empty();
check_matcher_core(sess, node_id, &first_sets, matcher, &empty_suffix)?;
check_matcher_core(sess, features, node_id, &first_sets, matcher, &empty_suffix)?;
Ok(())
}
@@ -1331,6 +1338,7 @@ fn add_all(&mut self, other: &Self) {
// see `FirstSets::new`.
fn check_matcher_core<'tt>(
sess: &Session,
features: &Features,
node_id: NodeId,
first_sets: &FirstSets<'tt>,
matcher: &'tt [mbe::TokenTree],
@@ -1369,6 +1377,17 @@ fn check_matcher_core<'tt>(
| TokenTree::MetaVar(..)
| TokenTree::MetaVarDecl { .. }
| TokenTree::MetaVarExpr(..) => {
if let TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } = token
&& !features.macro_guard_matcher()
{
feature_err(
sess,
sym::macro_guard_matcher,
token.span(),
"`guard` fragments in macro are unstable",
)
.emit();
}
if token_can_be_followed_by_any(token) {
// don't need to track tokens that work with any,
last.replace_with_irrelevant();
@@ -1385,7 +1404,7 @@ fn check_matcher_core<'tt>(
d.delim.as_close_token_kind(),
span.close,
));
check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?;
check_matcher_core(sess, features, node_id, first_sets, &d.tts, &my_suffix)?;
// don't track non NT tokens
last.replace_with_irrelevant();
@@ -1417,7 +1436,14 @@ fn check_matcher_core<'tt>(
// At this point, `suffix_first` is built, and
// `my_suffix` is some TokenSet that we can use
// for checking the interior of `seq_rep`.
let next = check_matcher_core(sess, node_id, first_sets, &seq_rep.tts, my_suffix)?;
let next = check_matcher_core(
sess,
features,
node_id,
first_sets,
&seq_rep.tts,
my_suffix,
)?;
if next.maybe_empty {
last.add_all(&next);
} else {
@@ -1609,7 +1635,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
}
}
NonterminalKind::Pat(PatParam { .. }) => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`if let`", "`in`"];
match tok {
TokenTree::Token(token) => match token.kind {
FatArrow | Comma | Eq | Or => IsInFollow::Yes,
@@ -1618,11 +1644,12 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
}
_ => IsInFollow::No(TOKENS),
},
TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } => IsInFollow::Yes,
_ => IsInFollow::No(TOKENS),
}
}
NonterminalKind::Pat(PatWithOr) => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`in`"];
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`if`", "`if let`", "`in`"];
match tok {
TokenTree::Token(token) => match token.kind {
FatArrow | Comma | Eq => IsInFollow::Yes,
@@ -1631,6 +1658,17 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
}
_ => IsInFollow::No(TOKENS),
},
TokenTree::MetaVarDecl { kind: NonterminalKind::Guard, .. } => IsInFollow::Yes,
_ => IsInFollow::No(TOKENS),
}
}
NonterminalKind::Guard => {
const TOKENS: &[&str] = &["`=>`", "`,`", "`{`"];
match tok {
TokenTree::Token(token) => match token.kind {
FatArrow | Comma | OpenBrace => IsInFollow::Yes,
_ => IsInFollow::No(TOKENS),
},
_ => IsInFollow::No(TOKENS),
}
}
+15 -1
View File
@@ -12,7 +12,8 @@
use rustc_session::parse::ParseSess;
use rustc_span::hygiene::{LocalExpnId, Transparency};
use rustc_span::{
Ident, MacroRulesNormalizedIdent, Span, Symbol, SyntaxContext, sym, with_metavar_spans,
BytePos, Ident, MacroRulesNormalizedIdent, Span, Symbol, SyntaxContext, kw, sym,
with_metavar_spans,
};
use smallvec::{SmallVec, smallvec};
@@ -556,6 +557,19 @@ fn transcribe_pnr<'tx>(
ParseNtResult::Vis(vis) => {
mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis))
}
ParseNtResult::Guard(guard) => {
// FIXME(macro_guard_matcher):
// Perhaps it would be better to treat the leading `if` as part of `ast::Guard` during parsing?
// Currently they are separate, but in macros we match and emit the leading `if` for `:guard` matchers, which creates some inconsistency.
let leading_if_span =
guard.span_with_leading_if.with_hi(guard.span_with_leading_if.lo() + BytePos(2));
let mut ts =
TokenStream::token_alone(token::Ident(kw::If, IdentIsRaw::No), leading_if_span);
ts.push_stream(TokenStream::from_ast(&guard.cond));
mk_delimited(guard.span_with_leading_if, MetaVarKind::Guard, ts)
}
};
tscx.result.push(tt);
+1 -1
View File
@@ -773,7 +773,7 @@ pub struct BuiltinAttribute {
DuplicatesOk, EncodeCrossCrate::No, effective_target_features, experimental!(force_target_feature)
),
gated!(
sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding,
sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kernel_hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding,
EncodeCrossCrate::No, sanitize, experimental!(sanitize),
),
gated!(
+2
View File
@@ -569,6 +569,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, macro_attr, "1.91.0", Some(143547)),
/// Allow `macro_rules!` derive rules
(unstable, macro_derive, "1.91.0", Some(143549)),
/// Allow `$x:guard` matcher in macros
(unstable, macro_guard_matcher, "CURRENT_RUSTC_VERSION", Some(153104)),
/// Give access to additional metadata about declarative macro meta-variables.
(unstable, macro_metavar_expr, "1.61.0", Some(83527)),
/// Provides a way to concatenate identifiers using metavariable expressions.
@@ -138,7 +138,6 @@ fn create_mapping<'tcx>(
tcx: TyCtxt<'tcx>,
sig_id: DefId,
def_id: LocalDefId,
args: &[ty::GenericArg<'tcx>],
) -> FxHashMap<u32, u32> {
let mut mapping: FxHashMap<u32, u32> = Default::default();
@@ -176,13 +175,6 @@ fn create_mapping<'tcx>(
}
}
// If there are still unmapped lifetimes left and we are to map types and maybe self
// then skip them, now it is the case when we generated more lifetimes then needed.
// FIXME(fn_delegation): proper support for late bound lifetimes.
while args_index < args.len() && args[args_index].as_region().is_some() {
args_index += 1;
}
// If self after lifetimes insert mapping, relying that self is at 0 in sig parent.
if matches!(self_pos_kind, SelfPositionKind::AfterLifetimes) {
mapping.insert(0, args_index as u32);
@@ -511,7 +503,7 @@ fn create_folder_and_args<'tcx>(
child_args: &'tcx [ty::GenericArg<'tcx>],
) -> (ParamIndexRemapper<'tcx>, Vec<ty::GenericArg<'tcx>>) {
let args = create_generic_args(tcx, sig_id, def_id, parent_args, child_args);
let remap_table = create_mapping(tcx, sig_id, def_id, &args);
let remap_table = create_mapping(tcx, sig_id, def_id);
(ParamIndexRemapper { tcx, remap_table }, args)
}
+24
View File
@@ -1323,6 +1323,12 @@ pub fn insert(&mut self, elem: T) -> bool {
self.bit_set.insert(elem)
}
#[inline]
pub fn insert_range(&mut self, elems: Range<T>) {
self.ensure(elems.end.index());
self.bit_set.insert_range(elems);
}
/// Returns `true` if the set has changed.
#[inline]
pub fn remove(&mut self, elem: T) -> bool {
@@ -1330,6 +1336,16 @@ pub fn remove(&mut self, elem: T) -> bool {
self.bit_set.remove(elem)
}
#[inline]
pub fn clear(&mut self) {
self.bit_set.clear();
}
#[inline]
pub fn count(&self) -> usize {
self.bit_set.count()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.bit_set.is_empty()
@@ -1341,6 +1357,14 @@ pub fn contains(&self, elem: T) -> bool {
self.bit_set.words.get(word_index).is_some_and(|word| (word & mask) != 0)
}
#[inline]
pub fn contains_any(&self, elems: Range<T>) -> bool {
elems.start.index() < self.bit_set.domain_size
&& self
.bit_set
.contains_any(elems.start..T::new(elems.end.index().min(self.bit_set.domain_size)))
}
#[inline]
pub fn iter(&self) -> BitIter<'_, T> {
self.bit_set.iter()
@@ -540,6 +540,8 @@ struct LLVMRustSanitizerOptions {
bool SanitizeHWAddressRecover;
bool SanitizeKernelAddress;
bool SanitizeKernelAddressRecover;
bool SanitizeKernelHWAddress;
bool SanitizeKernelHWAddressRecover;
};
extern "C" typedef void (*registerEnzymeAndPassPipelineFn)(
@@ -767,13 +769,15 @@ extern "C" LLVMRustResult LLVMRustOptimize(
!TM->getTargetTriple().isOSWindows()));
});
}
if (SanitizerOptions->SanitizeHWAddress) {
if (SanitizerOptions->SanitizeHWAddress ||
SanitizerOptions->SanitizeKernelHWAddress) {
OptimizerLastEPCallbacks.push_back(
[SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level,
ThinOrFullLTOPhase phase) {
HWAddressSanitizerOptions opts(
/*CompileKernel=*/false,
SanitizerOptions->SanitizeHWAddressRecover,
SanitizerOptions->SanitizeKernelHWAddress,
SanitizerOptions->SanitizeHWAddressRecover ||
SanitizerOptions->SanitizeKernelHWAddressRecover,
/*DisableOptimization=*/false);
MPM.addPass(HWAddressSanitizerPass(opts));
});
@@ -779,6 +779,7 @@ ASSERT_DIFLAG_VALUE(FlagThunk, 1 << 25);
ASSERT_DIFLAG_VALUE(FlagNonTrivial, 1 << 26);
ASSERT_DIFLAG_VALUE(FlagBigEndian, 1 << 27);
ASSERT_DIFLAG_VALUE(FlagLittleEndian, 1 << 28);
static_assert(DINode::DIFlags::FlagAllCallsDescribed == (1 << 29));
ASSERT_DIFLAG_VALUE(FlagIndirectVirtualBase, (1 << 2) | (1 << 5));
#undef ASSERT_DIFLAG_VALUE
@@ -791,7 +792,7 @@ ASSERT_DIFLAG_VALUE(FlagIndirectVirtualBase, (1 << 2) | (1 << 5));
// to copying each bit/subvalue.
static DINode::DIFlags fromRust(LLVMDIFlags Flags) {
// Check that all set bits are covered by the static assertions above.
const unsigned UNKNOWN_BITS = (1 << 31) | (1 << 30) | (1 << 29) | (1 << 21);
const unsigned UNKNOWN_BITS = (1 << 31) | (1 << 30) | (1 << 21);
if (Flags & UNKNOWN_BITS) {
report_fatal_error("bad LLVMDIFlags");
}
+69 -295
View File
@@ -10,13 +10,12 @@
use std::mem::MaybeUninit;
use rustc_ast::tokenstream::TokenStream;
use rustc_data_structures::steal::Steal;
use rustc_span::{ErrorGuaranteed, Spanned};
use crate::mir::interpret::EvalToValTreeResult;
use crate::mir::mono::{MonoItem, NormalizationErrorInMono};
use crate::traits::solve;
use crate::ty::{self, Ty, TyCtxt};
use crate::{mir, traits};
use crate::{mir, thir, traits};
/// Internal implementation detail of [`Erased`].
#[derive(Copy, Clone)]
@@ -101,192 +100,42 @@ pub fn restore_val<T: Erasable>(erased_value: Erased<T>) -> T {
// FIXME(#151565): Using `T: ?Sized` here should let us remove the separate
// impls for fat reference types.
impl<T> Erasable for &'_ T {
type Storage = [u8; size_of::<&'static ()>()];
type Storage = [u8; size_of::<&'_ ()>()];
}
impl<T> Erasable for &'_ [T] {
type Storage = [u8; size_of::<&'static [()]>()];
}
impl Erasable for &'_ OsStr {
type Storage = [u8; size_of::<&'static OsStr>()];
type Storage = [u8; size_of::<&'_ [()]>()];
}
impl<T> Erasable for &'_ ty::List<T> {
type Storage = [u8; size_of::<&'static ty::List<()>>()];
type Storage = [u8; size_of::<&'_ ty::List<()>>()];
}
impl<T> Erasable for &'_ ty::ListWithCachedTypeInfo<T> {
type Storage = [u8; size_of::<&'static ty::ListWithCachedTypeInfo<()>>()];
}
impl<I: rustc_index::Idx, T> Erasable for &'_ rustc_index::IndexSlice<I, T> {
type Storage = [u8; size_of::<&'static rustc_index::IndexSlice<u32, ()>>()];
type Storage = [u8; size_of::<&'_ ty::ListWithCachedTypeInfo<()>>()];
}
impl<T> Erasable for Result<&'_ T, traits::query::NoSolution> {
type Storage = [u8; size_of::<Result<&'static (), traits::query::NoSolution>>()];
type Storage = [u8; size_of::<Result<&'_ (), traits::query::NoSolution>>()];
}
impl<T> Erasable for Result<&'_ [T], traits::query::NoSolution> {
type Storage = [u8; size_of::<Result<&'static [()], traits::query::NoSolution>>()];
}
impl<T> Erasable for Result<&'_ T, rustc_errors::ErrorGuaranteed> {
type Storage = [u8; size_of::<Result<&'static (), rustc_errors::ErrorGuaranteed>>()];
}
impl<T> Erasable for Result<&'_ [T], rustc_errors::ErrorGuaranteed> {
type Storage = [u8; size_of::<Result<&'static [()], rustc_errors::ErrorGuaranteed>>()];
}
impl<T> Erasable for Result<&'_ T, traits::CodegenObligationError> {
type Storage = [u8; size_of::<Result<&'static (), traits::CodegenObligationError>>()];
}
impl<T> Erasable for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> {
type Storage = [u8; size_of::<Result<&'static (), &'static ty::layout::FnAbiError<'static>>>()];
}
impl<T> Erasable for Result<(&'_ T, crate::thir::ExprId), rustc_errors::ErrorGuaranteed> {
type Storage = [u8; size_of::<
Result<(&'static (), crate::thir::ExprId), rustc_errors::ErrorGuaranteed>,
>()];
}
impl Erasable for Result<Option<ty::Instance<'_>>, rustc_errors::ErrorGuaranteed> {
type Storage =
[u8; size_of::<Result<Option<ty::Instance<'static>>, rustc_errors::ErrorGuaranteed>>()];
}
impl Erasable
for Result<Option<ty::EarlyBinder<'_, ty::Const<'_>>>, rustc_errors::ErrorGuaranteed>
{
type Storage = [u8; size_of::<
Result<Option<ty::EarlyBinder<'static, ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
>()];
}
impl Erasable for Result<ty::GenericArg<'_>, traits::query::NoSolution> {
type Storage = [u8; size_of::<Result<ty::GenericArg<'static>, traits::query::NoSolution>>()];
}
impl Erasable for Result<bool, &ty::layout::LayoutError<'_>> {
type Storage = [u8; size_of::<Result<bool, &'static ty::layout::LayoutError<'static>>>()];
}
impl Erasable for Result<rustc_abi::TyAndLayout<'_, Ty<'_>>, &ty::layout::LayoutError<'_>> {
type Storage = [u8; size_of::<
Result<
rustc_abi::TyAndLayout<'static, Ty<'static>>,
&'static ty::layout::LayoutError<'static>,
>,
>()];
}
impl Erasable for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
type Storage =
[u8; size_of::<Result<mir::ConstAlloc<'static>, mir::interpret::ErrorHandled>>()];
}
impl Erasable for Option<(mir::ConstValue, Ty<'_>)> {
type Storage = [u8; size_of::<Option<(mir::ConstValue, Ty<'_>)>>()];
}
impl Erasable for EvalToValTreeResult<'_> {
type Storage = [u8; size_of::<EvalToValTreeResult<'static>>()];
}
impl Erasable for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {
type Storage =
[u8; size_of::<Result<&'static ty::List<Ty<'static>>, ty::util::AlwaysRequiresDrop>>()];
}
impl Erasable
for Result<(&'_ [Spanned<MonoItem<'_>>], &'_ [Spanned<MonoItem<'_>>]), NormalizationErrorInMono>
{
type Storage = [u8; size_of::<
Result<
(&'static [Spanned<MonoItem<'static>>], &'static [Spanned<MonoItem<'static>>]),
NormalizationErrorInMono,
>,
>()];
}
impl Erasable for Result<&'_ TokenStream, ()> {
type Storage = [u8; size_of::<Result<&'static TokenStream, ()>>()];
impl<T> Erasable for Result<&'_ T, ErrorGuaranteed> {
type Storage = [u8; size_of::<Result<&'_ (), ErrorGuaranteed>>()];
}
impl<T> Erasable for Option<&'_ T> {
type Storage = [u8; size_of::<Option<&'static ()>>()];
}
impl<T> Erasable for Option<&'_ [T]> {
type Storage = [u8; size_of::<Option<&'static [()]>>()];
}
impl Erasable for Option<&'_ OsStr> {
type Storage = [u8; size_of::<Option<&'static OsStr>>()];
}
impl Erasable for Option<mir::DestructuredConstant<'_>> {
type Storage = [u8; size_of::<Option<mir::DestructuredConstant<'static>>>()];
}
impl Erasable for ty::ImplTraitHeader<'_> {
type Storage = [u8; size_of::<ty::ImplTraitHeader<'static>>()];
}
impl Erasable for Option<ty::EarlyBinder<'_, Ty<'_>>> {
type Storage = [u8; size_of::<Option<ty::EarlyBinder<'static, Ty<'static>>>>()];
}
impl Erasable for Option<ty::Value<'_>> {
type Storage = [u8; size_of::<Option<ty::Value<'static>>>()];
}
impl Erasable for rustc_hir::MaybeOwner<'_> {
type Storage = [u8; size_of::<rustc_hir::MaybeOwner<'static>>()];
type Storage = [u8; size_of::<Option<&'_ ()>>()];
}
impl<T: Erasable> Erasable for ty::EarlyBinder<'_, T> {
type Storage = T::Storage;
}
impl Erasable for ty::Binder<'_, ty::FnSig<'_>> {
type Storage = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
}
impl Erasable for ty::Binder<'_, ty::CoroutineWitnessTypes<TyCtxt<'_>>> {
type Storage =
[u8; size_of::<ty::Binder<'static, ty::CoroutineWitnessTypes<TyCtxt<'static>>>>()];
}
impl Erasable for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
type Storage = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
}
impl<T0, T1> Erasable for (&'_ T0, &'_ T1) {
type Storage = [u8; size_of::<(&'static (), &'static ())>()];
type Storage = [u8; size_of::<(&'_ (), &'_ ())>()];
}
impl<T0> Erasable for (solve::QueryResult<'_>, &'_ T0) {
type Storage = [u8; size_of::<(solve::QueryResult<'static>, &'static ())>()];
}
impl<T0, T1> Erasable for (&'_ T0, &'_ [T1]) {
type Storage = [u8; size_of::<(&'static (), &'static [()])>()];
}
impl<T0, T1> Erasable for (&'_ [T0], &'_ [T1]) {
type Storage = [u8; size_of::<(&'static [()], &'static [()])>()];
}
impl<T0> Erasable for (&'_ T0, Result<(), ErrorGuaranteed>) {
type Storage = [u8; size_of::<(&'static (), Result<(), ErrorGuaranteed>)>()];
}
macro_rules! impl_erasable_for_simple_types {
macro_rules! impl_erasable_for_types_with_no_type_params {
($($ty:ty),+ $(,)?) => {
$(
impl Erasable for $ty {
@@ -296,171 +145,96 @@ impl Erasable for $ty {
}
}
// For concrete types with no lifetimes, the erased storage for `Foo` is
// `[u8; size_of::<Foo>()]`.
impl_erasable_for_simple_types! {
// FIXME(#151565): Add `tidy-alphabetical-{start,end}` and sort this.
// For types with no type parameters the erased storage for `Foo` is
// `[u8; size_of::<Foo>()]`. ('_ lifetimes are allowed.)
impl_erasable_for_types_with_no_type_params! {
// tidy-alphabetical-start
(&'_ ty::CrateInherentImpls, Result<(), ErrorGuaranteed>),
(),
bool,
(traits::solve::QueryResult<'_>, &'_ traits::solve::inspect::Probe<TyCtxt<'_>>),
Option<&'_ OsStr>,
Option<&'_ [rustc_hir::PreciseCapturingArgKind<rustc_span::Symbol, rustc_span::Symbol>]>,
Option<(mir::ConstValue, Ty<'_>)>,
Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>,
Option<rustc_abi::Align>,
Option<rustc_ast::expand::allocator::AllocatorKind>,
Option<rustc_data_structures::svh::Svh>,
Option<rustc_hir::ConstStability>,
Option<rustc_hir::CoroutineKind>,
Option<rustc_hir::DefaultBodyStability>,
Option<rustc_hir::Stability>,
Option<rustc_data_structures::svh::Svh>,
Option<rustc_hir::def::DefKind>,
Option<rustc_hir::CoroutineKind>,
Option<rustc_hir::HirId>,
Option<rustc_middle::middle::stability::DeprecationEntry>,
Option<rustc_middle::ty::AsyncDestructor>,
Option<rustc_middle::ty::Destructor>,
Option<rustc_middle::ty::ImplTraitInTraitData>,
Option<rustc_middle::ty::IntrinsicDef>,
Option<rustc_middle::ty::ScalarInt>,
Option<rustc_span::Span>,
Option<rustc_span::def_id::CrateNum>,
Option<rustc_span::def_id::DefId>,
Option<rustc_span::def_id::LocalDefId>,
Option<rustc_span::Span>,
Option<rustc_abi::FieldIdx>,
Option<rustc_target::spec::PanicStrategy>,
Option<ty::EarlyBinder<'_, Ty<'_>>>,
Option<ty::Value<'_>>,
Option<usize>,
Option<rustc_middle::ty::IntrinsicDef>,
Option<rustc_abi::Align>,
Result<(), rustc_errors::ErrorGuaranteed>,
Result<(), rustc_middle::traits::query::NoSolution>,
Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>,
Result<rustc_middle::ty::adjustment::CoerceUnsizedInfo, rustc_errors::ErrorGuaranteed>,
Result<&'_ TokenStream, ()>,
Result<&'_ rustc_target::callconv::FnAbi<'_, Ty<'_>>, &'_ ty::layout::FnAbiError<'_>>,
Result<&'_ traits::ImplSource<'_, ()>, traits::CodegenObligationError>,
Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop>,
Result<(&'_ Steal<thir::Thir<'_>>, thir::ExprId), ErrorGuaranteed>,
Result<(&'_ [Spanned<MonoItem<'_>>], &'_ [Spanned<MonoItem<'_>>]), NormalizationErrorInMono>,
Result<(), ErrorGuaranteed>,
Result<Option<ty::EarlyBinder<'_, ty::Const<'_>>>, ErrorGuaranteed>,
Result<Option<ty::Instance<'_>>, ErrorGuaranteed>,
Result<bool, &ty::layout::LayoutError<'_>>,
Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled>,
Result<mir::ConstValue, mir::interpret::ErrorHandled>,
rustc_abi::ReprOptions,
rustc_ast::expand::allocator::AllocatorKind,
rustc_hir::DefaultBodyStability,
rustc_hir::attrs::Deprecation,
rustc_hir::attrs::EiiDecl,
rustc_hir::attrs::EiiImpl,
Result<rustc_abi::TyAndLayout<'_, Ty<'_>>, &ty::layout::LayoutError<'_>>,
Result<rustc_middle::traits::EvaluationResult, rustc_middle::traits::OverflowError>,
Result<rustc_middle::ty::adjustment::CoerceUnsizedInfo, ErrorGuaranteed>,
Result<ty::GenericArg<'_>, traits::query::NoSolution>,
Ty<'_>,
bool,
rustc_data_structures::svh::Svh,
rustc_errors::ErrorGuaranteed,
rustc_hir::Constness,
rustc_hir::ConstStability,
rustc_hir::def_id::DefId,
rustc_hir::def_id::DefIndex,
rustc_hir::def_id::LocalDefId,
rustc_hir::def_id::LocalModDefId,
rustc_hir::def::DefKind,
rustc_hir::Defaultness,
rustc_hir::definitions::DefKey,
rustc_hir::CoroutineKind,
rustc_hir::HirId,
rustc_hir::IsAsync,
rustc_hir::ItemLocalId,
rustc_hir::LangItem,
rustc_hir::MaybeOwner<'_>,
rustc_hir::OpaqueTyOrigin<rustc_hir::def_id::DefId>,
rustc_hir::OwnerId,
rustc_hir::Stability,
rustc_hir::Upvar,
rustc_middle::middle::deduced_param_attrs::DeducedParamAttrs,
rustc_middle::middle::dependency_format::Linkage,
rustc_middle::middle::exported_symbols::SymbolExportInfo,
rustc_hir::def::DefKind,
rustc_hir::def_id::DefId,
rustc_middle::middle::codegen_fn_attrs::SanitizerFnAttrs,
rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault,
rustc_middle::middle::resolve_bound_vars::ResolvedArg,
rustc_middle::middle::stability::DeprecationEntry,
rustc_middle::mir::ConstQualifs,
rustc_middle::mir::ConstValue,
rustc_middle::mir::interpret::AllocId,
rustc_middle::mir::interpret::CtfeProvenance,
rustc_middle::mir::interpret::ErrorHandled,
rustc_middle::thir::ExprId,
rustc_middle::traits::CodegenObligationError,
rustc_middle::traits::EvaluationResult,
rustc_middle::traits::OverflowError,
rustc_middle::traits::query::NoSolution,
rustc_middle::traits::WellFormedLoc,
rustc_middle::ty::adjustment::CoerceUnsizedInfo,
rustc_middle::ty::AssocItem,
rustc_middle::ty::AssocContainer,
rustc_middle::ty::Asyncness,
rustc_middle::ty::AsyncDestructor,
rustc_middle::mir::interpret::EvalStaticInitializerRawResult<'_>,
rustc_middle::mir::interpret::EvalToValTreeResult<'_>,
rustc_middle::mir::mono::MonoItemPartitions<'_>,
rustc_middle::traits::query::MethodAutoderefStepsResult<'_>,
rustc_middle::ty::AdtDef<'_>,
rustc_middle::ty::AnonConstKind,
rustc_middle::ty::Destructor,
rustc_middle::ty::fast_reject::SimplifiedType,
rustc_middle::ty::ImplPolarity,
rustc_middle::ty::util::AlwaysRequiresDrop,
rustc_middle::ty::AssocItem,
rustc_middle::ty::Asyncness,
rustc_middle::ty::Binder<'_, ty::CoroutineWitnessTypes<TyCtxt<'_>>>,
rustc_middle::ty::Binder<'_, ty::FnSig<'_>>,
rustc_middle::ty::ClosureTypeInfo<'_>,
rustc_middle::ty::Const<'_>,
rustc_middle::ty::ConstConditions<'_>,
rustc_middle::ty::GenericPredicates<'_>,
rustc_middle::ty::ImplTraitHeader<'_>,
rustc_middle::ty::ParamEnv<'_>,
rustc_middle::ty::SymbolName<'_>,
rustc_middle::ty::TypingEnv<'_>,
rustc_middle::ty::Visibility<rustc_span::def_id::DefId>,
rustc_middle::middle::codegen_fn_attrs::SanitizerFnAttrs,
rustc_session::config::CrateType,
rustc_session::config::EntryFnType,
rustc_middle::ty::inhabitedness::InhabitedPredicate<'_>,
rustc_session::Limits,
rustc_session::config::OptLevel,
rustc_session::config::SymbolManglingVersion,
rustc_session::cstore::CrateDepKind,
rustc_session::cstore::ExternCrate,
rustc_session::cstore::LinkagePreference,
rustc_session::Limits,
rustc_session::lint::LintExpectationId,
rustc_span::def_id::CrateNum,
rustc_span::def_id::DefPathHash,
rustc_span::ExpnHash,
rustc_span::ExpnId,
rustc_span::Span,
rustc_span::Symbol,
rustc_span::Ident,
rustc_target::spec::PanicStrategy,
rustc_type_ir::Variance,
u32,
usize,
}
macro_rules! impl_erasable_for_single_lifetime_types {
($($($fake_path:ident)::+),+ $(,)?) => {
$(
impl<'tcx> Erasable for $($fake_path)::+<'tcx> {
type Storage = [u8; size_of::<$($fake_path)::+<'static>>()];
}
)*
}
}
// For types containing a single lifetime and no other generics, e.g.
// `Foo<'tcx>`, the erased storage is `[u8; size_of::<Foo<'static>>()]`.
//
// FIXME(#151565): Some of the hand-written impls above that only use one
// lifetime can probably be migrated here.
impl_erasable_for_single_lifetime_types! {
// FIXME(#151565): Add `tidy-alphabetical-{start,end}` and sort this.
rustc_middle::middle::exported_symbols::ExportedSymbol,
rustc_middle::mir::Const,
rustc_middle::mir::DestructuredConstant,
rustc_middle::mir::ConstAlloc,
rustc_middle::mir::interpret::GlobalId,
rustc_middle::mir::interpret::EvalStaticInitializerRawResult,
rustc_middle::mir::mono::MonoItemPartitions,
rustc_middle::traits::query::MethodAutoderefStepsResult,
rustc_middle::traits::query::type_op::AscribeUserType,
rustc_middle::traits::query::type_op::Eq,
rustc_middle::traits::query::type_op::ProvePredicate,
rustc_middle::traits::query::type_op::Subtype,
rustc_middle::ty::AdtDef,
rustc_middle::ty::AliasTy,
rustc_middle::ty::ClauseKind,
rustc_middle::ty::ClosureTypeInfo,
rustc_middle::ty::Const,
rustc_middle::ty::DestructuredAdtConst,
rustc_middle::ty::ExistentialTraitRef,
rustc_middle::ty::FnSig,
rustc_middle::ty::GenericArg,
rustc_middle::ty::GenericPredicates,
rustc_middle::ty::ConstConditions,
rustc_middle::ty::inhabitedness::InhabitedPredicate,
rustc_middle::ty::Instance,
rustc_middle::ty::BoundVariableKind,
rustc_middle::ty::InstanceKind,
rustc_middle::ty::layout::FnAbiError,
rustc_middle::ty::layout::LayoutError,
rustc_middle::ty::LitToConstInput,
rustc_middle::ty::ParamEnv,
rustc_middle::ty::TypingEnv,
rustc_middle::ty::Predicate,
rustc_middle::ty::SymbolName,
rustc_middle::ty::TraitRef,
rustc_middle::ty::Ty,
rustc_middle::ty::UnevaluatedConst,
rustc_middle::ty::ValTree,
rustc_middle::ty::VtblEntry,
// tidy-alphabetical-end
}
+86 -42
View File
@@ -15,8 +15,8 @@
use rustc_ast::{
self as ast, AnonConst, Arm, AssignOp, AssignOpKind, AttrStyle, AttrVec, BinOp, BinOpKind,
BlockCheckMode, CaptureBy, ClosureBinder, DUMMY_NODE_ID, Expr, ExprField, ExprKind, FnDecl,
FnRetTy, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param, RangeLimits,
StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
FnRetTy, Guard, Label, MacCall, MetaItemLit, MgcaDisambiguation, Movability, Param,
RangeLimits, StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
@@ -2767,7 +2767,7 @@ pub fn parse_expr_cond(
/// Parses a `let $pat = $expr` pseudo-expression.
fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, Box<Expr>> {
let recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
let recovered: Recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
let err = errors::ExpectedExpressionFoundLet {
span: self.token.span,
reason: errors::ForbiddenLetReason::OtherForbidden,
@@ -3463,20 +3463,54 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
})
}
fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<Box<Expr>>> {
pub(crate) fn eat_metavar_guard(&mut self) -> Option<Box<Guard>> {
self.eat_metavar_seq_with_matcher(
|mv_kind| matches!(mv_kind, MetaVarKind::Guard),
|this| this.parse_match_arm_guard(),
)
.flatten()
}
fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<Box<Guard>>> {
if let Some(guard) = self.eat_metavar_guard() {
return Ok(Some(guard));
}
if !self.eat_keyword(exp!(If)) {
// No match arm guard present.
return Ok(None);
}
self.expect_match_arm_guard_cond(ForceCollect::No).map(Some)
}
let mut cond = self.parse_match_guard_condition()?;
pub(crate) fn expect_match_arm_guard(
&mut self,
force_collect: ForceCollect,
) -> PResult<'a, Box<Guard>> {
if let Some(guard) = self.eat_metavar_guard() {
return Ok(guard);
}
self.expect_keyword(exp!(If))?;
self.expect_match_arm_guard_cond(force_collect)
}
fn expect_match_arm_guard_cond(
&mut self,
force_collect: ForceCollect,
) -> PResult<'a, Box<Guard>> {
let leading_if_span = self.prev_token.span;
let mut cond = self.parse_match_guard_condition(force_collect)?;
let cond_span = cond.span;
CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
Ok(Some(cond))
let guard = Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) };
Ok(Box::new(guard))
}
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr>>)> {
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Guard>>)> {
if self.token == token::OpenParen {
let left = self.token.span;
let pat = self.parse_pat_no_top_guard(
@@ -3492,10 +3526,10 @@ fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr
// FIXME(guard_patterns): convert this to a normal guard instead
let span = pat.span;
let ast::PatKind::Paren(subpat) = pat.kind else { unreachable!() };
let ast::PatKind::Guard(_, mut cond) = subpat.kind else { unreachable!() };
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
let ast::PatKind::Guard(_, mut guard) = subpat.kind else { unreachable!() };
self.psess.gated_spans.ungate_last(sym::guard_patterns, guard.span());
let mut checker = CondChecker::new(self, LetChainsPolicy::AlwaysAllowed);
checker.visit_expr(&mut cond);
checker.visit_expr(&mut guard.cond);
let right = self.prev_token.span;
self.dcx().emit_err(errors::ParenthesesInMatchPat {
@@ -3503,14 +3537,10 @@ fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr
sugg: errors::ParenthesesInMatchPatSugg { left, right },
});
Ok((
self.mk_pat(span, ast::PatKind::Wild),
(if let Some(guar) = checker.found_incorrect_let_chain {
Some(self.mk_expr_err(cond.span, guar))
} else {
Some(cond)
}),
))
if let Some(guar) = checker.found_incorrect_let_chain {
guard.cond = *self.mk_expr_err(guard.span(), guar);
}
Ok((self.mk_pat(span, ast::PatKind::Wild), Some(guard)))
} else {
Ok((pat, self.parse_match_arm_guard()?))
}
@@ -3526,33 +3556,47 @@ fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (Pat, Option<Box<Expr
}
}
fn parse_match_guard_condition(&mut self) -> PResult<'a, Box<Expr>> {
fn parse_match_guard_condition(
&mut self,
force_collect: ForceCollect,
) -> PResult<'a, Box<Expr>> {
let attrs = self.parse_outer_attributes()?;
match self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) {
Ok((expr, _)) => Ok(expr),
Err(mut err) => {
if self.prev_token == token::OpenBrace {
let sugg_sp = self.prev_token.span.shrink_to_lo();
// Consume everything within the braces, let's avoid further parse
// errors.
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
let msg = "you might have meant to start a match arm after the match guard";
if self.eat(exp!(CloseBrace)) {
let applicability = if self.token != token::FatArrow {
// We have high confidence that we indeed didn't have a struct
// literal in the match guard, but rather we had some operation
// that ended in a path, immediately followed by a block that was
// meant to be the match arm.
Applicability::MachineApplicable
} else {
Applicability::MaybeIncorrect
};
err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
let expr = self.collect_tokens(
None,
AttrWrapper::empty(),
force_collect,
|this, _empty_attrs| {
match this
.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs)
{
Ok((expr, _)) => Ok((expr, Trailing::No, UsePreAttrPos::No)),
Err(mut err) => {
if this.prev_token == token::OpenBrace {
let sugg_sp = this.prev_token.span.shrink_to_lo();
// Consume everything within the braces, let's avoid further parse
// errors.
this.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
let msg =
"you might have meant to start a match arm after the match guard";
if this.eat(exp!(CloseBrace)) {
let applicability = if this.token != token::FatArrow {
// We have high confidence that we indeed didn't have a struct
// literal in the match guard, but rather we had some operation
// that ended in a path, immediately followed by a block that was
// meant to be the match arm.
Applicability::MachineApplicable
} else {
Applicability::MaybeIncorrect
};
err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability);
}
}
Err(err)
}
}
Err(err)
}
}
},
)?;
Ok(expr)
}
pub(crate) fn is_builtin(&self) -> bool {
+1
View File
@@ -1788,4 +1788,5 @@ pub enum ParseNtResult {
Meta(Box<ast::AttrItem>),
Path(Box<ast::Path>),
Vis(Box<ast::Visibility>),
Guard(Box<ast::Guard>),
}
@@ -31,7 +31,8 @@ fn may_be_ident(kind: MetaVarKind) -> bool {
MetaVarKind::Item
| MetaVarKind::Block
| MetaVarKind::Vis => false,
| MetaVarKind::Vis
| MetaVarKind::Guard => false,
MetaVarKind::Ident
| MetaVarKind::Lifetime
@@ -86,7 +87,8 @@ fn may_be_ident(kind: MetaVarKind) -> bool {
| MetaVarKind::Ty { .. }
| MetaVarKind::Meta { .. }
| MetaVarKind::Path
| MetaVarKind::Vis => false,
| MetaVarKind::Vis
| MetaVarKind::Guard => false,
MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => {
unreachable!()
}
@@ -103,6 +105,7 @@ fn may_be_ident(kind: MetaVarKind) -> bool {
token::Lifetime(..) | token::NtLifetime(..) => true,
_ => false,
},
NonterminalKind::Guard => token.is_keyword(kw::If),
NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => {
token.kind.close_delim().is_none()
}
@@ -196,6 +199,9 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseN
}))
}
}
NonterminalKind::Guard => {
Ok(ParseNtResult::Guard(self.expect_match_arm_guard(ForceCollect::Yes)?))
}
}
}
}
+19 -9
View File
@@ -6,8 +6,9 @@
use rustc_ast::util::parser::ExprPrecedence;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{
self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, LocalKind, MacCall, Mutability,
Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt, StmtKind,
self as ast, Arm, AttrVec, BindingMode, ByRef, Expr, ExprKind, Guard, LocalKind, MacCall,
Mutability, Pat, PatField, PatFieldsRest, PatKind, Path, QSelf, RangeEnd, RangeSyntax, Stmt,
StmtKind,
};
use rustc_ast_pretty::pprust;
use rustc_errors::{Applicability, Diag, DiagArgValue, PResult, StashKey};
@@ -110,11 +111,19 @@ pub fn parse_pat_allow_top_guard(
let pat = self.parse_pat_no_top_guard(expected, rc, ra, rt)?;
if self.eat_keyword(exp!(If)) {
let cond = self.parse_expr()?;
let guard = if let Some(guard) = self.eat_metavar_guard() {
guard
} else {
let leading_if_span = self.prev_token.span;
let cond = self.parse_expr()?;
let cond_span = cond.span;
Box::new(Guard { cond: *cond, span_with_leading_if: leading_if_span.to(cond_span) })
};
// Feature-gate guard patterns
self.psess.gated_spans.gate(sym::guard_patterns, cond.span);
let span = pat.span.to(cond.span);
Ok(self.mk_pat(span, PatKind::Guard(Box::new(pat), cond)))
self.psess.gated_spans.gate(sym::guard_patterns, guard.span());
let span = pat.span.to(guard.span());
Ok(self.mk_pat(span, PatKind::Guard(Box::new(pat), guard)))
} else {
Ok(pat)
}
@@ -601,17 +610,18 @@ fn maybe_add_suggestions_then_emit(
}
Some(guard) => {
// Are parentheses required around the old guard?
let wrap_guard = guard.precedence() <= ExprPrecedence::LAnd;
let wrap_guard =
guard.cond.precedence() <= ExprPrecedence::LAnd;
err.subdiagnostic(
UnexpectedExpressionInPatternSugg::UpdateGuard {
ident_span,
guard_lo: if wrap_guard {
Some(guard.span.shrink_to_lo())
Some(guard.span().shrink_to_lo())
} else {
None
},
guard_hi: guard.span.shrink_to_hi(),
guard_hi: guard.span().shrink_to_hi(),
guard_hi_paren: if wrap_guard { ")" } else { "" },
ident,
expr,
+2 -2
View File
@@ -4073,7 +4073,7 @@ fn check_consistent_bindings(&mut self, pat: &'ast Pat) {
fn resolve_arm(&mut self, arm: &'ast Arm) {
self.with_rib(ValueNS, RibKind::Normal, |this| {
this.resolve_pattern_top(&arm.pat, PatternSource::Match);
visit_opt!(this, visit_expr, &arm.guard);
visit_opt!(this, visit_expr, arm.guard.as_ref().map(|g| &g.cond));
visit_opt!(this, visit_expr, &arm.body);
});
}
@@ -4215,7 +4215,7 @@ fn resolve_pattern_inner(
let subpat_bindings = bindings.pop().unwrap().1;
self.with_rib(ValueNS, RibKind::Normal, |this| {
*this.innermost_rib_bindings(ValueNS) = subpat_bindings.clone();
this.resolve_expr(guard, None);
this.resolve_expr(&guard.cond, None);
});
// Propagate the subpattern's bindings upwards.
// FIXME(guard_patterns): For `if let` guards, we'll also need to get the
+24 -9
View File
@@ -547,6 +547,13 @@ fn name(&self) -> Option<Symbol> {
ModuleKind::Def(.., name) => name,
}
}
fn opt_def_id(&self) -> Option<DefId> {
match self {
ModuleKind::Def(_, def_id, _) => Some(*def_id),
_ => None,
}
}
}
/// Combination of a symbol and its macros 2.0 normalized hygiene context.
@@ -784,10 +791,7 @@ fn def_id(self) -> DefId {
}
fn opt_def_id(self) -> Option<DefId> {
match self.kind {
ModuleKind::Def(_, def_id, _) => Some(def_id),
_ => None,
}
self.kind.opt_def_id()
}
// `self` resolves to the first module ancestor that `is_normal`.
@@ -1450,14 +1454,19 @@ fn new_module(
&'ra self,
parent: Option<Module<'ra>>,
kind: ModuleKind,
vis: Visibility<DefId>,
expn_id: ExpnId,
span: Span,
no_implicit_prelude: bool,
) -> Module<'ra> {
let self_decl = match kind {
ModuleKind::Def(def_kind, def_id, _) => {
Some(self.new_pub_def_decl(Res::Def(def_kind, def_id), span, LocalExpnId::ROOT))
}
ModuleKind::Def(def_kind, def_id, _) => Some(self.new_def_decl(
Res::Def(def_kind, def_id),
vis,
span,
LocalExpnId::ROOT,
None,
)),
ModuleKind::Block => None,
};
Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new(
@@ -1639,6 +1648,7 @@ pub fn new(
let graph_root = arenas.new_module(
None,
ModuleKind::Def(DefKind::Mod, root_def_id, None),
Visibility::Public,
ExpnId::root(),
crate_span,
attr::contains_name(attrs, sym::no_implicit_prelude),
@@ -1648,6 +1658,7 @@ pub fn new(
let empty_module = arenas.new_module(
None,
ModuleKind::Def(DefKind::Mod, root_def_id, None),
Visibility::Public,
ExpnId::root(),
DUMMY_SP,
true,
@@ -1749,7 +1760,9 @@ fn new_local_module(
span: Span,
no_implicit_prelude: bool,
) -> Module<'ra> {
let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude);
let vis =
kind.opt_def_id().map_or(Visibility::Public, |def_id| self.tcx.visibility(def_id));
let module = self.arenas.new_module(parent, kind, vis, expn_id, span, no_implicit_prelude);
self.local_modules.push(module);
if let Some(def_id) = module.opt_def_id() {
self.local_module_map.insert(def_id.expect_local(), module);
@@ -1765,7 +1778,9 @@ fn new_extern_module(
span: Span,
no_implicit_prelude: bool,
) -> Module<'ra> {
let module = self.arenas.new_module(parent, kind, expn_id, span, no_implicit_prelude);
let vis =
kind.opt_def_id().map_or(Visibility::Public, |def_id| self.tcx.visibility(def_id));
let module = self.arenas.new_module(parent, kind, vis, expn_id, span, no_implicit_prelude);
self.extern_module_map.borrow_mut().insert(module.def_id(), module);
module
}
+4
View File
@@ -229,6 +229,10 @@ macro_rules! ins_sym {
if s == SanitizerSet::KERNELADDRESS {
s = SanitizerSet::ADDRESS;
}
// KHWASAN is still HWASAN under the hood, so it uses the same attribute.
if s == SanitizerSet::KERNELHWADDRESS {
s = SanitizerSet::HWADDRESS;
}
ins_str!(sym::sanitize, &s.to_string());
}
+3 -1
View File
@@ -106,6 +106,7 @@ pub(super) fn sanitizer(l: &TargetModifier, r: Option<&TargetModifier>) -> bool
| SanitizerSet::SHADOWCALLSTACK
| SanitizerSet::KCFI
| SanitizerSet::KERNELADDRESS
| SanitizerSet::KERNELHWADDRESS
| SanitizerSet::SAFESTACK
| SanitizerSet::DATAFLOW;
@@ -817,7 +818,7 @@ mod desc {
pub(crate) const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)";
pub(crate) const parse_opt_panic_strategy: &str = parse_panic_strategy;
pub(crate) const parse_relro_level: &str = "one of: `full`, `partial`, or `off`";
pub(crate) const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`, or 'realtime'";
pub(crate) const parse_sanitizers: &str = "comma separated list of sanitizers: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `kernel-hwaddress`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`, or 'realtime'";
pub(crate) const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
pub(crate) const parse_cfguard: &str =
"either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
@@ -1265,6 +1266,7 @@ pub(crate) fn parse_sanitizers(slot: &mut SanitizerSet, v: Option<&str>) -> bool
"dataflow" => SanitizerSet::DATAFLOW,
"kcfi" => SanitizerSet::KCFI,
"kernel-address" => SanitizerSet::KERNELADDRESS,
"kernel-hwaddress" => SanitizerSet::KERNELHWADDRESS,
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"memtag" => SanitizerSet::MEMTAG,
+5 -2
View File
@@ -533,9 +533,12 @@ pub fn needs_plt(&self) -> bool {
pub fn emit_lifetime_markers(&self) -> bool {
self.opts.optimize != config::OptLevel::No
// AddressSanitizer and KernelAddressSanitizer uses lifetimes to detect use after scope bugs.
//
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
// HWAddressSanitizer will use lifetimes to detect use after scope bugs in the future.
|| self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS)
//
// HWAddressSanitizer and KernelHWAddressSanitizer will use lifetimes to detect use after
// scope bugs in the future.
|| self.sanitizers().intersects(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS | SanitizerSet::MEMORY | SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS)
}
pub fn diagnostic_width(&self) -> usize {
+3
View File
@@ -1028,6 +1028,7 @@
global_registration,
globs,
gt,
guard,
guard_patterns,
half_open_range_patterns,
half_open_range_patterns_in_slices,
@@ -1116,6 +1117,7 @@
iterator_collect_fn,
kcfi,
kernel_address,
kernel_hwaddress,
keylocker_x86,
keyword,
kind,
@@ -1192,6 +1194,7 @@
macro_derive,
macro_escape,
macro_export,
macro_guard_matcher,
macro_lifetime_matcher,
macro_literal_matcher,
macro_metavar_expr,
+14 -3
View File
@@ -1175,9 +1175,10 @@ impl SanitizerSet: u16 {
const SHADOWCALLSTACK = 1 << 7;
const KCFI = 1 << 8;
const KERNELADDRESS = 1 << 9;
const SAFESTACK = 1 << 10;
const DATAFLOW = 1 << 11;
const REALTIME = 1 << 12;
const KERNELHWADDRESS = 1 << 10;
const SAFESTACK = 1 << 11;
const DATAFLOW = 1 << 12;
const REALTIME = 1 << 13;
}
}
rustc_data_structures::external_bitflags_debug! { SanitizerSet }
@@ -1191,24 +1192,32 @@ impl SanitizerSet {
(SanitizerSet::ADDRESS, SanitizerSet::HWADDRESS),
(SanitizerSet::ADDRESS, SanitizerSet::MEMTAG),
(SanitizerSet::ADDRESS, SanitizerSet::KERNELADDRESS),
(SanitizerSet::ADDRESS, SanitizerSet::KERNELHWADDRESS),
(SanitizerSet::ADDRESS, SanitizerSet::SAFESTACK),
(SanitizerSet::LEAK, SanitizerSet::MEMORY),
(SanitizerSet::LEAK, SanitizerSet::THREAD),
(SanitizerSet::LEAK, SanitizerSet::KERNELADDRESS),
(SanitizerSet::LEAK, SanitizerSet::KERNELHWADDRESS),
(SanitizerSet::LEAK, SanitizerSet::SAFESTACK),
(SanitizerSet::MEMORY, SanitizerSet::THREAD),
(SanitizerSet::MEMORY, SanitizerSet::HWADDRESS),
(SanitizerSet::MEMORY, SanitizerSet::KERNELADDRESS),
(SanitizerSet::MEMORY, SanitizerSet::KERNELHWADDRESS),
(SanitizerSet::MEMORY, SanitizerSet::SAFESTACK),
(SanitizerSet::THREAD, SanitizerSet::HWADDRESS),
(SanitizerSet::THREAD, SanitizerSet::KERNELADDRESS),
(SanitizerSet::THREAD, SanitizerSet::KERNELHWADDRESS),
(SanitizerSet::THREAD, SanitizerSet::SAFESTACK),
(SanitizerSet::HWADDRESS, SanitizerSet::MEMTAG),
(SanitizerSet::HWADDRESS, SanitizerSet::KERNELADDRESS),
(SanitizerSet::HWADDRESS, SanitizerSet::KERNELHWADDRESS),
(SanitizerSet::HWADDRESS, SanitizerSet::SAFESTACK),
(SanitizerSet::CFI, SanitizerSet::KCFI),
(SanitizerSet::MEMTAG, SanitizerSet::KERNELADDRESS),
(SanitizerSet::MEMTAG, SanitizerSet::KERNELHWADDRESS),
(SanitizerSet::KERNELADDRESS, SanitizerSet::KERNELHWADDRESS),
(SanitizerSet::KERNELADDRESS, SanitizerSet::SAFESTACK),
(SanitizerSet::KERNELHWADDRESS, SanitizerSet::SAFESTACK),
];
/// Return sanitizer's name
@@ -1221,6 +1230,7 @@ pub fn as_str(self) -> Option<&'static str> {
SanitizerSet::DATAFLOW => "dataflow",
SanitizerSet::KCFI => "kcfi",
SanitizerSet::KERNELADDRESS => "kernel-address",
SanitizerSet::KERNELHWADDRESS => "kernel-hwaddress",
SanitizerSet::LEAK => "leak",
SanitizerSet::MEMORY => "memory",
SanitizerSet::MEMTAG => "memtag",
@@ -1266,6 +1276,7 @@ fn from_str(s: &str) -> Result<Self, Self::Err> {
"dataflow" => SanitizerSet::DATAFLOW,
"kcfi" => SanitizerSet::KCFI,
"kernel-address" => SanitizerSet::KERNELADDRESS,
"kernel-hwaddress" => SanitizerSet::KERNELHWADDRESS,
"leak" => SanitizerSet::LEAK,
"memory" => SanitizerSet::MEMORY,
"memtag" => SanitizerSet::MEMTAG,
@@ -22,7 +22,9 @@ pub(crate) fn target() -> Target {
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
supported_sanitizers: SanitizerSet::KCFI
| SanitizerSet::KERNELADDRESS
| SanitizerSet::KERNELHWADDRESS,
stack_probes: StackProbeType::Inline,
panic_strategy: PanicStrategy::Abort,
endian: Endian::Big,
@@ -21,7 +21,9 @@ pub(crate) fn target() -> Target {
&["--fix-cortex-a53-843419"],
),
features: "+v8a,+strict-align,+neon".into(),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
supported_sanitizers: SanitizerSet::KCFI
| SanitizerSet::KERNELADDRESS
| SanitizerSet::KERNELHWADDRESS,
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(128),
@@ -21,7 +21,9 @@ pub(crate) fn target() -> Target {
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
supported_sanitizers: SanitizerSet::KCFI
| SanitizerSet::KERNELADDRESS
| SanitizerSet::KERNELHWADDRESS,
stack_probes: StackProbeType::Inline,
panic_strategy: PanicStrategy::Abort,
default_uwtable: true,
@@ -21,7 +21,9 @@ pub(crate) fn target() -> Target {
&["--fix-cortex-a53-843419"],
),
features: "+v8a,+strict-align,+neon".into(),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
supported_sanitizers: SanitizerSet::KCFI
| SanitizerSet::KERNELADDRESS
| SanitizerSet::KERNELHWADDRESS,
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(128),
@@ -8,7 +8,9 @@ pub(crate) fn target() -> Target {
// based off the aarch64-unknown-none target at time of addition
linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
linker: Some("rust-lld".into()),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
supported_sanitizers: SanitizerSet::KCFI
| SanitizerSet::KERNELADDRESS
| SanitizerSet::KERNELHWADDRESS,
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(128),
@@ -12,7 +12,9 @@ pub(crate) fn target() -> Target {
relocation_model: RelocModel::Static,
disable_redzone: true,
max_atomic_width: Some(128),
supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
supported_sanitizers: SanitizerSet::KCFI
| SanitizerSet::KERNELADDRESS
| SanitizerSet::KERNELHWADDRESS,
stack_probes: StackProbeType::Inline,
panic_strategy: PanicStrategy::Abort,
default_uwtable: true,
+1 -1
View File
@@ -1212,7 +1212,7 @@ pub fn to_lowercase(self) -> ToLowercase {
/// returned by [`Self::to_uppercase`]. Prefer this method when seeking to capitalize
/// Only The First Letter of a word, but use [`Self::to_uppercase`] for ALL CAPS.
///
/// If this `char` does not have an titlecase mapping, the iterator yields the same `char`.
/// If this `char` does not have a titlecase mapping, the iterator yields the same `char`.
///
/// If this `char` has a one-to-one titlecase mapping given by the [Unicode Character
/// Database][ucd] [`UnicodeData.txt`], the iterator yields that `char`.
+2 -1
View File
@@ -138,8 +138,9 @@ pub const fn dangling() -> Self {
///
/// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API.
#[stable(feature = "nonnull_provenance", since = "1.89.0")]
#[rustc_const_unstable(feature = "const_nonnull_with_exposed_provenance", issue = "154215")]
#[inline]
pub fn with_exposed_provenance(addr: NonZero<usize>) -> Self {
pub const fn with_exposed_provenance(addr: NonZero<usize>) -> Self {
// SAFETY: we know `addr` is non-zero.
unsafe {
let ptr = crate::ptr::with_exposed_provenance_mut(addr.get());
+1 -1
View File
@@ -509,7 +509,7 @@ auto:
- name: dist-aarch64-apple
env:
SCRIPT: >-
./x.py dist bootstrap
./x.py dist bootstrap enzyme
--include-default-paths
--host=aarch64-apple-darwin
--target=aarch64-apple-darwin
@@ -22,6 +22,8 @@ This feature allows for use of one of following sanitizers:
* [AddressSanitizer](#addresssanitizer) a fast memory error detector.
* [HWAddressSanitizer](#hwaddresssanitizer) a memory error detector similar to
AddressSanitizer, but based on partial hardware assistance.
* [KernelHWAddressSanitizer](#kernelhwaddresssanitizer) variant of
HWAddressSanitizer that is designed for bare metal environments.
* [LeakSanitizer](#leaksanitizer) a run-time memory leak detector.
* [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads.
* [RealtimeSanitizer](#realtimesanitizer) a detector of calls to function with
@@ -622,6 +624,16 @@ Registers where the failure occurred (pc 0xaaaae0ae4a98):
SUMMARY: HWAddressSanitizer: tag-mismatch (/.../main+0x54a94)
```
# KernelHWAddressSanitizer
KernelHWAddressSanitizer is the kernel version of [HWAddressSanitizer](#hwaddresssanitizer),
which achieves the same purpose but is designed for bare-metal environments.
HWAddressSanitizer is supported on the `aarch64*-unknown-none` and
`aarch64*-unknown-none-softfloat` targets.
See the [Clang HWAddressSanitizer documentation][clang-hwasan] for more details.
# KernelControlFlowIntegrity
The LLVM Kernel Control Flow Integrity (CFI) support to the Rust compiler
@@ -280,7 +280,7 @@ pub fn eq_arm(l: &Arm, r: &Arm) -> bool {
l.is_placeholder == r.is_placeholder
&& eq_pat(&l.pat, &r.pat)
&& eq_expr_opt(l.body.as_deref(), r.body.as_deref())
&& eq_expr_opt(l.guard.as_deref(), r.guard.as_deref())
&& eq_expr_opt(l.guard.as_deref().map(|g| &g.cond), r.guard.as_deref().map(|g| &g.cond))
&& over(&l.attrs, &r.attrs, eq_attr)
}
+1
View File
@@ -168,6 +168,7 @@ pub enum Sanitizer {
Dataflow,
Kcfi,
KernelAddress,
KernelHwaddress,
Leak,
Memory,
Memtag,
@@ -179,6 +179,7 @@
"needs-sanitizer-hwaddress",
"needs-sanitizer-kasan",
"needs-sanitizer-kcfi",
"needs-sanitizer-khwasan",
"needs-sanitizer-leak",
"needs-sanitizer-memory",
"needs-sanitizer-memtag",
@@ -46,6 +46,11 @@ pub(super) fn handle_needs(
condition: cache.sanitizer_kasan,
ignore_reason: "ignored on targets without kernel address sanitizer",
},
Need {
name: "needs-sanitizer-khwasan",
condition: cache.sanitizer_khwasan,
ignore_reason: "ignored on targets without kernel hardware-assisted address sanitizer",
},
Need {
name: "needs-sanitizer-leak",
condition: cache.sanitizer_leak,
@@ -332,6 +337,7 @@ pub(super) struct CachedNeedsConditions {
sanitizer_dataflow: bool,
sanitizer_kcfi: bool,
sanitizer_kasan: bool,
sanitizer_khwasan: bool,
sanitizer_leak: bool,
sanitizer_memory: bool,
sanitizer_thread: bool,
@@ -359,6 +365,7 @@ pub(super) fn load(config: &Config) -> Self {
sanitizer_dataflow: sanitizers.contains(&Sanitizer::Dataflow),
sanitizer_kcfi: sanitizers.contains(&Sanitizer::Kcfi),
sanitizer_kasan: sanitizers.contains(&Sanitizer::KernelAddress),
sanitizer_khwasan: sanitizers.contains(&Sanitizer::KernelHwaddress),
sanitizer_leak: sanitizers.contains(&Sanitizer::Leak),
sanitizer_memory: sanitizers.contains(&Sanitizer::Memory),
sanitizer_thread: sanitizers.contains(&Sanitizer::Thread),
+3 -2
View File
@@ -476,8 +476,9 @@ to Miri failing to detect cases of undefined behavior in a program.
but reports to the program that it did actually write. This is useful when you
are not interested in the actual program's output, but only want to see Miri's
errors and warnings.
* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking
recurse below references.
* `-Zmiri-recursive-validation` is a *highly experimental* flag that makes validity checking recurse
*one level* below references. The in-memory value is treated as-if it was inside a
`MaybeDangling`, i.e., nested references do not even have to be dereferenceable.
* `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active
thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables
preemption. Note that even without preemption, the schedule is still non-deterministic:
@@ -5,6 +5,7 @@
use std::{mem, ptr};
extern "C" fn thread_start() -> *mut libc::c_void {
//~^ERROR: calling a function with more arguments than it expected
panic!()
}
@@ -16,7 +17,6 @@ fn main() {
mem::transmute(thread_start);
assert_eq!(
libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()),
//~^ERROR: calling a function with more arguments than it expected
0
);
assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
@@ -1,14 +1,17 @@
error: Undefined Behavior: calling a function with more arguments than it expected
--> tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs:LL:CC
|
LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code
LL | extern "C" fn thread_start() -> *mut libc::c_void {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: this is on thread `unnamed-ID`
= note: this error occurred while pushing a call frame onto an empty stack
= note: the span indicates which code caused the function to be called, but may not be the literal call site
note: the current function got called indirectly due to this code
--> tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs:LL:CC
|
LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
@@ -5,6 +5,7 @@
use std::{mem, ptr};
extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void {
//~^ERROR: calling a function with fewer arguments than it requires
panic!()
}
@@ -16,7 +17,6 @@ fn main() {
mem::transmute(thread_start);
assert_eq!(
libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()),
//~^ERROR: calling a function with fewer arguments than it requires
0
);
assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0);
@@ -1,14 +1,17 @@
error: Undefined Behavior: calling a function with fewer arguments than it requires
--> tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs:LL:CC
|
LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code
LL | extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void {
| ^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: this is on thread `unnamed-ID`
= note: this error occurred while pushing a call frame onto an empty stack
= note: the span indicates which code caused the function to be called, but may not be the literal call site
note: the current function got called indirectly due to this code
--> tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs:LL:CC
|
LL | libc::pthread_create(&mut native, ptr::null(), thread_start, ptr::null_mut()),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
@@ -21,8 +21,6 @@ fn main() {
// This specifically uses a type with scalar representation to tempt Miri to use the
// efficient way of storing local variables (outside adressable memory).
Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
//~[stack]^ ERROR: not granting access
//~[tree]| ERROR: /read access .* forbidden/
}
after_call = {
Return()
@@ -32,6 +30,8 @@ fn main() {
#[expect(unused_variables, unused_assignments)]
fn callee(x: S, mut y: S) {
//~[stack]^ ERROR: not granting access
//~[tree]| ERROR: /read access .* forbidden/
// With the setup above, if `x` and `y` are both moved,
// then writing to `y` will change the value stored in `x`!
y.0 = 0;
@@ -1,8 +1,8 @@
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
LL | fn callee(x: S, mut y: S) {
| ^^^^^ Undefined Behavior occurred here
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -14,8 +14,13 @@ LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(a
help: <TAG> is this argument
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | y.0 = 0;
| ^^^^^^^
LL | fn callee(x: S, mut y: S) {
| ^
= note: stack backtrace:
0: callee
at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
1: main
at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -1,8 +1,8 @@
error: Undefined Behavior: read access through <TAG> (root of the allocation) at ALLOC[0x0] is forbidden
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
LL | fn callee(x: S, mut y: S) {
| ^^^^^ Undefined Behavior occurred here
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
@@ -17,14 +17,19 @@ LL | Call(_unit = callee(Move(non_copy), Move(non_copy)), ReturnTo(a
help: the protected tag <TAG> was created here, in the initial state Reserved
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | y.0 = 0;
| ^^^^^^^
LL | fn callee(x: S, mut y: S) {
| ^
help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
--> tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
|
LL | y.0 = 0;
| ^^^^^^^
LL | fn callee(x: S, mut y: S) {
| ^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: stack backtrace:
0: callee
at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
1: main
at tests/fail/function_calls/arg_inplace_locals_alias.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -20,8 +20,6 @@ fn main() {
// This specifically uses a type with scalar representation to tempt Miri to use the
// efficient way of storing local variables (outside adressable memory).
Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue())
//~[stack]^ ERROR: not granting access
//~[tree]| ERROR: /reborrow .* forbidden/
}
after_call = {
Return()
@@ -30,5 +28,7 @@ fn main() {
}
fn callee(x: S) -> S {
//~[stack]^ ERROR: not granting access
//~[tree]| ERROR: /reborrow .* forbidden/
x
}
@@ -1,8 +1,8 @@
error: Undefined Behavior: not granting access to tag <TAG> because that would remove [Unique for <TAG>] which is strongly protected
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
LL | fn callee(x: S) -> S {
| ^ Undefined Behavior occurred here
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
@@ -14,8 +14,13 @@ LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call),
help: <TAG> is this argument
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
LL | x
| ^
LL | fn callee(x: S) -> S {
| ^
= note: stack backtrace:
0: callee
at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
1: main
at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -1,8 +1,8 @@
error: Undefined Behavior: reborrow through <TAG> (root of the allocation) at ALLOC[0x0] is forbidden
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call), UnwindContinue())
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
LL | fn callee(x: S) -> S {
| ^ Undefined Behavior occurred here
|
= help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental
= help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information
@@ -17,14 +17,19 @@ LL | Call(_non_copy = callee(Move(_non_copy)), ReturnTo(after_call),
help: the protected tag <TAG> was created here, in the initial state Reserved
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
LL | x
| ^
LL | fn callee(x: S) -> S {
| ^
help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
--> tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
|
LL | x
| ^
LL | fn callee(x: S) -> S {
| ^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: stack backtrace:
0: callee
at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
1: main
at tests/fail/function_calls/arg_inplace_locals_alias_ret.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -19,8 +19,8 @@ LL | | }
help: <TAG> is this argument
--> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC
|
LL | unsafe { ptr.write(S(0)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | fn callee(x: S, ptr: *mut S) {
| ^
= note: stack backtrace:
0: callee
at tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC
@@ -22,13 +22,13 @@ LL | | }
help: the protected tag <TAG> was created here, in the initial state Reserved
--> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC
|
LL | unsafe { ptr.write(S(0)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | fn callee(x: S, ptr: *mut S) {
| ^
help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
--> tests/fail/function_calls/arg_inplace_mutate.rs:LL:CC
|
LL | unsafe { ptr.write(S(0)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | fn callee(x: S, ptr: *mut S) {
| ^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: stack backtrace:
0: callee
@@ -19,8 +19,8 @@ LL | | }
help: <TAG> is this argument
--> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC
|
LL | x.0 = 0;
| ^^^^^^^
LL | fn change_arg(mut x: S, ptr: *mut S) {
| ^^^^^
= note: stack backtrace:
0: change_arg
at tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC
@@ -22,13 +22,13 @@ LL | | }
help: the protected tag <TAG> was created here, in the initial state Reserved
--> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC
|
LL | x.0 = 0;
| ^^^^^^^
LL | fn change_arg(mut x: S, ptr: *mut S) {
| ^^^^^
help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
--> tests/fail/function_calls/arg_inplace_observe_during.rs:LL:CC
|
LL | x.0 = 0;
| ^^^^^^^
LL | fn change_arg(mut x: S, ptr: *mut S) {
| ^^^^^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: stack backtrace:
0: change_arg
@@ -1,9 +1,9 @@
#[no_mangle]
fn foo() {}
fn foo() {} //~ ERROR: calling a function with more arguments than it expected
fn main() {
extern "Rust" {
fn foo(_: i32);
}
unsafe { foo(1) } //~ ERROR: calling a function with more arguments than it expected
unsafe { foo(1) }
}
@@ -1,11 +1,16 @@
error: Undefined Behavior: calling a function with more arguments than it expected
--> tests/fail/function_calls/exported_symbol_wrong_arguments.rs:LL:CC
|
LL | unsafe { foo(1) }
| ^^^^^^ Undefined Behavior occurred here
LL | fn foo() {}
| ^^^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: stack backtrace:
0: foo
at tests/fail/function_calls/exported_symbol_wrong_arguments.rs:LL:CC
1: main
at tests/fail/function_calls/exported_symbol_wrong_arguments.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -19,8 +19,8 @@ LL | | }
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection
--> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
|
LL | unsafe { ptr.read() };
| ^^^^^^^^^^^^^^^^^^^^^
LL | fn myfun(ptr: *mut i32) -> i32 {
| ^^^
= note: stack backtrace:
0: myfun
at tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
@@ -22,13 +22,13 @@ LL | | }
help: the protected tag <TAG> was created here, in the initial state Reserved
--> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
|
LL | unsafe { ptr.read() };
| ^^^^^^^^^^^^^^^^^^^^^
LL | fn myfun(ptr: *mut i32) -> i32 {
| ^^^
help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
--> tests/fail/function_calls/return_pointer_aliasing_read.rs:LL:CC
|
LL | unsafe { ptr.read() };
| ^^^^^^^^^^^^^^^^^^^^^
LL | fn myfun(ptr: *mut i32) -> i32 {
| ^^^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: stack backtrace:
0: myfun
@@ -19,8 +19,8 @@ LL | | }
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection
--> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
|
LL | unsafe { ptr.write(0) };
| ^^^^^^^^^^^^^^^^^^^^^^^
LL | fn myfun(ptr: *mut i32) -> i32 {
| ^^^
= note: stack backtrace:
0: myfun
at tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
@@ -22,13 +22,13 @@ LL | | }
help: the protected tag <TAG> was created here, in the initial state Reserved
--> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
|
LL | unsafe { ptr.write(0) };
| ^^^^^^^^^^^^^^^^^^^^^^^
LL | fn myfun(ptr: *mut i32) -> i32 {
| ^^^
help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
--> tests/fail/function_calls/return_pointer_aliasing_write.rs:LL:CC
|
LL | unsafe { ptr.write(0) };
| ^^^^^^^^^^^^^^^^^^^^^^^
LL | fn myfun(ptr: *mut i32) -> i32 {
| ^^^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: stack backtrace:
0: myfun
@@ -19,8 +19,8 @@ LL | | }
help: <TAG> was later invalidated at offsets [0x0..0x4] by a Unique in-place function argument/return passing protection
--> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
|
LL | become myfun2(ptr)
| ^^^^^^^^^^^^^^^^^^
LL | fn myfun(ptr: *mut i32) -> i32 {
| ^^^
= note: stack backtrace:
0: myfun2
at tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
@@ -22,13 +22,13 @@ LL | | }
help: the protected tag <TAG> was created here, in the initial state Reserved
--> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
|
LL | unsafe { ptr.write(0) };
| ^^^^^^^^^^^^^^^^^^^^^^^
LL | fn myfun2(ptr: *mut i32) -> i32 {
| ^^^
help: the protected tag <TAG> later transitioned to Unique due to a child write access at offsets [0x0..0x4]
--> tests/fail/function_calls/return_pointer_aliasing_write_tail_call.rs:LL:CC
|
LL | unsafe { ptr.write(0) };
| ^^^^^^^^^^^^^^^^^^^^^^^
LL | fn myfun2(ptr: *mut i32) -> i32 {
| ^^^
= help: this transition corresponds to the first write to a 2-phase borrowed mutable reference
= note: stack backtrace:
0: myfun2
@@ -12,10 +12,10 @@ struct S(
type A = [i32; 4];
fn main() {
fn f(_: S) {}
fn f(_: S) {} //~ ERROR: type S passing argument of type [i32; 4]
// These two types have the same size but are still not compatible.
let g = unsafe { std::mem::transmute::<fn(S), fn(A)>(f) };
g(Default::default()) //~ ERROR: type S passing argument of type [i32; 4]
g(Default::default())
}
@@ -1,13 +1,18 @@
error: Undefined Behavior: calling a function whose parameter #1 has type S passing argument of type [i32; 4]
--> tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC
|
LL | g(Default::default())
| ^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
LL | fn f(_: S) {}
| ^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: stack backtrace:
0: main::f
at tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC
1: main
at tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -1,7 +1,7 @@
fn main() {
fn f(_: f32) {}
fn f(_: f32) {} //~ ERROR: type f32 passing argument of type i32
let g = unsafe { std::mem::transmute::<fn(f32), fn(i32)>(f) };
g(42) //~ ERROR: type f32 passing argument of type i32
g(42)
}
@@ -1,13 +1,18 @@
error: Undefined Behavior: calling a function whose parameter #1 has type f32 passing argument of type i32
--> tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC
|
LL | g(42)
| ^^^^^ Undefined Behavior occurred here
LL | fn f(_: f32) {}
| ^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: stack backtrace:
0: main::f
at tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC
1: main
at tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -1,7 +1,7 @@
fn main() {
fn f(_: *const [i32]) {}
fn f(_: *const [i32]) {} //~ ERROR: type *const [i32] passing argument of type *const i32
let g = unsafe { std::mem::transmute::<fn(*const [i32]), fn(*const i32)>(f) };
g(&42 as *const i32) //~ ERROR: type *const [i32] passing argument of type *const i32
g(&42 as *const i32)
}
@@ -1,13 +1,18 @@
error: Undefined Behavior: calling a function whose parameter #1 has type *const [i32] passing argument of type *const i32
--> tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC
|
LL | g(&42 as *const i32)
| ^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
LL | fn f(_: *const [i32]) {}
| ^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: stack backtrace:
0: main::f
at tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC
1: main
at tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -7,10 +7,10 @@
struct S2(i32);
fn callee(_s: S2) {}
//~^ ERROR: type S2 passing argument of type S1
fn main() {
let fnptr: fn(S2) = callee;
let fnptr: fn(S1) = unsafe { std::mem::transmute(fnptr) };
fnptr(S1(NonZero::new(1).unwrap()));
//~^ ERROR: type S2 passing argument of type S1
}
@@ -1,13 +1,18 @@
error: Undefined Behavior: calling a function whose parameter #1 has type S2 passing argument of type S1
--> tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC
|
LL | fnptr(S1(NonZero::new(1).unwrap()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
LL | fn callee(_s: S2) {}
| ^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: stack backtrace:
0: callee
at tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC
1: main
at tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -1,9 +1,9 @@
fn main() {
fn f() -> u32 {
fn f() -> u32 { //~ ERROR: type u32 passing return place of type ()
42
}
let g = unsafe { std::mem::transmute::<fn() -> u32, fn()>(f) };
g() //~ ERROR: type u32 passing return place of type ()
g()
}
@@ -1,13 +1,18 @@
error: Undefined Behavior: calling a function with return type u32 passing return place of type ()
--> tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC
|
LL | g()
| ^^^ Undefined Behavior occurred here
LL | fn f() -> u32 {
| ^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: stack backtrace:
0: main::f
at tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC
1: main
at tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -1,7 +1,7 @@
fn main() {
fn f(_: (i32, i32)) {}
fn f(_: (i32, i32)) {} //~ ERROR: type (i32, i32) passing argument of type i32
let g = unsafe { std::mem::transmute::<fn((i32, i32)), fn(i32)>(f) };
g(42) //~ ERROR: type (i32, i32) passing argument of type i32
g(42)
}
@@ -1,13 +1,18 @@
error: Undefined Behavior: calling a function whose parameter #1 has type (i32, i32) passing argument of type i32
--> tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC
|
LL | g(42)
| ^^^^^ Undefined Behavior occurred here
LL | fn f(_: (i32, i32)) {}
| ^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: stack backtrace:
0: main::f
at tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC
1: main
at tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -1,7 +1,7 @@
fn main() {
fn f(_: (i32, i32)) {}
fn f(_: (i32, i32)) {} //~ ERROR: calling a function with fewer arguments than it requires
let g = unsafe { std::mem::transmute::<fn((i32, i32)), fn()>(f) };
g() //~ ERROR: calling a function with fewer arguments than it requires
g()
}
@@ -1,11 +1,16 @@
error: Undefined Behavior: calling a function with fewer arguments than it requires
--> tests/fail/function_pointers/abi_mismatch_too_few_args.rs:LL:CC
|
LL | g()
| ^^^ Undefined Behavior occurred here
LL | fn f(_: (i32, i32)) {}
| ^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: stack backtrace:
0: main::f
at tests/fail/function_pointers/abi_mismatch_too_few_args.rs:LL:CC
1: main
at tests/fail/function_pointers/abi_mismatch_too_few_args.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -1,7 +1,7 @@
fn main() {
fn f() {}
fn f() {} //~ ERROR: calling a function with more arguments than it expected
let g = unsafe { std::mem::transmute::<fn(), fn(i32)>(f) };
g(42) //~ ERROR: calling a function with more arguments than it expected
g(42)
}
@@ -1,11 +1,16 @@
error: Undefined Behavior: calling a function with more arguments than it expected
--> tests/fail/function_pointers/abi_mismatch_too_many_args.rs:LL:CC
|
LL | g(42)
| ^^^^^ Undefined Behavior occurred here
LL | fn f() {}
| ^^^^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: stack backtrace:
0: main::f
at tests/fail/function_pointers/abi_mismatch_too_many_args.rs:LL:CC
1: main
at tests/fail/function_pointers/abi_mismatch_too_many_args.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -2,10 +2,10 @@
use std::simd;
fn main() {
fn f(_: simd::u32x8) {}
fn f(_: simd::u32x8) {} //~ ERROR: type std::simd::Simd<u32, 8> passing argument of type std::simd::Simd<u64, 4>
// These two vector types have the same size but are still not compatible.
let g = unsafe { std::mem::transmute::<fn(simd::u32x8), fn(simd::u64x4)>(f) };
g(Default::default()) //~ ERROR: type std::simd::Simd<u32, 8> passing argument of type std::simd::Simd<u64, 4>
g(Default::default())
}
@@ -1,13 +1,18 @@
error: Undefined Behavior: calling a function whose parameter #1 has type std::simd::Simd<u32, 8> passing argument of type std::simd::Simd<u64, 4>
--> tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC
|
LL | g(Default::default())
| ^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
LL | fn f(_: simd::u32x8) {}
| ^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: stack backtrace:
0: main::f
at tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC
1: main
at tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
@@ -1,4 +1,5 @@
unsafe extern "C" fn ctor() -> i32 {
//~^ERROR: calling a function with return type i32 passing return place of type ()
0
}
@@ -30,7 +31,6 @@ macro_rules! ctor {
)]
#[used]
static $ident: unsafe extern "C" fn() -> i32 = $ctor;
//~^ERROR: calling a function with return type i32 passing return place of type ()
};
}
@@ -1,18 +1,21 @@
error: Undefined Behavior: calling a function with return type i32 passing return place of type ()
--> tests/fail/shims/ctor_wrong_ret_type.rs:LL:CC
|
LL | static $ident: unsafe extern "C" fn() -> i32 = $ctor;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred due to this code
...
LL | ctor! { CTOR = ctor }
| --------------------- in this macro invocation
LL | unsafe extern "C" fn ctor() -> i32 {
| ^^^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: this error occurred while pushing a call frame onto an empty stack
= note: the span indicates which code caused the function to be called, but may not be the literal call site
note: the current function got called indirectly due to this code
--> tests/fail/shims/ctor_wrong_ret_type.rs:LL:CC
|
LL | static $ident: unsafe extern "C" fn() -> i32 = $ctor;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | ctor! { CTOR = ctor }
| --------------------- in this macro invocation
= note: this error originates in the macro `ctor` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
@@ -2,16 +2,14 @@
#![allow(incomplete_features)]
fn main() {
// FIXME(explicit_tail_calls):
// the error should point to `become g(x)`,
// but tail calls mess up the backtrace it seems like...
f(0);
//~^ error: type i32 passing argument of type u32
}
fn f(x: u32) {
let g = unsafe { std::mem::transmute::<fn(i32), fn(u32)>(g) };
become g(x);
become g(x); // FIXME ideally this should also be involved in the error somehow,
// but by the time we pass the argument, `f`'s stackframe has already been popped.
}
fn g(_: i32) {}
//~^ error: type i32 passing argument of type u32
@@ -1,13 +1,18 @@
error: Undefined Behavior: calling a function whose parameter #1 has type i32 passing argument of type u32
--> tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC
|
LL | f(0);
| ^^^^ Undefined Behavior occurred here
LL | fn g(_: i32) {}
| ^ Undefined Behavior occurred here
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue with Miri
= note: stack backtrace:
0: g
at tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC
1: main
at tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

Some files were not shown because too many files have changed in this diff Show More