diff --git a/Cargo.lock b/Cargo.lock index 7f0076bae73ee..4189a9d7d149f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -561,9 +561,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "chacha20" @@ -1400,10 +1400,11 @@ dependencies = [ [[package]] name = "eyre" -version = "0.6.12" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +checksum = "c08309dbcc659c5549a24ddb9b27027640641b282ef5768267c7e675558986a3" dependencies = [ + "autocfg", "indenter", "once_cell", ] diff --git a/compiler/rustc_builtin_macros/src/diagnostics.rs b/compiler/rustc_builtin_macros/src/diagnostics.rs index ce5fb4e86dab6..4ebc39f1976fb 100644 --- a/compiler/rustc_builtin_macros/src/diagnostics.rs +++ b/compiler/rustc_builtin_macros/src/diagnostics.rs @@ -562,7 +562,7 @@ pub(crate) enum EnvNotDefined { CargoEnvVar { #[primary_span] span: Span, - var: Symbol, + var: String, var_expr: String, }, #[diag("environment variable `{$var}` not defined at compile time")] @@ -570,7 +570,7 @@ pub(crate) enum EnvNotDefined { CargoEnvVarTypo { #[primary_span] span: Span, - var: Symbol, + var: String, suggested_var: Symbol, }, #[diag("environment variable `{$var}` not defined at compile time")] @@ -578,7 +578,7 @@ pub(crate) enum EnvNotDefined { CustomEnvVar { #[primary_span] span: Span, - var: Symbol, + var: String, var_expr: String, }, } @@ -588,7 +588,7 @@ pub(crate) enum EnvNotDefined { pub(crate) struct EnvNotUnicode { #[primary_span] pub(crate) span: Span, - pub(crate) var: Symbol, + pub(crate) var: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index aaa9117bb092b..38077109b7811 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -6,9 +6,8 @@ use std::env; use std::env::VarError; -use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{ExprKind, GenericArg, Mutability}; +use rustc_ast::{GenericArg, Mutability}; use rustc_ast_pretty::pprust; use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult}; use rustc_span::edit_distance::edit_distance; @@ -69,14 +68,8 @@ pub(crate) fn expand_option_env<'cx>( )) } Err(VarError::NotUnicode(_)) => { - let ExprKind::Lit(token::Lit { - kind: LitKind::Str | LitKind::StrRaw(..), symbol, .. - }) = &var_expr.kind - else { - unreachable!("`expr_to_string` ensures this is a string lit") - }; - - let guar = cx.dcx().emit_err(diagnostics::EnvNotUnicode { span: sp, var: *symbol }); + let escaped_var = var.as_str().escape_debug().to_string(); + let guar = cx.dcx().emit_err(diagnostics::EnvNotUnicode { span: sp, var: escaped_var }); return ExpandResult::Ready(DummyResult::any(sp, guar)); } Ok(value) => cx.expr_call_global( @@ -106,6 +99,7 @@ pub(crate) fn expand_env<'cx>( }; let var_expr = exprs.next().unwrap(); + // FIXME: `get_exprs_from_tts()` already performed macro expansion... let ExpandResult::Ready(mac) = expr_to_string(cx, var_expr.clone(), "expected string literal") else { return ExpandResult::Retry(()); @@ -133,49 +127,37 @@ pub(crate) fn expand_env<'cx>( let value = lookup_env(cx, var); cx.sess.env_depinfo.borrow_mut().insert((var, value.as_ref().ok().copied())); let e = match value { - Err(err) => { - let ExprKind::Lit(token::Lit { - kind: LitKind::Str | LitKind::StrRaw(..), symbol, .. - }) = &var_expr.kind - else { - unreachable!("`expr_to_string` ensures this is a string lit") - }; - - let var = var.as_str(); - let guar = match err { - VarError::NotPresent => { - if let Some(msg_from_user) = custom_msg { - cx.dcx().emit_err(diagnostics::EnvNotDefinedWithUserMessage { - span, - msg_from_user, - }) - } else if let Some(suggested_var) = find_similar_cargo_var(var) - && suggested_var != var - { - cx.dcx().emit_err(diagnostics::EnvNotDefined::CargoEnvVarTypo { - span, - var: *symbol, - suggested_var: Symbol::intern(suggested_var), - }) - } else if is_cargo_env_var(var) { - cx.dcx().emit_err(diagnostics::EnvNotDefined::CargoEnvVar { - span, - var: *symbol, - var_expr: pprust::expr_to_string(&var_expr), - }) - } else { - cx.dcx().emit_err(diagnostics::EnvNotDefined::CustomEnvVar { - span, - var: *symbol, - var_expr: pprust::expr_to_string(&var_expr), - }) - } - } - VarError::NotUnicode(_) => { - cx.dcx().emit_err(diagnostics::EnvNotUnicode { span, var: *symbol }) - } + Err(VarError::NotPresent) => { + let var_str = var.as_str(); + let escaped_var = var_str.escape_debug().to_string(); + let guar = if let Some(msg_from_user) = custom_msg { + cx.dcx().emit_err(diagnostics::EnvNotDefinedWithUserMessage { span, msg_from_user }) + } else if let Some(suggested_var) = find_similar_cargo_var(var_str) + && suggested_var != var_str + { + cx.dcx().emit_err(diagnostics::EnvNotDefined::CargoEnvVarTypo { + span, + var: escaped_var, + suggested_var: Symbol::intern(suggested_var), + }) + } else if is_cargo_env_var(var_str) { + cx.dcx().emit_err(diagnostics::EnvNotDefined::CargoEnvVar { + span, + var: escaped_var, + var_expr: pprust::expr_to_string(&var_expr), + }) + } else { + cx.dcx().emit_err(diagnostics::EnvNotDefined::CustomEnvVar { + span, + var: escaped_var, + var_expr: pprust::expr_to_string(&var_expr), + }) }; - + return ExpandResult::Ready(DummyResult::any(sp, guar)); + } + Err(VarError::NotUnicode(_)) => { + let escaped_var = var.as_str().escape_debug().to_string(); + let guar = cx.dcx().emit_err(diagnostics::EnvNotUnicode { span, var: escaped_var }); return ExpandResult::Ready(DummyResult::any(sp, guar)); } Ok(value) => cx.expr_str(span, value), diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index 7bb8979e8820f..f8166b8c766d2 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -70,8 +70,8 @@ fn get_rpath_relative_to_output(config: &RPathConfig<'_>, lib: &Path) -> OsStrin let output = config.out_filename.parent().unwrap(); // If output or lib is empty, just assume it locates in current path - let lib = if lib == Path::new("") { Path::new(".") } else { lib }; - let output = if output == Path::new("") { Path::new(".") } else { output }; + let lib = if lib.is_empty() { Path::new(".") } else { lib }; + let output = if output.is_empty() { Path::new(".") } else { output }; let lib = try_canonicalize(lib).unwrap(); let output = try_canonicalize(output).unwrap(); diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index f8c308ece55b7..00057dc503827 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -60,7 +60,7 @@ pub(crate) enum MinMax { /// Whether two types `T` and `U` are compatible when a value of type `T` is passed as a c-variadic /// argument and read as a value of type `U`. -enum VarArgCompatible { +pub enum VarArgCompatible { /// `T` and `U` are compatible, e.g. /// /// - They're the same type. @@ -829,15 +829,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return interp_ok(()); } - // Types of different sizes can never be compatible. - if arg_mplace.layout.size != callee_type.size { - throw_ub_format!( - "va_arg type mismatch: requested `{}` is incompatible with next argument of type `{}`", - callee_ty, - caller_ty, - ) - } - match self.validate_c_variadic_compatible_ty(arg_mplace.layout.ty, callee_type.ty)? { VarArgCompatible::Compatible => interp_ok(()), VarArgCompatible::Incompatible => throw_ub_format!( @@ -875,7 +866,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// - `T` and `U` are both pointers, and their target types are compatible. /// - `T` is a pointer to [`std::ffi::c_void`] and `U` is a pointer to [`i8`] or [`u8`], /// or vice versa. - fn validate_c_variadic_compatible_ty( + pub fn validate_c_variadic_compatible_ty( &mut self, caller_type: Ty<'tcx>, callee_type: Ty<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/mod.rs b/compiler/rustc_const_eval/src/interpret/mod.rs index cd1a5cf6a46d5..1eceff75e092b 100644 --- a/compiler/rustc_const_eval/src/interpret/mod.rs +++ b/compiler/rustc_const_eval/src/interpret/mod.rs @@ -29,6 +29,7 @@ pub use self::intern::{ HasStaticRootDefId, InternError, InternKind, intern_const_alloc_for_constprop, intern_const_alloc_recursive, }; +pub use self::intrinsics::VarArgCompatible; pub use self::machine::{ AllocMap, Machine, MayLeak, RetagMode, ReturnAction, compile_time_machine, }; diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 18ea454f82c65..d63bffab88221 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -75,20 +75,15 @@ fn check_transmute<'tcx>( hir_id: HirId, ) -> Result<(), ErrorGuaranteed> { let span = tcx.hir_span(hir_id); - let normalize = |ty| { - if let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) { - ty - } else { - Ty::new_error_with_message( - tcx, - span, - format!("tried to normalize non-wf type {ty:#?} in check_transmute"), - ) - } + let normalize = |ty: Unnormalized<'tcx, Ty<'tcx>>| -> Result, ErrorGuaranteed> { + tcx.try_normalize_erasing_regions(typing_env, ty).map_err(|err| { + let err = LayoutError::NormalizationFailure(ty.skip_normalization(), err); + tcx.dcx().struct_span_err(span, err.to_string()).emit() + }) }; - let from = normalize(from); - let to = normalize(to); + let from = normalize(from)?; + let to = normalize(to)?; trace!(?from, ?to); // Transmutes that are only changing lifetimes are always ok. diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 60de9d179cb98..a9a99336d1894 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -86,12 +86,6 @@ pub struct CStore { has_crate_resolve_with_fail: bool, } -impl std::fmt::Debug for CStore { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("CStore").finish_non_exhaustive() - } -} - pub enum LoadedMacro { MacroDef { def: MacroDef, @@ -113,12 +107,10 @@ enum LoadResult { Loaded(Library), } -struct CrateDump<'a>(&'a CStore); - -impl<'a> std::fmt::Debug for CrateDump<'a> { +impl std::fmt::Debug for CStore { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(fmt, "resolved crates:")?; - for (cnum, data) in self.0.iter_crate_data() { + for (cnum, data) in self.iter_crate_data() { writeln!(fmt, " name: {}", data.name())?; writeln!(fmt, " cnum: {cnum}")?; writeln!(fmt, " hash: {}", data.hash())?; @@ -1288,7 +1280,7 @@ impl CStore { self.report_unused_deps_in_crate(tcx, krate); self.report_future_incompatible_deps(tcx, krate); - info!("{:?}", CrateDump(self)); + info!("{:?}", self); } /// Process an `extern crate foo` AST node. diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index d7db7d90acc38..a0abc918107df 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -282,10 +282,7 @@ where goal: Goal::Predicate>, ) -> bool { self.probe(|| { - EvalCtxt::enter_root(self, self.cx().recursion_limit(), I::Span::dummy(), |ecx| { - ecx.evaluate_goal(GoalSource::Misc, goal, None) - }) - .is_ok_and(|r| match r.certainty { + self.evaluate_root_goal(goal, I::Span::dummy(), None).is_ok_and(|r| match r.certainty { Certainty::Yes => true, Certainty::Maybe(MaybeInfo { cause: _, @@ -359,12 +356,11 @@ fn maybe_evaluate_root_goal_with_higher_recursion_limit( EvalCtxt::enter_root(delegate, delegate.cx().recursion_limit() * 2, span, |ecx| { ecx.evaluate_goal_no_fast_paths(GoalSource::Misc, goal) }); - if let Ok(goal_evaluation) = &rerun_result - && !goal_evaluation.certainty.is_overflow() - { - Ok(rerun_result) - } else { + + if rerun_result.as_ref().is_ok_and(|evaluation| evaluation.certainty.is_overflow()) { Err(()) + } else { + Ok(rerun_result) } }); if let Ok(rerun_result) = rerun_result { @@ -408,12 +404,11 @@ fn maybe_evaluate_root_goal_for_proof_tree_with_higher_recursion_limit( span, delegate.cx().recursion_limit() * 2, ); - if let Ok(response) = &new_goal_evaluation.result - && !response.value.certainty.is_overflow() - { - Ok((new_result, new_goal_evaluation)) - } else { + + if new_goal_evaluation.result.is_ok_and(|response| response.value.certainty.is_overflow()) { Err(()) + } else { + Ok((new_result, new_goal_evaluation)) } }); if let Ok(rerun_result) = rerun_result { diff --git a/compiler/rustc_parse/src/diagnostics.rs b/compiler/rustc_parse/src/diagnostics.rs index 7897239d248ea..397baa0ae4ddb 100644 --- a/compiler/rustc_parse/src/diagnostics.rs +++ b/compiler/rustc_parse/src/diagnostics.rs @@ -1118,6 +1118,27 @@ pub(crate) struct ArrayBracketsInsteadOfBracesSugg { pub right: Span, } +#[derive(Diagnostic)] +#[diag("attributes are not allowed inside imports")] +pub(crate) struct AttrInUseTree { + #[primary_span] + pub attr_span: Span, + #[subdiagnostic] + pub sub: Option, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion("move the import to its own item", style = "verbose")] +pub(crate) struct AttrInUseTreeSugg { + #[suggestion_part(code = "{code}")] + pub use_lo: Span, + #[suggestion_part(code = "")] + pub attr_span: Span, + #[suggestion_part(code = "")] + pub tree_span: Span, + pub code: String, +} + #[derive(Diagnostic)] #[diag("`match` arm body without braces")] pub(crate) struct MatchArmBodyWithoutBraces { diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index fae58c29954d0..0f49e3c02873d 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -310,11 +310,15 @@ impl<'a> Parser<'a> { /// Parses an inner part of an attribute (the path and following tokens). /// The tokens must be either a delimited token stream, or empty token stream, /// or the "legacy" key-value form. - /// PATH `(` TOKEN_STREAM `)` - /// PATH `[` TOKEN_STREAM `]` - /// PATH `{` TOKEN_STREAM `}` - /// PATH - /// PATH `=` UNSUFFIXED_LIT + /// + /// ```text + /// PATH `(` TOKEN_STREAM `)` + /// PATH `[` TOKEN_STREAM `]` + /// PATH `{` TOKEN_STREAM `}` + /// PATH + /// PATH `=` UNSUFFIXED_LIT + /// ``` + /// /// The delimiters or `=` are still put into the resulting token stream. pub fn parse_attr_item( &mut self, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 1306f1fcfb1ce..44ce647568d00 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -434,7 +434,8 @@ impl<'a> Parser<'a> { } fn parse_use_item(&mut self) -> PResult<'a, ItemKind> { - let tree = self.parse_use_tree()?; + let use_token_span = self.prev_token.span; + let tree = self.parse_use_tree(use_token_span, None)?; if let Err(mut e) = self.expect_semi() { match tree.kind { UseTreeKind::Glob(_) => { @@ -1317,7 +1318,11 @@ impl<'a> Parser<'a> { /// PATH `::` `{` USE_TREE_LIST `}` | /// PATH [`as` IDENT] /// ``` - fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { + fn parse_use_tree<'b>( + &mut self, + use_token_span: Span, + use_path: Option<&'b UsePathList<'b>>, + ) -> PResult<'a, UseTree> { let lo = self.token.span; let mut prefix = ast::Path { segments: ThinVec::new(), span: lo.shrink_to_lo() }; @@ -1331,13 +1336,14 @@ impl<'a> Parser<'a> { .push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt))); } - self.parse_use_tree_glob_or_nested()? + self.parse_use_tree_glob_or_nested(use_token_span, use_path)? } else { // `use path::*;` or `use path::{...};` or `use path;` or `use path as bar;` prefix = self.parse_path(PathStyle::Mod)?; if self.eat_path_sep() { - self.parse_use_tree_glob_or_nested()? + let use_path = UsePathList { elements: &prefix.segments, prev: use_path }; + self.parse_use_tree_glob_or_nested(use_token_span, Some(&use_path))? } else { // Recover from using a colon as path separator. while self.eat_noexpect(&token::Colon) { @@ -1358,13 +1364,17 @@ impl<'a> Parser<'a> { } /// Parses `*` or `{...}`. - fn parse_use_tree_glob_or_nested(&mut self) -> PResult<'a, UseTreeKind> { + fn parse_use_tree_glob_or_nested<'b>( + &mut self, + use_token_span: Span, + use_path: Option<&'b UsePathList<'b>>, + ) -> PResult<'a, UseTreeKind> { Ok(if self.eat(exp!(Star)) { UseTreeKind::Glob(self.prev_token.span) } else { let lo = self.token.span; UseTreeKind::Nested { - items: self.parse_use_tree_list()?, + items: self.parse_use_tree_list(use_token_span, use_path)?, span: lo.to(self.prev_token.span), } }) @@ -1375,14 +1385,85 @@ impl<'a> Parser<'a> { /// ```text /// USE_TREE_LIST = ∅ | (USE_TREE `,`)* USE_TREE [`,`] /// ``` - fn parse_use_tree_list(&mut self) -> PResult<'a, ThinVec<(UseTree, ast::NodeId)>> { + fn parse_use_tree_list<'b>( + &mut self, + use_token_span: Span, + prefix: Option<&'b UsePathList<'b>>, + ) -> PResult<'a, ThinVec<(UseTree, ast::NodeId)>> { self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), |p| { p.recover_vcs_conflict_marker(); - Ok((p.parse_use_tree()?, DUMMY_NODE_ID)) + + let mut attr_span = None; + let attrs = p.parse_outer_attributes()?; + if !attrs.is_empty() { + let raw_attrs = attrs.take_for_recovery(&p.psess); + attr_span = + Some(raw_attrs.first().unwrap().span.to(raw_attrs.last().unwrap().span)); + } + + let use_tree = p.parse_use_tree(use_token_span, prefix)?; + + if let Some(attr_span) = attr_span { + p.emit_error_attr_in_use_tree(use_token_span, prefix, use_tree.span(), attr_span); + } + + Ok((use_tree, DUMMY_NODE_ID)) }) .map(|(r, _)| r) } + fn emit_error_attr_in_use_tree( + &self, + use_token_span: Span, + mut prefix: Option<&UsePathList<'_>>, + use_tree_span: Span, + attr_span: Span, + ) { + let Ok(attr) = self.psess.source_map().span_to_snippet(attr_span) else { return }; + + let prefix: Vec<_> = { + let mut tmp = Vec::new(); + while let Some(prefix_) = prefix { + tmp.push(prefix_.elements); + prefix = prefix_.prev; + } + tmp.reverse(); + tmp.into_iter().flatten().collect() + }; + + let prefix: String = prefix + .iter() + .map(|seg| if seg.ident.name == kw::PathRoot { "" } else { seg.ident.as_str() }) + .intersperse("::") + .collect(); + + let mut comma_reached = false; + let Ok(tree_span) = self.psess.source_map().span_extend_while(use_tree_span, |c| { + if comma_reached { + return false; + } + comma_reached = c == ','; + c.is_whitespace() || comma_reached + }) else { + return; + }; + + let Ok(use_tree) = self.psess.source_map().span_to_snippet(use_tree_span) else { return }; + + // FIXME: duplicate the attributes that are at the root of the initial use-item. + let code = format!("{attr}\nuse {prefix}::{use_tree};\n"); + + self.dcx().emit_err(crate::diagnostics::AttrInUseTree { + attr_span, + sub: Some(crate::diagnostics::AttrInUseTreeSugg { + use_lo: use_token_span.shrink_to_lo(), + attr_span, + tree_span, + code, + }), + }); + } + fn parse_rename(&mut self) -> PResult<'a, Option> { if self.eat_keyword(exp!(As)) { self.parse_ident_or_underscore().map(Some) @@ -2737,7 +2818,13 @@ impl<'a> Parser<'a> { } } } + enum IsMacroRulesItem { Yes { has_bang: bool }, No, } + +struct UsePathList<'a> { + elements: &'a [ast::PathSegment], + prev: Option<&'a Self>, +} diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 38248013557a1..90459090ced87 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2335,10 +2335,12 @@ options! { parse_symbol_mangling_version, [TRACKED], "which mangling version to use for symbol names ('legacy', 'v0' (default), or 'hashed')"), target_cpu: Option = (None, parse_opt_string, [TRACKED] { TARGET_MODIFIER: TargetCpu }, - "select target processor (`rustc --print target-cpus` for details)"), + "select target processor (`rustc --print target-cpus` for details) \ + The resulting binary must only be executed on CPUs that have all the features \ + of the given CPU."), target_feature: String = (String::new(), parse_target_feature, [TRACKED], - "target specific attributes. (`rustc --print target-features` for details). \ - This feature is unsafe."), + "target-specific attributes (`rustc --print target-features` for details). \ + The resulting binary must only be executed on CPUs that have all the given features."), unsafe_allow_abi_mismatch: Vec = (Vec::new(), parse_comma_list, [UNTRACKED], "Allow incompatible target modifiers in dependency crates (comma separated list)"), // tidy-alphabetical-end diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 80d1bae71ae89..f394765ab9f8e 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -596,9 +596,13 @@ impl SourceMap { /// Extracts the source surrounding the given `Span` using the `extract_source` function. The /// extract function takes three arguments: a string slice containing the source, an index in /// the slice for the beginning of the span and an index in the slice for the end of the span. - pub fn span_to_source(&self, sp: Span, extract_source: F) -> Result + pub fn span_to_source( + &self, + sp: Span, + mut extract_source: F, + ) -> Result where - F: Fn(&str, usize, usize) -> Result, + F: FnMut(&str, usize, usize) -> Result, { let local_begin = self.lookup_byte_offset(sp.lo()); let local_end = self.lookup_byte_offset(sp.hi()); @@ -753,7 +757,7 @@ impl SourceMap { pub fn span_extend_while( &self, span: Span, - f: impl Fn(char) -> bool, + mut f: impl FnMut(char) -> bool, ) -> Result { self.span_to_source(span, |s, _start, end| { let n = s[end..].char_indices().find(|&(_, c)| !f(c)).map_or(s.len() - end, |(i, _)| i); diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs index 581c1e2e862c5..f0d9675de34f4 100644 --- a/compiler/rustc_target/src/callconv/s390x.rs +++ b/compiler/rustc_target/src/callconv/s390x.rs @@ -42,6 +42,11 @@ where return; } + if arg.layout.is_complex_number(cx) { + arg.make_indirect(); + return; + } + let size = arg.layout.size; if size.bits() <= 128 { if let BackendRepr::SimdVector { .. } = arg.layout.backend_repr { diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 3bff243427bb1..818d8e1a4e0c3 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -544,8 +544,9 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< pred_str(goal.predicate), )); for p in visitor.predicates.into_iter().skip(1) { - diag.note(format!("which requires {}", pred_str(p))); + diag.note(format!("which requires `{}`", pred_str(p))); } + diag.note("and so on..."); diag.help( "consider adding a manual `impl` of auto traits like `Send` for intermediate types, if auto traits are involved", ); diff --git a/library/coretests/tests/pattern.rs b/library/coretests/tests/pattern.rs index d4bec996d89a1..b5cd019c59e76 100644 --- a/library/coretests/tests/pattern.rs +++ b/library/coretests/tests/pattern.rs @@ -3,10 +3,10 @@ use std::str::pattern::*; // This macro makes it easier to write // tests that do a series of iterations macro_rules! search_asserts { - ($haystack:expr, $needle:expr, $testname:expr, [$($func:ident),*], $result:expr) => { + ($haystack:expr, $needle:expr, $testname:literal, $($func:ident => $result:expr),*) => { let mut searcher = $needle.into_searcher($haystack); - let arr = [$( Step::from(searcher.$func()) ),*]; - assert_eq!(&arr[..], &$result, $testname); + let arr = [$( searcher.$func().into_step(stringify!($func)) ),*]; + assert_eq!(&arr[..], &[$($result),*], $testname); } } @@ -17,26 +17,31 @@ enum Step { // be the same length for easy alignment Matches(usize, usize), Rejects(usize, usize), - InRange(usize, usize), Done, } -use self::Step::*; +use Step::*; -impl From for Step { - fn from(x: SearchStep) -> Self { - match x { - SearchStep::Match(a, b) => Matches(a, b), - SearchStep::Reject(a, b) => Rejects(a, b), +trait IntoStep { + fn into_step(self, method_name: &str) -> Step; +} + +impl IntoStep for SearchStep { + fn into_step(self, _name: &str) -> Step { + match self { + SearchStep::Match(s, e) => Matches(s, e), + SearchStep::Reject(s, e) => Rejects(s, e), SearchStep::Done => Done, } } } -impl From> for Step { - fn from(x: Option<(usize, usize)>) -> Self { - match x { - Some((a, b)) => InRange(a, b), +impl IntoStep for Option<(usize, usize)> { + fn into_step(self, method_name: &str) -> Step { + let is_reject = method_name.starts_with("next_reject"); + match self { + Some((s, e)) if is_reject => Rejects(s, e), + Some((s, e)) => Matches(s, e), None => Done, } } @@ -54,142 +59,134 @@ fn test_simple_iteration() { "abcdeabcd", 'a', "forward iteration for ASCII string", - // a b c d e a b c d EOF - [next, next, next, next, next, next, next, next, next, next], - [ - Matches(0, 1), - Rejects(1, 2), - Rejects(2, 3), - Rejects(3, 4), - Rejects(4, 5), - Matches(5, 6), - Rejects(6, 7), - Rejects(7, 8), - Rejects(8, 9), - Done - ] + next => Matches(0, 1), + next => Rejects(1, 2), + next => Rejects(2, 3), + next => Rejects(3, 4), + next => Rejects(4, 5), + next => Matches(5, 6), + next => Rejects(6, 7), + next => Rejects(7, 8), + next => Rejects(8, 9), + next => Done ); search_asserts!( "abcdeabcd", 'a', "reverse iteration for ASCII string", - // d c b a e d c b a EOF - [ - next_back, next_back, next_back, next_back, next_back, next_back, next_back, next_back, - next_back, next_back - ], - [ - Rejects(8, 9), - Rejects(7, 8), - Rejects(6, 7), - Matches(5, 6), - Rejects(4, 5), - Rejects(3, 4), - Rejects(2, 3), - Rejects(1, 2), - Matches(0, 1), - Done - ] + next_back => Rejects(8, 9), + next_back => Rejects(7, 8), + next_back => Rejects(6, 7), + next_back => Matches(5, 6), + next_back => Rejects(4, 5), + next_back => Rejects(3, 4), + next_back => Rejects(2, 3), + next_back => Rejects(1, 2), + next_back => Matches(0, 1), + next_back => Done ); search_asserts!( "我爱我的猫", '我', "forward iteration for Chinese string", - // 我 愛 我 的 貓 EOF - [next, next, next, next, next, next], - [Matches(0, 3), Rejects(3, 6), Matches(6, 9), Rejects(9, 12), Rejects(12, 15), Done] + next => Matches(0, 3), + next => Rejects(3, 6), + next => Matches(6, 9), + next => Rejects(9, 12), + next => Rejects(12, 15), + next => Done ); search_asserts!( "我的猫说meow", 'm', "forward iteration for mixed string", - // 我 的 猫 说 m e o w EOF - [next, next, next, next, next, next, next, next, next], - [ - Rejects(0, 3), - Rejects(3, 6), - Rejects(6, 9), - Rejects(9, 12), - Matches(12, 13), - Rejects(13, 14), - Rejects(14, 15), - Rejects(15, 16), - Done - ] + next => Rejects(0, 3), + next => Rejects(3, 6), + next => Rejects(6, 9), + next => Rejects(9, 12), + next => Matches(12, 13), + next => Rejects(13, 14), + next => Rejects(14, 15), + next => Rejects(15, 16), + next => Done ); search_asserts!( "我的猫说meow", '猫', "reverse iteration for mixed string", - // w o e m 说 猫 的 我 EOF - [ - next_back, next_back, next_back, next_back, next_back, next_back, next_back, next_back, - next_back - ], - [ - Rejects(15, 16), - Rejects(14, 15), - Rejects(13, 14), - Rejects(12, 13), - Rejects(9, 12), - Matches(6, 9), - Rejects(3, 6), - Rejects(0, 3), - Done - ] + next_back => Rejects(15, 16), + next_back => Rejects(14, 15), + next_back => Rejects(13, 14), + next_back => Rejects(12, 13), + next_back => Rejects(9, 12), + next_back => Matches(6, 9), + next_back => Rejects(3, 6), + next_back => Rejects(0, 3), + next_back => Done ); } +#[test] +fn backward_search_predicate() { + assert_eq!("abc".rfind(|c| c == 'a'), Some(0)); + assert_eq!("abcabc".rfind(|c| c == 'c'), Some(5)); + assert_eq!("éabc".rfind(['é']), Some(0)); + assert_eq!("éabc".rfind(|c| c == 'é'), Some(0)); + assert_eq!("éabcé".rfind(|c| c == 'é'), Some(5)); + assert_eq!("€abc".rfind(|c| c == '€'), Some(0)); + assert_eq!("😀abc".rfind(|c| c == '😀'), Some(0)); + + assert_eq!("abc".strip_suffix(|c| c == 'c'), Some("ab")); + assert_eq!("éabc".strip_suffix(|c| c == 'é'), None); +} + #[test] fn test_simple_search() { search_asserts!( "abcdeabcdeabcde", 'a', "next_match for ASCII string", - [next_match, next_match, next_match, next_match], - [InRange(0, 1), InRange(5, 6), InRange(10, 11), Done] + next_match => Matches(0, 1), + next_match => Matches(5, 6), + next_match => Matches(10, 11), + next_match => Done ); search_asserts!( "abcdeabcdeabcde", 'a', "next_match_back for ASCII string", - [next_match_back, next_match_back, next_match_back, next_match_back], - [InRange(10, 11), InRange(5, 6), InRange(0, 1), Done] + next_match_back => Matches(10, 11), + next_match_back => Matches(5, 6), + next_match_back => Matches(0, 1), + next_match_back => Done ); search_asserts!( "abcdeab", 'a', "next_reject for ASCII string", - [next_reject, next_reject, next_match, next_reject, next_reject], - [InRange(1, 2), InRange(2, 3), InRange(5, 6), InRange(6, 7), Done] + next_reject => Rejects(1, 2), + next_reject => Rejects(2, 3), + next_match => Matches(5, 6), + next_reject => Rejects(6, 7), + next_reject => Done ); search_asserts!( "abcdeabcdeabcde", 'a', "next_reject_back for ASCII string", - [ - next_reject_back, - next_reject_back, - next_match_back, - next_reject_back, - next_reject_back, - next_reject_back - ], - [ - InRange(14, 15), - InRange(13, 14), - InRange(10, 11), - InRange(9, 10), - InRange(8, 9), - InRange(7, 8) - ] + next_reject_back => Rejects(14, 15), + next_reject_back => Rejects(13, 14), + next_match_back => Matches(10, 11), + next_reject_back => Rejects(9, 10), + next_reject_back => Rejects(8, 9), + next_reject_back => Rejects(7, 8) ); } @@ -207,38 +204,58 @@ const STRESS: &str = "Áa🁀bÁꁁfg😁각กᘀ각aÁ각ꁁก😁a"; #[test] fn test_stress_indices() { // this isn't really a test, more of documentation on the indices of each character in the stresstest string + search_asserts!( + STRESS, + |_| true, + "Indices of characters in stress test", + next => Matches(0, 2), // Á + next => Matches(2, 3), // a + next => Matches(3, 7), // 🁀 + next => Matches(7, 8), // b + next => Matches(8, 10), // Á + next => Matches(10, 13), // ꁁ + next => Matches(13, 14), // f + next => Matches(14, 15), // g + next => Matches(15, 19), // 😀 + next => Matches(19, 22), // 각 + next => Matches(22, 25), // ก + next => Matches(25, 28), // ᘀ + next => Matches(28, 31), // 각 + next => Matches(31, 32), // a + next => Matches(32, 34), // Á + next => Matches(34, 37), // 각 + next => Matches(37, 40), // ꁁ + next => Matches(40, 43), // ก + next => Matches(43, 47), // 😀 + next => Matches(47, 48), // a + next => Done + ); search_asserts!( STRESS, 'x', "Indices of characters in stress test", - [ - next, next, next, next, next, next, next, next, next, next, next, next, next, next, - next, next, next, next, next, next, next - ], - [ - Rejects(0, 2), // Á - Rejects(2, 3), // a - Rejects(3, 7), // 🁀 - Rejects(7, 8), // b - Rejects(8, 10), // Á - Rejects(10, 13), // ꁁ - Rejects(13, 14), // f - Rejects(14, 15), // g - Rejects(15, 19), // 😀 - Rejects(19, 22), // 각 - Rejects(22, 25), // ก - Rejects(25, 28), // ᘀ - Rejects(28, 31), // 각 - Rejects(31, 32), // a - Rejects(32, 34), // Á - Rejects(34, 37), // 각 - Rejects(37, 40), // ꁁ - Rejects(40, 43), // ก - Rejects(43, 47), // 😀 - Rejects(47, 48), // a - Done - ] + next => Rejects(0, 2), // Á + next => Rejects(2, 3), // a + next => Rejects(3, 7), // 🁀 + next => Rejects(7, 8), // b + next => Rejects(8, 10), // Á + next => Rejects(10, 13), // ꁁ + next => Rejects(13, 14), // f + next => Rejects(14, 15), // g + next => Rejects(15, 19), // 😀 + next => Rejects(19, 22), // 각 + next => Rejects(22, 25), // ก + next => Rejects(25, 28), // ᘀ + next => Rejects(28, 31), // 각 + next => Rejects(31, 32), // a + next => Rejects(32, 34), // Á + next => Rejects(34, 37), // 각 + next => Rejects(37, 40), // ꁁ + next => Rejects(40, 43), // ก + next => Rejects(43, 47), // 😀 + next => Rejects(47, 48), // a + next => Done ); } @@ -248,96 +265,113 @@ fn test_forward_search_shared_bytes() { STRESS, 'Á', "Forward search for two-byte Latin character", - [next_match, next_match, next_match, next_match], - [InRange(0, 2), InRange(8, 10), InRange(32, 34), Done] + next_match => Matches(0, 2), + next_match => Matches(8, 10), + next_match => Matches(32, 34), + next_match => Done ); search_asserts!( STRESS, 'Á', "Forward search for two-byte Latin character; check if next() still works", - [next_match, next, next_match, next, next_match, next, next_match], - [ - InRange(0, 2), - Rejects(2, 3), - InRange(8, 10), - Rejects(10, 13), - InRange(32, 34), - Rejects(34, 37), - Done - ] + next_match => Matches(0, 2), + next => Rejects(2, 3), + next_match => Matches(8, 10), + next => Rejects(10, 13), + next_match => Matches(32, 34), + next => Rejects(34, 37), + next_match => Done ); search_asserts!( STRESS, '각', "Forward search for three-byte Hangul character", - [next_match, next, next_match, next_match, next_match], - [InRange(19, 22), Rejects(22, 25), InRange(28, 31), InRange(34, 37), Done] + next_match => Matches(19, 22), + next => Rejects(22, 25), + next_match => Matches(28, 31), + next_match => Matches(34, 37), + next_match => Done ); search_asserts!( STRESS, '각', "Forward search for three-byte Hangul character; check if next() still works", - [next_match, next, next_match, next, next_match, next, next_match], - [ - InRange(19, 22), - Rejects(22, 25), - InRange(28, 31), - Rejects(31, 32), - InRange(34, 37), - Rejects(37, 40), - Done - ] + next_match => Matches(19, 22), + next => Rejects(22, 25), + next_match => Matches(28, 31), + next => Rejects(31, 32), + next_match => Matches(34, 37), + next => Rejects(37, 40), + next_match => Done ); search_asserts!( STRESS, 'ก', "Forward search for three-byte Thai character", - [next_match, next, next_match, next, next_match], - [InRange(22, 25), Rejects(25, 28), InRange(40, 43), Rejects(43, 47), Done] + next_match => Matches(22, 25), + next => Rejects(25, 28), + next_match => Matches(40, 43), + next => Rejects(43, 47), + next_match => Done ); search_asserts!( STRESS, 'ก', "Forward search for three-byte Thai character; check if next() still works", - [next_match, next, next_match, next, next_match], - [InRange(22, 25), Rejects(25, 28), InRange(40, 43), Rejects(43, 47), Done] + next_match => Matches(22, 25), + next => Rejects(25, 28), + next_match => Matches(40, 43), + next => Rejects(43, 47), + next_match => Done ); search_asserts!( STRESS, '😁', "Forward search for four-byte emoji", - [next_match, next, next_match, next, next_match], - [InRange(15, 19), Rejects(19, 22), InRange(43, 47), Rejects(47, 48), Done] + next_match => Matches(15, 19), + next => Rejects(19, 22), + next_match => Matches(43, 47), + next => Rejects(47, 48), + next_match => Done ); search_asserts!( STRESS, '😁', "Forward search for four-byte emoji; check if next() still works", - [next_match, next, next_match, next, next_match], - [InRange(15, 19), Rejects(19, 22), InRange(43, 47), Rejects(47, 48), Done] + next_match => Matches(15, 19), + next => Rejects(19, 22), + next_match => Matches(43, 47), + next => Rejects(47, 48), + next_match => Done ); search_asserts!( STRESS, 'ꁁ', "Forward search for three-byte Yi character with repeated bytes", - [next_match, next, next_match, next, next_match], - [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(40, 43), Done] + next_match => Matches(10, 13), + next => Rejects(13, 14), + next_match => Matches(37, 40), + next => Rejects(40, 43), + next_match => Done ); search_asserts!( STRESS, 'ꁁ', "Forward search for three-byte Yi character with repeated bytes; check if next() still works", - [next_match, next, next_match, next, next_match], - [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(40, 43), Done] + next_match => Matches(10, 13), + next => Rejects(13, 14), + next_match => Matches(37, 40), + next => Rejects(40, 43), + next_match => Done ); } @@ -347,96 +381,112 @@ fn test_reverse_search_shared_bytes() { STRESS, 'Á', "Reverse search for two-byte Latin character", - [next_match_back, next_match_back, next_match_back, next_match_back], - [InRange(32, 34), InRange(8, 10), InRange(0, 2), Done] + next_match_back => Matches(32, 34), + next_match_back => Matches(8, 10), + next_match_back => Matches(0, 2), + next_match_back => Done ); search_asserts!( STRESS, 'Á', "Reverse search for two-byte Latin character; check if next_back() still works", - [next_match_back, next_back, next_match_back, next_back, next_match_back, next_back], - [InRange(32, 34), Rejects(31, 32), InRange(8, 10), Rejects(7, 8), InRange(0, 2), Done] + next_match_back => Matches(32, 34), + next_back => Rejects(31, 32), + next_match_back => Matches(8, 10), + next_back => Rejects(7, 8), + next_match_back => Matches(0, 2), + next_back => Done ); search_asserts!( STRESS, '각', "Reverse search for three-byte Hangul character", - [next_match_back, next_back, next_match_back, next_match_back, next_match_back], - [InRange(34, 37), Rejects(32, 34), InRange(28, 31), InRange(19, 22), Done] + next_match_back => Matches(34, 37), + next_back => Rejects(32, 34), + next_match_back => Matches(28, 31), + next_match_back => Matches(19, 22), + next_match_back => Done ); search_asserts!( STRESS, '각', "Reverse search for three-byte Hangul character; check if next_back() still works", - [ - next_match_back, - next_back, - next_match_back, - next_back, - next_match_back, - next_back, - next_match_back - ], - [ - InRange(34, 37), - Rejects(32, 34), - InRange(28, 31), - Rejects(25, 28), - InRange(19, 22), - Rejects(15, 19), - Done - ] + next_match_back => Matches(34, 37), + next_back => Rejects(32, 34), + next_match_back => Matches(28, 31), + next_back => Rejects(25, 28), + next_match_back => Matches(19, 22), + next_back => Rejects(15, 19), + next_match_back => Done ); search_asserts!( STRESS, 'ก', "Reverse search for three-byte Thai character", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(40, 43), Rejects(37, 40), InRange(22, 25), Rejects(19, 22), Done] + next_match_back => Matches(40, 43), + next_back => Rejects(37, 40), + next_match_back => Matches(22, 25), + next_back => Rejects(19, 22), + next_match_back => Done ); search_asserts!( STRESS, 'ก', "Reverse search for three-byte Thai character; check if next_back() still works", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(40, 43), Rejects(37, 40), InRange(22, 25), Rejects(19, 22), Done] + next_match_back => Matches(40, 43), + next_back => Rejects(37, 40), + next_match_back => Matches(22, 25), + next_back => Rejects(19, 22), + next_match_back => Done ); search_asserts!( STRESS, '😁', "Reverse search for four-byte emoji", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(43, 47), Rejects(40, 43), InRange(15, 19), Rejects(14, 15), Done] + next_match_back => Matches(43, 47), + next_back => Rejects(40, 43), + next_match_back => Matches(15, 19), + next_back => Rejects(14, 15), + next_match_back => Done ); search_asserts!( STRESS, '😁', "Reverse search for four-byte emoji; check if next_back() still works", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(43, 47), Rejects(40, 43), InRange(15, 19), Rejects(14, 15), Done] + next_match_back => Matches(43, 47), + next_back => Rejects(40, 43), + next_match_back => Matches(15, 19), + next_back => Rejects(14, 15), + next_match_back => Done ); search_asserts!( STRESS, 'ꁁ', "Reverse search for three-byte Yi character with repeated bytes", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(37, 40), Rejects(34, 37), InRange(10, 13), Rejects(8, 10), Done] + next_match_back => Matches(37, 40), + next_back => Rejects(34, 37), + next_match_back => Matches(10, 13), + next_back => Rejects(8, 10), + next_match_back => Done ); search_asserts!( STRESS, 'ꁁ', "Reverse search for three-byte Yi character with repeated bytes; check if next_back() still works", - [next_match_back, next_back, next_match_back, next_back, next_match_back], - [InRange(37, 40), Rejects(34, 37), InRange(10, 13), Rejects(8, 10), Done] + next_match_back => Matches(37, 40), + next_back => Rejects(34, 37), + next_match_back => Matches(10, 13), + next_back => Rejects(8, 10), + next_match_back => Done ); } @@ -448,56 +498,77 @@ fn double_ended_regression_test() { "abcdeabcdeabcde", 'a', "alternating double ended search", - [next_match, next_match_back, next_match, next_match_back], - [InRange(0, 1), InRange(10, 11), InRange(5, 6), Done] + next_match => Matches(0, 1), + next_match_back => Matches(10, 11), + next_match => Matches(5, 6), + next_match_back => Done ); search_asserts!( "abcdeabcdeabcde", 'a', "triple double ended search for a", - [next_match, next_match_back, next_match_back, next_match_back], - [InRange(0, 1), InRange(10, 11), InRange(5, 6), Done] + next_match => Matches(0, 1), + next_match_back => Matches(10, 11), + next_match_back => Matches(5, 6), + next_match_back => Done ); search_asserts!( "abcdeabcdeabcde", 'd', "triple double ended search for d", - [next_match, next_match_back, next_match_back, next_match_back], - [InRange(3, 4), InRange(13, 14), InRange(8, 9), Done] + next_match => Matches(3, 4), + next_match_back => Matches(13, 14), + next_match_back => Matches(8, 9), + next_match_back => Done ); search_asserts!( STRESS, 'Á', "Double ended search for two-byte Latin character", - [next_match, next_match_back, next_match, next_match_back], - [InRange(0, 2), InRange(32, 34), InRange(8, 10), Done] + next_match => Matches(0, 2), + next_match_back => Matches(32, 34), + next_match => Matches(8, 10), + next_match_back => Done ); search_asserts!( STRESS, '각', "Reverse double ended search for three-byte Hangul character", - [next_match_back, next_back, next_match, next, next_match_back, next_match], - [InRange(34, 37), Rejects(32, 34), InRange(19, 22), Rejects(22, 25), InRange(28, 31), Done] + next_match_back => Matches(34, 37), + next_back => Rejects(32, 34), + next_match => Matches(19, 22), + next => Rejects(22, 25), + next_match_back => Matches(28, 31), + next_match => Done ); search_asserts!( STRESS, 'ก', "Double ended search for three-byte Thai character", - [next_match, next_back, next, next_match_back, next_match], - [InRange(22, 25), Rejects(47, 48), Rejects(25, 28), InRange(40, 43), Done] + next_match => Matches(22, 25), + next_back => Rejects(47, 48), + next => Rejects(25, 28), + next_match_back => Matches(40, 43), + next_match => Done ); search_asserts!( STRESS, '😁', "Double ended search for four-byte emoji", - [next_match_back, next, next_match, next_back, next_match], - [InRange(43, 47), Rejects(0, 2), InRange(15, 19), Rejects(40, 43), Done] + next_match_back => Matches(43, 47), + next => Rejects(0, 2), + next_match => Matches(15, 19), + next_back => Rejects(40, 43), + next_match => Done ); search_asserts!( STRESS, 'ꁁ', "Double ended search for three-byte Yi character with repeated bytes", - [next_match, next, next_match_back, next_back, next_match], - [InRange(10, 13), Rejects(13, 14), InRange(37, 40), Rejects(34, 37), Done] + next_match => Matches(10, 13), + next => Rejects(13, 14), + next_match_back => Matches(37, 40), + next_back => Rejects(34, 37), + next_match => Done ); } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 0702148957695..1e46ddb99e010 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -3590,7 +3590,7 @@ impl DirBuilder { fn create_dir_all(&self, path: &Path) -> io::Result<()> { // if path's parent is None, it is "/" path, which should // return Ok immediately - if path == Path::new("") || path.parent() == None { + if path.is_empty() || path.parent() == None { return Ok(()); } @@ -3601,7 +3601,7 @@ impl DirBuilder { // for relative paths like "foo/bar", the parent of // "foo" will be "" which there's no need to invoke // a mkdir syscall on - if ancestor == Path::new("") || ancestor.parent() == None { + if ancestor.is_empty() || ancestor.parent() == None { break; } diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index a57da01a5d85d..048e5def1369b 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -16,12 +16,12 @@ mod tests; #[derive(Hash)] #[repr(transparent)] -pub struct Buf { +pub(crate) struct Buf { pub inner: Vec, } #[repr(transparent)] -pub struct Slice { +pub(crate) struct Slice { pub inner: [u8], } diff --git a/library/std/src/sys/os_str/mod.rs b/library/std/src/sys/os_str/mod.rs index f7007cbf18b4c..dd37b558a096e 100644 --- a/library/std/src/sys/os_str/mod.rs +++ b/library/std/src/sys/os_str/mod.rs @@ -3,14 +3,14 @@ cfg_select! { any(target_os = "windows", target_os = "uefi") => { mod wtf8; - pub use wtf8::{Buf, Slice}; + pub(crate) use wtf8::{Buf, Slice}; } any(target_os = "motor") => { mod utf8; - pub use utf8::{Buf, Slice}; + pub(crate) use utf8::{Buf, Slice}; } _ => { mod bytes; - pub use bytes::{Buf, Slice}; + pub(crate) use bytes::{Buf, Slice}; } } diff --git a/library/std/src/sys/os_str/utf8.rs b/library/std/src/sys/os_str/utf8.rs index 289f58aa480f7..3648962da5eeb 100644 --- a/library/std/src/sys/os_str/utf8.rs +++ b/library/std/src/sys/os_str/utf8.rs @@ -11,12 +11,12 @@ use crate::{fmt, mem}; #[derive(Hash)] #[repr(transparent)] -pub struct Buf { +pub(crate) struct Buf { pub inner: String, } #[repr(transparent)] -pub struct Slice { +pub(crate) struct Slice { pub inner: str, } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 9a32ab3f3ea12..5f9d64dc5d09c 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -13,12 +13,12 @@ use crate::{fmt, mem}; #[derive(Hash)] #[repr(transparent)] -pub struct Buf { +pub(crate) struct Buf { pub inner: Wtf8Buf, } #[repr(transparent)] -pub struct Slice { +pub(crate) struct Slice { pub inner: Wtf8, } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index c08f73c95b69b..1fba19c21a162 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -285,7 +285,7 @@ fn try_download_ci_llvm(builder: &Builder<'_>, target: TargetSelection) -> Optio Some(DownloadedLlvm { output: LlvmOutput { - host_llvm_config: ci_llvm.join("bin").join("llvm-config"), + host_llvm_config: ci_llvm.join("bin").join(exe("llvm-config", builder.host_target)), link_shared, llvm_root_dir: ci_llvm, kind: LlvmKind::DownloadedFromCi, diff --git a/src/bootstrap/src/core/session.rs b/src/bootstrap/src/core/session.rs index 3e6668258c641..6d0d29dcc1fc4 100644 --- a/src/bootstrap/src/core/session.rs +++ b/src/bootstrap/src/core/session.rs @@ -25,7 +25,8 @@ use crate::utils::build_stamp::BuildStamp; use crate::utils::channel::GitInfo; use crate::utils::exec::{BootstrapCommand, ExecutionContext, command}; use crate::utils::helpers::{ - self, dir_is_empty, exe, libdir, set_file_times, split_debuginfo, symlink_dir, t, + self, dir_is_empty, exe, is_symlink_dir, libdir, set_file_times, split_debuginfo, symlink_dir, + t, }; use crate::{debug, trace}; @@ -1606,7 +1607,11 @@ impl Build { metadata = t!(fs::metadata(&src), format!("target = {}", src.display())); } else { let link = t!(fs::read_link(src)); - t!(self.symlink_file(link, dst)); + if is_symlink_dir(&metadata) { + t!(symlink_dir(&self.config, &link, dst)); + } else { + t!(self.symlink_file(link, dst)); + } return; } } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 8e881f1bf7734..d41ce974c5009 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -185,6 +185,17 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result< } } +/// Detects a symlink or a junction on Windows +pub fn is_symlink_dir(_metadata: &fs::Metadata) -> bool { + #[cfg(windows)] + { + use std::os::windows::fs::FileTypeExt; + _metadata.file_type().is_symlink_dir() + } + #[cfg(not(windows))] + false +} + /// Return the host target on which we are currently running. pub fn get_host_target() -> TargetSelection { TargetSelection::from_user(env!("BUILD_TRIPLE")) diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index ccc524c577dd4..d418b15f2a952 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -156,9 +156,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.62" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d" dependencies = [ "find-msvc-tools", "jobserver", @@ -512,9 +512,9 @@ checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" [[package]] name = "foldhash" @@ -1507,9 +1507,9 @@ dependencies = [ [[package]] name = "shlex" -version = "1.3.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" [[package]] name = "siphasher" diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 503cc68fbc834..b9f8c10900853 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -168,7 +168,7 @@ case $HOST_TARGET in MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-freebsd run_tests MANY_SEEDS=16 TEST_TARGET=i686-unknown-freebsd run_tests MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-illumos run_tests - MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-netbsd run_tests_minimal hello + MANY_SEEDS=16 TEST_TARGET=x86_64-unknown-netbsd run_tests_minimal hello libc-env libc-misc ;; armv7-unknown-linux-gnueabihf) # Host diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 24fe5b66bb0b4..0a372dfbf0c6d 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -55,7 +55,7 @@ impl MiriEnv { .cargo_cmd("cargo-miri", "run", &[]) .arg("--quiet") .arg("--") - .args(&["miri", "setup", "--print-sysroot"]) + .args(["miri", "setup", "--print-sysroot"]) .args(target_flag); if quiet { cmd = cmd.arg("--quiet"); @@ -511,7 +511,7 @@ impl Command { // We invoke the test suite as that has all the logic for running with dependencies. let mut cmd = e .cargo_cmd(".", "test", &features) - .args(&["--test", "ui"]) + .args(["--test", "ui"]) // This does not show anything useful so we always hide it. .arg("--quiet") .arg("--") diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs index fd8b1958689df..01743c79f140b 100644 --- a/src/tools/miri/miri-script/src/util.rs +++ b/src/tools/miri/miri-script/src/util.rs @@ -178,7 +178,7 @@ impl MiriEnv { // parallelism in `./miri test` as we build Miri and its tests together. let mut cmd = self .cargo_cmd(crate_dir, "build", features) - .args(&["--all-targets"]) + .args(["--all-targets"]) .args(quiet_flag) .args(args); cmd.set_quiet(quiet); @@ -194,7 +194,7 @@ impl MiriEnv { ) -> Result { let cmd = self .cargo_cmd(crate_dir, "build", features) - .args(&["--all-targets", "--message-format=json"]); + .args(["--all-targets", "--message-format=json"]); let output = cmd.output()?; let mut bin = None; for line in output.stdout.lines() { diff --git a/src/tools/miri/priroda/README.md b/src/tools/miri/priroda/README.md index daab65fc3ad00..25ec34dce64d8 100644 --- a/src/tools/miri/priroda/README.md +++ b/src/tools/miri/priroda/README.md @@ -47,9 +47,13 @@ user-relevant source location after `configurationDone`, reports one current stack frame, exposes one flat Locals scope, and maps `list_locals()` into DAP variables with no child expansion. -The `next` and `stepIn` requests are wired to Priroda's existing source-line -step so VS Code can drive one visible step. They are not true DAP step-over or -step-in semantics yet. +DAP supports `stepIn`, `next`, and `stepOut`. `stepIn` stops at the next +displayed source location and can enter calls when the callee has a distinct +displayed source position. `next` steps over calls by tracking the starting stack +depth, and `stepOut` runs until execution reaches a shallower user frame. +`stepOut` from the outermost user frame is rejected. This is still +single-threaded and source-position based, not the full future thread/frame +model. ### VS Code @@ -152,7 +156,9 @@ RUSTC_BLESS=1 cargo test | Command | Description | |---|---| | Enter, `si`, `stepi` | Execute one Miri interpreter step. | -| `s`, `step` | Step until the displayed source location changes. | +| `s`, `step` | Step to the next displayed source location, entering calls with their own displayed position. | +| `n`, `next` | Step over the current displayed source location. | +| `out`, `stepout` | Run until execution returns to a shallower user frame. | | `c`, `continue` | Continue until the program finishes or reaches a breakpoint. | | `b :`, `break :` | Add a source-location breakpoint. | | `l`, `locals` | List source-level locals in the current frame by name. | diff --git a/src/tools/miri/priroda/src/debugger.rs b/src/tools/miri/priroda/src/debugger.rs index 646a4f2c570a5..4c4c811c01358 100644 --- a/src/tools/miri/priroda/src/debugger.rs +++ b/src/tools/miri/priroda/src/debugger.rs @@ -3,7 +3,7 @@ use std::ops::Range; use std::path::PathBuf; use miri::Immediate::Uninit; -use miri::*; +use miri::{InterpErrorInfo, InterpErrorKind, TerminationInfo, *}; use rustc_abi::{FIRST_VARIANT, FieldIdx, Size}; use rustc_hir::def::CtorKind; use rustc_middle::mir::interpret::AllocId; @@ -39,6 +39,9 @@ pub(super) struct PrirodaContext<'tcx> { breakpoints: BreakpointTable, pub(super) current_location: Option, last_location: Option, + // FIXME: add restart and other post-exit commands, similar to GDB and + // old Priroda, instead of only replaying the saved exit code. + exit_code: Option, } pub(super) enum StorageProj { @@ -98,11 +101,18 @@ impl LocalDesc { enum ResumeMode { /// Stop at the next visible MIR instruction. MirInstruction, - /// Stop at the next source line. + /// Step over the source position `start_position`, entered from a stack of + /// depth `start_stack_depth`. /// - /// `None` means the current interpreter position has no source location, so - /// the first mapped source location is good enough to report. - SourceLine(Option<(PathBuf, usize)>), + /// Execution keeps going while it is deeper than `start_stack_depth` (i.e. + /// inside a call made from the stepped-over line), and stops once it is back + /// at that depth or shallower and the displayed source position has changed. + /// A `start_stack_depth` of `usize::MAX` means execution is never deeper, + /// turning this into a plain source step that also stops inside called functions. + StepOver { start_position: Option<(PathBuf, usize)>, start_stack_depth: usize }, + /// Step out of the current user frame, stopping once execution returns to a + /// shallower user-frame depth. + StepOut { start_position: Option<(PathBuf, usize)>, start_user_frame_depth: usize }, /// Stop at the first mapped source location from a user-relevant frame. /// /// This is the DAP entry-stop primitive: it skips over interpreter startup @@ -119,10 +129,27 @@ enum InstructionVisibility { Visible, } +impl ResumeMode { + fn skipped_breakpoint(&self) -> Option<&(PathBuf, usize)> { + match self { + ResumeMode::StepOver { start_position: Some(position), .. } + | ResumeMode::StepOut { start_position: Some(position), .. } => Some(position), + _ => None, + } + } +} + /// Describes why execution stopped and returned control to the frontend. pub(super) enum StepResult { Step, Breakpoint, + Exception { message: String }, +} + +pub(super) enum ExecutionResult { + Stopped(StepResult), + ProgramExited { code: i32 }, + Rejected { message: &'static str }, } fn normalize_path(path: PathBuf) -> PathBuf { @@ -131,7 +158,13 @@ fn normalize_path(path: PathBuf) -> PathBuf { impl<'tcx> PrirodaContext<'tcx> { pub(super) fn new(ecx: MiriInterpCx<'tcx>) -> Self { - Self { ecx, breakpoints: HashMap::new(), current_location: None, last_location: None } + Self { + ecx, + breakpoints: HashMap::new(), + current_location: None, + last_location: None, + exit_code: None, + } } pub(super) fn local_path(&self, location: &SourceLocation) -> Option { @@ -152,17 +185,79 @@ impl<'tcx> PrirodaContext<'tcx> { Some((self.local_path(location)?, location.line)) } + fn already_finished(&self) -> Option { + self.exit_code.map(|code| ExecutionResult::ProgramExited { code }) + } + /// Step to the next visible MIR instruction. - fn stepi(&mut self) -> InterpResult<'tcx, StepResult> { + fn stepi(&mut self) -> InterpResult<'tcx, ExecutionResult> { + if let Some(result) = self.already_finished() { + return interp_ok(result); + } self.resume(ResumeMode::MirInstruction) } + /// Step until the displayed source file or line changes. - pub(super) fn step(&mut self) -> InterpResult<'tcx, StepResult> { - self.resume(ResumeMode::SourceLine(self.current_source_position())) + /// + /// This is the CLI source-level step; it shares its stepping semantics with + /// [`Self::step_in_source`]. + pub(super) fn step(&mut self) -> InterpResult<'tcx, ExecutionResult> { + self.step_in_source() + } + + /// Step into the next source location. + /// + /// This can enter calls that have a distinct displayed source position, + /// while `next` uses [`Self::step_over_source`]. + pub(super) fn step_in_source(&mut self) -> InterpResult<'tcx, ExecutionResult> { + if let Some(result) = self.already_finished() { + return interp_ok(result); + } + self.resume(ResumeMode::StepOver { + start_position: self.current_source_position(), + start_stack_depth: usize::MAX, + }) + } + + /// Step over the current source position, not stopping inside any call it makes. + /// + /// Records the current source position and stack depth before advancing, + /// then keeps stepping until execution is back at that depth (or shallower) + /// and the displayed source position has changed. + pub(super) fn step_over_source(&mut self) -> InterpResult<'tcx, ExecutionResult> { + if let Some(result) = self.already_finished() { + return interp_ok(result); + } + let start_position = self.current_source_position(); + let start_stack_depth = self.active_thread_stack_depth(); + self.resume(ResumeMode::StepOver { start_position, start_stack_depth }) + } + + /// Number of frames on the active thread's stack. + fn active_thread_stack_depth(&self) -> usize { + self.ecx.active_thread_stack().len() + } + + /// Step out of the current user frame. + /// + /// Records the current user-frame depth and runs until execution reaches a + /// source location in a shallower user frame. + pub(super) fn step_out_source(&mut self) -> InterpResult<'tcx, ExecutionResult> { + if let Some(result) = self.already_finished() { + return interp_ok(result); + } + let start_user_frame_depth = self.active_user_frame_depth(); + if start_user_frame_depth <= 1 { + return interp_ok(ExecutionResult::Rejected { + message: "stepOut is not meaningful in the outermost user frame", + }); + } + let start_position = self.current_source_position(); + self.resume(ResumeMode::StepOut { start_position, start_user_frame_depth }) } /// Run until the initial editor-visible stop point. - pub(super) fn stop_at_first_user_location(&mut self) -> InterpResult<'tcx, StepResult> { + pub(super) fn stop_at_first_user_location(&mut self) -> InterpResult<'tcx, ExecutionResult> { self.resume(ResumeMode::FirstUserSourceLocation) } @@ -173,10 +268,17 @@ impl<'tcx> PrirodaContext<'tcx> { } /// Continue execution until reaching a breakpoint or propagating termination. - pub(super) fn continue_execution(&mut self) -> InterpResult<'tcx, StepResult> { + pub(super) fn continue_execution(&mut self) -> InterpResult<'tcx, ExecutionResult> { + if let Some(result) = self.already_finished() { + return interp_ok(result); + } self.resume(ResumeMode::Continue) } + pub(super) fn finish_session(&mut self) -> InterpResult<'tcx, ()> { + interp_ok(()) + } + pub(super) fn set_breakpoint(&mut self, path: PathBuf, line: usize) -> BreakpointSetResult { // FIXME: validate breakpoints here so every frontend gets the same behavior. // Reject empty paths, missing files, directories, and line 0. Decide whether @@ -190,15 +292,44 @@ impl<'tcx> PrirodaContext<'tcx> { } } + fn program_exit(err: &InterpErrorInfo<'tcx>) -> Option { + let InterpErrorKind::MachineStop(info) = err.kind() else { + return None; + }; + // FIXME: Preserve `TerminationInfo::Exit::leak_check` and run Miri's + // leak/thread-leak diagnostics once Priroda grows a proper post-exit + // finalization path. For now, program exit only records the debuggee exit code. + let Some(TerminationInfo::Exit { code, .. }) = info.downcast_ref::() + else { + return None; + }; + Some(*code) + } + + fn stop_at_exception(&mut self, err: InterpErrorInfo<'tcx>) -> StepResult { + let message = err.kind().to_string(); + self.last_location = self.current_location.take(); + self.current_location = self.resolve_current_location(); + StepResult::Exception { message } + } + /// Advance execution until the selected resume mode reaches a stopping point. - fn resume(&mut self, mode: ResumeMode) -> InterpResult<'tcx, StepResult> { + fn resume(&mut self, mode: ResumeMode) -> InterpResult<'tcx, ExecutionResult> { loop { - self.advance()?; + // Program exits are not debugger exceptions. Preserve all other + // interpreter errors as stopped debugger events. + if let Err(err) = self.advance().report_err() { + if let Some(code) = Self::program_exit(&err) { + self.exit_code = Some(code); + return interp_ok(ExecutionResult::ProgramExited { code }); + } + return interp_ok(ExecutionResult::Stopped(self.stop_at_exception(err))); + } // An explicit breakpoint should stop execution even when the current // MIR instruction would normally be hidden during manual stepping. - if self.is_at_breakpoint() { - return interp_ok(StepResult::Breakpoint); + if self.is_at_breakpoint(mode.skipped_breakpoint()) { + return interp_ok(ExecutionResult::Stopped(StepResult::Breakpoint)); } match mode { @@ -208,48 +339,79 @@ impl<'tcx> PrirodaContext<'tcx> { InstructionVisibility::Visible ) => { - return interp_ok(StepResult::Step); + return interp_ok(ExecutionResult::Stopped(StepResult::Step)); } - ResumeMode::SourceLine(ref prev_location) => { - match (prev_location, &self.current_location) { + ResumeMode::StepOver { ref start_position, start_stack_depth } => { + // While deeper than where we started, we are inside a call + // made from the stepped-over line; keep going. + if self.active_thread_stack_depth() > start_stack_depth { + continue; + } + + // Back at (or shallower than) the starting depth: stop once + // the displayed source position has changed. + match (start_position, &self.current_location) { // We started from an unmapped location; stop once there // is a source position the frontend can display. - (None, Some(_)) => return interp_ok(StepResult::Step), - - (Some((prev_path, prev_line)), Some(current_location)) => { - if let Some(current_path) = self.local_path(current_location) { - // A source step stops when the displayed source - // position changes to a different file or line. - if *prev_path != current_path || *prev_line != current_location.line + (None, Some(_)) => + return interp_ok(ExecutionResult::Stopped(StepResult::Step)), + (Some((start_path, start_line)), Some(current_location)) => { + // A source step stops when the displayed source + // position changes to a different file or line. + if let Some(current_path) = self.local_path(current_location) + && (*start_path != current_path + || *start_line != current_location.line) + { + // Return spans can point at a function header. Keep walking when + // that would move `next` backwards within the same frame. + if self.active_thread_stack_depth() == start_stack_depth + && *start_path == current_path + && current_location.line < *start_line { - return interp_ok(StepResult::Step); + continue; } + return interp_ok(ExecutionResult::Stopped(StepResult::Step)); } } - _ => {} } } + ResumeMode::StepOut { start_user_frame_depth, .. } + if self.active_user_frame_depth() < start_user_frame_depth + && self.current_location.is_some() => + { + return interp_ok(ExecutionResult::Stopped(StepResult::Step)); + } + ResumeMode::FirstUserSourceLocation if self.current_location.is_some() && self.has_user_relevant_frame() => { - return interp_ok(StepResult::Step); + return interp_ok(ExecutionResult::Stopped(StepResult::Step)); } ResumeMode::MirInstruction | ResumeMode::FirstUserSourceLocation + | ResumeMode::StepOut { .. } | ResumeMode::Continue => {} } } } fn has_user_relevant_frame(&self) -> bool { + self.active_user_frame_depth() > 0 + } + + fn active_user_frame_depth(&self) -> usize { // Walk the whole stack, not just the top frame: during interpreter // startup the user's `main` can sit under Miri-internal frames that // have no source span, so checking only `last()` would miss it. - self.ecx.active_thread_stack().iter().any(|frame| frame.extra.user_relevance == u8::MAX) + self.ecx + .active_thread_stack() + .iter() + .filter(|frame| frame.extra.user_relevance == u8::MAX) + .count() } /// Advance Miri by one interpreter-loop transition. @@ -292,10 +454,13 @@ impl<'tcx> PrirodaContext<'tcx> { } } - fn is_at_breakpoint(&self) -> bool { + fn is_at_breakpoint(&self, skipped_breakpoint: Option<&(PathBuf, usize)>) -> bool { let Some(bp) = self.current_breakpoint() else { return false; }; + if skipped_breakpoint == Some(&bp) { + return false; + } // If the previous interpreter step had the same source position, this // is another MIR location for the breakpoint we just reported. @@ -326,10 +491,11 @@ impl<'tcx> PrirodaContext<'tcx> { command: DebuggerCommand, ) -> InterpResult<'tcx, CommandResult> { match command { - DebuggerCommand::StepI => self.stepi().map(CommandResult::ExecutionStopped), - DebuggerCommand::Step => self.step().map(CommandResult::ExecutionStopped), - DebuggerCommand::Continue => - self.continue_execution().map(CommandResult::ExecutionStopped), + DebuggerCommand::StepI => self.stepi().map(CommandResult::Execution), + DebuggerCommand::Step => self.step().map(CommandResult::Execution), + DebuggerCommand::Next => self.step_over_source().map(CommandResult::Execution), + DebuggerCommand::StepOut => self.step_out_source().map(CommandResult::Execution), + DebuggerCommand::Continue => self.continue_execution().map(CommandResult::Execution), DebuggerCommand::Breakpoint(path, line) => interp_ok(CommandResult::BreakpointResult(self.set_breakpoint(path, line))), DebuggerCommand::ListLocals => interp_ok(CommandResult::Locals(self.list_locals())), @@ -337,7 +503,8 @@ impl<'tcx> PrirodaContext<'tcx> { interp_ok(CommandResult::SingleLocal(self.get_local(local))), DebuggerCommand::Follow(alloc_id, offset) => self.follow_alloc(alloc_id, offset).map(CommandResult::Memory), - DebuggerCommand::TerminateSession => interp_ok(CommandResult::TerminateSession), + DebuggerCommand::TerminateSession => + self.finish_session().map(|()| CommandResult::TerminateSession), } } @@ -825,6 +992,8 @@ impl<'tcx> PrirodaContext<'tcx> { pub(super) enum DebuggerCommand { StepI, Step, + Next, + StepOut, TerminateSession, Continue, Breakpoint(PathBuf, usize), @@ -840,7 +1009,7 @@ pub(super) enum BreakpointSetResult { } pub(super) enum CommandResult { - ExecutionStopped(StepResult), + Execution(ExecutionResult), BreakpointResult(BreakpointSetResult), Locals(Vec), SingleLocal(Option), diff --git a/src/tools/miri/priroda/src/frontend/cli.rs b/src/tools/miri/priroda/src/frontend/cli.rs index e4e92351a92f6..d1af42d354872 100644 --- a/src/tools/miri/priroda/src/frontend/cli.rs +++ b/src/tools/miri/priroda/src/frontend/cli.rs @@ -6,7 +6,8 @@ use miri::{InterpResult, interp_ok}; use rustc_middle::mir::interpret::AllocId; use crate::debugger::{ - BreakpointSetResult, CommandResult, DebuggerCommand, PrirodaContext, StepResult, + BreakpointSetResult, CommandResult, DebuggerCommand, ExecutionResult, PrirodaContext, + StepResult, }; pub(crate) struct Cli; @@ -46,12 +47,23 @@ impl Cli { session: &PrirodaContext<'tcx>, ) -> InterpResult<'tcx, bool> { match command_res { - CommandResult::ExecutionStopped(result) => { - if matches!(result, StepResult::Breakpoint) { - println!("Hit breakpoint"); - } - Self::print_location(session); - } + CommandResult::Execution(result) => + match result { + ExecutionResult::Stopped(step) => + match step { + StepResult::Step => Self::print_location(session), + StepResult::Breakpoint => { + println!("Hit breakpoint"); + Self::print_location(session); + } + StepResult::Exception { ref message } => + Self::print_exception_stop(message, session), + }, + ExecutionResult::ProgramExited { code } => { + println!("program finished with exit code {code}"); + } + ExecutionResult::Rejected { message } => println!("{message}"), + }, CommandResult::BreakpointResult(res) => match res { BreakpointSetResult::Added(path, line) => { @@ -107,6 +119,11 @@ impl Cli { interp_ok(true) } + fn print_exception_stop<'tcx>(message: &str, session: &PrirodaContext<'tcx>) { + println!("program stopped with error: {message}"); + Self::print_location(session); + } + fn parse_command(&self, input: &str) -> Option { // TODO: look at the Spanned crate for how to easily produce errors in // rustc's style while manually parsing text input. @@ -121,6 +138,8 @@ impl Cli { // FIXME: empty line should repats last command user typed not exeute specific command. "" | "si" | "stepi" => Some(DebuggerCommand::StepI), "s" | "step" => Some(DebuggerCommand::Step), + "n" | "next" => Some(DebuggerCommand::Next), + "out" | "stepout" => Some(DebuggerCommand::StepOut), "q" | "quit" => Some(DebuggerCommand::TerminateSession), "c" | "continue" => Some(DebuggerCommand::Continue), "b" | "break" => self.parse_breakpoint(args), diff --git a/src/tools/miri/priroda/src/frontend/dap.rs b/src/tools/miri/priroda/src/frontend/dap.rs index 050830e705140..72a4cc470c8bb 100644 --- a/src/tools/miri/priroda/src/frontend/dap.rs +++ b/src/tools/miri/priroda/src/frontend/dap.rs @@ -13,9 +13,9 @@ use emmy_dap_types::prelude::types::{ StoppedEventReason, Thread, Variable, }; use emmy_dap_types::prelude::{Command, Event, Request, ResponseBody, Server}; -use miri::{InterpErrorInfo, InterpErrorKind, InterpResult, TerminationInfo, bug, interp_ok}; +use miri::{InterpErrorInfo, InterpErrorKind, InterpResult, TerminationInfo, bug}; -use crate::debugger::{LocalDesc, PrirodaContext, StepResult}; +use crate::debugger::{ExecutionResult, LocalDesc, PrirodaContext, StepResult}; // Priroda still exposes one interpreted thread and one selected frame to DAP. // Keep the ids stable so editor follow-up requests can address the stopped state. @@ -53,9 +53,17 @@ enum DapState { enum ExecutionOutcome { Stopped(StepResult), Terminated { code: i32 }, + Rejected(String), Failed(String), } +#[derive(Clone, Copy)] +enum StepKind { + In, + Over, + Out, +} + /// Debug Adapter Protocol frontend. pub(crate) struct Dap { pub(crate) port: Option, @@ -77,7 +85,7 @@ impl Dap { eprintln!("priroda dap error: {err:?}"); } - interp_ok(()) + session.finish_session() } } @@ -192,9 +200,12 @@ impl DapSession { Command::Variables(args) => self.handle_variables(args.variables_reference, session), Command::Continue(args) => self.handle_continue(args.thread_id, session), Command::SetBreakpoints(args) => self.handle_set_breakpoints(args, session), - Command::Next(args) => self.handle_step(ResponseBody::Next, args.thread_id, session), + Command::Next(args) => + self.handle_step(ResponseBody::Next, args.thread_id, session, StepKind::Over), Command::StepIn(args) => - self.handle_step(ResponseBody::StepIn, args.thread_id, session), + self.handle_step(ResponseBody::StepIn, args.thread_id, session, StepKind::In), + Command::StepOut(args) => + self.handle_step(ResponseBody::StepOut, args.thread_id, session, StepKind::Out), Command::Disconnect(_) => self.handle_disconnect(), Command::BreakpointLocations(_) | Command::Cancel(_) @@ -221,7 +232,6 @@ impl DapSession { | Command::Source(_) | Command::StepBack(_) | Command::StepInTargets(_) - | Command::StepOut(_) | Command::Terminate(_) | Command::TerminateThreads(_) | Command::WriteMemory(_) => self.handle_unsupported_request(&request.command), @@ -337,15 +347,20 @@ impl DapSession { self.require_state(DapState::Launched)?; match Self::execution_outcome(session.stop_at_first_user_location()) { - ExecutionOutcome::Stopped(_) => + ExecutionOutcome::Stopped(result) => { + // A normal startup stop is an entry event, but an interpreter + // error before the first user location is an exception stop. + let stopped = match result { + StepResult::Step => Self::stopped_event_body(StoppedEventReason::Entry), + result => Self::stopped_event_for(result), + }; Ok(HandlerSuccess { response: HandlerResponse::Success(ResponseBody::ConfigurationDone), state: Some(DapState::Stopped), - events: vec![Event::Stopped(Self::stopped_event_body( - StoppedEventReason::Entry, - ))], + events: vec![Event::Stopped(stopped)], outcome: HandlerOutcome::Continue, - }), + }) + } ExecutionOutcome::Terminated { code } => Ok(HandlerSuccess { response: HandlerResponse::Success(ResponseBody::ConfigurationDone), @@ -356,6 +371,13 @@ impl DapSession { ], outcome: HandlerOutcome::Exit, }), + ExecutionOutcome::Rejected(message) => + Ok(HandlerSuccess { + response: HandlerResponse::Error(message), + state: None, + events: Vec::new(), + outcome: HandlerOutcome::Continue, + }), ExecutionOutcome::Failed(message) => Ok(HandlerSuccess { response: HandlerResponse::Error(message), @@ -456,24 +478,28 @@ impl DapSession { }) } - /// FIXME: distinguish step-over from step-in once Priroda has call-aware stepping. fn handle_step<'tcx>( &self, body: ResponseBody, thread_id: i64, session: &mut PrirodaContext<'tcx>, + step: StepKind, ) -> Result { self.require_stopped()?; Self::require_thread_id(thread_id)?; - match Self::execution_outcome(session.step()) { + let result = match step { + StepKind::In => session.step_in_source(), + StepKind::Over => session.step_over_source(), + StepKind::Out => session.step_out_source(), + }; + + match Self::execution_outcome(result) { ExecutionOutcome::Stopped(result) => Ok(HandlerSuccess { response: HandlerResponse::Success(body), state: Some(DapState::Stopped), - events: vec![Event::Stopped(Self::stopped_event_body(Self::stopped_reason( - result, - )))], + events: vec![Event::Stopped(Self::stopped_event_for(result))], outcome: HandlerOutcome::Continue, }), ExecutionOutcome::Terminated { code } => @@ -486,6 +512,13 @@ impl DapSession { ], outcome: HandlerOutcome::Exit, }), + ExecutionOutcome::Rejected(message) => + Ok(HandlerSuccess { + response: HandlerResponse::Error(message), + state: None, + events: Vec::new(), + outcome: HandlerOutcome::Continue, + }), ExecutionOutcome::Failed(message) => Ok(HandlerSuccess { response: HandlerResponse::Error(message), @@ -511,9 +544,7 @@ impl DapSession { Ok(HandlerSuccess { response: HandlerResponse::Success(body), state: Some(DapState::Stopped), - events: vec![Event::Stopped(Self::stopped_event_body(Self::stopped_reason( - result, - )))], + events: vec![Event::Stopped(Self::stopped_event_for(result))], outcome: HandlerOutcome::Continue, }), ExecutionOutcome::Terminated { code } => @@ -526,6 +557,13 @@ impl DapSession { ], outcome: HandlerOutcome::Exit, }), + ExecutionOutcome::Rejected(message) => + Ok(HandlerSuccess { + response: HandlerResponse::Error(message), + state: None, + events: Vec::new(), + outcome: HandlerOutcome::Continue, + }), ExecutionOutcome::Failed(message) => Ok(HandlerSuccess { response: HandlerResponse::Error(message), @@ -650,9 +688,12 @@ impl DapSession { Ok(()) } - fn execution_outcome<'tcx>(result: InterpResult<'tcx, StepResult>) -> ExecutionOutcome { + fn execution_outcome<'tcx>(result: InterpResult<'tcx, ExecutionResult>) -> ExecutionOutcome { match result.report_err() { - Ok(step) => ExecutionOutcome::Stopped(step), + Ok(ExecutionResult::Stopped(step)) => ExecutionOutcome::Stopped(step), + Ok(ExecutionResult::ProgramExited { code }) => ExecutionOutcome::Terminated { code }, + Ok(ExecutionResult::Rejected { message }) => + ExecutionOutcome::Rejected(message.to_string()), Err(err) => Self::interp_error_outcome(err), } } @@ -668,22 +709,32 @@ impl DapSession { ExecutionOutcome::Failed(kind.to_string()) } - fn stopped_event_body(reason: StoppedEventReason) -> StoppedEventBody { + fn stopped_event_for(result: StepResult) -> StoppedEventBody { + let (reason, text) = match result { + StepResult::Step => (StoppedEventReason::Step, None), + StepResult::Breakpoint => (StoppedEventReason::Breakpoint, None), + StepResult::Exception { message } => (StoppedEventReason::Exception, Some(message)), + }; StoppedEventBody { reason, description: None, thread_id: Some(THREAD_ID), preserve_focus_hint: None, - text: None, + text, all_threads_stopped: Some(true), hit_breakpoint_ids: None, } } - fn stopped_reason(result: StepResult) -> StoppedEventReason { - match result { - StepResult::Step => StoppedEventReason::Step, - StepResult::Breakpoint => StoppedEventReason::Breakpoint, + fn stopped_event_body(reason: StoppedEventReason) -> StoppedEventBody { + StoppedEventBody { + reason, + description: None, + thread_id: Some(THREAD_ID), + preserve_focus_hint: None, + text: None, + all_threads_stopped: Some(true), + hit_breakpoint_ids: None, } } diff --git a/src/tools/miri/priroda/src/main.rs b/src/tools/miri/priroda/src/main.rs index 44743c446091b..3937b9ad03f4d 100644 --- a/src/tools/miri/priroda/src/main.rs +++ b/src/tools/miri/priroda/src/main.rs @@ -140,14 +140,7 @@ impl rustc_driver::Callbacks for PrirodaCompilerCalls { Ok(()) => {} Err(err) => if let Some((return_code, _leak_check)) = report_result(&session.ecx, err) { - // FIXME: translate Miri termination into a Priroda execution-state enum so - // the CLI loop can distinguish whole-program exit from individual thread - // completion, run Miri-equivalent leak checks, print the exit code, and - // return to the debugger prompt. - println!("program finished with exit code {return_code}"); - if return_code != 0 { - std::process::exit(return_code); - } + std::process::exit(return_code); }, } diff --git a/src/tools/miri/priroda/tests/ui/cli_next_command.rs b/src/tools/miri/priroda/tests/ui/cli_next_command.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_next_command.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/src/tools/miri/priroda/tests/ui/cli_next_command.stdin b/src/tools/miri/priroda/tests/ui/cli_next_command.stdin new file mode 100644 index 0000000000000..4e4a3137cbd67 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_next_command.stdin @@ -0,0 +1,2 @@ +next +quit diff --git a/src/tools/miri/priroda/tests/ui/cli_next_command.stdout b/src/tools/miri/priroda/tests/ui/cli_next_command.stdout new file mode 100644 index 0000000000000..304623d197977 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_next_command.stdout @@ -0,0 +1,2 @@ +(priroda) program finished with exit code 0 +(priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/cli_next_same_line_call.rs b/src/tools/miri/priroda/tests/ui/cli_next_same_line_call.rs new file mode 100644 index 0000000000000..d7f26894e3475 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_next_same_line_call.rs @@ -0,0 +1,10 @@ +// Verifies `next` at a same-line callee/caller location. +// Keep the breakpoint line number in the .stdin file in sync with this file. +#[rustfmt::skip] +fn same_line() { fn callee() {} callee(); let after = 1; let _ = after; } + +fn main() { + same_line(); + let after_same_line = 2; + let _ = after_same_line; +} diff --git a/src/tools/miri/priroda/tests/ui/cli_next_same_line_call.stdin b/src/tools/miri/priroda/tests/ui/cli_next_same_line_call.stdin new file mode 100644 index 0000000000000..ce815c2355b5f --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_next_same_line_call.stdin @@ -0,0 +1,4 @@ +break tests/ui/cli_next_same_line_call.rs:4 +continue +next +quit diff --git a/src/tools/miri/priroda/tests/ui/cli_next_same_line_call.stdout b/src/tools/miri/priroda/tests/ui/cli_next_same_line_call.stdout new file mode 100644 index 0000000000000..f4e52d0b39085 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_next_same_line_call.stdout @@ -0,0 +1,5 @@ +(priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/cli_next_same_line_call.rs:4 +(priroda) Hit breakpoint +{MANIFEST_DIR}/tests/ui/cli_next_same_line_call.rs:4 +(priroda) {MANIFEST_DIR}/tests/ui/cli_next_same_line_call.rs:7 +(priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/cli_step_out_command.rs b/src/tools/miri/priroda/tests/ui/cli_step_out_command.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_step_out_command.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/src/tools/miri/priroda/tests/ui/cli_step_out_command.stdin b/src/tools/miri/priroda/tests/ui/cli_step_out_command.stdin new file mode 100644 index 0000000000000..f3eade0065ea7 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_step_out_command.stdin @@ -0,0 +1,3 @@ +si +out +quit diff --git a/src/tools/miri/priroda/tests/ui/cli_step_out_command.stdout b/src/tools/miri/priroda/tests/ui/cli_step_out_command.stdout new file mode 100644 index 0000000000000..a1d982386e047 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_step_out_command.stdout @@ -0,0 +1,3 @@ +(priroda) {RUSTC_SYSROOT}/lib/rustlib/src/rust/library/std/src/rt.rs:206 +(priroda) stepOut is not meaningful in the outermost user frame +(priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/cli_step_over_demo.rs b/src/tools/miri/priroda/tests/ui/cli_step_over_demo.rs new file mode 100644 index 0000000000000..52ee4bfe4aa1f --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_step_over_demo.rs @@ -0,0 +1,18 @@ +fn leaf() { + let inside_leaf = 10; + let _ = inside_leaf; +} + +fn call_leaf() { + leaf(); // Break here, then run `next`. + let after_leaf = 20; + let _ = after_leaf; +} + +#[rustfmt::skip] +fn same_line() { fn callee() {} callee(); let after = 30; let _ = after; } + +fn main() { + call_leaf(); + same_line(); +} diff --git a/src/tools/miri/priroda/tests/ui/cli_step_over_demo.stdin b/src/tools/miri/priroda/tests/ui/cli_step_over_demo.stdin new file mode 100644 index 0000000000000..51698c01f38f1 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_step_over_demo.stdin @@ -0,0 +1,4 @@ +break tests/ui/cli_step_over_demo.rs:7 +continue +next +quit diff --git a/src/tools/miri/priroda/tests/ui/cli_step_over_demo.stdout b/src/tools/miri/priroda/tests/ui/cli_step_over_demo.stdout new file mode 100644 index 0000000000000..01d06c06d4d29 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/cli_step_over_demo.stdout @@ -0,0 +1,5 @@ +(priroda) breakpoint added: {MANIFEST_DIR}/tests/ui/cli_step_over_demo.rs:7 +(priroda) Hit breakpoint +{MANIFEST_DIR}/tests/ui/cli_step_over_demo.rs:7 +(priroda) {MANIFEST_DIR}/tests/ui/cli_step_over_demo.rs:8 +(priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/continue_finishes_nonzero.rs b/src/tools/miri/priroda/tests/ui/continue_finishes_nonzero.rs new file mode 100644 index 0000000000000..5c60cabc8e0ab --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/continue_finishes_nonzero.rs @@ -0,0 +1,3 @@ +fn main() { + std::process::exit(7); +} diff --git a/src/tools/miri/priroda/tests/ui/continue_finishes_nonzero.stdin b/src/tools/miri/priroda/tests/ui/continue_finishes_nonzero.stdin new file mode 100644 index 0000000000000..a072c2312df66 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/continue_finishes_nonzero.stdin @@ -0,0 +1,2 @@ +continue +quit diff --git a/src/tools/miri/priroda/tests/ui/continue_finishes_nonzero.stdout b/src/tools/miri/priroda/tests/ui/continue_finishes_nonzero.stdout new file mode 100644 index 0000000000000..50a003968709f --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/continue_finishes_nonzero.stdout @@ -0,0 +1,2 @@ +(priroda) program finished with exit code 7 +(priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/continue_finishes_program.stdin b/src/tools/miri/priroda/tests/ui/continue_finishes_program.stdin index 44c5d7d65ead7..8ce5905753dd5 100644 --- a/src/tools/miri/priroda/tests/ui/continue_finishes_program.stdin +++ b/src/tools/miri/priroda/tests/ui/continue_finishes_program.stdin @@ -1 +1,3 @@ continue +continue +quit diff --git a/src/tools/miri/priroda/tests/ui/continue_finishes_program.stdout b/src/tools/miri/priroda/tests/ui/continue_finishes_program.stdout index d6c4605d6baf3..e8040ca6a1896 100644 --- a/src/tools/miri/priroda/tests/ui/continue_finishes_program.stdout +++ b/src/tools/miri/priroda/tests/ui/continue_finishes_program.stdout @@ -1 +1,3 @@ (priroda) program finished with exit code 0 +(priroda) program finished with exit code 0 +(priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/dap_next_at_call.rs b/src/tools/miri/priroda/tests/ui/dap_next_at_call.rs new file mode 100644 index 0000000000000..d071191b60e3f --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_next_at_call.rs @@ -0,0 +1,12 @@ +//@ compile-flags: --dap + +fn callee() { + let inner = 1; + let _ = inner; +} + +fn main() { + callee(); + let after = 2; + let _ = after; +} diff --git a/src/tools/miri/priroda/tests/ui/dap_next_at_call.stdin b/src/tools/miri/priroda/tests/ui/dap_next_at_call.stdin new file mode 100644 index 0000000000000..d134de9af931e --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_next_at_call.stdin @@ -0,0 +1,11 @@ +Content-Length: 85 + +{"seq":1,"type":"request","command":"initialize","arguments":{"adapterID":"priroda"}}Content-Length: 60 + +{"seq":2,"type":"request","command":"launch","arguments":{}}Content-Length: 56 + +{"seq":3,"type":"request","command":"configurationDone"}Content-Length: 70 + +{"seq":4,"type":"request","command":"next","arguments":{"threadId":1}}Content-Length: 77 + +{"seq":5,"type":"request","command":"stackTrace","arguments":{"threadId":1}} diff --git a/src/tools/miri/priroda/tests/ui/dap_next_at_call.stdout b/src/tools/miri/priroda/tests/ui/dap_next_at_call.stdout new file mode 100644 index 0000000000000..35cc2f924cf17 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_next_at_call.stdout @@ -0,0 +1,17 @@ +Content-Length: {CONTENT_LENGTH} + +{"seq":1,"type":"response","request_seq":1,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true,"supportsSingleThreadExecutionRequests":true},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":2,"type":"event","event":"initialized"}Content-Length: {CONTENT_LENGTH} + +{"seq":3,"type":"response","request_seq":2,"success":true,"command":"launch","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":4,"type":"response","request_seq":3,"success":true,"command":"configurationDone","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":5,"type":"event","event":"stopped","body":{"reason":"entry","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":6,"type":"response","request_seq":4,"success":true,"command":"next","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":7,"type":"event","event":"stopped","body":{"reason":"step","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":8,"type":"response","request_seq":5,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1,"name":"main","source":{"name":"dap_next_at_call.rs","path":"{MANIFEST_DIR}/tests/ui/dap_next_at_call.rs","sourceReference":0},"line":10,"column":9}],"totalFrames":1},"error":null} \ No newline at end of file diff --git a/src/tools/miri/priroda/tests/ui/dap_repeated_next_from_call.rs b/src/tools/miri/priroda/tests/ui/dap_repeated_next_from_call.rs new file mode 100644 index 0000000000000..8b3a210f2eca5 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_repeated_next_from_call.rs @@ -0,0 +1,20 @@ +//@ compile-flags: --dap + +fn leaf() { + let inside_leaf = 10; + let _ = inside_leaf; +} + +fn call_leaf() { + leaf(); + let after_leaf = 20; + let _ = after_leaf; +} + +#[rustfmt::skip] +fn same_line() { fn callee() {} callee(); let after = 30; let _ = after; } + +fn main() { + call_leaf(); + same_line(); +} diff --git a/src/tools/miri/priroda/tests/ui/dap_repeated_next_from_call.stdin b/src/tools/miri/priroda/tests/ui/dap_repeated_next_from_call.stdin new file mode 100644 index 0000000000000..2b3c28ad9cef5 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_repeated_next_from_call.stdin @@ -0,0 +1,21 @@ +Content-Length: 85 + +{"seq":1,"type":"request","command":"initialize","arguments":{"adapterID":"priroda"}}Content-Length: 60 + +{"seq":2,"type":"request","command":"launch","arguments":{}}Content-Length: 56 + +{"seq":3,"type":"request","command":"configurationDone"}Content-Length: 76 + +{"seq":4,"type":"request","command":"stackTrace","arguments":{"threadId":1}}Content-Length: 70 + +{"seq":5,"type":"request","command":"next","arguments":{"threadId":1}}Content-Length: 76 + +{"seq":6,"type":"request","command":"stackTrace","arguments":{"threadId":1}}Content-Length: 70 + +{"seq":7,"type":"request","command":"next","arguments":{"threadId":1}}Content-Length: 76 + +{"seq":8,"type":"request","command":"stackTrace","arguments":{"threadId":1}}Content-Length: 70 + +{"seq":9,"type":"request","command":"next","arguments":{"threadId":1}}Content-Length: 77 + +{"seq":10,"type":"request","command":"stackTrace","arguments":{"threadId":1}} \ No newline at end of file diff --git a/src/tools/miri/priroda/tests/ui/dap_repeated_next_from_call.stdout b/src/tools/miri/priroda/tests/ui/dap_repeated_next_from_call.stdout new file mode 100644 index 0000000000000..5e6d0fab18a82 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_repeated_next_from_call.stdout @@ -0,0 +1,31 @@ +Content-Length: {CONTENT_LENGTH} + +{"seq":1,"type":"response","request_seq":1,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true,"supportsSingleThreadExecutionRequests":true},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":2,"type":"event","event":"initialized"}Content-Length: {CONTENT_LENGTH} + +{"seq":3,"type":"response","request_seq":2,"success":true,"command":"launch","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":4,"type":"response","request_seq":3,"success":true,"command":"configurationDone","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":5,"type":"event","event":"stopped","body":{"reason":"entry","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":6,"type":"response","request_seq":4,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1,"name":"main","source":{"name":"dap_repeated_next_from_call.rs","path":"{MANIFEST_DIR}/tests/ui/dap_repeated_next_from_call.rs","sourceReference":0},"line":18,"column":5}],"totalFrames":1},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":7,"type":"response","request_seq":5,"success":true,"command":"next","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":8,"type":"event","event":"stopped","body":{"reason":"step","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":9,"type":"response","request_seq":6,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1,"name":"main","source":{"name":"dap_repeated_next_from_call.rs","path":"{MANIFEST_DIR}/tests/ui/dap_repeated_next_from_call.rs","sourceReference":0},"line":19,"column":5}],"totalFrames":1},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":10,"type":"response","request_seq":7,"success":true,"command":"next","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":11,"type":"event","event":"stopped","body":{"reason":"step","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":12,"type":"response","request_seq":8,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1,"name":"main","source":{"name":"dap_repeated_next_from_call.rs","path":"{MANIFEST_DIR}/tests/ui/dap_repeated_next_from_call.rs","sourceReference":0},"line":20,"column":2}],"totalFrames":1},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":13,"type":"response","request_seq":9,"success":true,"command":"next","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":14,"type":"event","event":"stopped","body":{"reason":"step","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":15,"type":"response","request_seq":10,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1,"name":">::call_once - shim(fn())","source":{"name":"function.rs","path":"{RUSTC_SYSROOT}/lib/rustlib/src/rust/library/core/src/ops/function.rs","sourceReference":0},"line":250,"column":5}],"totalFrames":1},"error":null} \ No newline at end of file diff --git a/src/tools/miri/priroda/tests/ui/dap_step_out_from_callee.rs b/src/tools/miri/priroda/tests/ui/dap_step_out_from_callee.rs new file mode 100644 index 0000000000000..d071191b60e3f --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_step_out_from_callee.rs @@ -0,0 +1,12 @@ +//@ compile-flags: --dap + +fn callee() { + let inner = 1; + let _ = inner; +} + +fn main() { + callee(); + let after = 2; + let _ = after; +} diff --git a/src/tools/miri/priroda/tests/ui/dap_step_out_from_callee.stdin b/src/tools/miri/priroda/tests/ui/dap_step_out_from_callee.stdin new file mode 100644 index 0000000000000..8bba6a20352a6 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_step_out_from_callee.stdin @@ -0,0 +1,13 @@ +Content-Length: 85 + +{"seq":1,"type":"request","command":"initialize","arguments":{"adapterID":"priroda"}}Content-Length: 60 + +{"seq":2,"type":"request","command":"launch","arguments":{}}Content-Length: 56 + +{"seq":3,"type":"request","command":"configurationDone"}Content-Length: 72 + +{"seq":4,"type":"request","command":"stepIn","arguments":{"threadId":1}}Content-Length: 73 + +{"seq":5,"type":"request","command":"stepOut","arguments":{"threadId":1}}Content-Length: 77 + +{"seq":6,"type":"request","command":"stackTrace","arguments":{"threadId":1}} diff --git a/src/tools/miri/priroda/tests/ui/dap_step_out_from_callee.stdout b/src/tools/miri/priroda/tests/ui/dap_step_out_from_callee.stdout new file mode 100644 index 0000000000000..c65cb75e4e58a --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_step_out_from_callee.stdout @@ -0,0 +1,21 @@ +Content-Length: {CONTENT_LENGTH} + +{"seq":1,"type":"response","request_seq":1,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true,"supportsSingleThreadExecutionRequests":true},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":2,"type":"event","event":"initialized"}Content-Length: {CONTENT_LENGTH} + +{"seq":3,"type":"response","request_seq":2,"success":true,"command":"launch","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":4,"type":"response","request_seq":3,"success":true,"command":"configurationDone","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":5,"type":"event","event":"stopped","body":{"reason":"entry","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":6,"type":"response","request_seq":4,"success":true,"command":"stepIn","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":7,"type":"event","event":"stopped","body":{"reason":"step","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":8,"type":"response","request_seq":5,"success":true,"command":"stepOut","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":9,"type":"event","event":"stopped","body":{"reason":"step","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":10,"type":"response","request_seq":6,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1,"name":"main","source":{"name":"dap_step_out_from_callee.rs","path":"{MANIFEST_DIR}/tests/ui/dap_step_out_from_callee.rs","sourceReference":0},"line":9,"column":13}],"totalFrames":1},"error":null} \ No newline at end of file diff --git a/src/tools/miri/priroda/tests/ui/dap_step_out_from_main.rs b/src/tools/miri/priroda/tests/ui/dap_step_out_from_main.rs new file mode 100644 index 0000000000000..cf0f5204f211e --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_step_out_from_main.rs @@ -0,0 +1,10 @@ +//@ compile-flags: --dap + +fn callee() { + let inner = 1; + let _ = inner; +} + +fn main() { + callee(); +} diff --git a/src/tools/miri/priroda/tests/ui/dap_step_out_from_main.stdin b/src/tools/miri/priroda/tests/ui/dap_step_out_from_main.stdin new file mode 100644 index 0000000000000..d96fb4ad0c33f --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_step_out_from_main.stdin @@ -0,0 +1,13 @@ +Content-Length: 85 + +{"seq":1,"type":"request","command":"initialize","arguments":{"adapterID":"priroda"}}Content-Length: 60 + +{"seq":2,"type":"request","command":"launch","arguments":{}}Content-Length: 56 + +{"seq":3,"type":"request","command":"configurationDone"}Content-Length: 76 + +{"seq":4,"type":"request","command":"stackTrace","arguments":{"threadId":1}}Content-Length: 73 + +{"seq":5,"type":"request","command":"stepOut","arguments":{"threadId":1}}Content-Length: 76 + +{"seq":6,"type":"request","command":"stackTrace","arguments":{"threadId":1}} \ No newline at end of file diff --git a/src/tools/miri/priroda/tests/ui/dap_step_out_from_main.stdout b/src/tools/miri/priroda/tests/ui/dap_step_out_from_main.stdout new file mode 100644 index 0000000000000..bb8d2ee2354d7 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_step_out_from_main.stdout @@ -0,0 +1,17 @@ +Content-Length: {CONTENT_LENGTH} + +{"seq":1,"type":"response","request_seq":1,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true,"supportsSingleThreadExecutionRequests":true},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":2,"type":"event","event":"initialized"}Content-Length: {CONTENT_LENGTH} + +{"seq":3,"type":"response","request_seq":2,"success":true,"command":"launch","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":4,"type":"response","request_seq":3,"success":true,"command":"configurationDone","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":5,"type":"event","event":"stopped","body":{"reason":"entry","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":6,"type":"response","request_seq":4,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1,"name":"main","source":{"name":"dap_step_out_from_main.rs","path":"{MANIFEST_DIR}/tests/ui/dap_step_out_from_main.rs","sourceReference":0},"line":9,"column":5}],"totalFrames":1},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":7,"type":"response","request_seq":5,"success":false,"message":"stepOut is not meaningful in the outermost user frame","command":"stepOut","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":8,"type":"response","request_seq":6,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1,"name":"main","source":{"name":"dap_step_out_from_main.rs","path":"{MANIFEST_DIR}/tests/ui/dap_step_out_from_main.rs","sourceReference":0},"line":9,"column":5}],"totalFrames":1},"error":null} \ No newline at end of file diff --git a/src/tools/miri/priroda/tests/ui/dap_step_over_demo.rs b/src/tools/miri/priroda/tests/ui/dap_step_over_demo.rs new file mode 100644 index 0000000000000..1d9ea1b8461bb --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_step_over_demo.rs @@ -0,0 +1,20 @@ +//@ compile-flags: --dap + +fn leaf() { + let inside_leaf = 10; + let _ = inside_leaf; +} + +fn call_leaf() { + leaf(); + let after_leaf = 20; + let _ = after_leaf; +} + +#[rustfmt::skip] +fn same_line() { fn callee() {} callee(); let after = 30; let _ = after; } + +fn main() { + call_leaf(); // DAP `next` starts here. + same_line(); +} diff --git a/src/tools/miri/priroda/tests/ui/dap_step_over_demo.stdin b/src/tools/miri/priroda/tests/ui/dap_step_over_demo.stdin new file mode 100644 index 0000000000000..d134de9af931e --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_step_over_demo.stdin @@ -0,0 +1,11 @@ +Content-Length: 85 + +{"seq":1,"type":"request","command":"initialize","arguments":{"adapterID":"priroda"}}Content-Length: 60 + +{"seq":2,"type":"request","command":"launch","arguments":{}}Content-Length: 56 + +{"seq":3,"type":"request","command":"configurationDone"}Content-Length: 70 + +{"seq":4,"type":"request","command":"next","arguments":{"threadId":1}}Content-Length: 77 + +{"seq":5,"type":"request","command":"stackTrace","arguments":{"threadId":1}} diff --git a/src/tools/miri/priroda/tests/ui/dap_step_over_demo.stdout b/src/tools/miri/priroda/tests/ui/dap_step_over_demo.stdout new file mode 100644 index 0000000000000..27488f1c98232 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_step_over_demo.stdout @@ -0,0 +1,17 @@ +Content-Length: {CONTENT_LENGTH} + +{"seq":1,"type":"response","request_seq":1,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true,"supportsSingleThreadExecutionRequests":true},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":2,"type":"event","event":"initialized"}Content-Length: {CONTENT_LENGTH} + +{"seq":3,"type":"response","request_seq":2,"success":true,"command":"launch","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":4,"type":"response","request_seq":3,"success":true,"command":"configurationDone","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":5,"type":"event","event":"stopped","body":{"reason":"entry","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":6,"type":"response","request_seq":4,"success":true,"command":"next","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":7,"type":"event","event":"stopped","body":{"reason":"step","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":8,"type":"response","request_seq":5,"success":true,"command":"stackTrace","body":{"stackFrames":[{"id":1,"name":"main","source":{"name":"dap_step_over_demo.rs","path":"{MANIFEST_DIR}/tests/ui/dap_step_over_demo.rs","sourceReference":0},"line":19,"column":5}],"totalFrames":1},"error":null} \ No newline at end of file diff --git a/src/tools/miri/priroda/tests/ui/dap_ub_exception.rs b/src/tools/miri/priroda/tests/ui/dap_ub_exception.rs new file mode 100644 index 0000000000000..ec3b9860925eb --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_ub_exception.rs @@ -0,0 +1,7 @@ +//@ compile-flags: --dap +#![allow(deref_nullptr)] +fn main() { + unsafe { + *std::ptr::null_mut::() = 1; + } +} diff --git a/src/tools/miri/priroda/tests/ui/dap_ub_exception.stdin b/src/tools/miri/priroda/tests/ui/dap_ub_exception.stdin new file mode 100644 index 0000000000000..ad37d7e1f1742 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_ub_exception.stdin @@ -0,0 +1,9 @@ +Content-Length: 85 + +{"seq":1,"type":"request","command":"initialize","arguments":{"adapterID":"priroda"}}Content-Length: 72 + +{"seq":2,"type":"request","command":"launch","arguments":{"program":""}}Content-Length: 56 + +{"seq":3,"type":"request","command":"configurationDone"}Content-Length: 74 + +{"seq":4,"type":"request","command":"continue","arguments":{"threadId":1}} \ No newline at end of file diff --git a/src/tools/miri/priroda/tests/ui/dap_ub_exception.stdout b/src/tools/miri/priroda/tests/ui/dap_ub_exception.stdout new file mode 100644 index 0000000000000..9db6bc199cf01 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_ub_exception.stdout @@ -0,0 +1,15 @@ +Content-Length: {CONTENT_LENGTH} + +{"seq":1,"type":"response","request_seq":1,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true,"supportsSingleThreadExecutionRequests":true},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":2,"type":"event","event":"initialized"}Content-Length: {CONTENT_LENGTH} + +{"seq":3,"type":"response","request_seq":2,"success":true,"command":"launch","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":4,"type":"response","request_seq":3,"success":true,"command":"configurationDone","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":5,"type":"event","event":"stopped","body":{"reason":"entry","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":6,"type":"response","request_seq":4,"success":true,"command":"continue","body":{"allThreadsContinued":true},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":7,"type":"event","event":"stopped","body":{"reason":"exception","description":null,"threadId":1,"preserveFocusHint":null,"text":"memory access failed: attempting to access 1 byte, but got null pointer","allThreadsStopped":true,"hitBreakpointIds":null}} \ No newline at end of file diff --git a/src/tools/miri/priroda/tests/ui/dap_ub_exception_continue.rs b/src/tools/miri/priroda/tests/ui/dap_ub_exception_continue.rs new file mode 100644 index 0000000000000..ec3b9860925eb --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_ub_exception_continue.rs @@ -0,0 +1,7 @@ +//@ compile-flags: --dap +#![allow(deref_nullptr)] +fn main() { + unsafe { + *std::ptr::null_mut::() = 1; + } +} diff --git a/src/tools/miri/priroda/tests/ui/dap_ub_exception_continue.stdin b/src/tools/miri/priroda/tests/ui/dap_ub_exception_continue.stdin new file mode 100644 index 0000000000000..e92e12721d9e8 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_ub_exception_continue.stdin @@ -0,0 +1,11 @@ +Content-Length: 85 + +{"seq":1,"type":"request","command":"initialize","arguments":{"adapterID":"priroda"}}Content-Length: 72 + +{"seq":2,"type":"request","command":"launch","arguments":{"program":""}}Content-Length: 56 + +{"seq":3,"type":"request","command":"configurationDone"}Content-Length: 74 + +{"seq":4,"type":"request","command":"continue","arguments":{"threadId":1}}Content-Length: 74 + +{"seq":5,"type":"request","command":"continue","arguments":{"threadId":1}} \ No newline at end of file diff --git a/src/tools/miri/priroda/tests/ui/dap_ub_exception_continue.stdout b/src/tools/miri/priroda/tests/ui/dap_ub_exception_continue.stdout new file mode 100644 index 0000000000000..7dbd6f198f87e --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/dap_ub_exception_continue.stdout @@ -0,0 +1,19 @@ +Content-Length: {CONTENT_LENGTH} + +{"seq":1,"type":"response","request_seq":1,"success":true,"command":"initialize","body":{"supportsConfigurationDoneRequest":true,"supportsSingleThreadExecutionRequests":true},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":2,"type":"event","event":"initialized"}Content-Length: {CONTENT_LENGTH} + +{"seq":3,"type":"response","request_seq":2,"success":true,"command":"launch","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":4,"type":"response","request_seq":3,"success":true,"command":"configurationDone","error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":5,"type":"event","event":"stopped","body":{"reason":"entry","description":null,"threadId":1,"preserveFocusHint":null,"text":null,"allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":6,"type":"response","request_seq":4,"success":true,"command":"continue","body":{"allThreadsContinued":true},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":7,"type":"event","event":"stopped","body":{"reason":"exception","description":null,"threadId":1,"preserveFocusHint":null,"text":"memory access failed: attempting to access 1 byte, but got null pointer","allThreadsStopped":true,"hitBreakpointIds":null}}Content-Length: {CONTENT_LENGTH} + +{"seq":8,"type":"response","request_seq":5,"success":true,"command":"continue","body":{"allThreadsContinued":true},"error":null}Content-Length: {CONTENT_LENGTH} + +{"seq":9,"type":"event","event":"stopped","body":{"reason":"exception","description":null,"threadId":1,"preserveFocusHint":null,"text":"memory access failed: attempting to access 1 byte, but got null pointer","allThreadsStopped":true,"hitBreakpointIds":null}} \ No newline at end of file diff --git a/src/tools/miri/priroda/tests/ui/ub_exception_continue.rs b/src/tools/miri/priroda/tests/ui/ub_exception_continue.rs new file mode 100644 index 0000000000000..148fb9110f8ea --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/ub_exception_continue.rs @@ -0,0 +1,6 @@ +#![allow(deref_nullptr)] +fn main() { + unsafe { + *std::ptr::null_mut::() = 1; + } +} diff --git a/src/tools/miri/priroda/tests/ui/ub_exception_continue.stdin b/src/tools/miri/priroda/tests/ui/ub_exception_continue.stdin new file mode 100644 index 0000000000000..153508010cecd --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/ub_exception_continue.stdin @@ -0,0 +1,2 @@ +continue +continue diff --git a/src/tools/miri/priroda/tests/ui/ub_exception_continue.stdout b/src/tools/miri/priroda/tests/ui/ub_exception_continue.stdout new file mode 100644 index 0000000000000..cd5908a1540a4 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/ub_exception_continue.stdout @@ -0,0 +1,5 @@ +(priroda) program stopped with error: memory access failed: attempting to access 1 byte, but got null pointer +{MANIFEST_DIR}/tests/ui/ub_exception_continue.rs:4 +(priroda) program stopped with error: memory access failed: attempting to access 1 byte, but got null pointer +{MANIFEST_DIR}/tests/ui/ub_exception_continue.rs:4 +(priroda) stdin closed, stopping diff --git a/src/tools/miri/priroda/tests/ui/ub_exception_step.rs b/src/tools/miri/priroda/tests/ui/ub_exception_step.rs new file mode 100644 index 0000000000000..148fb9110f8ea --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/ub_exception_step.rs @@ -0,0 +1,6 @@ +#![allow(deref_nullptr)] +fn main() { + unsafe { + *std::ptr::null_mut::() = 1; + } +} diff --git a/src/tools/miri/priroda/tests/ui/ub_exception_step.stdin b/src/tools/miri/priroda/tests/ui/ub_exception_step.stdin new file mode 100644 index 0000000000000..3a45547d4fff4 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/ub_exception_step.stdin @@ -0,0 +1,3 @@ +continue +step +quit diff --git a/src/tools/miri/priroda/tests/ui/ub_exception_step.stdout b/src/tools/miri/priroda/tests/ui/ub_exception_step.stdout new file mode 100644 index 0000000000000..b3c54a238847e --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/ub_exception_step.stdout @@ -0,0 +1,5 @@ +(priroda) program stopped with error: memory access failed: attempting to access 1 byte, but got null pointer +{MANIFEST_DIR}/tests/ui/ub_exception_step.rs:4 +(priroda) program stopped with error: memory access failed: attempting to access 1 byte, but got null pointer +{MANIFEST_DIR}/tests/ui/ub_exception_step.rs:4 +(priroda) quitting diff --git a/src/tools/miri/priroda/tests/ui/ub_exception_stop.rs b/src/tools/miri/priroda/tests/ui/ub_exception_stop.rs new file mode 100644 index 0000000000000..148fb9110f8ea --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/ub_exception_stop.rs @@ -0,0 +1,6 @@ +#![allow(deref_nullptr)] +fn main() { + unsafe { + *std::ptr::null_mut::() = 1; + } +} diff --git a/src/tools/miri/priroda/tests/ui/ub_exception_stop.stdin b/src/tools/miri/priroda/tests/ui/ub_exception_stop.stdin new file mode 100644 index 0000000000000..2393571f36e8a --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/ub_exception_stop.stdin @@ -0,0 +1,3 @@ +continue +l +quit diff --git a/src/tools/miri/priroda/tests/ui/ub_exception_stop.stdout b/src/tools/miri/priroda/tests/ui/ub_exception_stop.stdout new file mode 100644 index 0000000000000..c63037e2e1b55 --- /dev/null +++ b/src/tools/miri/priroda/tests/ui/ub_exception_stop.stdout @@ -0,0 +1,5 @@ +(priroda) program stopped with error: memory access failed: attempting to access 1 byte, but got null pointer +{MANIFEST_DIR}/tests/ui/ub_exception_stop.rs:4 +(priroda) Name: , Id: _0, Ty: (), Value: +Name: , Id: _1, Ty: *mut u8, Value: {0x0 as *mut u8} +(priroda) quitting diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 6c163e62d963d..e01a381d55fd9 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -67854e511de21d881bb16426996cd4259d44aa2e +c656540d6467dee1381f0cbd882412d6bd1cd5ae diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index f28bb524775ed..7623422a66e57 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -45,9 +45,9 @@ use rustc_interface::util::DummyCodegenBackend; use rustc_log::tracing::debug; use rustc_middle::query::LocalCrate; use rustc_middle::ty::TyCtxt; -use rustc_structures::CrateType; -use rustc_session::config::{ ErrorOutputType, OptLevel}; +use rustc_session::config::{ErrorOutputType, OptLevel}; use rustc_session::{EarlyDiagCtxt, Session}; +use rustc_structures::CrateType; use crate::log::setup::{deinit_loggers, init_early_loggers, init_late_loggers}; diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 9bf202e8254e8..11f1fa2eb170d 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -12,8 +12,8 @@ use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::ty::layout::{LayoutOf, MaybeResult, TyAndLayout}; use rustc_middle::ty::{self, FnSigKind, IntTy, Ty, TyCtxt, UintTy}; -use rustc_structures::CrateType; use rustc_span::{Span, Symbol}; +use rustc_structures::CrateType; use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::Os; diff --git a/src/tools/miri/src/intrinsics/x86/avx2.rs b/src/tools/miri/src/intrinsics/x86/avx2.rs index 160bce2dec98b..dc7dbaff9927e 100644 --- a/src/tools/miri/src/intrinsics/x86/avx2.rs +++ b/src/tools/miri/src/intrinsics/x86/avx2.rs @@ -1,9 +1,8 @@ -use rustc_middle::mir; use rustc_span::Symbol; use super::{ - ShiftOp, horizontal_bin_op, mpsadbw, packssdw, packsswb, packusdw, packuswb, permute, pmaddbw, - pmaddwd, pmulhrsw, psadbw, pshufb, psign, shift_simd_by_scalar, + ShiftOp, mpsadbw, packssdw, packsswb, packusdw, packuswb, permute, pmaddbw, pmaddwd, pmulhrsw, + psadbw, pshufb, psign, shift_simd_by_scalar, }; use crate::*; @@ -21,20 +20,6 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.avx2.").unwrap(); match unprefixed_name { - // Used to implement the _mm256_h{adds,subs}_epi16 functions. - // Horizontally add / subtract with saturation adjacent 16-bit - // integer values in `left` and `right`. - "phadd.sw" | "phsub.sw" => { - let [left, right] = this.check_shim_sig_unadjusted(link_name, args)?; - - let which = match unprefixed_name { - "phadd.sw" => mir::BinOp::Add, - "phsub.sw" => mir::BinOp::Sub, - _ => unreachable!(), - }; - - horizontal_bin_op(this, which, /*saturating*/ true, left, right, dest)?; - } // Used to implement `_mm{,_mask}_{i32,i64}gather_{epi32,epi64,pd,ps}` functions // Gathers elements from `slice` using `offsets * scale` as indices. // When the highest bit of the corresponding element of `mask` is 0, diff --git a/src/tools/miri/src/intrinsics/x86/mod.rs b/src/tools/miri/src/intrinsics/x86/mod.rs index 25361a6435b0a..c0c9354b23a03 100644 --- a/src/tools/miri/src/intrinsics/x86/mod.rs +++ b/src/tools/miri/src/intrinsics/x86/mod.rs @@ -667,58 +667,6 @@ fn split_simd_to_128bit_chunks<'tcx, P: Projectable<'tcx, Provenance>>( interp_ok((num_chunks, items_per_chunk, chunked_op)) } -/// Horizontally performs `which` operation on adjacent values of -/// `left` and `right` SIMD vectors and stores the result in `dest`. -/// "Horizontal" means that the i-th output element is calculated -/// from the elements 2*i and 2*i+1 of the concatenation of `left` and -/// `right`. -/// -/// Each 128-bit chunk is treated independently (i.e., the value for -/// the is i-th 128-bit chunk of `dest` is calculated with the i-th -/// 128-bit chunks of `left` and `right`). -fn horizontal_bin_op<'tcx>( - ecx: &mut crate::MiriInterpCx<'tcx>, - which: mir::BinOp, - saturating: bool, - left: &OpTy<'tcx>, - right: &OpTy<'tcx>, - dest: &MPlaceTy<'tcx>, -) -> InterpResult<'tcx, ()> { - assert_eq!(left.layout, dest.layout); - assert_eq!(right.layout, dest.layout); - - let (num_chunks, items_per_chunk, left) = split_simd_to_128bit_chunks(ecx, left)?; - let (_, _, right) = split_simd_to_128bit_chunks(ecx, right)?; - let (_, _, dest) = split_simd_to_128bit_chunks(ecx, dest)?; - - let middle = items_per_chunk / 2; - for i in 0..num_chunks { - let left = ecx.project_index(&left, i)?; - let right = ecx.project_index(&right, i)?; - let dest = ecx.project_index(&dest, i)?; - - for j in 0..items_per_chunk { - // `j` is the index in `dest` - // `k` is the index of the 2-item chunk in `src` - let (k, src) = if j < middle { (j, &left) } else { (j.strict_sub(middle), &right) }; - // `base_i` is the index of the first item of the 2-item chunk in `src` - let base_i = k.strict_mul(2); - let lhs = ecx.read_immediate(&ecx.project_index(src, base_i)?)?; - let rhs = ecx.read_immediate(&ecx.project_index(src, base_i.strict_add(1))?)?; - - let res = if saturating { - Immediate::from(ecx.saturating_arith(which, &lhs, &rhs)?) - } else { - *ecx.binary_op(which, &lhs, &rhs)? - }; - - ecx.write_immediate(res, &ecx.project_index(&dest, j)?)?; - } - } - - interp_ok(()) -} - /// Conditionally multiplies the packed floating-point elements in /// `left` and `right` using the high 4 bits in `imm`, sums the calculated /// products (up to 4), and conditionally stores the sum in `dest` using diff --git a/src/tools/miri/src/intrinsics/x86/ssse3.rs b/src/tools/miri/src/intrinsics/x86/ssse3.rs index 5b4746e5b1a04..1c88c50e830d2 100644 --- a/src/tools/miri/src/intrinsics/x86/ssse3.rs +++ b/src/tools/miri/src/intrinsics/x86/ssse3.rs @@ -1,7 +1,6 @@ -use rustc_middle::mir; use rustc_span::Symbol; -use super::{horizontal_bin_op, pmaddbw, pmulhrsw, pshufb, psign}; +use super::{pmaddbw, pmulhrsw, pshufb, psign}; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -26,20 +25,6 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { pshufb(this, left, right, dest)?; } - // Used to implement the _mm_h{adds,subs}_epi16 functions. - // Horizontally add / subtract with saturation adjacent 16-bit - // integer values in `left` and `right`. - "phadd.sw.128" | "phsub.sw.128" => { - let [left, right] = this.check_shim_sig_unadjusted(link_name, args)?; - - let which = match unprefixed_name { - "phadd.sw.128" => mir::BinOp::Add, - "phsub.sw.128" => mir::BinOp::Sub, - _ => unreachable!(), - }; - - horizontal_bin_op(this, which, /*saturating*/ true, left, right, dest)?; - } // Used to implement the _mm_maddubs_epi16 function. "pmadd.ub.sw.128" => { let [left, right] = this.check_shim_sig_unadjusted(link_name, args)?; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 29289df8d823f..361ebef73b357 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1472,8 +1472,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { panic!("extern_statics cannot contain wildcards") }; let info = ecx.get_alloc_info(alloc_id); - if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align { - throw_unsup_format!( + if extern_decl_layout.size > info.size || extern_decl_layout.align.abi > info.align { + throw_ub_format!( "extern static `{link_name}` has been declared as `{krate}::{name}` \ with a size of {decl_size} bytes and alignment of {decl_align} bytes, \ but Miri emulates it via an extern static shim \ @@ -1516,7 +1516,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { // Validate the allocation matches the declared size and alignment. let alloc_id = static_ptr.provenance.get_alloc_id().unwrap(); let info = ecx.get_alloc_info(alloc_id); - if extern_decl_layout.size != info.size || extern_decl_layout.align.abi != info.align { + if extern_decl_layout.size > info.size || extern_decl_layout.align.abi > info.align { throw_ub_format!( "extern static `{link_name}` has been declared as `{krate}::{name}` \ with a size of {decl_size} bytes and alignment of {decl_align} bytes, \ diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index b4d53c36d19b3..3874c00187fdc 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match method { SpecialAllocatorMethod::Alloc | SpecialAllocatorMethod::AllocZeroed => { let [size, align] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::Rust, link_name, args)?; let size = this.read_target_usize(size)?; let align = this.read_target_usize(align)?; @@ -145,7 +145,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } SpecialAllocatorMethod::Dealloc => { let [ptr, old_size, align] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_target_usize(old_size)?; let align = this.read_target_usize(align)?; @@ -159,7 +159,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } SpecialAllocatorMethod::Realloc => { let [ptr, old_size, align, new_size] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_target_usize(old_size)?; let align = this.read_target_usize(align)?; diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 1ca814ee7afff..7b66ce563f646 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -15,7 +15,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let [flags] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [flags] = + this.check_shim_sig(shim_sig!(extern "Rust" fn(u64) -> usize), link_name, abi, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -37,7 +38,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let ptr_ty = this.machine.layouts.mut_raw_ptr.ty; let ptr_layout = this.layout_of(ptr_ty)?; - let [flags, buf] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [flags, buf] = + this.check_shim_sig(shim_sig!(extern "Rust" fn(u64, *_) -> ()), link_name, abi, args)?; let flags = this.read_scalar(flags)?.to_u64()?; let buf_place = this.deref_pointer_as(buf, ptr_layout)?; @@ -114,7 +116,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let [ptr, flags] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [ptr, flags] = this.check_shim_sig_deprecated(abi, CanonAbi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; @@ -191,8 +193,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let [ptr, flags, name_ptr, filename_ptr] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [ptr, flags, name_ptr, filename_ptr] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(*_, u64, *_, *_) -> ()), + link_name, + abi, + args, + )?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 793a225efab9e..df87fb5322982 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -2,7 +2,7 @@ use std::collections::hash_map::Entry; use std::io::Write; use std::path::Path; -use rustc_abi::{Align, CanonAbi, ExternAbi, Size}; +use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::expand::allocator::NO_ALLOC_SHIM_IS_UNSTABLE; use rustc_data_structures::either::Either; use rustc_hir::attrs::Linkage; @@ -317,13 +317,22 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { name if name == this.mangle_internal_symbol(NO_ALLOC_SHIM_IS_UNSTABLE) => { // This is a no-op shim that only exists to prevent making the allocator shims // instantly stable. - let [] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig_nounwind!(extern "Rust" fn() -> ()), + link_name, + abi, + args, + )?; } // Miri-specific extern functions "miri_alloc" => { - let [size, align] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [size, align] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(usize, usize) -> *_), + link_name, + abi, + args, + )?; let size = this.read_target_usize(size)?; let align = this.read_target_usize(align)?; @@ -339,8 +348,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(ptr, dest)?; } "miri_dealloc" => { - let [ptr, old_size, align] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [ptr, old_size, align] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(*_, usize, usize) -> ()), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_target_usize(old_size)?; let align = this.read_target_usize(align)?; @@ -353,7 +366,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "miri_track_alloc" => { - let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [ptr] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(*_) -> ()), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr, 0).map_err_kind(|_e| { err_machine_stop!(TerminationInfo::Abort(format!( @@ -368,17 +386,27 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "miri_start_unwind" => { - let [payload] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [payload] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(*_) -> !), + link_name, + abi, + args, + )?; this.handle_miri_start_unwind(payload)?; return interp_ok(EmulateItemResult::NeedsUnwind); } "miri_run_provenance_gc" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [] = + this.check_shim_sig(shim_sig!(extern "Rust" fn() -> ()), link_name, abi, args)?; this.run_provenance_gc(); } "miri_get_alloc_id" => { - let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [ptr] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(*_) -> u64), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let (alloc_id, _, _) = this.ptr_get_alloc_id(ptr, 0).map_err_kind(|_e| { err_machine_stop!(TerminationInfo::Abort(format!( @@ -388,8 +416,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_u64(alloc_id.0.get()), dest)?; } "miri_print_borrow_state" => { - let [id, show_unnamed] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [id, show_unnamed] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(u64, bool) -> ()), + link_name, + abi, + args, + )?; let id = this.read_scalar(id)?.to_u64()?; let show_unnamed = this.read_scalar(show_unnamed)?.to_bool()?; if let Some(id) = std::num::NonZero::new(id).map(AllocId) @@ -403,8 +435,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "miri_pointer_name" => { // This associates a name to a tag. Very useful for debugging, and also makes // tests more strict. - let [ptr, nth_parent, name] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [ptr, nth_parent, name] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(*_, u8, &[u8]) -> ()), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let nth_parent = this.read_scalar(nth_parent)?.to_u8()?; let name = this.read_immediate(name)?; @@ -417,7 +453,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.give_pointer_debug_name(ptr, nth_parent, &name)?; } "miri_static_root" => { - let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [ptr] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(*_) -> ()), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr, 0)?; if offset != Size::ZERO { @@ -428,8 +469,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.machine.static_roots.push(alloc_id); } "miri_host_to_target_path" => { - let [ptr, out, out_size] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [ptr, out, out_size] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(*_, *_, usize) -> usize), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let out = this.read_pointer(out)?; let out_size = this.read_scalar(out_size)?.to_target_usize(this)?; @@ -445,9 +490,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_int(if success { 0 } else { needed_size }, dest)?; } "miri_thread_spawn" => { - // FIXME: `check_shim_sig` does not work with function pointers. - let [start_routine, func_arg] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [start_routine, func_arg] = this.check_shim_sig( + // FIXME: The first argument is actually a function pointer. + shim_sig!(extern "Rust" fn(fn(..) -> _, *_) -> usize), + link_name, + abi, + args, + )?; let start_routine = this.read_pointer(start_routine)?; let func_arg = this.read_immediate(func_arg)?; @@ -486,7 +535,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Hint that a loop is spinning indefinitely. "miri_spin_loop" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [] = + this.check_shim_sig(shim_sig!(extern "Rust" fn() -> ()), link_name, abi, args)?; // Try to run another thread to maximize the chance of finding actual bugs. this.yield_active_thread(); @@ -509,10 +559,14 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "miri_resolve_frame_names" => { this.handle_miri_resolve_frame_names(abi, link_name, args)?; } - // Writes some bytes to the interpreter's stdout/stderr. See the - // README for details. + // Writes some bytes to the interpreter's stdout/stderr. See the README for details. "miri_write_to_stdout" | "miri_write_to_stderr" => { - let [msg] = this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [msg] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(&[u8]) -> ()), + link_name, + abi, + args, + )?; let msg = this.read_immediate(msg)?; let msg = this.read_byte_slice(&msg)?; // Note: we're ignoring errors writing to host stdout/stderr. @@ -526,8 +580,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { "miri_promise_symbolic_alignment" => { use rustc_abi::AlignFromBytesError; - let [ptr, align] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [ptr, align] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(*_, usize) -> ()), + link_name, + abi, + args, + )?; + let ptr = this.read_pointer(ptr)?; let align = this.read_target_usize(align)?; if !align.is_power_of_two() { @@ -567,8 +626,13 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } // GenMC mode: Assume statements block the current thread when their condition is false. "miri_genmc_assume" => { - let [condition] = - this.check_shim_sig_lenient(abi, CanonAbi::Rust, link_name, args)?; + let [condition] = this.check_shim_sig( + shim_sig!(extern "Rust" fn(bool) -> ()), + link_name, + abi, + args, + )?; + if this.machine.data_race.as_genmc_ref().is_some() { this.handle_genmc_verifier_assume(condition)?; } else { @@ -579,7 +643,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Aborting the process. "exit" => { // FIXME: This does not have a direct test (#3179). - let [code] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [code] = + this.check_shim_sig(shim_sig!(extern "C" fn(i32) -> ()), link_name, abi, args)?; let code = this.read_scalar(code)?.to_i32()?; if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { // If there is no error, execution should continue (on a different thread). @@ -594,7 +659,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "abort" => { // FIXME: This does not have a direct test (#3179). - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = + this.check_shim_sig(shim_sig!(extern "C" fn() -> ()), link_name, abi, args)?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )); @@ -602,7 +668,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Standard C allocation "malloc" => { - let [size] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [size] = this.check_shim_sig( + shim_sig!(extern "C" fn(usize) -> *_), + link_name, + abi, + args, + )?; let size = this.read_target_usize(size)?; if size <= this.max_size_of_val().bytes() { let res = this.malloc(size, AllocInit::Uninit)?; @@ -616,8 +687,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "calloc" => { - let [items, elem_size] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [items, elem_size] = this.check_shim_sig( + shim_sig!(extern "C" fn(usize, usize) -> *_), + link_name, + abi, + args, + )?; let items = this.read_target_usize(items)?; let elem_size = this.read_target_usize(elem_size)?; if let Some(size) = this.compute_size_in_bytes(Size::from_bytes(elem_size), items) { @@ -632,13 +707,18 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "free" => { - let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [ptr] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> ()), link_name, abi, args)?; let ptr = this.read_pointer(ptr)?; this.free(ptr)?; } "realloc" => { - let [old_ptr, new_size] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [old_ptr, new_size] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, usize) -> *_), + link_name, + abi, + args, + )?; let old_ptr = this.read_pointer(old_ptr)?; let new_size = this.read_target_usize(new_size)?; if new_size <= this.max_size_of_val().bytes() { @@ -652,11 +732,48 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } } + "malloc_usable_size" => { + this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?; + + let [ptr] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_) -> usize), + link_name, + abi, + args, + )?; + let ptr = this.read_pointer(ptr)?; + let size = if this.ptr_is_null(ptr)? { + 0 + } else { + let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr, 0)?; + if offset.bytes() != 0 { + throw_ub_format!( + "`malloc_usable_size` was called on a pointer that does not point to the beginning of its allocation" + ); + } + let Some((alloc_kind, _)) = this.memory.alloc_map().get(alloc_id) else { + throw_ub_format!( + "`malloc_usable_size` was called on a pointer to memory not managed by the C allocator" + ); + }; + if *alloc_kind != MiriMemoryKind::C.into() { + throw_ub_format!( + "`malloc_usable_size` was called on a pointer to {alloc_kind} memory, which is not managed by the C allocator" + ); + } + this.get_alloc_info(alloc_id).size.bytes() + }; + this.write_scalar(Scalar::from_target_usize(size, this), dest)?; + } // C memory handling functions "memcmp" => { - let [left, right, n] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [left, right, n] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_, usize) -> i32), + link_name, + abi, + args, + )?; let left = this.read_pointer(left)?; let right = this.read_pointer(right)?; let n = Size::from_bytes(this.read_target_usize(n)?); @@ -685,7 +802,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } "memchr" => { let [ptr, val, num] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, i32, usize) -> *const _), + shim_sig!(extern "C" fn(*_, i32, usize) -> *_), link_name, abi, args, @@ -714,7 +831,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.check_target_os(&[Os::Linux, Os::Android, Os::FreeBsd], link_name)?; let [ptr, val, num] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, i32, usize) -> *const _), + shim_sig!(extern "C" fn(*_, i32, usize) -> *_), link_name, abi, args, @@ -739,7 +856,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } } "strlen" => { - let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [ptr] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_) -> usize), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; // This reads at least 1 byte, so we are already enforcing that this is a valid pointer. let n = this.read_c_str(ptr)?.len(); @@ -749,7 +871,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "strnlen" => { - let [ptr, num] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [ptr, num] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, usize) -> usize), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let num = this.read_target_usize(num)?; @@ -762,7 +889,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(Scalar::from_target_usize(idx, this), dest)?; } "wcslen" => { - let [ptr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [ptr] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_) -> usize), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; // This reads at least 1 byte, so we are already enforcing that this is a valid pointer. let n = this.read_wchar_t_str(ptr)?.len(); @@ -772,8 +904,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; } "memcpy" => { - let [ptr_dest, ptr_src, n] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [ptr_dest, ptr_src, n] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_, usize) -> *_), + link_name, + abi, + args, + )?; let ptr_dest = this.read_pointer(ptr_dest)?; let ptr_src = this.read_pointer(ptr_src)?; let n = this.read_target_usize(n)?; @@ -787,8 +923,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(ptr_dest, dest)?; } "strcpy" => { - let [ptr_dest, ptr_src] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [ptr_dest, ptr_src] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_) -> *_), + link_name, + abi, + args, + )?; let ptr_dest = this.read_pointer(ptr_dest)?; let ptr_src = this.read_pointer(ptr_src)?; @@ -803,8 +943,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_pointer(ptr_dest, dest)?; } "memset" => { - let [ptr_dest, val, n] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [ptr_dest, val, n] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, i32, usize) -> *_), + link_name, + abi, + args, + )?; let ptr_dest = this.read_pointer(ptr_dest)?; let val = this.read_scalar(val)?.to_i32()?; let n = this.read_target_usize(n)?; diff --git a/src/tools/miri/src/shims/math.rs b/src/tools/miri/src/shims/math.rs index 593e4883cc08a..1a3228425af9a 100644 --- a/src/tools/miri/src/shims/math.rs +++ b/src/tools/miri/src/shims/math.rs @@ -38,7 +38,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "erff" | "erfcf" => { - let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; + let [f] = this.check_shim_sig_deprecated(abi, CanonAbi::C , link_name, args)?; let f = this.read_scalar(f)?.to_f32()?; let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| { @@ -81,7 +81,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "atan2f" | "fdimf" => { - let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; + let [f1, f2] = this.check_shim_sig_deprecated(abi, CanonAbi::C , link_name, args)?; let f1 = this.read_scalar(f1)?.to_f32()?; let f2 = this.read_scalar(f2)?.to_f32()?; @@ -125,7 +125,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "erf" | "erfc" => { - let [f] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; + let [f] = this.check_shim_sig_deprecated(abi, CanonAbi::C , link_name, args)?; let f = this.read_scalar(f)?.to_f64()?; let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| { @@ -168,7 +168,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "atan2" | "fdim" => { - let [f1, f2] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; + let [f1, f2] = this.check_shim_sig_deprecated(abi, CanonAbi::C , link_name, args)?; let f1 = this.read_scalar(f1)?.to_f64()?; let f2 = this.read_scalar(f2)?.to_f64()?; @@ -199,7 +199,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "ldexp" | "scalbn" => { - let [x, exp] = this.check_shim_sig_lenient(abi, CanonAbi::C , link_name, args)?; + let [x, exp] = this.check_shim_sig_deprecated(abi, CanonAbi::C , link_name, args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -209,7 +209,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "lgammaf_r" => { - let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [x, signp] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let x = this.read_scalar(x)?.to_f32()?; let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?; @@ -228,7 +229,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "lgamma_r" => { - let [x, signp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [x, signp] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let x = this.read_scalar(x)?.to_f64()?; let signp = this.deref_pointer_as(signp, this.machine.layouts.i32)?; diff --git a/src/tools/miri/src/shims/sig.rs b/src/tools/miri/src/shims/sig.rs index d40e9039f2b60..6bf1873d1d670 100644 --- a/src/tools/miri/src/shims/sig.rs +++ b/src/tools/miri/src/shims/sig.rs @@ -12,6 +12,7 @@ pub struct ShimSig<'tcx, const ARGS: usize> { pub abi: ExternAbi, pub args: [Ty<'tcx>; ARGS], pub ret: Ty<'tcx>, + pub nounwind: bool, } /// Construct a `ShimSig` with convenient syntax: @@ -22,7 +23,7 @@ pub struct ShimSig<'tcx, const ARGS: usize> { /// The following types are supported: /// - primitive integer types /// - `()` -/// - (thin) raw pointers, written `*const _` and `*mut _` since the pointee type is irrelevant +/// - (thin) raw pointers, written `*_` since the mutability and pointee type are irrelevant /// - `$crate::$mod::...::$ty` for a type from the given crate (most commonly that is `libc`) /// - `winapi::$ty` for a type from `std::sys::pal::windows::c` #[macro_export] @@ -32,6 +33,20 @@ macro_rules! shim_sig { abi: std::str::FromStr::from_str($abi).expect("incorrect abi specified"), args: shim_sig_args_sep!(this, [$($args)*]), ret: shim_sig_arg!(this, $($ret)*), + nounwind: false, + } + }; +} + +/// Same as `shim_sig!` but promises that this function will not unwind, even if the ABI allows it. +#[macro_export] +macro_rules! shim_sig_nounwind { + (extern $abi:literal fn($($args:tt)*) -> $($ret:tt)*) => { + |this| $crate::shims::sig::ShimSig { + abi: std::str::FromStr::from_str($abi).expect("incorrect abi specified"), + args: shim_sig_args_sep!(this, [$($args)*]), + ret: shim_sig_arg!(this, $($ret)*), + nounwind: true, } }; } @@ -43,9 +58,9 @@ macro_rules! shim_sig { /// # Examples /// /// ```ignore -/// shim_sig_args_sep!(this, [*const _, i32, libc::off64_t]); +/// shim_sig_args_sep!(this, [*_, i32, libc::off64_t]); /// // expands to: -/// [shim_sig_arg!(*const _), shim_sig_arg!(i32), shim_sig_arg!(libc::off64_t)]; +/// [shim_sig_arg!(*_), shim_sig_arg!(i32), shim_sig_arg!(libc::off64_t)]; /// ``` #[macro_export] macro_rules! shim_sig_args_sep { @@ -121,14 +136,27 @@ macro_rules! shim_sig_arg { ($this:ident, ()) => { $this.tcx.types.unit }; + ($this:ident, !) => { + $this.tcx.types.never + }; ($this:ident, bool) => { $this.tcx.types.bool }; - ($this:ident, *const _) => { + ($this:ident, *_) => { + // Mutability does not matter for ABI. + $this.machine.layouts.mut_raw_ptr.ty + }; + ($this:ident, fn(..) -> _) => { + // We currently treat fn ptrs as ABI-compatible with data ptrs so we can just use a raw ptr. $this.machine.layouts.const_raw_ptr.ty }; - ($this:ident, *mut _) => { - $this.machine.layouts.mut_raw_ptr.ty + ($this:ident, &[$($ty:tt)*]) => { + rustc_middle::ty::Ty::new_ref( + *$this.tcx, + $this.tcx.lifetimes.re_erased, + rustc_middle::ty::Ty::new_slice(*$this.tcx, shim_sig_arg!($this, $($ty)*)), + rustc_middle::mir::Mutability::Not, + ) }; ($this:ident, winapi::$ty:ident) => { $this.windows_ty_layout(stringify!($ty)).ty @@ -144,37 +172,42 @@ macro_rules! shim_sig_arg { /// Helper function to compare two ABIs. fn check_shim_abi<'tcx>( this: &MiriInterpCx<'tcx>, + link_name: Symbol, callee_abi: &FnAbi<'tcx, Ty<'tcx>>, + callee_nounwind: bool, caller_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> InterpResult<'tcx> { if callee_abi.conv != caller_abi.conv { throw_ub_format!( - r#"calling a function with calling convention "{callee}" using caller calling convention "{caller}""#, + r#"ABI mismatch: `{link_name}` has calling convention "{callee}", but the caller is using calling convention "{caller}""#, callee = callee_abi.conv, caller = caller_abi.conv, ); } - if callee_abi.can_unwind && !caller_abi.can_unwind { + // FIXME: is this needed? Or is it enough to just check this if/when an actual unwind happens? + if callee_abi.can_unwind && !callee_nounwind && !caller_abi.can_unwind { throw_ub_format!( - "ABI mismatch: callee may unwind, but caller-side signature prohibits unwinding", + "ABI mismatch: callee may unwind, but caller asumes that no unwinding will occur", ); } if caller_abi.c_variadic && !callee_abi.c_variadic { throw_ub_format!( - "ABI mismatch: calling a non-variadic function with a variadic caller-side signature" + "ABI mismatch: `{link_name}` is a non-variadic function, but the caller is using a variadic signature" ); } if !caller_abi.c_variadic && callee_abi.c_variadic { throw_ub_format!( - "ABI mismatch: calling a variadic function with a non-variadic caller-side signature" + "ABI mismatch: `{link_name}` is a variadic function, but the caller is using a non-variadic signature" ); } if callee_abi.fixed_count != caller_abi.fixed_count { throw_ub_format!( - "ABI mismatch: expected {} arguments, found {} arguments ", + "ABI mismatch: calling `{link_name}` which takes {} argument{}, but {} argument{} given", callee_abi.fixed_count, - caller_abi.fixed_count + if callee_abi.fixed_count == 1 { "" } else { "s" }, + caller_abi.fixed_count, + if caller_abi.fixed_count == 1 { " was" } else { "s were" }, ); } @@ -223,7 +256,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(()) } - fn check_shim_sig_lenient<'a, const N: usize>( + /// 'Lenient' signature check. Deprecated; use `check_shim_sig` instead. + fn check_shim_sig_deprecated<'a, const N: usize>( &mut self, abi: &FnAbi<'tcx, Ty<'tcx>>, exp_abi: CanonAbi, @@ -280,7 +314,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let callee_fn_abi = this.fn_abi_of_fn_ptr(fn_sig_binder, Default::default())?; // Check everything. - check_shim_abi(this, callee_fn_abi, caller_fn_abi)?; + check_shim_abi(this, link_name, callee_fn_abi, shim_sig.nounwind, caller_fn_abi)?; this.check_shim_symbol_clash(link_name)?; // Return arguments. diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 999750a9e00a9..37f789362cc81 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -30,7 +30,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "pread64" => { // FIXME: This does not have a direct test (#3179). let [fd, buf, count, offset] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize), + shim_sig!(extern "C" fn(i32, *_, usize, libc::off64_t) -> isize), link_name, abi, args, @@ -44,7 +44,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "pwrite64" => { // FIXME: This does not have a direct test (#3179). let [fd, buf, n, offset] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize), + shim_sig!(extern "C" fn(i32, *_, usize, libc::off64_t) -> isize), link_name, abi, args, @@ -84,36 +84,37 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // epoll, eventfd "epoll_create1" => { - let [flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [flag] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_create1(flag)?; this.write_scalar(result, dest)?; } "epoll_ctl" => { let [epfd, op, fd, event] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_ctl(epfd, op, fd, event)?; this.write_scalar(result, dest)?; } "epoll_wait" => { let [epfd, events, maxevents, timeout] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.epoll_wait(epfd, events, maxevents, timeout, dest)?; } "eventfd" => { - let [val, flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [val, flag] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.eventfd(val, flag)?; this.write_scalar(result, dest)?; } // Miscellaneous "__errno" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } "gettid" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.unix_gettid(link_name.as_str())?; this.write_scalar(result, dest)?; } diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 2eb8ee0f6105f..f255531d65a6b 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -12,6 +12,7 @@ use self::shims::unix::android::foreign_items as android; use self::shims::unix::freebsd::foreign_items as freebsd; use self::shims::unix::linux::foreign_items as linux; use self::shims::unix::macos::foreign_items as macos; +use self::shims::unix::netbsd::foreign_items as netbsd; use self::shims::unix::solarish::foreign_items as solarish; use crate::concurrency::cpu_affinity::CpuAffinityMask; use crate::shims::alloc::EvalContextExt as _; @@ -42,6 +43,7 @@ pub fn is_dyn_sym(name: &str, target_os: &Os) -> bool { Os::Linux => linux::is_dyn_sym(name), Os::MacOs => macos::is_dyn_sym(name), Os::Solaris | Os::Illumos => solarish::is_dyn_sym(name), + Os::NetBsd => netbsd::is_dyn_sym(name), _ => false, }, } @@ -129,28 +131,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // Environment related shims "getenv" => { - let [name] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _) -> *mut _), - link_name, - abi, - args, - )?; + let [name] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> *_), link_name, abi, args)?; let result = this.getenv(name)?; this.write_pointer(result, dest)?; } "unsetenv" => { - let [name] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _) -> i32), - link_name, - abi, - args, - )?; + let [name] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.unsetenv(name)?; this.write_scalar(result, dest)?; } "setenv" => { let [name, value, overwrite] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, *const _, i32) -> i32), + shim_sig!(extern "C" fn(*_, *_, i32) -> i32), link_name, abi, args, @@ -162,7 +156,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "getcwd" => { // FIXME: This does not have a direct test (#3179). let [buf, size] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _, usize) -> *mut _), + shim_sig!(extern "C" fn(*_, usize) -> *_), link_name, abi, args, @@ -172,7 +166,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "gethostname" => { let [name, len] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _, usize) -> i32), + shim_sig!(extern "C" fn(*_, usize) -> i32), link_name, abi, args, @@ -182,12 +176,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "chdir" => { // FIXME: This does not have a direct test (#3179). - let [path] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _) -> i32), - link_name, - abi, - args, - )?; + let [path] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.chdir(path)?; this.write_scalar(result, dest)?; } @@ -208,12 +198,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { link_name, )?; - let [uname] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _) -> i32), - link_name, - abi, - args, - )?; + let [uname] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.uname(uname, None)?; this.write_scalar(result, dest)?; } @@ -230,7 +216,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File descriptors "read" => { let [fd, buf, count] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _, usize) -> isize), + shim_sig!(extern "C" fn(i32, *_, usize) -> isize), link_name, abi, args, @@ -242,7 +228,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "write" => { let [fd, buf, n] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, usize) -> isize), + shim_sig!(extern "C" fn(i32, *_, usize) -> isize), link_name, abi, args, @@ -255,7 +241,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "readv" => { let [fd, iov, iovcnt] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, i32) -> isize), + shim_sig!(extern "C" fn(i32, *_, i32) -> isize), link_name, abi, args, @@ -264,7 +250,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "writev" => { let [fd, iov, iovcnt] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, i32) -> isize), + shim_sig!(extern "C" fn(i32, *_, i32) -> isize), link_name, abi, args, @@ -273,7 +259,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pread" => { let [fd, buf, count, offset] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off_t) -> isize), + shim_sig!(extern "C" fn(i32, *_, usize, libc::off_t) -> isize), link_name, abi, args, @@ -286,7 +272,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pwrite" => { let [fd, buf, n, offset] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, usize, libc::off_t) -> isize), + shim_sig!(extern "C" fn(i32, *_, usize, libc::off_t) -> isize), link_name, abi, args, @@ -300,7 +286,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "preadv" => { let [fd, iov, iovcnt, offset] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, i32, libc::off_t) -> isize), + shim_sig!(extern "C" fn(i32, *_, i32, libc::off_t) -> isize), link_name, abi, args, @@ -309,7 +295,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pwritev" => { let [fd, iov, iovcnt, offset] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, i32, libc::off_t) -> isize), + shim_sig!(extern "C" fn(i32, *_, i32, libc::off_t) -> isize), link_name, abi, args, @@ -393,19 +379,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "unlink" => { // FIXME: This does not have a direct test (#3179). - let [path] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _) -> i32), - link_name, - abi, - args, - )?; + let [path] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.unlink(path)?; this.write_scalar(result, dest)?; } "symlink" => { // FIXME: This does not have a direct test (#3179). let [target, linkpath] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, *const _) -> i32), + shim_sig!(extern "C" fn(*_, *_) -> i32), link_name, abi, args, @@ -415,7 +397,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "linkat" => { let [oldfd, oldpath, newfd, newpath, flags] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, i32, *const _, i32) -> i32), + shim_sig!(extern "C" fn(i32, *_, i32, *_, i32) -> i32), link_name, abi, args, @@ -424,23 +406,38 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "fstat" => { - let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [fd, buf] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *_) -> i32), + link_name, + abi, + args, + )?; let result = this.fstat(fd, buf)?; this.write_scalar(result, dest)?; } "lstat" => { - let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [path, buf] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_) -> i32), + link_name, + abi, + args, + )?; let result = this.lstat(path, buf)?; this.write_scalar(result, dest)?; } "stat" => { - let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [path, buf] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_) -> i32), + link_name, + abi, + args, + )?; let result = this.stat(path, buf)?; this.write_scalar(result, dest)?; } "chmod" => { let [path, mode] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, libc::mode_t) -> i32), + shim_sig!(extern "C" fn(*_, libc::mode_t) -> i32), link_name, abi, args, @@ -461,7 +458,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "rename" => { // FIXME: This does not have a direct test (#3179). let [oldpath, newpath] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, *const _) -> i32), + shim_sig!(extern "C" fn(*_, *_) -> i32), link_name, abi, args, @@ -472,7 +469,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "mkdir" => { // FIXME: This does not have a direct test (#3179). let [path, mode] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, libc::mode_t) -> i32), + shim_sig!(extern "C" fn(*_, libc::mode_t) -> i32), link_name, abi, args, @@ -482,37 +479,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "rmdir" => { // FIXME: This does not have a direct test (#3179). - let [path] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _) -> i32), - link_name, - abi, - args, - )?; + let [path] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.rmdir(path)?; this.write_scalar(result, dest)?; } "opendir" => { - let [name] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _) -> *mut _), - link_name, - abi, - args, - )?; + let [name] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> *_), link_name, abi, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "closedir" => { - let [dirp] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _) -> i32), - link_name, - abi, - args, - )?; + let [dirp] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.closedir(dirp)?; this.write_scalar(result, dest)?; } "readdir" => { - let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [dirp] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> *_), link_name, abi, args)?; this.readdir(dirp, dest)?; } "lseek" => { @@ -564,7 +550,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "futimens" => { let [fd, times] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _) -> i32), + shim_sig!(extern "C" fn(i32, *_) -> i32), link_name, abi, args, @@ -574,7 +560,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "readlink" => { let [pathname, buf, bufsize] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, *mut _, usize) -> isize), + shim_sig!(extern "C" fn(*_, *_, usize) -> isize), link_name, abi, args, @@ -623,7 +609,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "realpath" => { let [path, resolved_path] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _), + shim_sig!(extern "C" fn(*_, *_) -> *_), link_name, abi, args, @@ -632,12 +618,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "mkstemp" => { - let [template] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _) -> i32), - link_name, - abi, - args, - )?; + let [template] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.mkstemp(template)?; this.write_scalar(result, dest)?; } @@ -645,7 +627,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Poll "poll" => { let [fds, nfds, timeout] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _, libc::nfds_t, i32) -> i32), + shim_sig!(extern "C" fn(*_, libc::nfds_t, i32) -> i32), link_name, abi, args, @@ -656,7 +638,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Sockets and pipes "socketpair" => { let [domain, type_, protocol, sv] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, i32, i32, *mut _) -> i32), + shim_sig!(extern "C" fn(i32, i32, i32, *_) -> i32), link_name, abi, args, @@ -665,12 +647,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "pipe" => { - let [pipefd] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _) -> i32), - link_name, - abi, - args, - )?; + let [pipefd] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.pipe2(pipefd, /*flags*/ None)?; this.write_scalar(result, dest)?; } @@ -682,7 +660,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; let [pipefd, flags] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _, i32) -> i32), + shim_sig!(extern "C" fn(*_, i32) -> i32), link_name, abi, args, @@ -704,7 +682,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "bind" => { let [socket, address, address_len] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32), + shim_sig!(extern "C" fn(i32, *_, libc::socklen_t) -> i32), link_name, abi, args, @@ -724,7 +702,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "accept" => { let [socket, address, address_len] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32), + shim_sig!(extern "C" fn(i32, *_, *_) -> i32), link_name, abi, args, @@ -733,7 +711,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "accept4" => { let [socket, address, address_len, flags] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _, *mut _, i32) -> i32), + shim_sig!(extern "C" fn(i32, *_, *_, i32) -> i32), link_name, abi, args, @@ -742,7 +720,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "connect" => { let [socket, address, address_len] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32), + shim_sig!(extern "C" fn(i32, *_, libc::socklen_t) -> i32), link_name, abi, args, @@ -751,7 +729,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "send" => { let [socket, buffer, length, flags] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, libc::size_t, i32) -> libc::ssize_t), + shim_sig!(extern "C" fn(i32, *_, libc::size_t, i32) -> libc::ssize_t), link_name, abi, args, @@ -760,7 +738,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "recv" => { let [socket, buffer, length, flags] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _, libc::size_t, i32) -> libc::ssize_t), + shim_sig!(extern "C" fn(i32, *_, libc::size_t, i32) -> libc::ssize_t), link_name, abi, args, @@ -769,7 +747,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "setsockopt" => { let [socket, level, option_name, option_value, option_len] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, i32, i32, *const _, libc::socklen_t) -> i32), + shim_sig!(extern "C" fn(i32, i32, i32, *_, libc::socklen_t) -> i32), link_name, abi, args, @@ -780,7 +758,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "getsockopt" => { let [socket, level, option_name, option_value, option_len] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, i32, i32, *mut _, *mut _) -> i32), + shim_sig!(extern "C" fn(i32, i32, i32, *_, *_) -> i32), link_name, abi, args, @@ -791,7 +769,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "getsockname" => { let [socket, address, address_len] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32), + shim_sig!(extern "C" fn(i32, *_, *_) -> i32), link_name, abi, args, @@ -801,7 +779,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "getpeername" => { let [socket, address, address_len] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _, *mut _) -> i32), + shim_sig!(extern "C" fn(i32, *_, *_) -> i32), link_name, abi, args, @@ -820,7 +798,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "getaddrinfo" => { let [node, service, hints, res] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, *const _, *const _, *mut _) -> i32), + shim_sig!(extern "C" fn(*_, *_, *_, *_) -> i32), link_name, abi, args, @@ -829,19 +807,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "freeaddrinfo" => { - let [res] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _) -> ()), - link_name, - abi, - args, - )?; + let [res] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> ()), link_name, abi, args)?; this.freeaddrinfo(res)?; } // Time "gettimeofday" => { let [tv, tz] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _, *mut _) -> i32), + shim_sig!(extern "C" fn(*_, *_) -> i32), link_name, abi, args, @@ -851,7 +825,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "localtime_r" => { let [timep, result_op] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, *mut _) -> *mut _), + shim_sig!(extern "C" fn(*_, *_) -> *_), link_name, abi, args, @@ -861,7 +835,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "clock_gettime" => { let [clk_id, tp] = this.check_shim_sig( - shim_sig!(extern "C" fn(libc::clockid_t, *mut _) -> i32), + shim_sig!(extern "C" fn(libc::clockid_t, *_) -> i32), link_name, abi, args, @@ -871,15 +845,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Allocation "posix_memalign" => { - let [memptr, align, size] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [memptr, align, size] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, usize, usize) -> i32), + link_name, + abi, + args, + )?; let result = this.posix_memalign(memptr, align, size)?; this.write_scalar(result, dest)?; } "mmap" => { let [addr, length, prot, flags, fd, offset] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _, usize, i32, i32, i32, libc::off_t) -> *mut _), + shim_sig!(extern "C" fn(*_, usize, i32, i32, i32, libc::off_t) -> *_), link_name, abi, args, @@ -890,7 +868,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "munmap" => { let [addr, length] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _, usize) -> i32), + shim_sig!(extern "C" fn(*_, usize) -> i32), link_name, abi, args, @@ -900,7 +878,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "mprotect" => { let [addr, length, prot] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _, usize, i32) -> i32), + shim_sig!(extern "C" fn(*_, usize, i32) -> i32), link_name, abi, args, @@ -910,7 +888,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "madvise" => { let [addr, length, advice] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _, usize, i32) -> i32), + shim_sig!(extern "C" fn(*_, usize, i32) -> i32), link_name, abi, args, @@ -923,8 +901,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?; - let [ptr, nmemb, size] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [ptr, nmemb, size] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, usize, usize) -> *_), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let nmemb = this.read_target_usize(nmemb)?; let size = this.read_target_usize(size)?; @@ -947,16 +929,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "aligned_alloc" => { // This is a C11 function, we assume all Unixes have it. // (MSVC explicitly does not support this.) - let [align, size] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [align, size] = this.check_shim_sig( + shim_sig!(extern "C" fn(usize, usize) -> *_), + link_name, + abi, + args, + )?; let res = this.aligned_alloc(align, size)?; this.write_pointer(res, dest)?; } // Dynamic symbol loading "dlsym" => { - let [handle, symbol] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [handle, symbol] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_) -> *_), + link_name, + abi, + args, + )?; this.read_target_usize(handle)?; let symbol = this.read_pointer(symbol)?; let name = this.read_c_str(symbol)?; @@ -975,7 +965,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Thread-local storage "pthread_key_create" => { - let [key, dtor] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [key, dtor] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, fn(..) -> _) -> i32), + link_name, + abi, + args, + )?; let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?; let dtor = this.read_pointer(dtor)?; @@ -1007,7 +1002,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_key_delete" => { // FIXME: This does not have a direct test (#3179). - let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [key] = this.check_shim_sig( + shim_sig!(extern "C" fn(libc::pthread_key_t) -> i32), + link_name, + abi, + args, + )?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) @@ -1015,16 +1015,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_getspecific" => { // FIXME: This does not have a direct test (#3179). - let [key] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [key] = this.check_shim_sig( + shim_sig!(extern "C" fn(libc::pthread_key_t) -> *_), + link_name, + abi, + args, + )?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; let active_thread = this.active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - // FIXME: This does not have a direct test (#3179). - let [key, new_ptr] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [key, new_ptr] = this.check_shim_sig( + shim_sig!(extern "C" fn(libc::pthread_key_t, *_) -> i32), + link_name, + abi, + args, + )?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; let active_thread = this.active_thread(); let new_data = this.read_scalar(new_ptr)?; @@ -1036,161 +1044,229 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Synchronization primitives "pthread_mutexattr_init" => { - let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [attr] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_mutexattr_init(attr)?; this.write_null(dest)?; } "pthread_mutexattr_settype" => { - let [attr, kind] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [attr, kind] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, i32) -> i32), + link_name, + abi, + args, + )?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(result, dest)?; } "pthread_mutexattr_destroy" => { - let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [attr] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_mutexattr_destroy(attr)?; this.write_null(dest)?; } "pthread_mutex_init" => { - let [mutex, attr] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [mutex, attr] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_) -> i32), + link_name, + abi, + args, + )?; this.pthread_mutex_init(mutex, attr)?; this.write_null(dest)?; } "pthread_mutex_lock" => { - let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [mutex] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_mutex_lock(mutex, dest)?; } "pthread_mutex_trylock" => { - let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [mutex] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(result, dest)?; } "pthread_mutex_unlock" => { - let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [mutex] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(result, dest)?; } "pthread_mutex_destroy" => { - let [mutex] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [mutex] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_mutex_destroy(mutex)?; this.write_int(0, dest)?; } "pthread_rwlock_rdlock" => { - let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [rwlock] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_rwlock_rdlock(rwlock, dest)?; } "pthread_rwlock_tryrdlock" => { - let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [rwlock] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(result, dest)?; } "pthread_rwlock_wrlock" => { - let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [rwlock] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_rwlock_wrlock(rwlock, dest)?; } "pthread_rwlock_trywrlock" => { - let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [rwlock] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(result, dest)?; } "pthread_rwlock_unlock" => { - let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [rwlock] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_rwlock_unlock(rwlock)?; this.write_null(dest)?; } "pthread_rwlock_destroy" => { - let [rwlock] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [rwlock] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_rwlock_destroy(rwlock)?; this.write_null(dest)?; } "pthread_condattr_init" => { - let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [attr] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_condattr_init(attr)?; this.write_null(dest)?; } "pthread_condattr_setclock" => { - let [attr, clock_id] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [attr, clock_id] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, i32) -> i32), + link_name, + abi, + args, + )?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(result, dest)?; } "pthread_condattr_getclock" => { - let [attr, clock_id] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [attr, clock_id] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_) -> i32), + link_name, + abi, + args, + )?; this.pthread_condattr_getclock(attr, clock_id)?; this.write_null(dest)?; } "pthread_condattr_destroy" => { - let [attr] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [attr] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_condattr_destroy(attr)?; this.write_null(dest)?; } "pthread_cond_init" => { - let [cond, attr] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [cond, attr] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_) -> i32), + link_name, + abi, + args, + )?; this.pthread_cond_init(cond, attr)?; this.write_null(dest)?; } "pthread_cond_signal" => { - let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [cond] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_cond_signal(cond)?; this.write_null(dest)?; } "pthread_cond_broadcast" => { - let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [cond] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_cond_broadcast(cond)?; this.write_null(dest)?; } "pthread_cond_wait" => { - let [cond, mutex] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [cond, mutex] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_) -> i32), + link_name, + abi, + args, + )?; this.pthread_cond_wait(cond, mutex, dest)?; } "pthread_cond_timedwait" => { - let [cond, mutex, abstime] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [cond, mutex, abstime] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_, *_) -> i32), + link_name, + abi, + args, + )?; this.pthread_cond_timedwait( cond, mutex, abstime, dest, /* macos_relative_np */ false, )?; } "pthread_cond_destroy" => { - let [cond] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [cond] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; this.pthread_cond_destroy(cond)?; this.write_null(dest)?; } // Threading "pthread_create" => { - let [thread, attr, start, arg] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [thread, attr, start, arg] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_, fn(..) -> _, *_) -> i32), + link_name, + abi, + args, + )?; this.pthread_create(thread, attr, start, arg)?; this.write_null(dest)?; } "pthread_join" => { - let [thread, retval] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [thread, retval] = this.check_shim_sig( + shim_sig!(extern "C" fn(libc::pthread_t, *_) -> i32), + link_name, + abi, + args, + )?; this.pthread_join(thread, retval, dest)?; } "pthread_detach" => { - let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [thread] = this.check_shim_sig( + shim_sig!(extern "C" fn(libc::pthread_t) -> i32), + link_name, + abi, + args, + )?; let res = this.pthread_detach(thread)?; this.write_scalar(res, dest)?; } "pthread_self" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "C" fn() -> libc::pthread_t), + link_name, + abi, + args, + )?; let res = this.pthread_self()?; this.write_scalar(res, dest)?; } "sched_yield" => { // FIXME: This does not have a direct test (#3179). - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = + this.check_shim_sig(shim_sig!(extern "C" fn() -> i32), link_name, abi, args)?; this.sched_yield()?; this.write_null(dest)?; } "nanosleep" => { - let [duration, rem] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [duration, rem] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, *_) -> i32), + link_name, + abi, + args, + )?; let result = this.nanosleep(duration, rem)?; this.write_scalar(result, dest)?; } @@ -1201,8 +1277,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { link_name, )?; - let [clock_id, flags, req, rem] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [clock_id, flags, req, rem] = this.check_shim_sig( + shim_sig!(extern "C" fn(libc::clockid_t, i32, *_, *_) -> i32), + link_name, + abi, + args, + )?; let result = this.clock_nanosleep(clock_id, flags, req, rem)?; this.write_scalar(result, dest)?; } @@ -1210,8 +1290,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?; - let [pid, cpusetsize, mask] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [pid, cpusetsize, mask] = this.check_shim_sig( + shim_sig!(extern "C" fn(libc::pid_t, usize, *_) -> i32), + link_name, + abi, + args, + )?; let pid = this.read_scalar(pid)?.to_u32()?; let cpusetsize = this.read_target_usize(cpusetsize)?; let mask = this.read_pointer(mask)?; @@ -1263,8 +1347,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Currently this function does not exist on all Unixes, e.g. on macOS. this.check_target_os(&[Os::Linux, Os::FreeBsd, Os::Android], link_name)?; - let [pid, cpusetsize, mask] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [pid, cpusetsize, mask] = this.check_shim_sig( + shim_sig!(extern "C" fn(libc::pid_t, usize, *_) -> i32), + link_name, + abi, + args, + )?; let pid = this.read_scalar(pid)?.to_u32()?; let cpusetsize = this.read_target_usize(cpusetsize)?; let mask = this.read_pointer(mask)?; @@ -1320,20 +1408,39 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "isatty" => { - let [fd] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [fd] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32) -> i32), + link_name, + abi, + args, + )?; let result = this.isatty(fd)?; this.write_scalar(result, dest)?; } "pthread_atfork" => { // FIXME: This does not have a direct test (#3179). - let [prepare, parent, child] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [prepare, parent, child] = this.check_shim_sig( + shim_sig!(extern "C" fn(fn(..) -> _, fn(..) -> _, fn(..) -> _) -> i32), + link_name, + abi, + args, + )?; this.read_pointer(prepare)?; this.read_pointer(parent)?; this.read_pointer(child)?; // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } + "strerror_r" => { + let [errnum, buf, buflen] = this.check_shim_sig( + shim_sig!(extern "C" fn(i32, *_, usize) -> i32), + link_name, + abi, + args, + )?; + let result = this.strerror_r(errnum, buf, buflen)?; + this.write_scalar(result, dest)?; + } "getentropy" => { // This function is non-standard but exists with the same signature and behavior on // Linux, macOS, FreeBSD and Solaris/Illumos. @@ -1342,8 +1449,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { link_name, )?; - let [buf, bufsize] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [buf, bufsize] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, usize) -> i32), + link_name, + abi, + args, + )?; let buf = this.read_pointer(buf)?; let bufsize = this.read_target_usize(bufsize)?; @@ -1359,14 +1470,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } } - - "strerror_r" => { - let [errnum, buf, buflen] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let result = this.strerror_r(errnum, buf, buflen)?; - this.write_scalar(result, dest)?; - } - "getrandom" => { // This function is non-standard but exists with the same signature and behavior on // Linux, FreeBSD and Solaris/Illumos. @@ -1375,8 +1478,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { link_name, )?; - let [ptr, len, flags] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [ptr, len, flags] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, usize, u32) -> isize), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; let _flags = this.read_scalar(flags)?.to_i32()?; @@ -1389,7 +1496,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // same behavior (eg never fails) on FreeBSD and Solaris/Illumos. this.check_target_os(&[Os::FreeBsd, Os::Illumos, Os::Solaris], link_name)?; - let [ptr, len] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [ptr, len] = this.check_shim_sig( + shim_sig!(extern "C" fn(*_, usize) -> ()), + link_name, + abi, + args, + )?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; this.gen_random(ptr, len)?; @@ -1414,12 +1526,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { )?; // This function looks and behaves exactly like miri_start_unwind. - let [payload] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [payload] = this.check_shim_sig( + // Look up the return type via `panic_unwind::`, not via `unwind::`, as + // the latter it not always unique. + shim_sig!(extern "C" fn(*_) -> panic_unwind::imp::uw::_Unwind_Reason_Code), + link_name, + abi, + args, + )?; this.handle_miri_start_unwind(payload)?; return interp_ok(EmulateItemResult::NeedsUnwind); } "getuid" | "geteuid" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig( + shim_sig!(extern "C" fn() -> libc::uid_t), + link_name, + abi, + args, + )?; // For now, just pretend we always have this fixed UID. this.write_int(UID, dest)?; } @@ -1428,7 +1552,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { let [_attr, guard_size] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let guard_size_layout = this.machine.layouts.usize; let guard_size = this.deref_pointer_as(guard_size, guard_size_layout)?; this.write_scalar( @@ -1441,11 +1565,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => { - let [_] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [_] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } "pthread_attr_setstacksize" if this.frame_in_std() => { - let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [_, _] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } @@ -1453,7 +1577,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. // Hence we can mostly ignore the input `attr_place`. let [attr_place, addr_place, size_place] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let _attr_place = this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?; let addr_place = this.deref_pointer_as(addr_place, this.machine.layouts.usize)?; @@ -1473,18 +1597,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "signal" | "sigaltstack" if this.frame_in_std() => { - let [_, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [_, _] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } "sigaction" if this.frame_in_std() => { - let [_, _, _] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [_, _, _] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => { // getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish let [uid, pwd, buf, buflen, result] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.check_no_isolation("`getpwuid_r`")?; let uid = this.read_scalar(uid)?.to_u32()?; @@ -1542,6 +1667,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { solarish::EvalContextExt::emulate_foreign_item_inner( this, link_name, abi, args, dest, ), + Os::NetBsd => + netbsd::EvalContextExt::emulate_foreign_item_inner( + this, link_name, abi, args, dest, + ), _ => interp_ok(EmulateItemResult::NotSupported), }; } diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 1cc87050e59d8..5a8df974a5bbb 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -25,7 +25,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "pthread_setname_np" => { let [thread, name] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let max_len = u64::MAX; // FreeBSD does not seem to have a limit. let res = match this.pthread_setname_np( this.read_scalar(thread)?, @@ -41,7 +41,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_getname_np" => { let [thread, name, len] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; // FreeBSD's pthread_getname_np uses strlcpy, which truncates the resulting value, // but always adds a null terminator (except for zero-sized buffers). // https://github.com/freebsd/freebsd-src/blob/c2d93a803acef634bd0eede6673aeea59e90c277/lib/libthr/thread/thr_info.c#L119-L144 @@ -59,7 +59,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "pthread_getthreadid_np" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.unix_gettid(link_name.as_str())?; this.write_scalar(result, dest)?; } @@ -67,7 +67,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "cpuset_getaffinity" => { // The "same" kind of api as `sched_getaffinity` but more fine grained control for FreeBSD specifically. let [level, which, id, set_size, mask] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let level = this.read_scalar(level)?.to_i32()?; let which = this.read_scalar(which)?.to_i32()?; @@ -139,33 +139,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Synchronization primitives "_umtx_op" => { let [obj, op, val, uaddr, uaddr2] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this._umtx_op(obj, op, val, uaddr, uaddr2, dest)?; } // File related shims "stat@FBSD_1.0" => { - let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [path, buf] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat@FBSD_1.0" => { - let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [path, buf] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat@FBSD_1.0" => { - let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [fd, buf] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.fstat(fd, buf)?; this.write_scalar(result, dest)?; } "readdir@FBSD_1.0" => { - let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [dirp] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.readdir(dirp, dest)?; } // Miscellaneous "__error" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } @@ -174,7 +177,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://github.com/freebsd/freebsd-src/blob/3542d60fb8042474f66fbf2d779ed8c5a80d0f78/sys/sys/utsname.h#L64 // https://github.com/freebsd/freebsd-src/blob/3542d60fb8042474f66fbf2d779ed8c5a80d0f78/lib/libc/gen/uname.c#L44 let [size, uname] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _) -> i32), + shim_sig!(extern "C" fn(i32, *_) -> i32), link_name, abi, args, @@ -187,7 +190,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // These shims are enabled only when the caller is in the standard library. "pthread_attr_get_np" if this.frame_in_std() => { let [_thread, _attr] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index b905bdcd68974..61d32c599680f 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -48,7 +48,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "pread64" => { // FIXME: This does not have a direct test (#3179). let [fd, buf, count, offset] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *mut _, usize, libc::off64_t) -> isize), + shim_sig!(extern "C" fn(i32, *_, usize, libc::off64_t) -> isize), link_name, abi, args, @@ -62,7 +62,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "pwrite64" => { // FIXME: This does not have a direct test (#3179). let [fd, buf, n, offset] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, usize, libc::off64_t) -> isize), + shim_sig!(extern "C" fn(i32, *_, usize, libc::off64_t) -> isize), link_name, abi, args, @@ -152,40 +152,41 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "readdir64" => { - let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [dirp] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.readdir(dirp, dest)?; } "sync_file_range" => { let [fd, offset, nbytes, flags] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(result, dest)?; } "statx" => { let [dirfd, pathname, flags, mask, statxbuf] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; this.write_scalar(result, dest)?; } // epoll, eventfd "epoll_create1" => { - let [flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [flag] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_create1(flag)?; this.write_scalar(result, dest)?; } "epoll_ctl" => { let [epfd, op, fd, event] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_ctl(epfd, op, fd, event)?; this.write_scalar(result, dest)?; } "epoll_wait" => { let [epfd, events, maxevents, timeout] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.epoll_wait(epfd, events, maxevents, timeout, dest)?; } "eventfd" => { - let [val, flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [val, flag] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.eventfd(val, flag)?; this.write_scalar(result, dest)?; } @@ -193,7 +194,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "pthread_setname_np" => { let [thread, name] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, @@ -209,7 +210,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_getname_np" => { let [thread, name, len] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; // The function's behavior isn't portable between platforms. // In case of glibc, the length of the output buffer must // be not shorter than TASK_COMM_LEN. @@ -232,7 +233,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(res, dest)?; } "gettid" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.unix_gettid(link_name.as_str())?; this.write_scalar(result, dest)?; } @@ -246,7 +247,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "mmap64" => { let [addr, length, prot, flags, fd, offset] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let offset = this.read_scalar(offset)?.to_i64()?; let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?; this.write_scalar(ptr, dest)?; @@ -259,22 +260,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "__xpg_strerror_r" => { let [errnum, buf, buflen] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.strerror_r(errnum, buf, buflen)?; this.write_scalar(result, dest)?; } "__errno_location" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } "__libc_current_sigrtmin" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.write_int(SIGRTMIN, dest)?; } "__libc_current_sigrtmax" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.write_int(SIGRTMAX, dest)?; } @@ -283,14 +284,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame_in_std() => { let [_thread, _attr] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.write_null(dest)?; } "gnu_get_libc_version" if this.frame_in_std() && this.tcx.sess.target.env == rustc_target::spec::Env::Gnu => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; // We have to be at least version 2.26 so that std does not call `res_init`. // This returns a C string, so we have to add a null terminator. let version = "2.26\0"; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 9254031a8a4d1..3d6694137b9e4 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -35,45 +35,48 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match link_name.as_str() { // errno "__error" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } // File related shims "close$NOCANCEL" => { - let [fd] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [fd] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let result = this.close(fd)?; this.write_scalar(result, dest)?; } "stat$INODE64" => { - let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [path, buf] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat$INODE64" => { - let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [path, buf] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.lstat(path, buf)?; this.write_scalar(result, dest)?; } "fstat$INODE64" => { - let [fd, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [fd, buf] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.fstat(fd, buf)?; this.write_scalar(result, dest)?; } "opendir$INODE64" => { - let [name] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [name] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir$INODE64" => { - let [dirp] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [dirp] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.readdir(dirp, dest)?; } "realpath$DARWIN_EXTSN" => { let [path, resolved_path] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.realpath(path, resolved_path)?; this.write_scalar(result, dest)?; } @@ -81,7 +84,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Environment related shims "_NSGetEnviron" => { // FIXME: This does not have a direct test (#3179). - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let environ = this.machine.env_vars.unix().environ(); this.write_pointer(environ, dest)?; } @@ -89,7 +92,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Random data generation "CCRandomGenerateBytes" => { let [bytes, count] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let bytes = this.read_pointer(bytes)?; let count = this.read_target_usize(count)?; let success = this.eval_libc_i32("kCCSuccess"); @@ -99,21 +102,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Time related shims "mach_absolute_time" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.mach_absolute_time()?; this.write_scalar(result, dest)?; } "mach_timebase_info" => { // FIXME: This does not have a direct test (#3179). - let [info] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [info] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(result, dest)?; } "mach_wait_until" => { // FIXME: This does not have a direct test (#3179). - let [deadline] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [deadline] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.mach_wait_until(deadline)?; this.write_scalar(result, dest)?; } @@ -121,18 +125,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Access to command-line arguments "_NSGetArgc" => { // FIXME: This does not have a direct test (#3179). - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.write_pointer(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { // FIXME: This does not have a direct test (#3179). - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.write_pointer(this.machine.argv.expect("machine must be initialized"), dest)?; } "_NSGetExecutablePath" => { // FIXME: This does not have a direct test (#3179). let [buf, bufsize] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.check_no_isolation("`_NSGetExecutablePath`")?; let buf_ptr = this.read_pointer(buf)?; @@ -158,7 +162,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Thread-local storage "_tlv_atexit" => { let [dtor, data] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let dtor = this.read_pointer(dtor)?; let dtor = this.get_ptr_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?; @@ -174,14 +178,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Querying system information "pthread_get_stackaddr_np" => { // FIXME: This does not have a direct test (#3179). - let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [thread] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.read_target_usize(thread)?; let stack_addr = Scalar::from_uint(this.machine.stack_addr, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { // FIXME: This does not have a direct test (#3179). - let [thread] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [thread] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.read_target_usize(thread)?; let stack_size = Scalar::from_uint(this.machine.stack_size, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -189,7 +193,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "pthread_setname_np" => { - let [name] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [name] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; // The real implementation has logic in two places: // * in userland at https://github.com/apple-oss-distributions/libpthread/blob/c032e0b076700a0a47db75528a282b8d3a06531a/src/pthread.c#L1178-L1200, @@ -217,7 +221,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_getname_np" => { let [thread, name, len] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; // The function's behavior isn't portable between platforms. // In case of macOS, a truncated name (due to a too small buffer) @@ -242,7 +246,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_threadid_np" => { let [thread, tid_ptr] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let res = this.apple_pthread_threadid_np(thread, tid_ptr)?; this.write_scalar(res, dest)?; } @@ -250,7 +254,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Synchronization primitives "os_sync_wait_on_address" => { let [addr_op, value_op, size_op, flags_op] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.os_sync_wait_on_address( addr_op, value_op, @@ -262,7 +266,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "os_sync_wait_on_address_with_deadline" => { let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.os_sync_wait_on_address( addr_op, value_op, @@ -274,7 +278,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "os_sync_wait_on_address_with_timeout" => { let [addr_op, value_op, size_op, flags_op, clock_op, timeout_op] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.os_sync_wait_on_address( addr_op, value_op, @@ -286,42 +290,47 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "os_sync_wake_by_address_any" => { let [addr_op, size_op, flags_op] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.os_sync_wake_by_address( addr_op, size_op, flags_op, /* all */ false, dest, )?; } "os_sync_wake_by_address_all" => { let [addr_op, size_op, flags_op] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.os_sync_wake_by_address( addr_op, size_op, flags_op, /* all */ true, dest, )?; } "os_unfair_lock_lock" => { - let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [lock_op] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.os_unfair_lock_lock(lock_op)?; } "os_unfair_lock_trylock" => { - let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [lock_op] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.os_unfair_lock_trylock(lock_op, dest)?; } "os_unfair_lock_unlock" => { - let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [lock_op] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.os_unfair_lock_unlock(lock_op)?; } "os_unfair_lock_assert_owner" => { - let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [lock_op] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.os_unfair_lock_assert_owner(lock_op)?; } "os_unfair_lock_assert_not_owner" => { - let [lock_op] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [lock_op] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.os_unfair_lock_assert_not_owner(lock_op)?; } "pthread_cond_timedwait_relative_np" => { let [cond, mutex, reltime] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.pthread_cond_timedwait( cond, mutex, reltime, dest, /* macos_relative_np */ true, )?; @@ -331,7 +340,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // These shims are enabled only when the caller is in the standard library. "confstr" => { let [_key, _buf, _buflen] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; // We just pretend that no configuration key exists, and return EINVAL. this.set_last_error(LibcError("EINVAL"))?; this.write_null(dest)?; diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs index 259bc79b7f9f4..c9423bae958f9 100644 --- a/src/tools/miri/src/shims/unix/mod.rs +++ b/src/tools/miri/src/shims/unix/mod.rs @@ -14,9 +14,10 @@ mod virtual_socket; mod android; mod freebsd; -pub mod linux; +mod linux; mod linux_like; mod macos; +mod netbsd; mod solarish; // All the Unix-specific extension traits diff --git a/src/tools/miri/src/shims/unix/netbsd/foreign_items.rs b/src/tools/miri/src/shims/unix/netbsd/foreign_items.rs new file mode 100644 index 0000000000000..c265cef273a57 --- /dev/null +++ b/src/tools/miri/src/shims/unix/netbsd/foreign_items.rs @@ -0,0 +1,43 @@ +use rustc_middle::ty::Ty; +use rustc_span::Symbol; +use rustc_target::callconv::FnAbi; + +use crate::shims::unix::*; +use crate::*; + +pub fn is_dyn_sym(_name: &str) -> bool { + false +} + +impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} +pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { + fn emulate_foreign_item_inner( + &mut self, + link_name: Symbol, + abi: &FnAbi<'tcx, Ty<'tcx>>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, + ) -> InterpResult<'tcx, EmulateItemResult> { + let this = self.eval_context_mut(); + match link_name.as_str() { + // Environment + "__unsetenv13" => { + let [name] = + this.check_shim_sig(shim_sig!(extern "C" fn(*_) -> i32), link_name, abi, args)?; + let result = this.unsetenv(name)?; + this.write_scalar(result, dest)?; + } + + // Miscellaneous + "__errno" => { + let [] = + this.check_shim_sig(shim_sig!(extern "C" fn() -> *_), link_name, abi, args)?; + let errno_place = this.last_error_place()?; + this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; + } + + _ => return interp_ok(EmulateItemResult::NotSupported), + } + interp_ok(EmulateItemResult::NeedsReturn) + } +} diff --git a/src/tools/miri/src/shims/unix/netbsd/mod.rs b/src/tools/miri/src/shims/unix/netbsd/mod.rs new file mode 100644 index 0000000000000..09c6507b24f84 --- /dev/null +++ b/src/tools/miri/src/shims/unix/netbsd/mod.rs @@ -0,0 +1 @@ +pub mod foreign_items; diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index 37b665ceebd1f..2b885aedecc11 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -28,26 +28,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // epoll, eventfd (NOT available on Solaris!) "epoll_create1" => { this.assert_target_os(Os::Illumos, "epoll_create1"); - let [flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [flag] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_create1(flag)?; this.write_scalar(result, dest)?; } "epoll_ctl" => { this.assert_target_os(Os::Illumos, "epoll_ctl"); let [epfd, op, fd, event] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.epoll_ctl(epfd, op, fd, event)?; this.write_scalar(result, dest)?; } "epoll_wait" => { this.assert_target_os(Os::Illumos, "epoll_wait"); let [epfd, events, maxevents, timeout] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; this.epoll_wait(epfd, events, maxevents, timeout, dest)?; } "eventfd" => { this.assert_target_os(Os::Illumos, "eventfd"); - let [val, flag] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [val, flag] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.eventfd(val, flag)?; this.write_scalar(result, dest)?; } @@ -55,7 +56,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Threading "pthread_setname_np" => { let [thread, name] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; // THREAD_NAME_MAX allows a thread name of 31+1 length // https://github.com/illumos/illumos-gate/blob/7671517e13b8123748eda4ef1ee165c6d9dba7fe/usr/src/uts/common/sys/thread.h#L613 let max_len = 32; @@ -74,7 +75,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "pthread_getname_np" => { let [thread, name, len] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; // See https://illumos.org/man/3C/pthread_getname_np for the error codes. let res = match this.pthread_getname_np( this.read_scalar(thread)?, @@ -92,13 +93,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File related shims "stat" => { // FIXME: This does not have a direct test (#3179). - let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [path, buf] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.stat(path, buf)?; this.write_scalar(result, dest)?; } "lstat" => { // FIXME: This does not have a direct test (#3179). - let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [path, buf] = + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.lstat(path, buf)?; this.write_scalar(result, dest)?; } @@ -106,7 +109,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Sockets and pipes "__xnet_socketpair" => { let [domain, type_, protocol, sv] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.socketpair(domain, type_, protocol, sv)?; this.write_scalar(result, dest)?; } @@ -124,7 +127,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "__xnet_bind" => { let [socket, address, address_len] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32), + shim_sig!(extern "C" fn(i32, *_, libc::socklen_t) -> i32), link_name, abi, args, @@ -134,7 +137,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "__xnet_connect" => { let [socket, address, address_len] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, *const _, libc::socklen_t) -> i32), + shim_sig!(extern "C" fn(i32, *_, libc::socklen_t) -> i32), link_name, abi, args, @@ -143,7 +146,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "__xnet_getaddrinfo" => { let [node, service, hints, res] = this.check_shim_sig( - shim_sig!(extern "C" fn(*const _, *const _, *const _, *mut _) -> i32), + shim_sig!(extern "C" fn(*_, *_, *_, *_) -> i32), link_name, abi, args, @@ -153,7 +156,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "__xnet_getsockopt" => { let [socket, level, option_name, option_value, option_len] = this.check_shim_sig( - shim_sig!(extern "C" fn(i32, i32, i32, *mut _, *mut _) -> i32), + shim_sig!(extern "C" fn(i32, i32, i32, *_, *_) -> i32), link_name, abi, args, @@ -165,14 +168,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "___errno" => { - let [] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } "stack_getbounds" => { // FIXME: This does not have a direct test (#3179). - let [stack] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [stack] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?; this.write_int_fields_named( @@ -192,7 +195,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "pset_info" => { // FIXME: This does not have a direct test (#3179). let [pset, tpe, cpus, list] = - this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; // We do not need to handle the current process cpu mask, available_parallelism // implementation pass null anyway. We only care for the number of // cpus. @@ -221,7 +224,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "__sysconf_xpg7" => { - let [val] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + let [val] = this.check_shim_sig_deprecated(abi, CanonAbi::C, link_name, args)?; let result = this.sysconf(val)?; this.write_scalar(result, dest)?; } diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index efef55f5cf91b..0b85243ffb75b 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -150,7 +150,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetEnvironmentVariableW" => { // FIXME: This does not have a direct test (#3179). let [name, buf, size] = this.check_shim_sig( - shim_sig!(extern "system" fn(*const _, *mut _, u32) -> u32), + shim_sig!(extern "system" fn(*_, *_, u32) -> u32), link_name, abi, args, @@ -161,7 +161,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "SetEnvironmentVariableW" => { // FIXME: This does not have a direct test (#3179). let [name, value] = this.check_shim_sig( - shim_sig!(extern "system" fn(*const _, *const _) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_, *_) -> winapi::BOOL), link_name, abi, args, @@ -172,7 +172,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetEnvironmentStringsW" => { // FIXME: This does not have a direct test (#3179). let [] = this.check_shim_sig( - shim_sig!(extern "system" fn() -> *mut _), + shim_sig!(extern "system" fn() -> *_), link_name, abi, args, @@ -183,7 +183,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "FreeEnvironmentStringsW" => { // FIXME: This does not have a direct test (#3179). let [env_block] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_) -> winapi::BOOL), link_name, abi, args, @@ -194,7 +194,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetCurrentDirectoryW" => { // FIXME: This does not have a direct test (#3179). let [size, buf] = this.check_shim_sig( - shim_sig!(extern "system" fn(u32, *mut _) -> u32), + shim_sig!(extern "system" fn(u32, *_) -> u32), link_name, abi, args, @@ -205,7 +205,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "SetCurrentDirectoryW" => { // FIXME: This does not have a direct test (#3179). let [path] = this.check_shim_sig( - shim_sig!(extern "system" fn(*const _) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_) -> winapi::BOOL), link_name, abi, args, @@ -216,7 +216,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetUserProfileDirectoryW" => { // FIXME: This does not have a direct test (#3179). let [token, buf, size] = this.check_shim_sig( - shim_sig!(extern "system" fn(winapi::HANDLE, *mut _, *mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(winapi::HANDLE, *_, *_) -> winapi::BOOL), link_name, abi, args, @@ -238,7 +238,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetTempPathW" => { // FIXME: This does not have a direct test (#3179). let [bufferlength, buffer] = this.check_shim_sig( - shim_sig!(extern "system" fn(u32, *mut _) -> u32), + shim_sig!(extern "system" fn(u32, *_) -> u32), link_name, abi, args, @@ -264,13 +264,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { extern "system" fn( winapi::HANDLE, winapi::HANDLE, - *mut _, - *mut _, - *mut _, - *mut _, + *_, + *_, + *_, + *_, u32, - *mut _, - *mut _, + *_, + *_, ) -> i32 ), link_name, @@ -306,13 +306,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { extern "system" fn( winapi::HANDLE, winapi::HANDLE, - *mut _, - *mut _, - *mut _, - *mut _, + *_, + *_, + *_, + *_, u32, - *mut _, - *mut _, + *_, + *_, ) -> i32 ), link_name, @@ -335,7 +335,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetFullPathNameW" => { // FIXME: This does not have a direct test (#3179). let [filename, size, buffer, filepart] = this.check_shim_sig( - shim_sig!(extern "system" fn(*const _, u32, *mut _, *mut _) -> u32), + shim_sig!(extern "system" fn(*_, u32, *_, *_) -> u32), link_name, abi, args, @@ -379,10 +379,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ] = this.check_shim_sig( shim_sig!( extern "system" fn( - *const _, + *_, u32, u32, - *mut _, + *_, u32, u32, winapi::HANDLE, @@ -405,7 +405,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetFileInformationByHandle" => { let [handle, info] = this.check_shim_sig( - shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(winapi::HANDLE, *_) -> winapi::BOOL), link_name, abi, args, @@ -419,7 +419,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { extern "system" fn( winapi::HANDLE, winapi::FILE_INFO_BY_HANDLE_CLASS, - *mut _, + *_, u32, ) -> winapi::BOOL ), @@ -442,7 +442,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "DeleteFileW" => { let [file_name] = this.check_shim_sig( - shim_sig!(extern "system" fn(*const _) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_) -> winapi::BOOL), link_name, abi, args, @@ -453,7 +453,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "SetFilePointerEx" => { let [file, distance_to_move, new_file_pointer, move_method] = this.check_shim_sig( // i64 is actually a LARGE_INTEGER union of {u32, i32} and {i64} - shim_sig!(extern "system" fn(winapi::HANDLE, i64, *mut _, u32) -> winapi::BOOL), + shim_sig!(extern "system" fn(winapi::HANDLE, i64, *_, u32) -> winapi::BOOL), link_name, abi, args, @@ -464,7 +464,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "MoveFileExW" => { let [existing_name, new_name, flags] = this.check_shim_sig( - shim_sig!(extern "system" fn(*const _, *const _, u32) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_, *_, u32) -> winapi::BOOL), link_name, abi, args, @@ -477,7 +477,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "HeapAlloc" => { // FIXME: This does not have a direct test (#3179). let [handle, flags, size] = this.check_shim_sig( - shim_sig!(extern "system" fn(winapi::HANDLE, u32, usize) -> *mut _), + shim_sig!(extern "system" fn(winapi::HANDLE, u32, usize) -> *_), link_name, abi, args, @@ -505,7 +505,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "HeapFree" => { // FIXME: This does not have a direct test (#3179). let [handle, flags, ptr] = this.check_shim_sig( - shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(winapi::HANDLE, u32, *_) -> winapi::BOOL), link_name, abi, args, @@ -523,7 +523,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "HeapReAlloc" => { // FIXME: This does not have a direct test (#3179). let [handle, flags, old_ptr, size] = this.check_shim_sig( - shim_sig!(extern "system" fn(winapi::HANDLE, u32, *mut _, usize) -> *mut _), + shim_sig!(extern "system" fn(winapi::HANDLE, u32, *_, usize) -> *_), link_name, abi, args, @@ -614,7 +614,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // FIXME: This does not have a direct test (#3179). // Also called from `page_size` crate. let [system_info] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _) -> ()), + shim_sig!(extern "system" fn(*_) -> ()), link_name, abi, args, @@ -654,7 +654,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "TlsGetValue" => { // FIXME: This does not have a direct test (#3179). let [key] = this.check_shim_sig( - shim_sig!(extern "system" fn(u32) -> *mut _), + shim_sig!(extern "system" fn(u32) -> *_), link_name, abi, args, @@ -667,7 +667,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "TlsSetValue" => { // FIXME: This does not have a direct test (#3179). let [key, new_ptr] = this.check_shim_sig( - shim_sig!(extern "system" fn(u32, *mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(u32, *_) -> winapi::BOOL), link_name, abi, args, @@ -723,7 +723,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "FlsGetValue" => { // FIXME: This does not have a direct test (#3179). let [key] = this.check_shim_sig( - shim_sig!(extern "system" fn(u32) -> *mut _), + shim_sig!(extern "system" fn(u32) -> *_), link_name, abi, args, @@ -736,7 +736,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "FlsSetValue" => { // FIXME: This does not have a direct test (#3179). let [key, new_ptr] = this.check_shim_sig( - shim_sig!(extern "system" fn(u32, *mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(u32, *_) -> winapi::BOOL), link_name, abi, args, @@ -787,7 +787,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetCommandLineW" => { // FIXME: This does not have a direct test (#3179). let [] = this.check_shim_sig( - shim_sig!(extern "system" fn() -> *mut _), + shim_sig!(extern "system" fn() -> *_), link_name, abi, args, @@ -802,7 +802,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetSystemTimeAsFileTime" | "GetSystemTimePreciseAsFileTime" => { // FIXME: This does not have a direct test (#3179). let [filetime] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _) -> ()), + shim_sig!(extern "system" fn(*_) -> ()), link_name, abi, args, @@ -812,7 +812,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "QueryPerformanceCounter" => { // FIXME: This does not have a direct test (#3179). let [performance_count] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_) -> winapi::BOOL), link_name, abi, args, @@ -823,7 +823,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "QueryPerformanceFrequency" => { // FIXME: This does not have a direct test (#3179). let [frequency] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_) -> winapi::BOOL), link_name, abi, args, @@ -845,7 +845,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "CreateWaitableTimerExW" => { // FIXME: This does not have a direct test (#3179). let [attributes, name, flags, access] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _, *const _, u32, u32) -> winapi::HANDLE), + shim_sig!(extern "system" fn(*_, *_, u32, u32) -> winapi::HANDLE), link_name, abi, args, @@ -863,7 +863,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Synchronization primitives "InitOnceBeginInitialize" => { let [ptr, flags, pending, context] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _, u32, *mut _, *mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_, u32, *_, *_) -> winapi::BOOL), link_name, abi, args, @@ -872,7 +872,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "InitOnceComplete" => { let [ptr, flags, context] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _, u32, *mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_, u32, *_) -> winapi::BOOL), link_name, abi, args, @@ -884,7 +884,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // FIXME: This does not have a direct test (#3179). let [ptr_op, compare_op, size_op, timeout_op] = this.check_shim_sig( // First pointer is volatile - shim_sig!(extern "system" fn(*mut _, *mut _, usize, u32) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_, *_, usize, u32) -> winapi::BOOL), link_name, abi, args, @@ -895,7 +895,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "WakeByAddressSingle" => { // FIXME: This does not have a direct test (#3179). let [ptr_op] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _) -> ()), + shim_sig!(extern "system" fn(*_) -> ()), link_name, abi, args, @@ -906,7 +906,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "WakeByAddressAll" => { // FIXME: This does not have a direct test (#3179). let [ptr_op] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _) -> ()), + shim_sig!(extern "system" fn(*_) -> ()), link_name, abi, args, @@ -919,7 +919,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetProcAddress" => { // FIXME: This does not have a direct test (#3179). let [module, proc_name] = this.check_shim_sig( - shim_sig!(extern "system" fn(winapi::HMODULE, *const _) -> winapi::FARPROC), + shim_sig!(extern "system" fn(winapi::HMODULE, *_) -> winapi::FARPROC), link_name, abi, args, @@ -941,12 +941,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [security, stacksize, start, arg, flags, thread] = this.check_shim_sig( shim_sig!( extern "system" fn( - *mut _, + *_, usize, - *mut _, - *mut _, + *_, + *_, u32, - *mut _, + *_, ) -> winapi::HANDLE ), link_name, @@ -997,7 +997,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "SetThreadDescription" => { let [handle, name] = this.check_shim_sig( - shim_sig!(extern "system" fn(winapi::HANDLE, *const _) -> i32), + shim_sig!(extern "system" fn(winapi::HANDLE, *_) -> i32), link_name, abi, args, @@ -1017,7 +1017,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetThreadDescription" => { let [handle, name_ptr] = this.check_shim_sig( - shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> i32), + shim_sig!(extern "system" fn(winapi::HANDLE, *_) -> i32), link_name, abi, args, @@ -1086,7 +1086,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This is really 'RtlGenRandom'. let [ptr, len] = this.check_shim_sig( // Returns winapi::BOOLEAN, which is a byte - shim_sig!(extern "system" fn(*mut _, u32) -> u8), + shim_sig!(extern "system" fn(*_, u32) -> u8), link_name, abi, args, @@ -1100,7 +1100,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // FIXME: This does not have a direct test (#3179). // used by `std` let [ptr, len] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _, usize) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_, usize) -> winapi::BOOL), link_name, abi, args, @@ -1113,7 +1113,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "BCryptGenRandom" => { // used by getrandom 0.2 let [algorithm, ptr, len, flags] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _, *mut _, u32, u32) -> i32), + shim_sig!(extern "system" fn(*_, *_, u32, u32) -> i32), link_name, abi, args, @@ -1153,7 +1153,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // FIXME: This does not have a direct test (#3179). // `term` needs this, so we fake it. let [console, buffer_info] = this.check_shim_sig( - shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(winapi::HANDLE, *_) -> winapi::BOOL), link_name, abi, args, @@ -1184,7 +1184,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { winapi::HANDLE, winapi::HANDLE, winapi::HANDLE, - *mut _, + *_, u32, winapi::BOOL, u32, @@ -1220,7 +1220,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "GetModuleFileNameW" => { // FIXME: This does not have a direct test (#3179). let [handle, filename, size] = this.check_shim_sig( - shim_sig!(extern "system" fn(winapi::HMODULE, *mut _, u32) -> u32), + shim_sig!(extern "system" fn(winapi::HMODULE, *_, u32) -> u32), link_name, abi, args, @@ -1261,7 +1261,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [flags, module, message_id, language_id, buffer, size, arguments] = this .check_shim_sig( shim_sig!( - extern "system" fn(u32, *const _, u32, u32, *mut _, u32, *mut _) -> u32 + extern "system" fn(u32, *_, u32, u32, *_, u32, *_) -> u32 ), link_name, abi, @@ -1311,7 +1311,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // This function looks and behaves exactly like miri_start_unwind. let [payload] = this.check_shim_sig( - shim_sig!(extern "C" fn(*mut _) -> unwind::libunwind::_Unwind_Reason_Code), + // Look up the return type via `panic_unwind::`, not via `unwind::`, as + // the latter it not always unique. + shim_sig!(extern "C" fn(*_) -> panic_unwind::imp::uw::_Unwind_Reason_Code), link_name, abi, args, @@ -1335,7 +1337,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetModuleHandleA" if this.frame_in_std() => { let [_module_name] = this.check_shim_sig( - shim_sig!(extern "system" fn(*const _) -> winapi::HMODULE), + shim_sig!(extern "system" fn(*_) -> winapi::HMODULE), link_name, abi, args, @@ -1355,7 +1357,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "GetConsoleMode" if this.frame_in_std() => { let [console, mode] = this.check_shim_sig( - shim_sig!(extern "system" fn(winapi::HANDLE, *mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(winapi::HANDLE, *_) -> winapi::BOOL), link_name, abi, args, @@ -1377,7 +1379,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "AddVectoredExceptionHandler" if this.frame_in_std() => { let [_first, _handler] = this.check_shim_sig( - shim_sig!(extern "system" fn(u32, *mut _) -> *mut _), + shim_sig!(extern "system" fn(u32, *_) -> *_), link_name, abi, args, @@ -1387,7 +1389,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "SetThreadStackGuarantee" if this.frame_in_std() => { let [_stack_size_in_bytes] = this.check_shim_sig( - shim_sig!(extern "system" fn(*mut _) -> winapi::BOOL), + shim_sig!(extern "system" fn(*_) -> winapi::BOOL), link_name, abi, args, diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_usable_size.rs b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size.rs new file mode 100644 index 0000000000000..7d0d24677b822 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size.rs @@ -0,0 +1,10 @@ +//@only-target: linux android freebsd + +fn main() { + unsafe { + // A Rust heap allocation is not managed by the C allocator. + let b = Box::new(42); + let p = Box::into_raw(b).cast::(); + libc::malloc_usable_size(p); //~ERROR: not managed by the C allocator + } +} diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_usable_size.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size.stderr new file mode 100644 index 0000000000000..e15f334908a6b --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size.stderr @@ -0,0 +1,13 @@ +error: Undefined Behavior: `malloc_usable_size` was called on a pointer to Rust heap memory, which is not managed by the C allocator + --> tests/fail-dep/libc/malloc_usable_size.rs:LL:CC + | +LL | libc::malloc_usable_size(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_interior.rs b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_interior.rs new file mode 100644 index 0000000000000..cb9b0858833df --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_interior.rs @@ -0,0 +1,10 @@ +//@only-target: linux android freebsd + +fn main() { + unsafe { + // The pointer must point to the beginning of the block. + let p = libc::malloc(1024); + let mid = p.cast::().add(512).cast::(); + libc::malloc_usable_size(mid); //~ERROR: does not point to the beginning + } +} diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_interior.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_interior.stderr new file mode 100644 index 0000000000000..c3a4c167bfd5f --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_interior.stderr @@ -0,0 +1,13 @@ +error: Undefined Behavior: `malloc_usable_size` was called on a pointer that does not point to the beginning of its allocation + --> tests/fail-dep/libc/malloc_usable_size_interior.rs:LL:CC + | +LL | libc::malloc_usable_size(mid); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_stack.rs b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_stack.rs new file mode 100644 index 0000000000000..57e1c81c1b702 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_stack.rs @@ -0,0 +1,10 @@ +//@only-target: linux android freebsd + +fn main() { + unsafe { + // A stack variable is not managed by the C allocator. + let mut x = 42; + let p = (&raw mut x).cast::(); + libc::malloc_usable_size(p); //~ERROR: not managed by the C allocator + } +} diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_stack.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_stack.stderr new file mode 100644 index 0000000000000..e9e33015782b9 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/malloc_usable_size_stack.stderr @@ -0,0 +1,13 @@ +error: Undefined Behavior: `malloc_usable_size` was called on a pointer to stack variable memory, which is not managed by the C allocator + --> tests/fail-dep/libc/malloc_usable_size_stack.rs:LL:CC + | +LL | libc::malloc_usable_size(p); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/extern_static/wrong_size_shim.rs b/src/tools/miri/tests/fail/extern_static/wrong_size_shim.rs index 56c3ddd351612..4bd2cb530db45 100644 --- a/src/tools/miri/tests/fail/extern_static/wrong_size_shim.rs +++ b/src/tools/miri/tests/fail/extern_static/wrong_size_shim.rs @@ -2,9 +2,13 @@ //@normalize-stderr-test: "[48] bytes" -> "N bytes" extern "C" { - static mut environ: i8; + #[link_name = "environ"] + static mut environ_good: i8; + #[link_name = "environ"] + static mut environ_bad: [i8; 10]; } fn main() { - let _val = unsafe { environ }; //~ ERROR: /with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of [48] bytes and alignment of [48] bytes/ + let _val = unsafe { environ_good }; + let _val = unsafe { environ_bad }; //~ ERROR: /with a size of 10 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of [48] bytes and alignment of [48] bytes/ } diff --git a/src/tools/miri/tests/fail/extern_static/wrong_size_shim.stderr b/src/tools/miri/tests/fail/extern_static/wrong_size_shim.stderr index d3a0f0205ee3b..6eddfe1163bd6 100644 --- a/src/tools/miri/tests/fail/extern_static/wrong_size_shim.stderr +++ b/src/tools/miri/tests/fail/extern_static/wrong_size_shim.stderr @@ -1,10 +1,11 @@ -error: unsupported operation: extern static `environ` has been declared as `wrong_size_shim::environ` with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes +error: Undefined Behavior: extern static `environ` has been declared as `wrong_size_shim::environ_bad` with a size of 10 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes --> tests/fail/extern_static/wrong_size_shim.rs:LL:CC | -LL | let _val = unsafe { environ }; - | ^^^^^^^ unsupported operation occurred here +LL | let _val = unsafe { environ_bad }; + | ^^^^^^^^^^^ Undefined Behavior occurred here | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = 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: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs b/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs index e36b516887962..ab0cb4d84251c 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs +++ b/src/tools/miri/tests/fail/function_calls/check_arg_abi.rs @@ -6,6 +6,6 @@ fn main() { } unsafe { - let _ = malloc(0); //~ ERROR: calling a function with calling convention "C" using caller calling convention "Rust" + let _ = malloc(0); //~ ERROR: has calling convention "C", but the caller is using calling convention "Rust" }; } diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr b/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr index 84a3c75538944..88060595ce90d 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_arg_abi.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with calling convention "C" using caller calling convention "Rust" +error: Undefined Behavior: ABI mismatch: `malloc` has calling convention "C", but the caller is using calling convention "Rust" --> tests/fail/function_calls/check_arg_abi.rs:LL:CC | LL | let _ = malloc(0); diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.rs b/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.rs index db7bd223bd45a..5e7d9a687b871 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.rs +++ b/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.rs @@ -5,6 +5,6 @@ fn main() { unsafe { abort(1); - //~^ ERROR: Undefined Behavior: incorrect number of arguments for `abort`: got 1, expected 0 + //~^ ERROR: takes 0 arguments, but 1 argument was given } } diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.stderr b/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.stderr index 5b4703ca16605..94f5ff1b64be8 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_arg_count_abort.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: incorrect number of arguments for `abort`: got 1, expected 0 +error: Undefined Behavior: ABI mismatch: calling `abort` which takes 0 arguments, but 1 argument was given --> tests/fail/function_calls/check_arg_count_abort.rs:LL:CC | LL | abort(1); diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.rs b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.rs index ecdda9e509d4e..2e2b1e019479c 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.rs +++ b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.rs @@ -6,6 +6,6 @@ fn main() { } unsafe { - let _ = malloc(); //~ ERROR: Undefined Behavior: incorrect number of arguments for `malloc`: got 0, expected 1 + let _ = malloc(); //~ ERROR: takes 1 argument, but 0 arguments were given }; } diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.stderr b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.stderr index 5f81145d26afd..56e75a8ac55ac 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_few_args.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: incorrect number of arguments for `malloc`: got 0, expected 1 +error: Undefined Behavior: ABI mismatch: calling `malloc` which takes 1 argument, but 0 arguments were given --> tests/fail/function_calls/check_arg_count_too_few_args.rs:LL:CC | LL | let _ = malloc(); diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.rs b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.rs index 1d3fec0fe32f8..2334f524dbca0 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.rs +++ b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.rs @@ -6,6 +6,6 @@ fn main() { } unsafe { - let _ = malloc(1, 2); //~ ERROR: Undefined Behavior: incorrect number of arguments for `malloc`: got 2, expected 1 + let _ = malloc(1, 2); //~ ERROR: takes 1 argument, but 2 arguments were given }; } diff --git a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.stderr b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.stderr index 3ed4aaacb8c40..a586fafe1eb1b 100644 --- a/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.stderr +++ b/src/tools/miri/tests/fail/function_calls/check_arg_count_too_many_args.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: incorrect number of arguments for `malloc`: got 2, expected 1 +error: Undefined Behavior: ABI mismatch: calling `malloc` which takes 1 argument, but 2 arguments were given --> tests/fail/function_calls/check_arg_count_too_many_args.rs:LL:CC | LL | let _ = malloc(1, 2); diff --git a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs index ac6e221fcd8d3..1dc36706e284b 100644 --- a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs +++ b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.rs @@ -9,6 +9,6 @@ extern "C" { fn main() { let mut fds = [-1, -1]; let res = unsafe { pipe(fds.as_mut_ptr()) }; - //~^ ERROR: ABI mismatch: calling a non-variadic function with a variadic caller-side signature + //~^ ERROR: is a non-variadic function, but the caller is using a variadic signature assert_eq!(res, 0); } diff --git a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr index 12c5a21909ab8..0405fe0ef7501 100644 --- a/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr +++ b/src/tools/miri/tests/fail/shims/vararg_caller_signature_mismatch.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: ABI mismatch: calling a non-variadic function with a variadic caller-side signature +error: Undefined Behavior: ABI mismatch: `pipe` is a non-variadic function, but the caller is using a variadic signature --> tests/fail/shims/vararg_caller_signature_mismatch.rs:LL:CC | LL | let res = unsafe { pipe(fds.as_mut_ptr()) }; diff --git a/src/tools/miri/tests/pass-dep/concurrency/tls_errno.rs b/src/tools/miri/tests/pass-dep/concurrency/tls_errno.rs new file mode 100644 index 0000000000000..6de404c8c0813 --- /dev/null +++ b/src/tools/miri/tests/pass-dep/concurrency/tls_errno.rs @@ -0,0 +1,25 @@ +//@ignore-target: windows # No libc errno on Windows + +/// Tests whether each thread has its own `__errno_location`. +fn main() { + #[cfg(any(target_os = "illumos", target_os = "solaris"))] + use libc::___errno as __errno_location; + #[cfg(target_os = "android")] + use libc::__errno as __errno_location; + #[cfg(target_os = "linux")] + use libc::__errno_location; + #[cfg(any(target_os = "freebsd", target_os = "macos"))] + use libc::__error as __errno_location; + + unsafe { + *__errno_location() = 0xBEEF; + std::thread::spawn(|| { + assert_eq!(*__errno_location(), 0); + *__errno_location() = 0xBAD1DEA; + assert_eq!(*__errno_location(), 0xBAD1DEA); + }) + .join() + .unwrap(); + assert_eq!(*__errno_location(), 0xBEEF); + } +} diff --git a/src/tools/miri/tests/pass-dep/libc/libc-mem.rs b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs index a64a23aa5a38f..7e7c7e99338cc 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-mem.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs @@ -408,6 +408,24 @@ fn test_strnlen() { } } +#[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] +fn test_malloc_usable_size() { + unsafe { + // `malloc_usable_size(NULL)` returns 0. + assert_eq!(libc::malloc_usable_size(ptr::null_mut()), 0); + + for size in [1, 2, 5, 16, 123, 1024] { + let p = libc::malloc(size); + if cfg!(miri) { + // Miri returns the exact size, but it doesn't need to. + assert_eq!(libc::malloc_usable_size(p), size); + } + assert!(libc::malloc_usable_size(p) >= size); + libc::free(p); + } + } +} + fn test_wcslen() { fn to_c_wchar_t_str(s: &str) -> Vec { let mut r = Vec::::new(); @@ -444,6 +462,8 @@ fn main() { test_reallocarray(); #[cfg(not(target_os = "windows"))] test_aligned_alloc(); + #[cfg(any(target_os = "linux", target_os = "android", target_os = "freebsd"))] + test_malloc_usable_size(); test_memcpy(); test_strcpy(); diff --git a/src/tools/miri/tests/pass-dep/libc/libc-misc.rs b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs index 10d756e05104b..c941e8b82bed1 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-misc.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs @@ -3,11 +3,11 @@ use std::mem::transmute; -/// Tests whether each thread has its own `__errno_location`. -fn test_thread_local_errno() { +/// Ensure errno can be written and read. +fn test_errno() { #[cfg(any(target_os = "illumos", target_os = "solaris"))] use libc::___errno as __errno_location; - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_os = "netbsd"))] use libc::__errno as __errno_location; #[cfg(target_os = "linux")] use libc::__errno_location; @@ -16,13 +16,6 @@ fn test_thread_local_errno() { unsafe { *__errno_location() = 0xBEEF; - std::thread::spawn(|| { - assert_eq!(*__errno_location(), 0); - *__errno_location() = 0xBAD1DEA; - assert_eq!(*__errno_location(), 0xBAD1DEA); - }) - .join() - .unwrap(); assert_eq!(*__errno_location(), 0xBEEF); } } @@ -86,7 +79,7 @@ fn test_geteuid() { } fn main() { - test_thread_local_errno(); + test_errno(); test_environ(); test_dlsym(); test_getuid(); diff --git a/src/tools/miri/tests/pass/extern_static.rs b/src/tools/miri/tests/pass/extern_static.rs index 70b8ff304c086..87f776cd92670 100644 --- a/src/tools/miri/tests/pass/extern_static.rs +++ b/src/tools/miri/tests/pass/extern_static.rs @@ -20,6 +20,9 @@ static FOO_U32: u32 = 42; #[no_mangle] static INTERIOR_MUT: SyncUnsafeCell = SyncUnsafeCell::new(42); +#[no_mangle] +static ARRAY: [u32; 5] = [1, 2, 3, 4, 5]; + fn increase_mutable_static_by_original_def(add_val: i32) { unsafe { let new_val = (&raw mut MUTABLE_STATIC).read() + add_val; @@ -60,6 +63,30 @@ fn main() { (&raw mut INTERIOR_MUT_AS_MUTABLE_STATIC).write(7); MUTABLE_STATIC_AS_INTERIOR_MUT.get().write(3); } + + // It's okay for the actual static to be bigger or more aligned than the extern declaration. + extern "C" { + // Actual size is bigger (20 bytes). + #[link_name = "ARRAY"] + static ARRAY_UNKNOWN_SIZE: [u32; 0]; + + // Actual size and alignment is that of u32, not u16. + #[link_name = "FOO_U32"] + static U16_TO_FOO_U32: u16; + } + + unsafe { + let ptr = (&raw const ARRAY_UNKNOWN_SIZE).cast::(); + assert_eq!(ptr.read(), 1); + assert_eq!(ptr.offset(2).read(), 3); + + // We see one half of FOO_U32, depending on endianess. + if cfg!(target_endian = "little") { + assert_eq!(U16_TO_FOO_U32, 42); + } else { + assert_eq!(U16_TO_FOO_U32, 0); + } + } } extern "Rust" { diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs index 67b35405ccdf8..82b0d26d4df1b 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs @@ -11,10 +11,20 @@ use std::arch::x86_64::*; fn main() { assert!(is_x86_feature_detected!("aes")); - assert!(is_x86_feature_detected!("vaes")); unsafe { test_aes(); + } + + // The tests below require vaes, which is recent enough that contributors may be using CPUs that + // do not support it. But we still want to run this natively if the machine happens to have vaes. + // So we bail out dynamically. + if !is_x86_feature_detected!("vaes") { + println!("warning: skipping vaes tests"); + return; + } + + unsafe { test_vaes(); } } diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs index 5ceaf405f4040..22bd697cfd0a1 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-vpclmulqdq.rs @@ -19,8 +19,15 @@ use std::mem::transmute; fn main() { // Mostly copied from library/stdarch/crates/core_arch/src/x86/vpclmulqdq.rs + // These tests require vpclmuldqd, which is recent enough that contributors may be using CPUs that + // do not support it. But we still want to run this natively if the machine happens to have vpclmulqdq. + // So we bail out dynamically. + if !is_x86_feature_detected!("vpclmulqdq") { + println!("warning: skipping vpclmulqdq tests"); + return; + } + assert!(is_x86_feature_detected!("pclmulqdq")); - assert!(is_x86_feature_detected!("vpclmulqdq")); unsafe { test_mm256_clmulepi64_epi128(); diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index e77c4f20750ed..b2fda8e0c62c9 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -300,7 +300,6 @@ fn run_tests( ) .into(), ); - if let Ok(extra_flags) = env::var("MIRIFLAGS") { for flag in extra_flags.split_whitespace() { config.program.args.push(flag.into()); diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml index 727d3cc868742..c4c2008a9afa4 100644 --- a/src/tools/miri/triagebot.toml +++ b/src/tools/miri/triagebot.toml @@ -17,6 +17,7 @@ allow-unauthenticated = [ [assign] warn_non_default_branch = true contributing_url = "https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#pr-review-process" +llm_policy_url = "https://github.com/rust-lang/miri/blob/master/CONTRIBUTING.md#ai-policy" [no-merges] exclude_titles = ["Rustup"] diff --git a/tests/codegen-llvm/complex-abi.rs b/tests/codegen-llvm/complex-abi.rs index bb1d6affd10c4..81d93b704ee1c 100644 --- a/tests/codegen-llvm/complex-abi.rs +++ b/tests/codegen-llvm/complex-abi.rs @@ -21,43 +21,47 @@ //@ [WIN32_GNU] compile-flags: --target i686-pc-windows-gnu //@ [WIN32_GNU] needs-llvm-components: x86 -// FIXME: the below revisions are deliberately disabled for now. +//@ revisions: AARCH64 AARCH64_DARWIN AARCH64_MSVC ARM64EC +//@ [AARCH64] compile-flags: --target aarch64-unknown-linux-gnu +//@ [AARCH64] needs-llvm-components: aarch64 +//@ [AARCH64_DARWIN] compile-flags: --target aarch64-apple-darwin +//@ [AARCH64_DARWIN] needs-llvm-components: aarch64 +//@ [AARCH64_MSVC] compile-flags: --target aarch64-pc-windows-msvc +//@ [AARCH64_MSVC] needs-llvm-components: aarch64 +//@ [ARM64EC] compile-flags: --target arm64ec-pc-windows-msvc +//@ [ARM64EC] needs-llvm-components: aarch64 + +//@ revisions: ARM +//@ [ARM] compile-flags: --target arm-unknown-linux-gnueabihf +//@ [ARM] needs-llvm-components: arm -// revisions: AARCH64 AARCH64_DARWIN AARCH64_MSVC ARM64EC -// [AARCH64] compile-flags: --target aarch64-unknown-linux-gnu -// [AARCH64] needs-llvm-components: aarch64 -// [AARCH64_DARWIN] compile-flags: --target aarch64-apple-darwin -// [AARCH64_DARWIN] needs-llvm-components: aarch64 -// [AARCH64_MSVC] compile-flags: --target aarch64-pc-windows-msvc -// [AARCH64_MSVC] needs-llvm-components: aarch64 -// [ARM64EC] compile-flags: --target arm64ec-pc-windows-msvc -// [ARM64EC] needs-llvm-components: aarch64 +//@ revisions: RISCV64 RISCV32 +//@ [RISCV64] compile-flags: --target riscv64gc-unknown-linux-gnu +//@ [RISCV64] needs-llvm-components: riscv +//@ [RISCV32] compile-flags: --target riscv32gc-unknown-linux-gnu +//@ [RISCV32] needs-llvm-components: riscv -// revisions: ARM -// [ARM] compile-flags: --target arm-unknown-linux-gnueabihf -// [ARM] needs-llvm-components: arm +//@ revisions: LOONGARCH64 LOONGARCH32 +//@ [LOONGARCH64] compile-flags: --target loongarch64-unknown-linux-gnu +//@ [LOONGARCH64] needs-llvm-components: loongarch +//@ [LOONGARCH32] compile-flags: --target loongarch32-unknown-none +//@ [LOONGARCH32] needs-llvm-components: loongarch -// revisions: RISCV64 RISCV32 -// [RISCV64] compile-flags: --target riscv64gc-unknown-linux-gnu -// [RISCV64] needs-llvm-components: riscv -// [RISCV32] compile-flags: --target riscv32gc-unknown-linux-gnu -// [RISCV32] needs-llvm-components: riscv +//@ revisions: S390X +//@ [S390X] compile-flags: --target s390x-unknown-linux-gnu +//@ [S390X] needs-llvm-components: systemz -// revisions: LOONGARCH64 LOONGARCH32 -// [LOONGARCH64] compile-flags: --target loongarch64-unknown-linux-gnu -// [LOONGARCH64] needs-llvm-components: loongarch -// [LOONGARCH32] compile-flags: --target loongarch32-unknown-none -// [LOONGARCH32] needs-llvm-components: loongarch +//@ revisions: WASM32 WASM64 +//@ [WASM32] compile-flags: --target wasm32-unknown-unknown +//@ [WASM32] needs-llvm-components: webassembly +//@ [WASM64] compile-flags: --target wasm64-unknown-unknown +//@ [WASM64] needs-llvm-components: webassembly -// revisions: SPARC64 SPARC -// [SPARC64] compile-flags: --target sparc64-unknown-linux-gnu -// [SPARC64] needs-llvm-components: sparc -// [SPARC] compile-flags: --target sparc-unknown-linux-gnu -// [SPARC] needs-llvm-components: sparc +//@ revisions: CSKY +//@ [CSKY] compile-flags: --target csky-unknown-linux-gnuabiv2 +//@ [CSKY] needs-llvm-components: csky -// revisions: S390X -// [S390X] compile-flags: --target s390x-unknown-linux-gnu -// [S390X] needs-llvm-components: systemz +// FIXME: the below revisions are deliberately disabled for now. // revisions: POWERPC POWERPC64LE POWERPC64 AIX // [POWERPC] compile-flags: --target powerpc-unknown-linux-gnu @@ -75,16 +79,6 @@ // [MIPS] compile-flags: --target mips-unknown-linux-gnu // [MIPS] needs-llvm-components: mips -// revisions: WASM32 WASM64 -// [WASM32] compile-flags: --target wasm32-unknown-unknown -// [WASM32] needs-llvm-components: webassembly -// [WASM64] compile-flags: --target wasm64-unknown-unknown -// [WASM64] needs-llvm-components: webassembly - -// revisions: CSKY -// [CSKY] compile-flags: --target csky-unknown-linux-gnuabiv2 -// [CSKY] needs-llvm-components: csky - // revisions: NVPTX // [NVPTX] compile-flags: --target nvptx64-nvidia-cuda // [NVPTX] needs-llvm-components: nvptx @@ -103,18 +97,18 @@ use minicore::num::Complex; #[no_mangle] pub extern "C" fn cplx_f16(x: Complex) -> Complex { - // AARCH64: define{{.*}} { half, half } @cplx_f16([2 x half] {{.*}}) - // AARCH64_DARWIN: define{{.*}} { half, half } @cplx_f16([2 x half] {{.*}}) - // AARCH64_MSVC: define{{.*}} { half, half } @cplx_f16([2 x half] {{.*}}) - // ARM64EC: define{{.*}} { half, half } @cplx_f16([2 x half] {{.*}}) - // ARM: define{{.*}} i32 @cplx_f16([1 x i32] {{.*}}) + // AARCH64: define{{.*}} [2 x half] @cplx_f16([2 x half] {{.*}}) + // AARCH64_DARWIN: define{{.*}} [2 x half] @cplx_f16([2 x half] {{.*}}) + // AARCH64_MSVC: define{{.*}} [2 x half] @cplx_f16([2 x half] {{.*}}) + // ARM64EC: define{{.*}} [2 x half] @cplx_f16([2 x half] {{.*}}) + // ARM: define{{.*}} [2 x half] @cplx_f16([2 x half] {{.*}}) // I686: define{{.*}} <2 x half> @cplx_f16(ptr {{.*}} byval([4 x i8]) {{.*}}) - // LOONGARCH32: define{{.*}} { half, half } @cplx_f16(half {{.*}}, half {{.*}}) - // LOONGARCH64: define{{.*}} { half, half } @cplx_f16(half {{.*}}, half {{.*}}) + // LOONGARCH32: define{{.*}} { half, half } @cplx_f16({ half, half } {{.*}}) + // LOONGARCH64: define{{.*}} { half, half } @cplx_f16({ half, half } {{.*}}) // NVPTX: define{{.*}} { half, half } @cplx_f16(ptr {{.*}} byval({ half, half }) {{.*}}) - // RISCV32: define{{.*}} { half, half } @cplx_f16(half {{.*}}, half {{.*}}) - // RISCV64: define{{.*}} { half, half } @cplx_f16(half {{.*}}, half {{.*}}) - // S390X: define{{.*}} void @cplx_f16(ptr {{.*}} sret({ half, half }) {{.*}}, ptr {{.*}}) + // RISCV32: define{{.*}} { half, half } @cplx_f16({ half, half } {{.*}}) + // RISCV64: define{{.*}} { half, half } @cplx_f16({ half, half } {{.*}}) + // S390X: define{{.*}} void @cplx_f16(ptr {{.*}} sret([4 x i8]) {{.*}}, ptr {{.*}}) // WIN32_GNU: define{{.*}} <2 x half> @cplx_f16(ptr {{.*}} byval([4 x i8]) {{.*}}) // WIN32_MSVC: define{{.*}} <2 x half> @cplx_f16(ptr {{.*}} byval([4 x i8]) {{.*}}) // WINDOWS_GNU: define{{.*}} i32 @cplx_f16(i32 {{.*}}) @@ -125,30 +119,30 @@ pub extern "C" fn cplx_f16(x: Complex) -> Complex { #[no_mangle] pub extern "C" fn cplx_f32(x: Complex) -> Complex { - // AARCH64: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) - // AARCH64_DARWIN: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) - // AARCH64_MSVC: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) + // AARCH64: define{{.*}} [2 x float] @cplx_f32([2 x float] {{.*}}) + // AARCH64_DARWIN: define{{.*}} [2 x float] @cplx_f32([2 x float] {{.*}}) + // AARCH64_MSVC: define{{.*}} [2 x float] @cplx_f32([2 x float] {{.*}}) // AIX: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) - // ARM64EC: define{{.*}} { float, float } @cplx_f32([2 x float] {{.*}}) - // ARM: define{{.*}} { float, float } @cplx_f32({ float, float } {{.*}}) + // ARM64EC: define{{.*}} [2 x float] @cplx_f32([2 x float] {{.*}}) + // ARM: define{{.*}} [2 x float] @cplx_f32([2 x float] {{.*}}) // BPF: define{{.*}} void @cplx_f32(ptr {{.*}} sret({ float, float }) {{.*}}, i64 {{.*}}) // CSKY: define{{.*}} [2 x i32] @cplx_f32([2 x i32] {{.*}}) // I686: define{{.*}} i64 @cplx_f32(ptr {{.*}} byval([8 x i8]) {{.*}}) - // LOONGARCH32: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) - // LOONGARCH64: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) + // LOONGARCH32: define{{.*}} { float, float } @cplx_f32({ float, float } {{.*}}) + // LOONGARCH64: define{{.*}} { float, float } @cplx_f32({ float, float } {{.*}}) // MIPS64EL: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) - // MIPS: define{{.*}} { float, float } @cplx_f32(i32 {{.*}}, i32 {{.*}}) + // MIPS: define{{.*}} { float, float } @cplx_f32([2 x i32] {{.*}}) // NVPTX: define{{.*}} { float, float } @cplx_f32(ptr {{.*}} byval({ float, float }) {{.*}}) // POWERPC64: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) // POWERPC64LE: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) // POWERPC: define{{.*}} void @cplx_f32(ptr {{.*}} sret({ float, float }) {{.*}}, ptr {{.*}} byval({ float, float }) {{.*}}) - // RISCV32: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) - // RISCV64: define{{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) - // S390X: define{{.*}} void @cplx_f32(ptr {{.*}} sret({ float, float }) {{.*}}, ptr {{.*}}) + // RISCV32: define{{.*}} { float, float } @cplx_f32({ float, float } {{.*}}) + // RISCV64: define{{.*}} { float, float } @cplx_f32({ float, float } {{.*}}) + // S390X: define{{.*}} void @cplx_f32(ptr {{.*}} sret([8 x i8]) {{.*}}, ptr {{.*}}) // SPARC64: define{{.*}} {{.*}} { float, float } @cplx_f32(float {{.*}}, float {{.*}}) // SPARC: define{{.*}} { float, float } @cplx_f32(ptr {{.*}} byval({ float, float }) {{.*}}) - // WASM32: define{{.*}} void @cplx_f32(ptr {{.*}} sret({ float, float }) {{.*}}, ptr {{.*}} byval({ float, float }) {{.*}}) - // WASM64: define{{.*}} void @cplx_f32(ptr {{.*}} sret({ float, float }) {{.*}}, ptr {{.*}} byval({ float, float }) {{.*}}) + // WASM32: define{{.*}} void @cplx_f32(ptr {{.*}} sret([8 x i8]) {{.*}}, ptr {{.*}}) + // WASM64: define{{.*}} void @cplx_f32(ptr {{.*}} sret([8 x i8]) {{.*}}, ptr {{.*}}) // WIN32_GNU: define{{.*}} i64 @cplx_f32(ptr {{.*}} byval([8 x i8]) {{.*}}) // WIN32_MSVC: define{{.*}} i64 @cplx_f32(ptr {{.*}} byval([8 x i8]) {{.*}}) // WINDOWS_GNU: define{{.*}} i64 @cplx_f32(i64 {{.*}}) @@ -159,30 +153,30 @@ pub extern "C" fn cplx_f32(x: Complex) -> Complex { #[no_mangle] pub extern "C" fn cplx_f64(x: Complex) -> Complex { - // AARCH64: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) - // AARCH64_DARWIN: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) - // AARCH64_MSVC: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) + // AARCH64: define{{.*}} [2 x double] @cplx_f64([2 x double] {{.*}}) + // AARCH64_DARWIN: define{{.*}} [2 x double] @cplx_f64([2 x double] {{.*}}) + // AARCH64_MSVC: define{{.*}} [2 x double] @cplx_f64([2 x double] {{.*}}) // AIX: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) - // ARM64EC: define{{.*}} { double, double } @cplx_f64([2 x double] {{.*}}) - // ARM: define{{.*}} { double, double } @cplx_f64({ double, double } {{.*}}) + // ARM64EC: define{{.*}} [2 x double] @cplx_f64([2 x double] {{.*}}) + // ARM: define{{.*}} [2 x double] @cplx_f64([2 x double] {{.*}}) // BPF: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, [2 x i64] {{.*}}) - // CSKY: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, [4 x i32] {{.*}}) + // CSKY: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, [4 x i32] {{.*}}) // I686: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) - // LOONGARCH32: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) - // LOONGARCH64: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) + // LOONGARCH32: define{{.*}} { double, double } @cplx_f64({ double, double } {{.*}}) + // LOONGARCH64: define{{.*}} { double, double } @cplx_f64({ double, double } {{.*}}) // MIPS64EL: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) // MIPS: define{{.*}} { double, double } @cplx_f64(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) // NVPTX: define{{.*}} { double, double } @cplx_f64(ptr {{.*}} byval({ double, double }) {{.*}}) // POWERPC64: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) // POWERPC64LE: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) // POWERPC: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) - // RISCV32: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) - // RISCV64: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) - // S390X: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}}) + // RISCV32: define{{.*}} { double, double } @cplx_f64({ double, double } {{.*}}) + // RISCV64: define{{.*}} { double, double } @cplx_f64({ double, double } {{.*}}) + // S390X: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // SPARC64: define{{.*}} { double, double } @cplx_f64(double {{.*}}, double {{.*}}) // SPARC: define{{.*}} { double, double } @cplx_f64(ptr {{.*}} byval({ double, double }) {{.*}}) - // WASM32: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) - // WASM64: define{{.*}} void @cplx_f64(ptr {{.*}} sret({ double, double }) {{.*}}, ptr {{.*}} byval({ double, double }) {{.*}}) + // WASM32: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) + // WASM64: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // WIN32_GNU: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // WIN32_MSVC: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // WINDOWS_GNU: define{{.*}} void @cplx_f64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) @@ -193,41 +187,44 @@ pub extern "C" fn cplx_f64(x: Complex) -> Complex { #[no_mangle] pub extern "C" fn cplx_f128(x: Complex) -> Complex { + // AARCH64: define{{.*}} [2 x fp128] {{.*}}) // I686: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}} byval([32 x i8]) {{.*}}) - // WASM32: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}} byval({ fp128, fp128 }) {{.*}}) - // WASM64: define{{.*}} void @cplx_f128(ptr {{.*}} sret({ fp128, fp128 }) {{.*}}, ptr {{.*}} byval({ fp128, fp128 }) {{.*}}) + // WASM32: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}}) + // WASM64: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}}) // WIN32_GNU: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}} byval([32 x i8]) {{.*}}) // WINDOWS_GNU: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}}) // X86_64: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}} byval([32 x i8]) {{.*}}) + // LOONGARCH64: define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}}) + // RISCV64 define{{.*}} void @cplx_f128(ptr {{.*}} sret([32 x i8]) {{.*}}, ptr {{.*}}) x } #[no_mangle] pub extern "C" fn cplx_i8(x: Complex) -> Complex { - // AARCH64: define{{.*}} i16 @cplx_i8(i64{{.*}}) - // AARCH64_DARWIN: define{{.*}} i16 @cplx_i8(i64{{.*}}) - // AARCH64_MSVC: define{{.*}} i16 @cplx_i8(i64{{.*}}) + // AARCH64: define{{.*}} i64 @cplx_i8(i64{{.*}}) + // AARCH64_DARWIN: define{{.*}} i64 @cplx_i8(i64{{.*}}) + // AARCH64_MSVC: define{{.*}} i64 @cplx_i8(i64{{.*}}) // AIX: define{{.*}} { i8, i8 } @cplx_i8(i8 {{.*}}, i8 {{.*}}) - // ARM64EC: define{{.*}} i16 @cplx_i8(i64{{.*}}) - // ARM: define{{.*}} i16 @cplx_i8([1 x i32]{{.*}}) + // ARM64EC: define{{.*}} i64 @cplx_i8(i64{{.*}}) + // ARM: define{{.*}} i32 @cplx_i8(i32{{.*}}) // BPF: define{{.*}} void @cplx_i8(ptr {{.*}} sret({ i8, i8 }) {{.*}}, i16 {{.*}}) - // CSKY: define{{.*}} {{.*}} i32 @cplx_i8(i32{{.*}}) + // CSKY: define{{.*}} i32 @cplx_i8(i32{{.*}}) // I686: define{{.*}} i16 @cplx_i8(ptr {{.*}} byval([2 x i8]) {{.*}}) - // LOONGARCH32: define{{.*}} {{.*}} i32 @cplx_i8(i32{{.*}}) - // LOONGARCH64: define{{.*}} {{.*}} i64 @cplx_i8(i64{{.*}}) + // LOONGARCH32: define{{.*}} i32 @cplx_i8(i32{{.*}}) + // LOONGARCH64: define{{.*}} i64 @cplx_i8(i64{{.*}}) // MIPS64EL: define{{.*}} { i8, i8 } @cplx_i8(i16 {{.*}}) // MIPS: define{{.*}} { i8, i8 } @cplx_i8(i16 {{.*}}) // NVPTX: define{{.*}} { i8, i8 } @cplx_i8(ptr {{.*}} byval({ i8, i8 }) {{.*}}) // POWERPC64: define{{.*}} { i8, i8 } @cplx_i8(i8 {{.*}}, i8 {{.*}}) // POWERPC64LE: define{{.*}} { i8, i8 } @cplx_i8(i8 {{.*}}, i8 {{.*}}) // POWERPC: define{{.*}} void @cplx_i8(ptr {{.*}} sret({ i8, i8 }) {{.*}}, ptr {{.*}} byval({ i8, i8 }) {{.*}}) - // RISCV32: define{{.*}} {{.*}} i32 @cplx_i8(i32{{.*}}) - // RISCV64: define{{.*}} {{.*}} i64 @cplx_i8(i64{{.*}}) - // S390X: define{{.*}} void @cplx_i8(ptr {{.*}} sret({ i8, i8 }) {{.*}}, ptr {{.*}}) + // RISCV32: define{{.*}} i32 @cplx_i8(i32{{.*}}) + // RISCV64: define{{.*}} i64 @cplx_i8(i64{{.*}}) + // S390X: define{{.*}} void @cplx_i8(ptr {{.*}} sret([2 x i8]) {{.*}}, ptr {{.*}}) // SPARC64: define{{.*}} {{.*}} i64 @cplx_i8(i64{{.*}}) // SPARC: define{{.*}} { i8, i8 } @cplx_i8(ptr {{.*}} byval({ i8, i8 }) {{.*}}) - // WASM32: define{{.*}} void @cplx_i8(ptr {{.*}} sret({ i8, i8 }) {{.*}}, ptr {{.*}} byval({ i8, i8 }) {{.*}}) - // WASM64: define{{.*}} void @cplx_i8(ptr {{.*}} sret({ i8, i8 }) {{.*}}, ptr {{.*}} byval({ i8, i8 }) {{.*}}) + // WASM32: define{{.*}} void @cplx_i8(ptr {{.*}} sret([2 x i8]) {{.*}}, ptr {{.*}}) + // WASM64: define{{.*}} void @cplx_i8(ptr {{.*}} sret([2 x i8]) {{.*}}, ptr {{.*}}) // WIN32_GNU: define{{.*}} i16 @cplx_i8(ptr {{.*}} byval([2 x i8]) {{.*}}) // WIN32_MSVC: define{{.*}} i16 @cplx_i8(ptr {{.*}} byval([2 x i8]) {{.*}}) // WINDOWS_GNU: define{{.*}} i16 @cplx_i8(i16 {{.*}}) @@ -238,17 +235,17 @@ pub extern "C" fn cplx_i8(x: Complex) -> Complex { #[no_mangle] pub extern "C" fn cplx_i16(x: Complex) -> Complex { - // AARCH64: define{{.*}} i32 @cplx_i16(i64{{.*}}) - // AARCH64_DARWIN: define{{.*}} i32 @cplx_i16(i64{{.*}}) - // AARCH64_MSVC: define{{.*}} i32 @cplx_i16(i64{{.*}}) + // AARCH64: define{{.*}} i64 @cplx_i16(i64{{.*}}) + // AARCH64_DARWIN: define{{.*}} i64 @cplx_i16(i64{{.*}}) + // AARCH64_MSVC: define{{.*}} i64 @cplx_i16(i64{{.*}}) // AIX: define{{.*}} { i16, i16 } @cplx_i16(i16 {{.*}}, i16 {{.*}}) - // ARM64EC: define{{.*}} i32 @cplx_i16(i64{{.*}}) - // ARM: define{{.*}} i32 @cplx_i16([1 x i32] {{.*}}) + // ARM64EC: define{{.*}} i64 @cplx_i16(i64{{.*}}) + // ARM: define{{.*}} i32 @cplx_i16(i32{{.*}}) // BPF: define{{.*}} void @cplx_i16(ptr {{.*}} sret({ i16, i16 }) {{.*}}, i32 {{.*}}) // CSKY: define{{.*}} i32 @cplx_i16(i32 {{.*}}) // I686: define{{.*}} i32 @cplx_i16(ptr {{.*}} byval([4 x i8]) {{.*}}) // LOONGARCH32: define{{.*}} i32 @cplx_i16(i32 {{.*}}) - // LOONGARCH64: define{{.*}} {{.*}} i64 @cplx_i16(i64{{.*}}) + // LOONGARCH64: define{{.*}} i64 @cplx_i16(i64{{.*}}) // MIPS64EL: define{{.*}} { i16, i16 } @cplx_i16(i32 {{.*}}) // MIPS: define{{.*}} { i16, i16 } @cplx_i16(i32 {{.*}}) // NVPTX: define{{.*}} { i16, i16 } @cplx_i16(ptr {{.*}} byval({ i16, i16 }) {{.*}}) @@ -256,12 +253,12 @@ pub extern "C" fn cplx_i16(x: Complex) -> Complex { // POWERPC64LE: define{{.*}} { i16, i16 } @cplx_i16(i16 {{.*}}, i16 {{.*}}) // POWERPC: define{{.*}} void @cplx_i16(ptr {{.*}} sret({ i16, i16 }) {{.*}}, ptr {{.*}} byval({ i16, i16 }) {{.*}}) // RISCV32: define{{.*}} i32 @cplx_i16(i32 {{.*}}) - // RISCV64: define{{.*}} {{.*}} i64 @cplx_i16(i64{{.*}}) - // S390X: define{{.*}} void @cplx_i16(ptr {{.*}} sret({ i16, i16 }) {{.*}}, ptr {{.*}}) + // RISCV64: define{{.*}} i64 @cplx_i16(i64{{.*}}) + // S390X: define{{.*}} void @cplx_i16(ptr {{.*}} sret([4 x i8]) {{.*}}, ptr {{.*}}) // SPARC64: define{{.*}} {{.*}} i64 @cplx_i16(i64{{.*}}) // SPARC: define{{.*}} { i16, i16 } @cplx_i16(ptr {{.*}} byval({ i16, i16 }) {{.*}}) - // WASM32: define{{.*}} void @cplx_i16(ptr {{.*}} sret({ i16, i16 }) {{.*}}, ptr {{.*}} byval({ i16, i16 }) {{.*}}) - // WASM64: define{{.*}} void @cplx_i16(ptr {{.*}} sret({ i16, i16 }) {{.*}}, ptr {{.*}} byval({ i16, i16 }) {{.*}}) + // WASM32: define{{.*}} void @cplx_i16(ptr {{.*}} sret([4 x i8]) {{.*}}, ptr {{.*}}) + // WASM64: define{{.*}} void @cplx_i16(ptr {{.*}} sret([4 x i8]) {{.*}}, ptr {{.*}}) // WIN32_GNU: define{{.*}} i32 @cplx_i16(ptr {{.*}} byval([4 x i8]) {{.*}}) // WIN32_MSVC: define{{.*}} i32 @cplx_i16(ptr {{.*}} byval([4 x i8]) {{.*}}) // WINDOWS_GNU: define{{.*}} i32 @cplx_i16(i32 {{.*}}) @@ -277,7 +274,7 @@ pub extern "C" fn cplx_i32(x: Complex) -> Complex { // AARCH64_MSVC: define{{.*}} i64 @cplx_i32(i64 {{.*}}) // AIX: define{{.*}} { i32, i32 } @cplx_i32(i32 {{.*}}, i32 {{.*}}) // ARM64EC: define{{.*}} i64 @cplx_i32(i64 {{.*}}) - // ARM: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, [2 x i32] {{.*}}) + // ARM: define{{.*}} void @cplx_i32(ptr {{.*}} sret([8 x i8]) {{.*}}, [2 x i32] {{.*}}) // BPF: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, i64 {{.*}}) // CSKY: define{{.*}} [2 x i32] @cplx_i32([2 x i32] {{.*}}) // I686: define{{.*}} i64 @cplx_i32(ptr {{.*}} byval([8 x i8]) {{.*}}) @@ -291,11 +288,11 @@ pub extern "C" fn cplx_i32(x: Complex) -> Complex { // POWERPC: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, ptr {{.*}} byval({ i32, i32 }) {{.*}}) // RISCV32: define{{.*}} [2 x i32] @cplx_i32([2 x i32] {{.*}}) // RISCV64: define{{.*}} i64 @cplx_i32(i64 {{.*}}) - // S390X: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, ptr {{.*}}) + // S390X: define{{.*}} void @cplx_i32(ptr {{.*}} sret([8 x i8]) {{.*}}, ptr {{.*}}) // SPARC64: define{{.*}} i64 @cplx_i32(i64 {{.*}}) // SPARC: define{{.*}} { i32, i32 } @cplx_i32(ptr {{.*}} byval({ i32, i32 }) {{.*}}) - // WASM32: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, ptr {{.*}} byval({ i32, i32 }) {{.*}}) - // WASM64: define{{.*}} void @cplx_i32(ptr {{.*}} sret({ i32, i32 }) {{.*}}, ptr {{.*}} byval({ i32, i32 }) {{.*}}) + // WASM32: define{{.*}} void @cplx_i32(ptr {{.*}} sret([8 x i8]) {{.*}}, ptr {{.*}}) + // WASM64: define{{.*}} void @cplx_i32(ptr {{.*}} sret([8 x i8]) {{.*}}, ptr {{.*}}) // WIN32_GNU: define{{.*}} i64 @cplx_i32(ptr {{.*}} byval([8 x i8]) {{.*}}) // WIN32_MSVC: define{{.*}} i64 @cplx_i32(ptr {{.*}} byval([8 x i8]) {{.*}}) // WINDOWS_GNU: define{{.*}} i64 @cplx_i32(i64 {{.*}}) @@ -311,11 +308,11 @@ pub extern "C" fn cplx_i64(x: Complex) -> Complex { // AARCH64_MSVC: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) // AIX: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) // ARM64EC: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) - // ARM: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, [2 x i64] {{.*}}) + // ARM: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, [2 x i64] {{.*}}) // BPF: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, [2 x i64] {{.*}}) - // CSKY: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, [4 x i32] {{.*}}) + // CSKY: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, [4 x i32] {{.*}}) // I686: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) - // LOONGARCH32: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) + // LOONGARCH32: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // LOONGARCH64: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) // MIPS64EL: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) // MIPS: define{{.*}} { i64, i64 } @cplx_i64(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) @@ -323,13 +320,13 @@ pub extern "C" fn cplx_i64(x: Complex) -> Complex { // POWERPC64: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) // POWERPC64LE: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) // POWERPC: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) - // RISCV32: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) + // RISCV32: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // RISCV64: define{{.*}} [2 x i64] @cplx_i64([2 x i64] {{.*}}) - // S390X: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) + // S390X: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // SPARC64: define{{.*}} { i64, i64 } @cplx_i64(i64 {{.*}}, i64 {{.*}}) // SPARC: define{{.*}} { i64, i64 } @cplx_i64(ptr {{.*}} byval({ i64, i64 }) {{.*}}) - // WASM32: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) - // WASM64: define{{.*}} void @cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) + // WASM32: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) + // WASM64: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // WIN32_GNU: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // WIN32_MSVC: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // WINDOWS_GNU: define{{.*}} void @cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) @@ -350,11 +347,11 @@ pub extern "C" fn wrapper_cplx_i64( // AARCH64_MSVC: define{{.*}} [2 x i64] @wrapper_cplx_i64([2 x i64] {{.*}}) // AIX: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i64 {{.*}}, i64 {{.*}}) // ARM64EC: define{{.*}} [2 x i64] @wrapper_cplx_i64([2 x i64] {{.*}}) - // ARM: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, [2 x i64] {{.*}}) + // ARM: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, [2 x i64] {{.*}}) // BPF: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, [2 x i64] {{.*}}) - // CSKY: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, [4 x i32] {{.*}}) + // CSKY: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, [4 x i32] {{.*}}) // I686: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) - // LOONGARCH32: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) + // LOONGARCH32: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // LOONGARCH64: define{{.*}} [2 x i64] @wrapper_cplx_i64([2 x i64] {{.*}}) // MIPS64EL: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i64 {{.*}}, i64 {{.*}}) // MIPS: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i32 {{.*}}, i32 {{.*}}, i32 {{.*}}, i32 {{.*}}) @@ -362,13 +359,13 @@ pub extern "C" fn wrapper_cplx_i64( // POWERPC64: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i64 {{.*}}, i64 {{.*}}) // POWERPC64LE: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i64 {{.*}}, i64 {{.*}}) // POWERPC: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) - // RISCV32: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) + // RISCV32: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // RISCV64: define{{.*}} [2 x i64] @wrapper_cplx_i64([2 x i64] {{.*}}) - // S390X: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}}) + // S390X: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // SPARC64: define{{.*}} { i64, i64 } @wrapper_cplx_i64(i64 {{.*}}, i64 {{.*}}) // SPARC: define{{.*}} { i64, i64 } @wrapper_cplx_i64(ptr {{.*}} byval({ i64, i64 }) {{.*}}) - // WASM32: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) - // WASM64: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret({ i64, i64 }) {{.*}}, ptr {{.*}} byval({ i64, i64 }) {{.*}}) + // WASM32: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) + // WASM64: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) // WIN32_GNU: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // WIN32_MSVC: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}} byval([16 x i8]) {{.*}}) // WINDOWS_GNU: define{{.*}} void @wrapper_cplx_i64(ptr {{.*}} sret([16 x i8]) {{.*}}, ptr {{.*}}) @@ -381,18 +378,18 @@ pub extern "C" fn wrapper_cplx_i64( pub extern "C" fn wrapper_cplx_f16( x: Wrapper>>, ) -> Wrapper>> { - // AARCH64: define{{.*}} { half, half } @wrapper_cplx_f16([2 x half] {{.*}}) - // AARCH64_DARWIN: define{{.*}} { half, half } @wrapper_cplx_f16([2 x half] {{.*}}) - // AARCH64_MSVC: define{{.*}} { half, half } @wrapper_cplx_f16([2 x half] {{.*}}) - // ARM64EC: define{{.*}} { half, half } @wrapper_cplx_f16([2 x half] {{.*}}) - // ARM: define{{.*}} i32 @wrapper_cplx_f16([1 x i32] {{.*}}) + // AARCH64: define{{.*}} [2 x half] @wrapper_cplx_f16([2 x half] {{.*}}) + // AARCH64_DARWIN: define{{.*}} [2 x half] @wrapper_cplx_f16([2 x half] {{.*}}) + // AARCH64_MSVC: define{{.*}} [2 x half] @wrapper_cplx_f16([2 x half] {{.*}}) + // ARM64EC: define{{.*}} [2 x half] @wrapper_cplx_f16([2 x half] {{.*}}) + // ARM: define{{.*}} [2 x half] @wrapper_cplx_f16([2 x half] {{.*}}) // I686: define{{.*}} <2 x half> @wrapper_cplx_f16(ptr {{.*}} byval([4 x i8]) {{.*}}) - // LOONGARCH32: define{{.*}} { half, half } @wrapper_cplx_f16(half {{.*}}, half {{.*}}) - // LOONGARCH64: define{{.*}} { half, half } @wrapper_cplx_f16(half {{.*}}, half {{.*}}) + // LOONGARCH32: define{{.*}} { half, half } @wrapper_cplx_f16({ half, half } {{.*}}) + // LOONGARCH64: define{{.*}} { half, half } @wrapper_cplx_f16({ half, half } {{.*}}) // NVPTX: define{{.*}} { half, half } @wrapper_cplx_f16(ptr {{.*}} byval({ half, half }) {{.*}}) - // RISCV32: define{{.*}} { half, half } @wrapper_cplx_f16(half {{.*}}, half {{.*}}) - // RISCV64: define{{.*}} { half, half } @wrapper_cplx_f16(half {{.*}}, half {{.*}}) - // S390X: define{{.*}} void @wrapper_cplx_f16(ptr {{.*}} sret({ half, half }) {{.*}}, ptr {{.*}}) + // RISCV32: define{{.*}} { half, half } @wrapper_cplx_f16({ half, half } {{.*}}) + // RISCV64: define{{.*}} { half, half } @wrapper_cplx_f16({ half, half } {{.*}}) + // S390X: define{{.*}} void @wrapper_cplx_f16(ptr {{.*}} sret([4 x i8]) {{.*}}, ptr {{.*}}) // WIN32_GNU: define{{.*}} <2 x half> @wrapper_cplx_f16(ptr {{.*}} byval([4 x i8]) {{.*}}) // WIN32_MSVC: define{{.*}} <2 x half> @wrapper_cplx_f16(ptr {{.*}} byval([4 x i8]) {{.*}}) // WINDOWS_GNU: define{{.*}} i32 @wrapper_cplx_f16(i32 {{.*}}) diff --git a/tests/codegen-llvm/issues/redundant-mask-after-range-check-78745.rs b/tests/codegen-llvm/issues/redundant-mask-after-range-check-78745.rs new file mode 100644 index 0000000000000..3bcd6acf68ab1 --- /dev/null +++ b/tests/codegen-llvm/issues/redundant-mask-after-range-check-78745.rs @@ -0,0 +1,30 @@ +// Tests that a bit mask is elided when a preceding range check or clamp already +// guarantees the masked bits are clear. +// See . + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @redundant_mask_after_range_check( +// CHECK-NOT: and i32 +// CHECK: ret i32 +#[no_mangle] +pub fn redundant_mask_after_range_check(mut u: u32) -> u32 { + if u <= 0x3F { + u &= 0x7F; + } + u +} + +// CHECK-LABEL: @redundant_mask_after_clamp( +// CHECK-NOT: and i32 +// CHECK: ret i32 +#[no_mangle] +pub fn redundant_mask_after_clamp(mut u: u32) -> u32 { + if u > 0x7F { + u = 0x7F; + } + u &= 0x7F; + u +} diff --git a/tests/crashes/108428.rs b/tests/crashes/108248.rs similarity index 84% rename from tests/crashes/108428.rs rename to tests/crashes/108248.rs index b18123b6a7c40..36252e29d33f0 100644 --- a/tests/crashes/108428.rs +++ b/tests/crashes/108248.rs @@ -1,4 +1,4 @@ -//@ known-bug: #108428 +//@ known-bug: #108248 //@ needs-rustc-debug-assertions //@ compile-flags: -Wunused-lifetimes fn main() { diff --git a/tests/crashes/138262.rs b/tests/crashes/138262.rs new file mode 100644 index 0000000000000..38864a2ae2a27 --- /dev/null +++ b/tests/crashes/138262.rs @@ -0,0 +1,12 @@ +//@ known-bug: #138262 +//@ compile-flags: -Zsanitizer=cfi -Ccodegen-units=1 -Clto -Clink-dead-code=true -Cunsafe-allow-abi-mismatch=sanitizer +//@ ignore-backends: gcc +//@ needs-sanitizer-cfi +fn foo() {} + +core::arch::global_asm!("/* {} */", sym foo::<{ + || {}; + 0 +}>); + +fn main() {} diff --git a/tests/crashes/142155.rs b/tests/crashes/142155.rs new file mode 100644 index 0000000000000..8c0769bf2b586 --- /dev/null +++ b/tests/crashes/142155.rs @@ -0,0 +1,12 @@ +//@ known-bug: #142155 +//@ needs-rustc-debug-assertions +//@ edition: 2021 + +#![warn(tail_expr_drop_order)] +use core::future::Future; + +fn f() -> impl Future> { + async { Some("nope".into()) } +} + +fn main() {} diff --git a/tests/crashes/144241.rs b/tests/crashes/144241.rs new file mode 100644 index 0000000000000..3f91fcc7c6275 --- /dev/null +++ b/tests/crashes/144241.rs @@ -0,0 +1,4 @@ +//@ known-bug: #144241 +fn main() { + |_: dyn ?Sized + !Send| {} +} diff --git a/tests/crashes/149562.rs b/tests/crashes/149562.rs new file mode 100644 index 0000000000000..4d032a0af5c3e --- /dev/null +++ b/tests/crashes/149562.rs @@ -0,0 +1,10 @@ +//@ known-bug: #149562 +//@ needs-rustc-debug-assertions +fn a() -> T +where + T: ?Sized, + T: ?Sized, +{ +} + +fn main() {} diff --git a/tests/crashes/152414.rs b/tests/crashes/152414.rs new file mode 100644 index 0000000000000..226f9e29faad6 --- /dev/null +++ b/tests/crashes/152414.rs @@ -0,0 +1,6 @@ +//@ known-bug: #152414 +//@ needs-rustc-debug-assertions +#![feature(generic_assert)] +fn main() { + assert!(size_of(val, 1) >= 1); +} diff --git a/tests/crashes/152416.rs b/tests/crashes/152416.rs new file mode 100644 index 0000000000000..9ca418cce3628 --- /dev/null +++ b/tests/crashes/152416.rs @@ -0,0 +1,17 @@ +//@ known-bug: #152416 +//@ needs-rustc-debug-assertions +//@ compile-flags: -Zunstable-options + +trait AssetID {} +trait Archive { + fn name(&self); +} +struct NorthlightAssetID; +impl AssetID for NorthlightAssetID {} +fn get() -> Box> { + let x: Box> = todo!(); + x +} +fn main() { + get().name(); +} diff --git a/tests/crashes/152626.rs b/tests/crashes/152626.rs new file mode 100644 index 0000000000000..eafb714c2f5c2 --- /dev/null +++ b/tests/crashes/152626.rs @@ -0,0 +1,7 @@ +//@ known-bug: #152626 +//@ needs-rustc-debug-assertions +struct A>(T); +fn f() -> A<&'static ()> { + todo!() +} +fn main() {} diff --git a/tests/crashes/153005.rs b/tests/crashes/153005.rs new file mode 100644 index 0000000000000..44b4e029958cd --- /dev/null +++ b/tests/crashes/153005.rs @@ -0,0 +1,15 @@ +//@ known-bug: #153005 +#![feature(non_lifetime_binders)] +#![feature(derive_coerce_pointee)] + +#[derive(core::marker::CoercePointee)] +#[repr(transparent)] +struct _Ptr5<'a, #[pointee] T: ?Sized, X> +where + for V: Sized, +{ + data: &'a T, + x: core::marker::PhantomData, +} + +fn main() {} diff --git a/tests/crashes/153362.rs b/tests/crashes/153362.rs new file mode 100644 index 0000000000000..0a8e4ddae6283 --- /dev/null +++ b/tests/crashes/153362.rs @@ -0,0 +1,6 @@ +//@ known-bug: #153362 +struct ThinDst { + b: unsafe<> (), +} + +const C1: &ThinDst = unsafe { std::mem::transmute(b"d".as_ptr()) }; diff --git a/tests/crashes/153375.rs b/tests/crashes/153375.rs new file mode 100644 index 0000000000000..46ed4be3b829b --- /dev/null +++ b/tests/crashes/153375.rs @@ -0,0 +1,15 @@ +//@ known-bug: #153375 +//@ aux-build: aux153375.rs +extern crate aux153375; +use aux153375::Request; + +struct Bar<'ws>(&'ws ()); + +impl<'ws> Request for Bar<'ws> { + type A<'a> + = u8 + where + Self: 'a; + + fn f(_: Self::A<'_>) -> impl Sized {} +} diff --git a/tests/crashes/153947.rs b/tests/crashes/153947.rs new file mode 100644 index 0000000000000..39bc8c074cfc0 --- /dev/null +++ b/tests/crashes/153947.rs @@ -0,0 +1,10 @@ +//@ known-bug: #153947 +#![expect(drop_bounds)] +pub struct Thing(T) where [T]: Sized, Self: Drop; +impl Drop for Thing where [T]: Sized, Self: Drop { + fn drop(&mut self) {} +} +impl Drop for Thing where [T]: Sized, Self: Drop { + fn drop(&mut self) {} +} +fn main() {} diff --git a/tests/crashes/154296.rs b/tests/crashes/154296.rs new file mode 100644 index 0000000000000..d904a4d82e426 --- /dev/null +++ b/tests/crashes/154296.rs @@ -0,0 +1,12 @@ +//@ known-bug: #154296 +//@ edition: 2024 +mod m1 { + mod inner { + pub struct S; + } + pub use inner::*; + #[derive(Debug)] + pub struct S; +} +use m1::*; +use S; diff --git a/tests/crashes/154779.rs b/tests/crashes/154779.rs new file mode 100644 index 0000000000000..e6c03e88b0b90 --- /dev/null +++ b/tests/crashes/154779.rs @@ -0,0 +1,4 @@ +//@ known-bug: #154779 +struct Data([[&'static str]; 1]); +const _: &'static Data = &*(&[] as *const Data) ; +fn main() {} diff --git a/tests/crashes/154782.rs b/tests/crashes/154782.rs new file mode 100644 index 0000000000000..d5fdfb84b48ce --- /dev/null +++ b/tests/crashes/154782.rs @@ -0,0 +1,9 @@ +//@ known-bug: #154782 +//@ edition: 2024 +#![feature(pin_ergonomics)] +use core::pin::Pin; +fn test_idempotency(x: Pin<&mut T>) { + || { + x.poll(loop {}); + }; +} diff --git a/tests/crashes/154871.rs b/tests/crashes/154871.rs new file mode 100644 index 0000000000000..c106028623d75 --- /dev/null +++ b/tests/crashes/154871.rs @@ -0,0 +1,7 @@ +//@ known-bug: #154871 +struct Struct { + b: unsafe<> (), +} +fn main() { + std::ptr::null::; +} diff --git a/tests/crashes/154903.rs b/tests/crashes/154903.rs new file mode 100644 index 0000000000000..63e80d8f9e251 --- /dev/null +++ b/tests/crashes/154903.rs @@ -0,0 +1,7 @@ +//@ known-bug: #154903 +//@ compile-flags: -Zlint-mir +#![feature(guard_patterns)] + +fn a(((x if true, _) | (_, x)): (i32, i32)) {} + +fn main() {} diff --git a/tests/crashes/154963.rs b/tests/crashes/154963.rs new file mode 100644 index 0000000000000..8fafc29c48342 --- /dev/null +++ b/tests/crashes/154963.rs @@ -0,0 +1,10 @@ +//@ known-bug: #154963 +#![feature(extern_types, negative_impls)] + +unsafe extern "C" { + type ExternType; +} + +impl !Unpin for ExternType {} + +fn main() {} diff --git a/tests/crashes/155053.rs b/tests/crashes/155053.rs new file mode 100644 index 0000000000000..31b9ccaf20540 --- /dev/null +++ b/tests/crashes/155053.rs @@ -0,0 +1,11 @@ +//@ known-bug: #155053 +#![feature(pin_ergonomics)] +#![feature(extern_types)] + +unsafe extern "C" { + type ExternType; +} + +impl Unpin for ExternType {} + +fn main() {} diff --git a/tests/crashes/156101.rs b/tests/crashes/156101.rs new file mode 100644 index 0000000000000..c95361fab2ecc --- /dev/null +++ b/tests/crashes/156101.rs @@ -0,0 +1,4 @@ +//@ known-bug: #156101 +fn main() { + format_args!(concat!("𐏿", "{f:?#}")); +} diff --git a/tests/crashes/156288.rs b/tests/crashes/156288.rs new file mode 100644 index 0000000000000..b745cfe063dda --- /dev/null +++ b/tests/crashes/156288.rs @@ -0,0 +1,3 @@ +//@ known-bug: #156288 +#[warn(rust_2021_incompatible_closure_captures)] +const _: () = |b| move || b; diff --git a/tests/crashes/auxiliary/aux132985.rs b/tests/crashes/auxiliary/aux132985.rs deleted file mode 100644 index 7ae5567bdc59d..0000000000000 --- a/tests/crashes/auxiliary/aux132985.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![feature(adt_const_params)] - -use std::marker::ConstParamTy; - -#[derive(Eq, PartialEq, ConstParamTy)] -pub struct Foo; diff --git a/tests/crashes/auxiliary/aux153375.rs b/tests/crashes/auxiliary/aux153375.rs new file mode 100644 index 0000000000000..c5f09489181b6 --- /dev/null +++ b/tests/crashes/auxiliary/aux153375.rs @@ -0,0 +1,6 @@ +pub trait Request { + type A<'a> + where + Self: 'a; + fn f(_: Self::A<'_>) -> impl Sized; +} diff --git a/tests/crashes/auxiliary/overlapping_spans_helper.rs b/tests/crashes/auxiliary/overlapping_spans_helper.rs deleted file mode 100644 index e449fcd36c376..0000000000000 --- a/tests/crashes/auxiliary/overlapping_spans_helper.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Auxiliary lib for the issue 147973 regression test with ICEs due to overlapping spans. - -#[macro_export] -macro_rules! identity { - ($x:ident) => { - $x - }; -} - -#[macro_export] -macro_rules! do_loop { - ($x:ident) => { - for $crate::identity!($x) in $x {} - }; -} diff --git a/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json b/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json index 4b4ffabdc2c95..39ccd60fecfa4 100644 --- a/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json +++ b/tests/debuginfo/pretty-std/lldb_input/windows_gnu.json @@ -91,7 +91,7 @@ "some": { "type": "core::option::Option", "pretty_print": "Some(8)", - "synthetic": "lldb_lookup.synthetic_lookup", + "synthetic": "lldb_lookup.ClangEncodedEnumProvider", "summary": "lldb_lookup.ClangEncodedEnumSummaryProvider", "children": [ { @@ -104,13 +104,12 @@ "none": { "type": "core::option::Option", "pretty_print": "None", - "synthetic": "lldb_lookup.synthetic_lookup", + "synthetic": "lldb_lookup.ClangEncodedEnumProvider", "summary": "lldb_lookup.ClangEncodedEnumSummaryProvider" }, "os_string": { "type": "std::ffi::os_str::OsString", "pretty_print": "\"IAMA OS string \ud83d\ude03\"", - "synthetic": "lldb_lookup.synthetic_lookup", "summary": "lldb_lookup.StdOsStringSummaryProvider", "children": [ { diff --git a/tests/debuginfo/pretty-std/lldb_input/windows_msvc.json b/tests/debuginfo/pretty-std/lldb_input/windows_msvc.json index 2a67d1cfb60b7..1b070b2ad5106 100644 --- a/tests/debuginfo/pretty-std/lldb_input/windows_msvc.json +++ b/tests/debuginfo/pretty-std/lldb_input/windows_msvc.json @@ -114,7 +114,6 @@ "os_string": { "type": "std::ffi::os_str::OsString", "pretty_print": "\"IAMA OS string \ud83d\ude03\"", - "synthetic": "lldb_lookup.synthetic_lookup", "summary": "lldb_lookup.StdOsStringSummaryProvider", "children": [ { diff --git a/tests/run-make/non-unicode-env/non_unicode_env.rs b/tests/run-make/non-unicode-env/non_unicode_env.rs index 3efa4842d94a5..787ccb20e065c 100644 --- a/tests/run-make/non-unicode-env/non_unicode_env.rs +++ b/tests/run-make/non-unicode-env/non_unicode_env.rs @@ -1,4 +1,12 @@ +macro_rules! var_named_via_macro { + () => { + "NON_UNICODE_VAR" + }; +} + fn main() { let _ = env!("NON_UNICODE_VAR"); let _ = option_env!("NON_UNICODE_VAR"); + let _ = env!(var_named_via_macro!()); + let _ = option_env!(var_named_via_macro!()); } diff --git a/tests/run-make/non-unicode-env/non_unicode_env.stderr b/tests/run-make/non-unicode-env/non_unicode_env.stderr index 32868b13f742f..3cfc997b4931e 100644 --- a/tests/run-make/non-unicode-env/non_unicode_env.stderr +++ b/tests/run-make/non-unicode-env/non_unicode_env.stderr @@ -1,14 +1,25 @@ error: environment variable `NON_UNICODE_VAR` is not a valid Unicode string - --> non_unicode_env.rs:2:13 + --> non_unicode_env.rs:8:13 | -2 | let _ = env!("NON_UNICODE_VAR"); +8 | let _ = env!("NON_UNICODE_VAR"); | ^^^^^^^^^^^^^^^^^^^^^^^ error: environment variable `NON_UNICODE_VAR` is not a valid Unicode string - --> non_unicode_env.rs:3:13 + --> non_unicode_env.rs:9:13 | -3 | let _ = option_env!("NON_UNICODE_VAR"); +9 | let _ = option_env!("NON_UNICODE_VAR"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: environment variable `NON_UNICODE_VAR` is not a valid Unicode string + --> non_unicode_env.rs:10:13 + | +10 | let _ = env!(var_named_via_macro!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: environment variable `NON_UNICODE_VAR` is not a valid Unicode string + --> non_unicode_env.rs:11:13 + | +11 | let _ = option_env!(var_named_via_macro!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: aborting due to 4 previous errors diff --git a/tests/rustdoc-gui/headers-color.goml b/tests/rustdoc-gui/headers-color.goml index 688c14c3ee078..7471f222739d6 100644 --- a/tests/rustdoc-gui/headers-color.goml +++ b/tests/rustdoc-gui/headers-color.goml @@ -24,15 +24,14 @@ define-function: ( move-cursor-to: "#impl-Foo" // Then we click on it. click: "a.anchor[href='#impl-Foo']" - assert-css: ( + wait-for-css: ( "#impl-Foo", {"color": |color|, "background-color": |focus_background_color|}, ) click: "a.fn[href='#method.must_use']" - assert-css: ( + wait-for-css: ( "#method\.must_use", {"color": |color|, "background-color": |focus_background_color|}, - ALL, ) go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-css: (".section-header a", {"color": |color|}, ALL) diff --git a/tests/rustdoc-gui/search-about-this-result.goml b/tests/rustdoc-gui/search-about-this-result.goml index ec1df737c8150..c3fea3ba9e5c4 100644 --- a/tests/rustdoc-gui/search-about-this-result.goml +++ b/tests/rustdoc-gui/search-about-this-result.goml @@ -1,13 +1,15 @@ // Check the "About this Result" popover. // Try a complex result. + +include: "utils.goml" + go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=scroll_traits::Iterator,(T->bool)->(Extend,Extend)" // These two commands are used to be sure the search will be run. focus: ".search-input" press-key: "Enter" -wait-for: "#search-tabs" -wait-for-false: "#search-tabs .count.loading" +call-function: ("wait-for-search-results", {}) assert-count: ("#search-tabs button", 1) assert-count: (".search-results > a", 1) @@ -32,8 +34,7 @@ go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=F->lib2::WhereWhitespac focus: ".search-input" press-key: "Enter" -wait-for: "#search-tabs" -wait-for-false: "#search-tabs .count.loading" +call-function: ("wait-for-search-results", {}) assert-text: ("//div[@class='type-signature']", "F -> WhereWhitespace") assert-count: ("#search-tabs button", 1) assert-count: (".search-results > a", 1) diff --git a/tests/rustdoc-gui/search-error.goml b/tests/rustdoc-gui/search-error.goml index 4d7c2263fd123..5d2ad41dc5615 100644 --- a/tests/rustdoc-gui/search-error.goml +++ b/tests/rustdoc-gui/search-error.goml @@ -8,7 +8,7 @@ define-function: ( [theme, error_background], block { call-function: ("switch-theme", {"theme": |theme|}) - wait-for-false: "#search-tabs .count.loading" + call-function: ("wait-for-search-results", {}) wait-for: "#search .error code" assert-css: ("#search .error code", {"background-color": |error_background|}) } diff --git a/tests/rustdoc-gui/search-filter.goml b/tests/rustdoc-gui/search-filter.goml index 7d0facfb7202b..86893b7867d2f 100644 --- a/tests/rustdoc-gui/search-filter.goml +++ b/tests/rustdoc-gui/search-filter.goml @@ -8,9 +8,7 @@ assert-text: ("#results .externcrate", "test_docs") wait-for: "#crate-search" // We now want to change the crate filter to "lib2". click: "#crate-search option[value='lib2']" -// Waiting for the search results to appear... -wait-for: "#search-tabs" -wait-for-false: "#search-tabs .count.loading" +call-function: ("wait-for-search-results", {}) assert-document-property: ({"URL": "&filter-crate="}, CONTAINS) // We check that there is no more "test_docs" appearing. assert-false: "#results .externcrate" @@ -30,9 +28,7 @@ assert-property: ("#crate-search", {"value": "lib2"}) // Selecting back "All crates" click: "#crate-search option[value='all crates']" -// Waiting for the search results to appear... -wait-for: "#search-tabs" -wait-for-false: "#search-tabs .count.loading" +call-function: ("wait-for-search-results", {}) assert-property: ("#crate-search", {"value": "all crates"}) // Checking that the URL parameter is taken into account for crate filtering. diff --git a/tests/rustdoc-gui/search-form-elements.goml b/tests/rustdoc-gui/search-form-elements.goml index fdf0afb7e8f72..a1e44032bff70 100644 --- a/tests/rustdoc-gui/search-form-elements.goml +++ b/tests/rustdoc-gui/search-form-elements.goml @@ -1,8 +1,7 @@ // This test ensures that the elements in ".search-form" have the expected display. include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=test" -wait-for: "#search-tabs" // Waiting for the search.js to load. -wait-for-false: "#search-tabs .count.loading" +call-function: ("wait-for-search-results", {}) show-text: true define-function: ( @@ -120,11 +119,9 @@ call-function: ( // Check that search input correctly decodes form encoding. go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a+b" -wait-for: "#search-tabs" // Waiting for the search.js to load. -wait-for-false: "#search-tabs .count.loading" +call-function: ("wait-for-search-results", {}) assert-property: (".search-input", { "value": "a b" }) // Check that literal + is not treated as space. go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a%2Bb" -wait-for: "#search-tabs" // Waiting for the search.js to load. -wait-for-false: "#search-tabs .count.loading" +call-function: ("wait-for-search-results", {}) assert-property: (".search-input", { "value": "a+b" }) diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml index e5c11651bd27d..fa7b0658c0923 100644 --- a/tests/rustdoc-gui/search-result-color.goml +++ b/tests/rustdoc-gui/search-result-color.goml @@ -13,9 +13,7 @@ define-function: ( block { call-function: ("switch-theme", {"theme": |theme|}) - // Waiting for the search results to appear... - wait-for: "#search-tabs" - wait-for-false: "#search-tabs .count.loading" + call-function: ("wait-for-search-results", {}) assert-css: ( "#search-tabs > button > .count", {"color": |count_color|}, diff --git a/tests/rustdoc-gui/search-result-description.goml b/tests/rustdoc-gui/search-result-description.goml index 4ab250b472d0f..a3b07466c69a3 100644 --- a/tests/rustdoc-gui/search-result-description.goml +++ b/tests/rustdoc-gui/search-result-description.goml @@ -1,6 +1,5 @@ // This test is to ensure that the codeblocks are correctly rendered in the search results. +include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=some_more_function" -// Waiting for the search results to appear... -wait-for: "#search-tabs" -wait-for-false: "#search-tabs .count.loading" +call-function: ("wait-for-search-results", {}) assert-text: (".search-results .desc code", "format!") diff --git a/tests/rustdoc-gui/search-result-display.goml b/tests/rustdoc-gui/search-result-display.goml new file mode 100644 index 0000000000000..fa74a7452185c --- /dev/null +++ b/tests/rustdoc-gui/search-result-display.goml @@ -0,0 +1,112 @@ +// ignore-tidy-linelength +// Checks that the search results have the expected width. +include: "utils.goml" +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +set-window-size: (900, 1000) +call-function: ("perform-search", {"query": "test"}) +// The width is returned by "getComputedStyle" which returns the exact number instead of the +// CSS rule which is "50%"... +assert-size: (".search-results div.desc", {"width": 248}) +store-size: (".search-results .result-name .typename", {"width": width}) +set-window-size: (600, 100) +// As counter-intuitive as it may seem, in this width, the width is "100%", which is why +// when computed it's larger. +assert-size: (".search-results div.desc", {"width": 566}) + +// The result set is all on one line. +compare-elements-position-near: ( + ".search-results .result-name .typename", + ".search-results .result-name .path", + {"y": 2}, +) +compare-elements-position-near-false: ( + ".search-results .result-name .typename", + ".search-results .result-name .path", + {"x": 5}, +) +// The width of the "typename" isn't fixed anymore in this display mode. +store-size: (".search-results .result-name .typename", {"width": new_width}) +assert: |new_width| < |width| - 10 + +store-value: ( + value, + "SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName", +) +// Check that if the search is too long on mobile, it'll go under the "typename". +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=" + |value| +call-function: ("wait-for-search-results", {}) +compare-elements-position-near: ( + ".search-results .result-name .typename", + ".search-results .result-name .path", + {"y": 2, "x": 0}, +) +compare-elements-size-near: ( + ".search-results .result-name", + ".search-results .result-name .path", + {"width": 8, "height": 8}, +) + +// Check that the crate filter `