mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-16 05:56:56 +00:00
Auto merge of #127998 - matthiaskrgr:rollup-ykp0h5r, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #123196 (Add Process support for UEFI) - #127556 (Replace a long inline "autoref" comment with method docs) - #127693 (Migrate `crate-hash-rustc-version` to `rmake`) - #127866 (Conditionally build `wasm-component-ld` ) - #127918 (Safely enforce thread name requirements) - #127948 (fixes panic error `index out of bounds` in conflicting error) - #127980 (Avoid ref when using format! in compiler) - #127984 (Avoid ref when using format! in src) - #127987 (More accurate suggestion for `-> Box<dyn Trait>` or `-> impl Trait`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
1afc5fd042
@ -456,10 +456,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, '_, 'infcx, 'tcx> {
|
||||
if let Some(def_id) = def_id
|
||||
&& self.infcx.tcx.def_kind(def_id).is_fn_like()
|
||||
&& let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
|
||||
&& let ty::Param(_) =
|
||||
self.infcx.tcx.fn_sig(def_id).skip_binder().skip_binder().inputs()
|
||||
[pos + offset]
|
||||
.kind()
|
||||
&& let Some(arg) = self
|
||||
.infcx
|
||||
.tcx
|
||||
.fn_sig(def_id)
|
||||
.skip_binder()
|
||||
.skip_binder()
|
||||
.inputs()
|
||||
.get(pos + offset)
|
||||
&& let ty::Param(_) = arg.kind()
|
||||
{
|
||||
let place = &self.move_data.move_paths[mpi].place;
|
||||
let ty = place.ty(self.body, self.infcx.tcx).ty;
|
||||
|
@ -505,7 +505,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
|
||||
let nop_inst = fx.bcx.ins().nop();
|
||||
fx.add_comment(
|
||||
nop_inst,
|
||||
format!("virtual call; self arg pass mode: {:?}", &fn_abi.args[0]),
|
||||
format!("virtual call; self arg pass mode: {:?}", fn_abi.args[0]),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -759,7 +759,7 @@ fn link_natively(
|
||||
sess.dcx().abort_if_errors();
|
||||
|
||||
// Invoke the system linker
|
||||
info!("{:?}", &cmd);
|
||||
info!("{cmd:?}");
|
||||
let retry_on_segfault = env::var("RUSTC_RETRY_LINKER_ON_SEGFAULT").is_ok();
|
||||
let unknown_arg_regex =
|
||||
Regex::new(r"(unknown|unrecognized) (command line )?(option|argument)").unwrap();
|
||||
@ -796,7 +796,7 @@ fn link_natively(
|
||||
cmd.arg(arg);
|
||||
}
|
||||
}
|
||||
info!("{:?}", &cmd);
|
||||
info!("{cmd:?}");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -817,7 +817,7 @@ fn link_natively(
|
||||
cmd.arg(arg);
|
||||
}
|
||||
}
|
||||
info!("{:?}", &cmd);
|
||||
info!("{cmd:?}");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -878,7 +878,7 @@ fn link_natively(
|
||||
cmd.arg(arg);
|
||||
}
|
||||
}
|
||||
info!("{:?}", &cmd);
|
||||
info!("{cmd:?}");
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -996,7 +996,7 @@ fn link_natively(
|
||||
sess.dcx().emit_err(errors::UnableToExeLinker {
|
||||
linker_path,
|
||||
error: e,
|
||||
command_formatted: format!("{:?}", &cmd),
|
||||
command_formatted: format!("{cmd:?}"),
|
||||
});
|
||||
}
|
||||
|
||||
@ -1567,7 +1567,7 @@ fn print_native_static_libs(
|
||||
sess.dcx().emit_note(errors::StaticLibraryNativeArtifacts);
|
||||
// Prefix for greppability
|
||||
// Note: This must not be translated as tools are allowed to depend on this exact string.
|
||||
sess.dcx().note(format!("native-static-libs: {}", &lib_args.join(" ")));
|
||||
sess.dcx().note(format!("native-static-libs: {}", lib_args.join(" ")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -328,7 +328,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
sym::link_section => {
|
||||
if let Some(val) = attr.value_str() {
|
||||
if val.as_str().bytes().any(|b| b == 0) {
|
||||
let msg = format!("illegal null byte in link_section value: `{}`", &val);
|
||||
let msg = format!("illegal null byte in link_section value: `{val}`");
|
||||
tcx.dcx().span_err(attr.span, msg);
|
||||
} else {
|
||||
codegen_fn_attrs.link_section = Some(val);
|
||||
@ -726,7 +726,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
|
||||
if *ordinal <= u16::MAX as u128 {
|
||||
Some(ordinal.get() as u16)
|
||||
} else {
|
||||
let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
|
||||
let msg = format!("ordinal value in `link_ordinal` is too large: `{ordinal}`");
|
||||
tcx.dcx()
|
||||
.struct_span_err(attr.span, msg)
|
||||
.with_note("the value may not exceed `u16::MAX`")
|
||||
|
@ -130,7 +130,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {
|
||||
|
||||
let symbol_name = self.symbol_name(cx.tcx()).name;
|
||||
|
||||
debug!("symbol {}", &symbol_name);
|
||||
debug!("symbol {symbol_name}");
|
||||
|
||||
match *self {
|
||||
MonoItem::Static(def_id) => {
|
||||
|
@ -253,7 +253,7 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok
|
||||
|
||||
for Attribute { id: Identifier { name: attr_name }, .. } in attributes {
|
||||
let snake_name = Ident::new(
|
||||
&format!("{}{}", &crate_prefix, &attr_name.replace('-', "_")),
|
||||
&format!("{crate_prefix}{}", attr_name.replace('-', "_")),
|
||||
resource_str.span(),
|
||||
);
|
||||
if !previous_attrs.insert(snake_name.clone()) {
|
||||
|
@ -651,7 +651,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
|
||||
self.path_segment.hir_id,
|
||||
num_params_to_take,
|
||||
);
|
||||
debug!("suggested_args: {:?}", &suggested_args);
|
||||
debug!("suggested_args: {suggested_args:?}");
|
||||
|
||||
match self.angle_brackets {
|
||||
AngleBrackets::Missing => {
|
||||
|
@ -249,7 +249,7 @@ fn check_explicit_predicates<'tcx>(
|
||||
let explicit_predicates = explicit_map.explicit_predicates_of(tcx, def_id);
|
||||
|
||||
for (outlives_predicate, &span) in explicit_predicates.as_ref().skip_binder() {
|
||||
debug!("outlives_predicate = {:?}", &outlives_predicate);
|
||||
debug!("outlives_predicate = {outlives_predicate:?}");
|
||||
|
||||
// Careful: If we are inferring the effects of a `dyn Trait<..>`
|
||||
// type, then when we look up the predicates for `Trait`,
|
||||
@ -289,12 +289,12 @@ fn check_explicit_predicates<'tcx>(
|
||||
&& let GenericArgKind::Type(ty) = outlives_predicate.0.unpack()
|
||||
&& ty.walk().any(|arg| arg == self_ty.into())
|
||||
{
|
||||
debug!("skipping self ty = {:?}", &ty);
|
||||
debug!("skipping self ty = {ty:?}");
|
||||
continue;
|
||||
}
|
||||
|
||||
let predicate = explicit_predicates.rebind(*outlives_predicate).instantiate(tcx, args);
|
||||
debug!("predicate = {:?}", &predicate);
|
||||
debug!("predicate = {predicate:?}");
|
||||
insert_outlives_predicate(tcx, predicate.0, predicate.1, span, required_predicates);
|
||||
}
|
||||
}
|
||||
|
@ -1265,9 +1265,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
(
|
||||
match parent_pred {
|
||||
None => format!("`{}`", &p),
|
||||
None => format!("`{p}`"),
|
||||
Some(parent_pred) => match format_pred(*parent_pred) {
|
||||
None => format!("`{}`", &p),
|
||||
None => format!("`{p}`"),
|
||||
Some((parent_p, _)) => {
|
||||
if !suggested
|
||||
&& !suggested_bounds.contains(pred)
|
||||
|
@ -112,7 +112,7 @@ pub fn report_unstable(
|
||||
) {
|
||||
let msg = match reason {
|
||||
Some(r) => format!("use of unstable library feature '{feature}': {r}"),
|
||||
None => format!("use of unstable library feature '{}'", &feature),
|
||||
None => format!("use of unstable library feature '{feature}'"),
|
||||
};
|
||||
|
||||
if is_soft {
|
||||
|
@ -2627,7 +2627,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
|
||||
self.prepare_region_info(value);
|
||||
}
|
||||
|
||||
debug!("self.used_region_names: {:?}", &self.used_region_names);
|
||||
debug!("self.used_region_names: {:?}", self.used_region_names);
|
||||
|
||||
let mut empty = true;
|
||||
let mut start_or_continue = |cx: &mut Self, start: &str, cont: &str| {
|
||||
|
@ -14,7 +14,7 @@ pub fn find_self_call<'tcx>(
|
||||
local: Local,
|
||||
block: BasicBlock,
|
||||
) -> Option<(DefId, GenericArgsRef<'tcx>)> {
|
||||
debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator);
|
||||
debug!("find_self_call(local={:?}): terminator={:?}", local, body[block].terminator);
|
||||
if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) =
|
||||
&body[block].terminator
|
||||
{
|
||||
|
@ -2162,92 +2162,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
self.ascribe_types(block, ascriptions);
|
||||
|
||||
// rust-lang/rust#27282: The `autoref` business deserves some
|
||||
// explanation here.
|
||||
//
|
||||
// The intent of the `autoref` flag is that when it is true,
|
||||
// then any pattern bindings of type T will map to a `&T`
|
||||
// within the context of the guard expression, but will
|
||||
// continue to map to a `T` in the context of the arm body. To
|
||||
// avoid surfacing this distinction in the user source code
|
||||
// (which would be a severe change to the language and require
|
||||
// far more revision to the compiler), when `autoref` is true,
|
||||
// then any occurrence of the identifier in the guard
|
||||
// expression will automatically get a deref op applied to it.
|
||||
//
|
||||
// So an input like:
|
||||
//
|
||||
// ```
|
||||
// let place = Foo::new();
|
||||
// match place { foo if inspect(foo)
|
||||
// => feed(foo), ... }
|
||||
// ```
|
||||
//
|
||||
// will be treated as if it were really something like:
|
||||
//
|
||||
// ```
|
||||
// let place = Foo::new();
|
||||
// match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) }
|
||||
// => { let tmp2 = place; feed(tmp2) }, ... }
|
||||
// ```
|
||||
//
|
||||
// And an input like:
|
||||
//
|
||||
// ```
|
||||
// let place = Foo::new();
|
||||
// match place { ref mut foo if inspect(foo)
|
||||
// => feed(foo), ... }
|
||||
// ```
|
||||
//
|
||||
// will be treated as if it were really something like:
|
||||
//
|
||||
// ```
|
||||
// let place = Foo::new();
|
||||
// match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) }
|
||||
// => { let tmp2 = &mut place; feed(tmp2) }, ... }
|
||||
// ```
|
||||
//
|
||||
// In short, any pattern binding will always look like *some*
|
||||
// kind of `&T` within the guard at least in terms of how the
|
||||
// MIR-borrowck views it, and this will ensure that guard
|
||||
// expressions cannot mutate their the match inputs via such
|
||||
// bindings. (It also ensures that guard expressions can at
|
||||
// most *copy* values from such bindings; non-Copy things
|
||||
// cannot be moved via pattern bindings in guard expressions.)
|
||||
//
|
||||
// ----
|
||||
//
|
||||
// Implementation notes (under assumption `autoref` is true).
|
||||
//
|
||||
// To encode the distinction above, we must inject the
|
||||
// temporaries `tmp1` and `tmp2`.
|
||||
//
|
||||
// There are two cases of interest: binding by-value, and binding by-ref.
|
||||
//
|
||||
// 1. Binding by-value: Things are simple.
|
||||
//
|
||||
// * Establishing `tmp1` creates a reference into the
|
||||
// matched place. This code is emitted by
|
||||
// bind_matched_candidate_for_guard.
|
||||
//
|
||||
// * `tmp2` is only initialized "lazily", after we have
|
||||
// checked the guard. Thus, the code that can trigger
|
||||
// moves out of the candidate can only fire after the
|
||||
// guard evaluated to true. This initialization code is
|
||||
// emitted by bind_matched_candidate_for_arm.
|
||||
//
|
||||
// 2. Binding by-reference: Things are tricky.
|
||||
//
|
||||
// * Here, the guard expression wants a `&&` or `&&mut`
|
||||
// into the original input. This means we need to borrow
|
||||
// the reference that we create for the arm.
|
||||
// * So we eagerly create the reference for the arm and then take a
|
||||
// reference to that.
|
||||
// Lower an instance of the arm guard (if present) for this candidate,
|
||||
// and then perform bindings for the arm body.
|
||||
if let Some((arm, match_scope)) = arm_match_scope
|
||||
&& let Some(guard) = arm.guard
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
|
||||
// Bindings for guards require some extra handling to automatically
|
||||
// insert implicit references/dereferences.
|
||||
self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone());
|
||||
let guard_frame = GuardFrame {
|
||||
locals: bindings.clone().map(|b| GuardFrameLocal::new(b.var_id)).collect(),
|
||||
@ -2387,6 +2310,82 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Binding for guards is a bit different from binding for the arm body,
|
||||
/// because an extra layer of implicit reference/dereference is added.
|
||||
///
|
||||
/// The idea is that any pattern bindings of type T will map to a `&T` within
|
||||
/// the context of the guard expression, but will continue to map to a `T`
|
||||
/// in the context of the arm body. To avoid surfacing this distinction in
|
||||
/// the user source code (which would be a severe change to the language and
|
||||
/// require far more revision to the compiler), any occurrence of the
|
||||
/// identifier in the guard expression will automatically get a deref op
|
||||
/// applied to it. (See the caller of [`Self::is_bound_var_in_guard`].)
|
||||
///
|
||||
/// So an input like:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// let place = Foo::new();
|
||||
/// match place { foo if inspect(foo)
|
||||
/// => feed(foo), ... }
|
||||
/// ```
|
||||
///
|
||||
/// will be treated as if it were really something like:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// let place = Foo::new();
|
||||
/// match place { Foo { .. } if { let tmp1 = &place; inspect(*tmp1) }
|
||||
/// => { let tmp2 = place; feed(tmp2) }, ... }
|
||||
/// ```
|
||||
///
|
||||
/// And an input like:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// let place = Foo::new();
|
||||
/// match place { ref mut foo if inspect(foo)
|
||||
/// => feed(foo), ... }
|
||||
/// ```
|
||||
///
|
||||
/// will be treated as if it were really something like:
|
||||
///
|
||||
/// ```ignore (illustrative)
|
||||
/// let place = Foo::new();
|
||||
/// match place { Foo { .. } if { let tmp1 = & &mut place; inspect(*tmp1) }
|
||||
/// => { let tmp2 = &mut place; feed(tmp2) }, ... }
|
||||
/// ```
|
||||
/// ---
|
||||
///
|
||||
/// ## Implementation notes
|
||||
///
|
||||
/// To encode the distinction above, we must inject the
|
||||
/// temporaries `tmp1` and `tmp2`.
|
||||
///
|
||||
/// There are two cases of interest: binding by-value, and binding by-ref.
|
||||
///
|
||||
/// 1. Binding by-value: Things are simple.
|
||||
///
|
||||
/// * Establishing `tmp1` creates a reference into the
|
||||
/// matched place. This code is emitted by
|
||||
/// [`Self::bind_matched_candidate_for_guard`].
|
||||
///
|
||||
/// * `tmp2` is only initialized "lazily", after we have
|
||||
/// checked the guard. Thus, the code that can trigger
|
||||
/// moves out of the candidate can only fire after the
|
||||
/// guard evaluated to true. This initialization code is
|
||||
/// emitted by [`Self::bind_matched_candidate_for_arm_body`].
|
||||
///
|
||||
/// 2. Binding by-reference: Things are tricky.
|
||||
///
|
||||
/// * Here, the guard expression wants a `&&` or `&&mut`
|
||||
/// into the original input. This means we need to borrow
|
||||
/// the reference that we create for the arm.
|
||||
/// * So we eagerly create the reference for the arm and then take a
|
||||
/// reference to that.
|
||||
///
|
||||
/// ---
|
||||
///
|
||||
/// See these PRs for some historical context:
|
||||
/// - <https://github.com/rust-lang/rust/pull/49870> (introduction of autoref)
|
||||
/// - <https://github.com/rust-lang/rust/pull/59114> (always use autoref)
|
||||
fn bind_matched_candidate_for_guard<'b>(
|
||||
&mut self,
|
||||
block: BasicBlock,
|
||||
@ -2418,10 +2417,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
);
|
||||
match binding.binding_mode.0 {
|
||||
ByRef::No => {
|
||||
// The arm binding will be by value, so for the guard binding
|
||||
// just take a shared reference to the matched place.
|
||||
let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source);
|
||||
self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
|
||||
}
|
||||
ByRef::Yes(mutbl) => {
|
||||
// The arm binding will be by reference, so eagerly create it now.
|
||||
let value_for_arm = self.storage_live_binding(
|
||||
block,
|
||||
binding.var_id,
|
||||
@ -2433,6 +2435,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let rvalue =
|
||||
Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source);
|
||||
self.cfg.push_assign(block, source_info, value_for_arm, rvalue);
|
||||
// For the guard binding, take a shared reference to that reference.
|
||||
let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm);
|
||||
self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
|
||||
}
|
||||
|
@ -688,7 +688,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, '_, 'tcx> {
|
||||
let init_loc_map = &move_data.init_loc_map;
|
||||
let rev_lookup = &move_data.rev_lookup;
|
||||
|
||||
debug!("initializes move_indexes {:?}", &init_loc_map[location]);
|
||||
debug!("initializes move_indexes {:?}", init_loc_map[location]);
|
||||
trans.gen_all(init_loc_map[location].iter().copied());
|
||||
|
||||
if let mir::StatementKind::StorageDead(local) = stmt.kind {
|
||||
|
@ -102,7 +102,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
| StatementKind::Nop => (),
|
||||
|
||||
StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
|
||||
bug!("{:?} not found in this MIR phase!", &statement.kind)
|
||||
bug!("{:?} not found in this MIR phase!", statement.kind)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,11 +106,11 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
|
||||
let parent = BasicBlock::from_usize(i);
|
||||
let Some(opt_data) = evaluate_candidate(tcx, body, parent) else { continue };
|
||||
|
||||
if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_data)) {
|
||||
if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {opt_data:?}")) {
|
||||
break;
|
||||
}
|
||||
|
||||
trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_data);
|
||||
trace!("SUCCESS: found optimization possibility to apply: {opt_data:?}");
|
||||
|
||||
should_cleanup = true;
|
||||
|
||||
|
@ -904,7 +904,7 @@ impl<Cx: PatCx> Constructor<Cx> {
|
||||
// be careful to detect strings here. However a string literal pattern will never
|
||||
// be reported as a non-exhaustiveness witness, so we can ignore this issue.
|
||||
Ref => {
|
||||
write!(f, "&{:?}", &fields.next().unwrap())?;
|
||||
write!(f, "&{:?}", fields.next().unwrap())?;
|
||||
}
|
||||
Slice(slice) => {
|
||||
write!(f, "[")?;
|
||||
|
@ -149,7 +149,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
BuiltinLintDiag::AmbiguousGlobImports { diag },
|
||||
);
|
||||
} else {
|
||||
let mut err = struct_span_code_err!(self.dcx(), diag.span, E0659, "{}", &diag.msg);
|
||||
let mut err = struct_span_code_err!(self.dcx(), diag.span, E0659, "{}", diag.msg);
|
||||
report_ambiguity_error(&mut err, diag);
|
||||
err.emit();
|
||||
}
|
||||
@ -798,7 +798,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
}
|
||||
ResolutionError::FailedToResolve { segment, label, suggestion, module } => {
|
||||
let mut err =
|
||||
struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {}", &label);
|
||||
struct_span_code_err!(self.dcx(), span, E0433, "failed to resolve: {label}");
|
||||
err.span_label(span, label);
|
||||
|
||||
if let Some((suggestions, msg, applicability)) = suggestion {
|
||||
@ -2893,7 +2893,7 @@ fn show_candidates(
|
||||
""
|
||||
};
|
||||
candidate.0 =
|
||||
format!("{add_use}{}{append}{trailing}{additional_newline}", &candidate.0);
|
||||
format!("{add_use}{}{append}{trailing}{additional_newline}", candidate.0);
|
||||
}
|
||||
|
||||
match mode {
|
||||
|
@ -694,7 +694,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
||||
.collect::<Vec<_>>();
|
||||
let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
|
||||
|
||||
let mut diag = struct_span_code_err!(self.dcx(), span, E0432, "{}", &msg);
|
||||
let mut diag = struct_span_code_err!(self.dcx(), span, E0432, "{msg}");
|
||||
|
||||
if let Some((_, UnresolvedImportError { note: Some(note), .. })) = errors.iter().last() {
|
||||
diag.note(note.clone());
|
||||
|
@ -339,7 +339,7 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen
|
||||
}
|
||||
}
|
||||
|
||||
debug!("path_str: {:?}\nstripped segments: {:?}", path_str, &stripped_segments);
|
||||
debug!("path_str: {path_str:?}\nstripped segments: {stripped_segments:?}");
|
||||
|
||||
let stripped_path = stripped_segments.join("::");
|
||||
|
||||
|
@ -238,12 +238,12 @@ fn encode_predicate<'tcx>(
|
||||
match predicate.as_ref().skip_binder() {
|
||||
ty::ExistentialPredicate::Trait(trait_ref) => {
|
||||
let name = encode_ty_name(tcx, trait_ref.def_id);
|
||||
let _ = write!(s, "u{}{}", name.len(), &name);
|
||||
let _ = write!(s, "u{}{}", name.len(), name);
|
||||
s.push_str(&encode_args(tcx, trait_ref.args, trait_ref.def_id, true, dict, options));
|
||||
}
|
||||
ty::ExistentialPredicate::Projection(projection) => {
|
||||
let name = encode_ty_name(tcx, projection.def_id);
|
||||
let _ = write!(s, "u{}{}", name.len(), &name);
|
||||
let _ = write!(s, "u{}{}", name.len(), name);
|
||||
s.push_str(&encode_args(tcx, projection.args, projection.def_id, true, dict, options));
|
||||
match projection.term.unpack() {
|
||||
TermKind::Ty(ty) => s.push_str(&encode_ty(tcx, ty, dict, options)),
|
||||
@ -258,7 +258,7 @@ fn encode_predicate<'tcx>(
|
||||
}
|
||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||
let name = encode_ty_name(tcx, *def_id);
|
||||
let _ = write!(s, "u{}{}", name.len(), &name);
|
||||
let _ = write!(s, "u{}{}", name.len(), name);
|
||||
}
|
||||
};
|
||||
compress(dict, DictKey::Predicate(*predicate.as_ref().skip_binder()), &mut s);
|
||||
@ -416,7 +416,7 @@ pub fn encode_ty<'tcx>(
|
||||
// A<array-length><element-type>
|
||||
let len = len.eval_target_usize(tcx, ty::ParamEnv::reveal_all());
|
||||
let mut s = String::from("A");
|
||||
let _ = write!(s, "{}", &len);
|
||||
let _ = write!(s, "{len}");
|
||||
s.push_str(&encode_ty(tcx, *ty0, dict, options));
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
typeid.push_str(&s);
|
||||
@ -492,13 +492,13 @@ pub fn encode_ty<'tcx>(
|
||||
// calling convention (or extern types [i.e., ty::Foreign]) as <length><name>, where
|
||||
// <name> is <unscoped-name>.
|
||||
let name = tcx.item_name(def_id).to_string();
|
||||
let _ = write!(s, "{}{}", name.len(), &name);
|
||||
let _ = write!(s, "{}{}", name.len(), name);
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
} else {
|
||||
// u<length><name>[I<element-type1..element-typeN>E], where <element-type> is
|
||||
// <subst>, as vendor extended type.
|
||||
let name = encode_ty_name(tcx, def_id);
|
||||
let _ = write!(s, "u{}{}", name.len(), &name);
|
||||
let _ = write!(s, "u{}{}", name.len(), name);
|
||||
s.push_str(&encode_args(tcx, args, def_id, false, dict, options));
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
}
|
||||
@ -530,7 +530,7 @@ pub fn encode_ty<'tcx>(
|
||||
}
|
||||
} else {
|
||||
let name = tcx.item_name(*def_id).to_string();
|
||||
let _ = write!(s, "{}{}", name.len(), &name);
|
||||
let _ = write!(s, "{}{}", name.len(), name);
|
||||
}
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
typeid.push_str(&s);
|
||||
@ -542,7 +542,7 @@ pub fn encode_ty<'tcx>(
|
||||
// as vendor extended type.
|
||||
let mut s = String::new();
|
||||
let name = encode_ty_name(tcx, *def_id);
|
||||
let _ = write!(s, "u{}{}", name.len(), &name);
|
||||
let _ = write!(s, "u{}{}", name.len(), name);
|
||||
s.push_str(&encode_args(tcx, args, *def_id, false, dict, options));
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
typeid.push_str(&s);
|
||||
@ -553,7 +553,7 @@ pub fn encode_ty<'tcx>(
|
||||
// as vendor extended type.
|
||||
let mut s = String::new();
|
||||
let name = encode_ty_name(tcx, *def_id);
|
||||
let _ = write!(s, "u{}{}", name.len(), &name);
|
||||
let _ = write!(s, "u{}{}", name.len(), name);
|
||||
let parent_args = tcx.mk_args(args.as_coroutine_closure().parent_args());
|
||||
s.push_str(&encode_args(tcx, parent_args, *def_id, false, dict, options));
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
@ -565,7 +565,7 @@ pub fn encode_ty<'tcx>(
|
||||
// as vendor extended type.
|
||||
let mut s = String::new();
|
||||
let name = encode_ty_name(tcx, *def_id);
|
||||
let _ = write!(s, "u{}{}", name.len(), &name);
|
||||
let _ = write!(s, "u{}{}", name.len(), name);
|
||||
// Encode parent args only
|
||||
s.push_str(&encode_args(
|
||||
tcx,
|
||||
@ -588,7 +588,7 @@ pub fn encode_ty<'tcx>(
|
||||
s.push('E');
|
||||
compress(dict, DictKey::Ty(Ty::new_imm_ref(tcx, *region, *ty0), TyQ::None), &mut s);
|
||||
if ty.is_mutable_ptr() {
|
||||
s = format!("{}{}", "U3mut", &s);
|
||||
s = format!("{}{}", "U3mut", s);
|
||||
compress(dict, DictKey::Ty(ty, TyQ::Mut), &mut s);
|
||||
}
|
||||
typeid.push_str(&s);
|
||||
@ -600,10 +600,10 @@ pub fn encode_ty<'tcx>(
|
||||
let mut s = String::new();
|
||||
s.push_str(&encode_ty(tcx, *ptr_ty, dict, options));
|
||||
if !ty.is_mutable_ptr() {
|
||||
s = format!("{}{}", "K", &s);
|
||||
s = format!("{}{}", "K", s);
|
||||
compress(dict, DictKey::Ty(*ptr_ty, TyQ::Const), &mut s);
|
||||
};
|
||||
s = format!("{}{}", "P", &s);
|
||||
s = format!("{}{}", "P", s);
|
||||
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
|
||||
typeid.push_str(&s);
|
||||
}
|
||||
@ -722,7 +722,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
|
||||
s.push('C');
|
||||
s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64()));
|
||||
let crate_name = tcx.crate_name(def_path.krate).to_string();
|
||||
let _ = write!(s, "{}{}", crate_name.len(), &crate_name);
|
||||
let _ = write!(s, "{}{}", crate_name.len(), crate_name);
|
||||
|
||||
// Disambiguators and names
|
||||
def_path.data.reverse();
|
||||
|
@ -1793,25 +1793,42 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
err.children.clear();
|
||||
|
||||
let span = obligation.cause.span;
|
||||
if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
&& snip.starts_with("dyn ")
|
||||
{
|
||||
err.span_suggestion(
|
||||
span.with_hi(span.lo() + BytePos(4)),
|
||||
"return an `impl Trait` instead of a `dyn Trait`, \
|
||||
if all returned values are the same type",
|
||||
"impl ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
|
||||
let body = self.tcx.hir().body_owned_by(obligation.cause.body_id);
|
||||
|
||||
let mut visitor = ReturnsVisitor::default();
|
||||
visitor.visit_body(&body);
|
||||
|
||||
let mut sugg =
|
||||
vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())];
|
||||
let (pre, impl_span) = if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
&& snip.starts_with("dyn ")
|
||||
{
|
||||
("", span.with_hi(span.lo() + BytePos(4)))
|
||||
} else {
|
||||
("dyn ", span.shrink_to_lo())
|
||||
};
|
||||
let alternatively = if visitor
|
||||
.returns
|
||||
.iter()
|
||||
.map(|expr| self.typeck_results.as_ref().unwrap().expr_ty_adjusted_opt(expr))
|
||||
.collect::<FxHashSet<_>>()
|
||||
.len()
|
||||
<= 1
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
impl_span,
|
||||
"consider returning an `impl Trait` instead of a `dyn Trait`",
|
||||
"impl ",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
"alternatively, "
|
||||
} else {
|
||||
err.help("if there were a single returned type, you could use `impl Trait` instead");
|
||||
""
|
||||
};
|
||||
|
||||
let mut sugg = vec![
|
||||
(span.shrink_to_lo(), format!("Box<{pre}")),
|
||||
(span.shrink_to_hi(), ">".to_string()),
|
||||
];
|
||||
sugg.extend(visitor.returns.into_iter().flat_map(|expr| {
|
||||
let span =
|
||||
expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span);
|
||||
@ -1837,7 +1854,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
}));
|
||||
|
||||
err.multipart_suggestion(
|
||||
"box the return type, and wrap all of the returned values in `Box::new`",
|
||||
format!(
|
||||
"{alternatively}box the return type, and wrap all of the returned values in \
|
||||
`Box::new`",
|
||||
),
|
||||
sugg,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
|
@ -65,15 +65,13 @@ impl<I: Interner> fmt::Debug for ConstKind<I> {
|
||||
|
||||
match self {
|
||||
Param(param) => write!(f, "{param:?}"),
|
||||
Infer(var) => write!(f, "{:?}", &var),
|
||||
Infer(var) => write!(f, "{var:?}"),
|
||||
Bound(debruijn, var) => crate::debug_bound_var(f, *debruijn, var),
|
||||
Placeholder(placeholder) => write!(f, "{placeholder:?}"),
|
||||
Unevaluated(uv) => {
|
||||
write!(f, "{:?}", &uv)
|
||||
}
|
||||
Value(ty, valtree) => write!(f, "({valtree:?}: {:?})", &ty),
|
||||
Unevaluated(uv) => write!(f, "{uv:?}"),
|
||||
Value(ty, valtree) => write!(f, "({valtree:?}: {ty:?})"),
|
||||
Error(_) => write!(f, "{{const error}}"),
|
||||
Expr(expr) => write!(f, "{:?}", &expr),
|
||||
Expr(expr) => write!(f, "{expr:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -232,7 +232,7 @@ impl<I: Interner> fmt::Debug for RegionKind<I> {
|
||||
|
||||
ReStatic => f.write_str("'static"),
|
||||
|
||||
ReVar(vid) => write!(f, "{:?}", &vid),
|
||||
ReVar(vid) => write!(f, "{vid:?}"),
|
||||
|
||||
RePlaceholder(placeholder) => write!(f, "{placeholder:?}"),
|
||||
|
||||
|
@ -367,18 +367,16 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
|
||||
}
|
||||
Foreign(d) => f.debug_tuple("Foreign").field(d).finish(),
|
||||
Str => write!(f, "str"),
|
||||
Array(t, c) => write!(f, "[{:?}; {:?}]", &t, &c),
|
||||
Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &t, &p),
|
||||
Array(t, c) => write!(f, "[{t:?}; {c:?}]"),
|
||||
Pat(t, p) => write!(f, "pattern_type!({t:?} is {p:?})"),
|
||||
Slice(t) => write!(f, "[{:?}]", &t),
|
||||
RawPtr(ty, mutbl) => write!(f, "*{} {:?}", mutbl.ptr_str(), ty),
|
||||
Ref(r, t, m) => write!(f, "&{:?} {}{:?}", r, m.prefix_str(), t),
|
||||
FnDef(d, s) => f.debug_tuple("FnDef").field(d).field(&s).finish(),
|
||||
FnPtr(s) => write!(f, "{:?}", &s),
|
||||
FnPtr(s) => write!(f, "{s:?}"),
|
||||
Dynamic(p, r, repr) => match repr {
|
||||
DynKind::Dyn => write!(f, "dyn {:?} + {:?}", &p, &r),
|
||||
DynKind::DynStar => {
|
||||
write!(f, "dyn* {:?} + {:?}", &p, &r)
|
||||
}
|
||||
DynKind::Dyn => write!(f, "dyn {p:?} + {r:?}"),
|
||||
DynKind::DynStar => write!(f, "dyn* {p:?} + {r:?}"),
|
||||
},
|
||||
Closure(d, s) => f.debug_tuple("Closure").field(d).field(&s).finish(),
|
||||
CoroutineClosure(d, s) => f.debug_tuple("CoroutineClosure").field(d).field(&s).finish(),
|
||||
@ -392,7 +390,7 @@ impl<I: Interner> fmt::Debug for TyKind<I> {
|
||||
if count > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{:?}", &ty)?;
|
||||
write!(f, "{ty:?}")?;
|
||||
count += 1;
|
||||
}
|
||||
// unary tuples need a trailing comma
|
||||
@ -1050,7 +1048,7 @@ impl<I: Interner> fmt::Debug for FnSig<I> {
|
||||
if i > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{:?}", &ty)?;
|
||||
write!(f, "{ty:?}")?;
|
||||
}
|
||||
if *c_variadic {
|
||||
if inputs.is_empty() {
|
||||
|
@ -179,7 +179,7 @@ fn pretty_terminator_head<W: Write>(writer: &mut W, terminator: &TerminatorKind)
|
||||
if !expected {
|
||||
write!(writer, "!")?;
|
||||
}
|
||||
write!(writer, "{}, ", &pretty_operand(cond))?;
|
||||
write!(writer, "{}, ", pretty_operand(cond))?;
|
||||
pretty_assert_message(writer, msg)?;
|
||||
write!(writer, ")")
|
||||
}
|
||||
@ -325,7 +325,7 @@ fn pretty_ty_const(ct: &TyConst) -> String {
|
||||
fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
|
||||
match rval {
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
write!(writer, "&raw {}(*{:?})", &pretty_mut(*mutability), place)
|
||||
write!(writer, "&raw {}(*{:?})", pretty_mut(*mutability), place)
|
||||
}
|
||||
Rvalue::Aggregate(aggregate_kind, operands) => {
|
||||
// FIXME: Add pretty_aggregate function that returns a pretty string
|
||||
@ -336,13 +336,13 @@ fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
|
||||
write!(writer, ")")
|
||||
}
|
||||
Rvalue::BinaryOp(bin, op1, op2) => {
|
||||
write!(writer, "{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2))
|
||||
write!(writer, "{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2))
|
||||
}
|
||||
Rvalue::Cast(_, op, ty) => {
|
||||
write!(writer, "{} as {}", pretty_operand(op), ty)
|
||||
}
|
||||
Rvalue::CheckedBinaryOp(bin, op1, op2) => {
|
||||
write!(writer, "Checked{:?}({}, {})", bin, &pretty_operand(op1), pretty_operand(op2))
|
||||
write!(writer, "Checked{:?}({}, {})", bin, pretty_operand(op1), pretty_operand(op2))
|
||||
}
|
||||
Rvalue::CopyForDeref(deref) => {
|
||||
write!(writer, "CopyForDeref({:?})", deref)
|
||||
@ -363,7 +363,7 @@ fn pretty_rvalue<W: Write>(writer: &mut W, rval: &Rvalue) -> io::Result<()> {
|
||||
write!(writer, "{kind}{:?}", place)
|
||||
}
|
||||
Rvalue::Repeat(op, cnst) => {
|
||||
write!(writer, "{} \" \" {}", &pretty_operand(op), &pretty_ty_const(cnst))
|
||||
write!(writer, "{} \" \" {}", pretty_operand(op), pretty_ty_const(cnst))
|
||||
}
|
||||
Rvalue::ShallowInitBox(_, _) => Ok(()),
|
||||
Rvalue::ThreadLocalRef(item) => {
|
||||
|
@ -333,6 +333,7 @@
|
||||
# "rust-analyzer-proc-macro-srv",
|
||||
# "analysis",
|
||||
# "src",
|
||||
# "wasm-component-ld",
|
||||
#]
|
||||
|
||||
# Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation
|
||||
|
@ -56,7 +56,7 @@ hermit-abi = { version = "0.4.0", features = ['rustc-dep-of-std'], public = true
|
||||
wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
|
||||
|
||||
[target.'cfg(target_os = "uefi")'.dependencies]
|
||||
r-efi = { version = "4.2.0", features = ['rustc-dep-of-std'] }
|
||||
r-efi = { version = "4.5.0", features = ['rustc-dep-of-std'] }
|
||||
r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] }
|
||||
|
||||
[features]
|
||||
|
@ -293,6 +293,7 @@
|
||||
#![feature(doc_masked)]
|
||||
#![feature(doc_notable_trait)]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(extended_varargs_abi_support)]
|
||||
#![feature(f128)]
|
||||
#![feature(f16)]
|
||||
#![feature(if_let_guard)]
|
||||
|
@ -12,15 +12,21 @@
|
||||
use r_efi::efi::{self, Guid};
|
||||
use r_efi::protocols::{device_path, device_path_to_text};
|
||||
|
||||
use crate::ffi::OsString;
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::io::{self, const_io_error};
|
||||
use crate::mem::{size_of, MaybeUninit};
|
||||
use crate::os::uefi::{self, env::boot_services, ffi::OsStringExt};
|
||||
use crate::os::uefi::{self, env::boot_services, ffi::OsStrExt, ffi::OsStringExt};
|
||||
use crate::ptr::NonNull;
|
||||
use crate::slice;
|
||||
use crate::sync::atomic::{AtomicPtr, Ordering};
|
||||
use crate::sys_common::wstr::WStrUnits;
|
||||
|
||||
type BootInstallMultipleProtocolInterfaces =
|
||||
unsafe extern "efiapi" fn(_: *mut r_efi::efi::Handle, _: ...) -> r_efi::efi::Status;
|
||||
|
||||
type BootUninstallMultipleProtocolInterfaces =
|
||||
unsafe extern "efiapi" fn(_: r_efi::efi::Handle, _: ...) -> r_efi::efi::Status;
|
||||
|
||||
const BOOT_SERVICES_UNAVAILABLE: io::Error =
|
||||
const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available");
|
||||
|
||||
@ -221,3 +227,192 @@ pub(crate) fn runtime_services() -> Option<NonNull<r_efi::efi::RuntimeServices>>
|
||||
let runtime_services = unsafe { (*system_table.as_ptr()).runtime_services };
|
||||
NonNull::new(runtime_services)
|
||||
}
|
||||
|
||||
pub(crate) struct DevicePath(NonNull<r_efi::protocols::device_path::Protocol>);
|
||||
|
||||
impl DevicePath {
|
||||
pub(crate) fn from_text(p: &OsStr) -> io::Result<Self> {
|
||||
fn inner(
|
||||
p: &OsStr,
|
||||
protocol: NonNull<r_efi::protocols::device_path_from_text::Protocol>,
|
||||
) -> io::Result<DevicePath> {
|
||||
let path_vec = p.encode_wide().chain(Some(0)).collect::<Vec<u16>>();
|
||||
if path_vec[..path_vec.len() - 1].contains(&0) {
|
||||
return Err(const_io_error!(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"strings passed to UEFI cannot contain NULs",
|
||||
));
|
||||
}
|
||||
|
||||
let path =
|
||||
unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) };
|
||||
|
||||
NonNull::new(path).map(DevicePath).ok_or_else(|| {
|
||||
const_io_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path")
|
||||
})
|
||||
}
|
||||
|
||||
static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =
|
||||
AtomicPtr::new(crate::ptr::null_mut());
|
||||
|
||||
if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {
|
||||
if let Ok(protocol) = open_protocol::<r_efi::protocols::device_path_from_text::Protocol>(
|
||||
handle,
|
||||
r_efi::protocols::device_path_from_text::PROTOCOL_GUID,
|
||||
) {
|
||||
return inner(p, protocol);
|
||||
}
|
||||
}
|
||||
|
||||
let handles = locate_handles(r_efi::protocols::device_path_from_text::PROTOCOL_GUID)?;
|
||||
for handle in handles {
|
||||
if let Ok(protocol) = open_protocol::<r_efi::protocols::device_path_from_text::Protocol>(
|
||||
handle,
|
||||
r_efi::protocols::device_path_from_text::PROTOCOL_GUID,
|
||||
) {
|
||||
LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release);
|
||||
return inner(p, protocol);
|
||||
}
|
||||
}
|
||||
|
||||
io::Result::Err(const_io_error!(
|
||||
io::ErrorKind::NotFound,
|
||||
"DevicePathFromText Protocol not found"
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol {
|
||||
self.0.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for DevicePath {
|
||||
fn drop(&mut self) {
|
||||
if let Some(bt) = boot_services() {
|
||||
let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
|
||||
unsafe {
|
||||
((*bt.as_ptr()).free_pool)(self.0.as_ptr() as *mut crate::ffi::c_void);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct OwnedProtocol<T> {
|
||||
guid: r_efi::efi::Guid,
|
||||
handle: NonNull<crate::ffi::c_void>,
|
||||
protocol: *mut T,
|
||||
}
|
||||
|
||||
impl<T> OwnedProtocol<T> {
|
||||
// FIXME: Consider using unsafe trait for matching protocol with guid
|
||||
pub(crate) unsafe fn create(protocol: T, mut guid: r_efi::efi::Guid) -> io::Result<Self> {
|
||||
let bt: NonNull<r_efi::efi::BootServices> =
|
||||
boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
|
||||
let protocol: *mut T = Box::into_raw(Box::new(protocol));
|
||||
let mut handle: r_efi::efi::Handle = crate::ptr::null_mut();
|
||||
|
||||
// FIXME: Move into r-efi once extended_varargs_abi_support is stablized
|
||||
let func: BootInstallMultipleProtocolInterfaces =
|
||||
unsafe { crate::mem::transmute((*bt.as_ptr()).install_multiple_protocol_interfaces) };
|
||||
|
||||
let r = unsafe {
|
||||
func(
|
||||
&mut handle,
|
||||
&mut guid as *mut _ as *mut crate::ffi::c_void,
|
||||
protocol as *mut crate::ffi::c_void,
|
||||
crate::ptr::null_mut() as *mut crate::ffi::c_void,
|
||||
)
|
||||
};
|
||||
|
||||
if r.is_error() {
|
||||
drop(unsafe { Box::from_raw(protocol) });
|
||||
return Err(crate::io::Error::from_raw_os_error(r.as_usize()));
|
||||
};
|
||||
|
||||
let handle = NonNull::new(handle)
|
||||
.ok_or(io::const_io_error!(io::ErrorKind::Uncategorized, "found null handle"))?;
|
||||
|
||||
Ok(Self { guid, handle, protocol })
|
||||
}
|
||||
|
||||
pub(crate) fn handle(&self) -> NonNull<crate::ffi::c_void> {
|
||||
self.handle
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for OwnedProtocol<T> {
|
||||
fn drop(&mut self) {
|
||||
// Do not deallocate a runtime protocol
|
||||
if let Some(bt) = boot_services() {
|
||||
let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
|
||||
// FIXME: Move into r-efi once extended_varargs_abi_support is stablized
|
||||
let func: BootUninstallMultipleProtocolInterfaces = unsafe {
|
||||
crate::mem::transmute((*bt.as_ptr()).uninstall_multiple_protocol_interfaces)
|
||||
};
|
||||
let status = unsafe {
|
||||
func(
|
||||
self.handle.as_ptr(),
|
||||
&mut self.guid as *mut _ as *mut crate::ffi::c_void,
|
||||
self.protocol as *mut crate::ffi::c_void,
|
||||
crate::ptr::null_mut() as *mut crate::ffi::c_void,
|
||||
)
|
||||
};
|
||||
|
||||
// Leak the protocol in case uninstall fails
|
||||
if status == r_efi::efi::Status::SUCCESS {
|
||||
let _ = unsafe { Box::from_raw(self.protocol) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<T> for OwnedProtocol<T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
unsafe { self.protocol.as_ref().unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct OwnedTable<T> {
|
||||
layout: crate::alloc::Layout,
|
||||
ptr: *mut T,
|
||||
}
|
||||
|
||||
impl<T> OwnedTable<T> {
|
||||
pub(crate) fn from_table_header(hdr: &r_efi::efi::TableHeader) -> Self {
|
||||
let header_size = hdr.header_size as usize;
|
||||
let layout = crate::alloc::Layout::from_size_align(header_size, 8).unwrap();
|
||||
let ptr = unsafe { crate::alloc::alloc(layout) as *mut T };
|
||||
Self { layout, ptr }
|
||||
}
|
||||
|
||||
pub(crate) const fn as_ptr(&self) -> *const T {
|
||||
self.ptr
|
||||
}
|
||||
|
||||
pub(crate) const fn as_mut_ptr(&self) -> *mut T {
|
||||
self.ptr
|
||||
}
|
||||
}
|
||||
|
||||
impl OwnedTable<r_efi::efi::SystemTable> {
|
||||
pub(crate) fn from_table(tbl: *const r_efi::efi::SystemTable) -> Self {
|
||||
let hdr = unsafe { (*tbl).hdr };
|
||||
|
||||
let owned_tbl = Self::from_table_header(&hdr);
|
||||
unsafe {
|
||||
crate::ptr::copy_nonoverlapping(
|
||||
tbl as *const u8,
|
||||
owned_tbl.as_mut_ptr() as *mut u8,
|
||||
hdr.header_size as usize,
|
||||
)
|
||||
};
|
||||
|
||||
owned_tbl
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for OwnedTable<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { crate::alloc::dealloc(self.ptr as *mut u8, self.layout) };
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ pub mod net;
|
||||
pub mod os;
|
||||
#[path = "../unsupported/pipe.rs"]
|
||||
pub mod pipe;
|
||||
#[path = "../unsupported/process.rs"]
|
||||
pub mod process;
|
||||
pub mod stdio;
|
||||
pub mod thread;
|
||||
|
689
library/std/src/sys/pal/uefi/process.rs
Normal file
689
library/std/src/sys/pal/uefi/process.rs
Normal file
@ -0,0 +1,689 @@
|
||||
use r_efi::protocols::simple_text_output;
|
||||
|
||||
use crate::ffi::OsStr;
|
||||
use crate::ffi::OsString;
|
||||
use crate::fmt;
|
||||
use crate::io;
|
||||
use crate::num::NonZero;
|
||||
use crate::num::NonZeroI32;
|
||||
use crate::path::Path;
|
||||
use crate::sys::fs::File;
|
||||
use crate::sys::pipe::AnonPipe;
|
||||
use crate::sys::unsupported;
|
||||
use crate::sys_common::process::{CommandEnv, CommandEnvs};
|
||||
|
||||
pub use crate::ffi::OsString as EnvKey;
|
||||
|
||||
use super::helpers;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Command
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Command {
|
||||
prog: OsString,
|
||||
stdout: Option<Stdio>,
|
||||
stderr: Option<Stdio>,
|
||||
}
|
||||
|
||||
// passed back to std::process with the pipes connected to the child, if any
|
||||
// were requested
|
||||
pub struct StdioPipes {
|
||||
pub stdin: Option<AnonPipe>,
|
||||
pub stdout: Option<AnonPipe>,
|
||||
pub stderr: Option<AnonPipe>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum Stdio {
|
||||
Inherit,
|
||||
Null,
|
||||
MakePipe,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn new(program: &OsStr) -> Command {
|
||||
Command { prog: program.to_os_string(), stdout: None, stderr: None }
|
||||
}
|
||||
|
||||
// FIXME: Implement arguments as reverse of parsing algorithm
|
||||
pub fn arg(&mut self, _arg: &OsStr) {
|
||||
panic!("unsupported")
|
||||
}
|
||||
|
||||
pub fn env_mut(&mut self) -> &mut CommandEnv {
|
||||
panic!("unsupported")
|
||||
}
|
||||
|
||||
pub fn cwd(&mut self, _dir: &OsStr) {
|
||||
panic!("unsupported")
|
||||
}
|
||||
|
||||
pub fn stdin(&mut self, _stdin: Stdio) {
|
||||
panic!("unsupported")
|
||||
}
|
||||
|
||||
pub fn stdout(&mut self, stdout: Stdio) {
|
||||
self.stdout = Some(stdout);
|
||||
}
|
||||
|
||||
pub fn stderr(&mut self, stderr: Stdio) {
|
||||
self.stderr = Some(stderr);
|
||||
}
|
||||
|
||||
pub fn get_program(&self) -> &OsStr {
|
||||
self.prog.as_ref()
|
||||
}
|
||||
|
||||
pub fn get_args(&self) -> CommandArgs<'_> {
|
||||
panic!("unsupported")
|
||||
}
|
||||
|
||||
pub fn get_envs(&self) -> CommandEnvs<'_> {
|
||||
panic!("unsupported")
|
||||
}
|
||||
|
||||
pub fn get_current_dir(&self) -> Option<&Path> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn spawn(
|
||||
&mut self,
|
||||
_default: Stdio,
|
||||
_needs_stdin: bool,
|
||||
) -> io::Result<(Process, StdioPipes)> {
|
||||
unsupported()
|
||||
}
|
||||
|
||||
fn create_pipe(
|
||||
s: Stdio,
|
||||
) -> io::Result<Option<helpers::OwnedProtocol<uefi_command_internal::PipeProtocol>>> {
|
||||
match s {
|
||||
Stdio::MakePipe => unsafe {
|
||||
helpers::OwnedProtocol::create(
|
||||
uefi_command_internal::PipeProtocol::new(),
|
||||
simple_text_output::PROTOCOL_GUID,
|
||||
)
|
||||
}
|
||||
.map(Some),
|
||||
Stdio::Null => unsafe {
|
||||
helpers::OwnedProtocol::create(
|
||||
uefi_command_internal::PipeProtocol::null(),
|
||||
simple_text_output::PROTOCOL_GUID,
|
||||
)
|
||||
}
|
||||
.map(Some),
|
||||
Stdio::Inherit => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
|
||||
let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
|
||||
|
||||
// Setup Stdout
|
||||
let stdout = self.stdout.unwrap_or(Stdio::MakePipe);
|
||||
let stdout = Self::create_pipe(stdout)?;
|
||||
if let Some(con) = stdout {
|
||||
cmd.stdout_init(con)
|
||||
} else {
|
||||
cmd.stdout_inherit()
|
||||
};
|
||||
|
||||
// Setup Stderr
|
||||
let stderr = self.stderr.unwrap_or(Stdio::MakePipe);
|
||||
let stderr = Self::create_pipe(stderr)?;
|
||||
if let Some(con) = stderr {
|
||||
cmd.stderr_init(con)
|
||||
} else {
|
||||
cmd.stderr_inherit()
|
||||
};
|
||||
|
||||
let stat = cmd.start_image()?;
|
||||
|
||||
let stdout = cmd.stdout()?;
|
||||
let stderr = cmd.stderr()?;
|
||||
|
||||
Ok((ExitStatus(stat), stdout, stderr))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AnonPipe> for Stdio {
|
||||
fn from(pipe: AnonPipe) -> Stdio {
|
||||
pipe.diverge()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Stdout> for Stdio {
|
||||
fn from(_: io::Stdout) -> Stdio {
|
||||
// FIXME: This is wrong.
|
||||
// Instead, the Stdio we have here should be a unit struct.
|
||||
panic!("unsupported")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Stderr> for Stdio {
|
||||
fn from(_: io::Stderr) -> Stdio {
|
||||
// FIXME: This is wrong.
|
||||
// Instead, the Stdio we have here should be a unit struct.
|
||||
panic!("unsupported")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<File> for Stdio {
|
||||
fn from(_file: File) -> Stdio {
|
||||
// FIXME: This is wrong.
|
||||
// Instead, the Stdio we have here should be a unit struct.
|
||||
panic!("unsupported")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub struct ExitStatus(r_efi::efi::Status);
|
||||
|
||||
impl ExitStatus {
|
||||
pub fn exit_ok(&self) -> Result<(), ExitStatusError> {
|
||||
if self.0 == r_efi::efi::Status::SUCCESS { Ok(()) } else { Err(ExitStatusError(self.0)) }
|
||||
}
|
||||
|
||||
pub fn code(&self) -> Option<i32> {
|
||||
Some(self.0.as_usize() as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ExitStatus {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let err_str = super::os::error_string(self.0.as_usize());
|
||||
write!(f, "{}", err_str)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ExitStatus {
|
||||
fn default() -> Self {
|
||||
ExitStatus(r_efi::efi::Status::SUCCESS)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct ExitStatusError(r_efi::efi::Status);
|
||||
|
||||
impl fmt::Debug for ExitStatusError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let err_str = super::os::error_string(self.0.as_usize());
|
||||
write!(f, "{}", err_str)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ExitStatus> for ExitStatusError {
|
||||
fn into(self) -> ExitStatus {
|
||||
ExitStatus(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ExitStatusError {
|
||||
pub fn code(self) -> Option<NonZero<i32>> {
|
||||
NonZeroI32::new(self.0.as_usize() as i32)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
pub struct ExitCode(bool);
|
||||
|
||||
impl ExitCode {
|
||||
pub const SUCCESS: ExitCode = ExitCode(false);
|
||||
pub const FAILURE: ExitCode = ExitCode(true);
|
||||
|
||||
pub fn as_i32(&self) -> i32 {
|
||||
self.0 as i32
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for ExitCode {
|
||||
fn from(code: u8) -> Self {
|
||||
match code {
|
||||
0 => Self::SUCCESS,
|
||||
1..=255 => Self::FAILURE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Process(!);
|
||||
|
||||
impl Process {
|
||||
pub fn id(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn kill(&mut self) -> io::Result<()> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CommandArgs<'a> {
|
||||
iter: crate::slice::Iter<'a, OsString>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for CommandArgs<'a> {
|
||||
type Item = &'a OsStr;
|
||||
|
||||
fn next(&mut self) -> Option<&'a OsStr> {
|
||||
self.iter.next().map(|x| x.as_ref())
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for CommandArgs<'a> {
|
||||
fn len(&self) -> usize {
|
||||
self.iter.len()
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.iter.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for CommandArgs<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_list().entries(self.iter.clone()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod uefi_command_internal {
|
||||
use r_efi::protocols::{loaded_image, simple_text_output};
|
||||
|
||||
use super::super::helpers;
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::io::{self, const_io_error};
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::os::uefi::env::{boot_services, image_handle, system_table};
|
||||
use crate::os::uefi::ffi::{OsStrExt, OsStringExt};
|
||||
use crate::ptr::NonNull;
|
||||
use crate::slice;
|
||||
use crate::sys::pal::uefi::helpers::OwnedTable;
|
||||
use crate::sys_common::wstr::WStrUnits;
|
||||
|
||||
pub struct Image {
|
||||
handle: NonNull<crate::ffi::c_void>,
|
||||
stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
|
||||
stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
|
||||
st: OwnedTable<r_efi::efi::SystemTable>,
|
||||
args: Option<Vec<u16>>,
|
||||
}
|
||||
|
||||
impl Image {
|
||||
pub fn load_image(p: &OsStr) -> io::Result<Self> {
|
||||
let path = helpers::DevicePath::from_text(p)?;
|
||||
let boot_services: NonNull<r_efi::efi::BootServices> = boot_services()
|
||||
.ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
|
||||
.cast();
|
||||
let mut child_handle: MaybeUninit<r_efi::efi::Handle> = MaybeUninit::uninit();
|
||||
let image_handle = image_handle();
|
||||
|
||||
let r = unsafe {
|
||||
((*boot_services.as_ptr()).load_image)(
|
||||
r_efi::efi::Boolean::FALSE,
|
||||
image_handle.as_ptr(),
|
||||
path.as_ptr(),
|
||||
crate::ptr::null_mut(),
|
||||
0,
|
||||
child_handle.as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
|
||||
if r.is_error() {
|
||||
Err(io::Error::from_raw_os_error(r.as_usize()))
|
||||
} else {
|
||||
let child_handle = unsafe { child_handle.assume_init() };
|
||||
let child_handle = NonNull::new(child_handle).unwrap();
|
||||
|
||||
let loaded_image: NonNull<loaded_image::Protocol> =
|
||||
helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap();
|
||||
let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table });
|
||||
|
||||
Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_image(&mut self) -> io::Result<r_efi::efi::Status> {
|
||||
self.update_st_crc32()?;
|
||||
|
||||
// Use our system table instead of the default one
|
||||
let loaded_image: NonNull<loaded_image::Protocol> =
|
||||
helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
|
||||
unsafe {
|
||||
(*loaded_image.as_ptr()).system_table = self.st.as_mut_ptr();
|
||||
}
|
||||
|
||||
let boot_services: NonNull<r_efi::efi::BootServices> = boot_services()
|
||||
.ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))?
|
||||
.cast();
|
||||
let mut exit_data_size: usize = 0;
|
||||
let mut exit_data: MaybeUninit<*mut u16> = MaybeUninit::uninit();
|
||||
|
||||
let r = unsafe {
|
||||
((*boot_services.as_ptr()).start_image)(
|
||||
self.handle.as_ptr(),
|
||||
&mut exit_data_size,
|
||||
exit_data.as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
|
||||
// Drop exitdata
|
||||
if exit_data_size != 0 {
|
||||
unsafe {
|
||||
let exit_data = exit_data.assume_init();
|
||||
((*boot_services.as_ptr()).free_pool)(exit_data as *mut crate::ffi::c_void);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn set_stdout(
|
||||
&mut self,
|
||||
handle: r_efi::efi::Handle,
|
||||
protocol: *mut simple_text_output::Protocol,
|
||||
) {
|
||||
unsafe {
|
||||
(*self.st.as_mut_ptr()).console_out_handle = handle;
|
||||
(*self.st.as_mut_ptr()).con_out = protocol;
|
||||
}
|
||||
}
|
||||
|
||||
fn set_stderr(
|
||||
&mut self,
|
||||
handle: r_efi::efi::Handle,
|
||||
protocol: *mut simple_text_output::Protocol,
|
||||
) {
|
||||
unsafe {
|
||||
(*self.st.as_mut_ptr()).standard_error_handle = handle;
|
||||
(*self.st.as_mut_ptr()).std_err = protocol;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
|
||||
self.set_stdout(
|
||||
protocol.handle().as_ptr(),
|
||||
protocol.as_ref() as *const PipeProtocol as *mut simple_text_output::Protocol,
|
||||
);
|
||||
self.stdout = Some(protocol);
|
||||
}
|
||||
|
||||
pub fn stdout_inherit(&mut self) {
|
||||
let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
|
||||
unsafe { self.set_stdout((*st.as_ptr()).console_out_handle, (*st.as_ptr()).con_out) }
|
||||
}
|
||||
|
||||
pub fn stderr_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
|
||||
self.set_stderr(
|
||||
protocol.handle().as_ptr(),
|
||||
protocol.as_ref() as *const PipeProtocol as *mut simple_text_output::Protocol,
|
||||
);
|
||||
self.stderr = Some(protocol);
|
||||
}
|
||||
|
||||
pub fn stderr_inherit(&mut self) {
|
||||
let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
|
||||
unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) }
|
||||
}
|
||||
|
||||
pub fn stderr(&self) -> io::Result<Vec<u8>> {
|
||||
match &self.stderr {
|
||||
Some(stderr) => stderr.as_ref().utf8(),
|
||||
None => Ok(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stdout(&self) -> io::Result<Vec<u8>> {
|
||||
match &self.stdout {
|
||||
Some(stdout) => stdout.as_ref().utf8(),
|
||||
None => Ok(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_args(&mut self, args: &OsStr) {
|
||||
let loaded_image: NonNull<loaded_image::Protocol> =
|
||||
helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
|
||||
|
||||
let mut args = args.encode_wide().collect::<Vec<u16>>();
|
||||
let args_size = (crate::mem::size_of::<u16>() * args.len()) as u32;
|
||||
|
||||
unsafe {
|
||||
(*loaded_image.as_ptr()).load_options =
|
||||
args.as_mut_ptr() as *mut crate::ffi::c_void;
|
||||
(*loaded_image.as_ptr()).load_options_size = args_size;
|
||||
}
|
||||
|
||||
self.args = Some(args);
|
||||
}
|
||||
|
||||
fn update_st_crc32(&mut self) -> io::Result<()> {
|
||||
let bt: NonNull<r_efi::efi::BootServices> = boot_services().unwrap().cast();
|
||||
let st_size = unsafe { (*self.st.as_ptr()).hdr.header_size as usize };
|
||||
let mut crc32: u32 = 0;
|
||||
|
||||
// Set crc to 0 before calcuation
|
||||
unsafe {
|
||||
(*self.st.as_mut_ptr()).hdr.crc32 = 0;
|
||||
}
|
||||
|
||||
let r = unsafe {
|
||||
((*bt.as_ptr()).calculate_crc32)(
|
||||
self.st.as_mut_ptr() as *mut crate::ffi::c_void,
|
||||
st_size,
|
||||
&mut crc32,
|
||||
)
|
||||
};
|
||||
|
||||
if r.is_error() {
|
||||
Err(io::Error::from_raw_os_error(r.as_usize()))
|
||||
} else {
|
||||
unsafe {
|
||||
(*self.st.as_mut_ptr()).hdr.crc32 = crc32;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Image {
|
||||
fn drop(&mut self) {
|
||||
if let Some(bt) = boot_services() {
|
||||
let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
|
||||
unsafe {
|
||||
((*bt.as_ptr()).unload_image)(self.handle.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct PipeProtocol {
|
||||
reset: simple_text_output::ProtocolReset,
|
||||
output_string: simple_text_output::ProtocolOutputString,
|
||||
test_string: simple_text_output::ProtocolTestString,
|
||||
query_mode: simple_text_output::ProtocolQueryMode,
|
||||
set_mode: simple_text_output::ProtocolSetMode,
|
||||
set_attribute: simple_text_output::ProtocolSetAttribute,
|
||||
clear_screen: simple_text_output::ProtocolClearScreen,
|
||||
set_cursor_position: simple_text_output::ProtocolSetCursorPosition,
|
||||
enable_cursor: simple_text_output::ProtocolEnableCursor,
|
||||
mode: *mut simple_text_output::Mode,
|
||||
_buffer: Vec<u16>,
|
||||
}
|
||||
|
||||
impl PipeProtocol {
|
||||
pub fn new() -> Self {
|
||||
let mode = Box::new(simple_text_output::Mode {
|
||||
max_mode: 0,
|
||||
mode: 0,
|
||||
attribute: 0,
|
||||
cursor_column: 0,
|
||||
cursor_row: 0,
|
||||
cursor_visible: r_efi::efi::Boolean::FALSE,
|
||||
});
|
||||
Self {
|
||||
reset: Self::reset,
|
||||
output_string: Self::output_string,
|
||||
test_string: Self::test_string,
|
||||
query_mode: Self::query_mode,
|
||||
set_mode: Self::set_mode,
|
||||
set_attribute: Self::set_attribute,
|
||||
clear_screen: Self::clear_screen,
|
||||
set_cursor_position: Self::set_cursor_position,
|
||||
enable_cursor: Self::enable_cursor,
|
||||
mode: Box::into_raw(mode),
|
||||
_buffer: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn null() -> Self {
|
||||
let mode = Box::new(simple_text_output::Mode {
|
||||
max_mode: 0,
|
||||
mode: 0,
|
||||
attribute: 0,
|
||||
cursor_column: 0,
|
||||
cursor_row: 0,
|
||||
cursor_visible: r_efi::efi::Boolean::FALSE,
|
||||
});
|
||||
Self {
|
||||
reset: Self::reset_null,
|
||||
output_string: Self::output_string_null,
|
||||
test_string: Self::test_string,
|
||||
query_mode: Self::query_mode,
|
||||
set_mode: Self::set_mode,
|
||||
set_attribute: Self::set_attribute,
|
||||
clear_screen: Self::clear_screen,
|
||||
set_cursor_position: Self::set_cursor_position,
|
||||
enable_cursor: Self::enable_cursor,
|
||||
mode: Box::into_raw(mode),
|
||||
_buffer: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn utf8(&self) -> io::Result<Vec<u8>> {
|
||||
OsString::from_wide(&self._buffer)
|
||||
.into_string()
|
||||
.map(Into::into)
|
||||
.map_err(|_| const_io_error!(io::ErrorKind::Other, "utf8 conversion failed"))
|
||||
}
|
||||
|
||||
extern "efiapi" fn reset(
|
||||
proto: *mut simple_text_output::Protocol,
|
||||
_: r_efi::efi::Boolean,
|
||||
) -> r_efi::efi::Status {
|
||||
let proto: *mut PipeProtocol = proto.cast();
|
||||
unsafe {
|
||||
(*proto)._buffer.clear();
|
||||
}
|
||||
r_efi::efi::Status::SUCCESS
|
||||
}
|
||||
|
||||
extern "efiapi" fn reset_null(
|
||||
_: *mut simple_text_output::Protocol,
|
||||
_: r_efi::efi::Boolean,
|
||||
) -> r_efi::efi::Status {
|
||||
r_efi::efi::Status::SUCCESS
|
||||
}
|
||||
|
||||
extern "efiapi" fn output_string(
|
||||
proto: *mut simple_text_output::Protocol,
|
||||
buf: *mut r_efi::efi::Char16,
|
||||
) -> r_efi::efi::Status {
|
||||
let proto: *mut PipeProtocol = proto.cast();
|
||||
let buf_len = unsafe {
|
||||
if let Some(x) = WStrUnits::new(buf) {
|
||||
x.count()
|
||||
} else {
|
||||
return r_efi::efi::Status::INVALID_PARAMETER;
|
||||
}
|
||||
};
|
||||
let buf_slice = unsafe { slice::from_raw_parts(buf, buf_len) };
|
||||
|
||||
unsafe {
|
||||
(*proto)._buffer.extend_from_slice(buf_slice);
|
||||
};
|
||||
|
||||
r_efi::efi::Status::SUCCESS
|
||||
}
|
||||
|
||||
extern "efiapi" fn output_string_null(
|
||||
_: *mut simple_text_output::Protocol,
|
||||
_: *mut r_efi::efi::Char16,
|
||||
) -> r_efi::efi::Status {
|
||||
r_efi::efi::Status::SUCCESS
|
||||
}
|
||||
|
||||
extern "efiapi" fn test_string(
|
||||
_: *mut simple_text_output::Protocol,
|
||||
_: *mut r_efi::efi::Char16,
|
||||
) -> r_efi::efi::Status {
|
||||
r_efi::efi::Status::SUCCESS
|
||||
}
|
||||
|
||||
extern "efiapi" fn query_mode(
|
||||
_: *mut simple_text_output::Protocol,
|
||||
_: usize,
|
||||
_: *mut usize,
|
||||
_: *mut usize,
|
||||
) -> r_efi::efi::Status {
|
||||
r_efi::efi::Status::UNSUPPORTED
|
||||
}
|
||||
|
||||
extern "efiapi" fn set_mode(
|
||||
_: *mut simple_text_output::Protocol,
|
||||
_: usize,
|
||||
) -> r_efi::efi::Status {
|
||||
r_efi::efi::Status::UNSUPPORTED
|
||||
}
|
||||
|
||||
extern "efiapi" fn set_attribute(
|
||||
_: *mut simple_text_output::Protocol,
|
||||
_: usize,
|
||||
) -> r_efi::efi::Status {
|
||||
r_efi::efi::Status::UNSUPPORTED
|
||||
}
|
||||
|
||||
extern "efiapi" fn clear_screen(
|
||||
_: *mut simple_text_output::Protocol,
|
||||
) -> r_efi::efi::Status {
|
||||
r_efi::efi::Status::UNSUPPORTED
|
||||
}
|
||||
|
||||
extern "efiapi" fn set_cursor_position(
|
||||
_: *mut simple_text_output::Protocol,
|
||||
_: usize,
|
||||
_: usize,
|
||||
) -> r_efi::efi::Status {
|
||||
r_efi::efi::Status::UNSUPPORTED
|
||||
}
|
||||
|
||||
extern "efiapi" fn enable_cursor(
|
||||
_: *mut simple_text_output::Protocol,
|
||||
_: r_efi::efi::Boolean,
|
||||
) -> r_efi::efi::Status {
|
||||
r_efi::efi::Status::UNSUPPORTED
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PipeProtocol {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let _ = Box::from_raw(self.mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -161,7 +161,7 @@ mod tests;
|
||||
use crate::any::Any;
|
||||
use crate::cell::{Cell, OnceCell, UnsafeCell};
|
||||
use crate::env;
|
||||
use crate::ffi::{CStr, CString};
|
||||
use crate::ffi::CStr;
|
||||
use crate::fmt;
|
||||
use crate::io;
|
||||
use crate::marker::PhantomData;
|
||||
@ -487,11 +487,7 @@ impl Builder {
|
||||
amt
|
||||
});
|
||||
|
||||
let my_thread = name.map_or_else(Thread::new_unnamed, |name| unsafe {
|
||||
Thread::new(
|
||||
CString::new(name).expect("thread name may not contain interior null bytes"),
|
||||
)
|
||||
});
|
||||
let my_thread = name.map_or_else(Thread::new_unnamed, Thread::new);
|
||||
let their_thread = my_thread.clone();
|
||||
|
||||
let my_packet: Arc<Packet<'scope, T>> = Arc::new(Packet {
|
||||
@ -1299,10 +1295,51 @@ impl ThreadId {
|
||||
/// The internal representation of a `Thread`'s name.
|
||||
enum ThreadName {
|
||||
Main,
|
||||
Other(CString),
|
||||
Other(ThreadNameString),
|
||||
Unnamed,
|
||||
}
|
||||
|
||||
// This module ensures private fields are kept private, which is necessary to enforce the safety requirements.
|
||||
mod thread_name_string {
|
||||
use super::ThreadName;
|
||||
use crate::ffi::{CStr, CString};
|
||||
use core::str;
|
||||
|
||||
/// Like a `String` it's guaranteed UTF-8 and like a `CString` it's null terminated.
|
||||
pub(crate) struct ThreadNameString {
|
||||
inner: CString,
|
||||
}
|
||||
impl core::ops::Deref for ThreadNameString {
|
||||
type Target = CStr;
|
||||
fn deref(&self) -> &CStr {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
impl From<String> for ThreadNameString {
|
||||
fn from(s: String) -> Self {
|
||||
Self {
|
||||
inner: CString::new(s).expect("thread name may not contain interior null bytes"),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl ThreadName {
|
||||
pub fn as_cstr(&self) -> Option<&CStr> {
|
||||
match self {
|
||||
ThreadName::Main => Some(c"main"),
|
||||
ThreadName::Other(other) => Some(other),
|
||||
ThreadName::Unnamed => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_str(&self) -> Option<&str> {
|
||||
// SAFETY: `as_cstr` can only return `Some` for a fixed CStr or a `ThreadNameString`,
|
||||
// which is guaranteed to be UTF-8.
|
||||
self.as_cstr().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(crate) use thread_name_string::ThreadNameString;
|
||||
|
||||
/// The internal representation of a `Thread` handle
|
||||
struct Inner {
|
||||
name: ThreadName, // Guaranteed to be UTF-8
|
||||
@ -1342,25 +1379,20 @@ pub struct Thread {
|
||||
|
||||
impl Thread {
|
||||
/// Used only internally to construct a thread object without spawning.
|
||||
///
|
||||
/// # Safety
|
||||
/// `name` must be valid UTF-8.
|
||||
pub(crate) unsafe fn new(name: CString) -> Thread {
|
||||
unsafe { Self::new_inner(ThreadName::Other(name)) }
|
||||
pub(crate) fn new(name: String) -> Thread {
|
||||
Self::new_inner(ThreadName::Other(name.into()))
|
||||
}
|
||||
|
||||
pub(crate) fn new_unnamed() -> Thread {
|
||||
unsafe { Self::new_inner(ThreadName::Unnamed) }
|
||||
Self::new_inner(ThreadName::Unnamed)
|
||||
}
|
||||
|
||||
// Used in runtime to construct main thread
|
||||
pub(crate) fn new_main() -> Thread {
|
||||
unsafe { Self::new_inner(ThreadName::Main) }
|
||||
Self::new_inner(ThreadName::Main)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// If `name` is `ThreadName::Other(_)`, the contained string must be valid UTF-8.
|
||||
unsafe fn new_inner(name: ThreadName) -> Thread {
|
||||
fn new_inner(name: ThreadName) -> Thread {
|
||||
// We have to use `unsafe` here to construct the `Parker` in-place,
|
||||
// which is required for the UNIX implementation.
|
||||
//
|
||||
@ -1483,15 +1515,11 @@ impl Thread {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[must_use]
|
||||
pub fn name(&self) -> Option<&str> {
|
||||
self.cname().map(|s| unsafe { str::from_utf8_unchecked(s.to_bytes()) })
|
||||
self.inner.name.as_str()
|
||||
}
|
||||
|
||||
fn cname(&self) -> Option<&CStr> {
|
||||
match &self.inner.name {
|
||||
ThreadName::Main => Some(c"main"),
|
||||
ThreadName::Other(other) => Some(&other),
|
||||
ThreadName::Unnamed => None,
|
||||
}
|
||||
self.inner.name.as_cstr()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -695,7 +695,7 @@ fn copy_sanitizers(
|
||||
|| target == "x86_64-apple-ios"
|
||||
{
|
||||
// Update the library’s install name to reflect that it has been renamed.
|
||||
apple_darwin_update_library_name(builder, &dst, &format!("@rpath/{}", &runtime.name));
|
||||
apple_darwin_update_library_name(builder, &dst, &format!("@rpath/{}", runtime.name));
|
||||
// Upon renaming the install name, the code signature of the file will invalidate,
|
||||
// so we will sign it again.
|
||||
apple_darwin_sign_file(builder, &dst);
|
||||
@ -1820,12 +1820,14 @@ impl Step for Assemble {
|
||||
&self_contained_lld_dir.join(exe(name, target_compiler.host)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// In addition to `rust-lld` also install `wasm-component-ld` when
|
||||
// LLD is enabled. This is a relatively small binary that primarily
|
||||
// delegates to the `rust-lld` binary for linking and then runs
|
||||
// logic to create the final binary. This is used by the
|
||||
// `wasm32-wasip2` target of Rust.
|
||||
// In addition to `rust-lld` also install `wasm-component-ld` when
|
||||
// LLD is enabled. This is a relatively small binary that primarily
|
||||
// delegates to the `rust-lld` binary for linking and then runs
|
||||
// logic to create the final binary. This is used by the
|
||||
// `wasm32-wasip2` target of Rust.
|
||||
if builder.build_wasm_component_ld() {
|
||||
let wasm_component_ld_exe =
|
||||
builder.ensure(crate::core::build_steps::tool::WasmComponentLd {
|
||||
compiler: build_compiler,
|
||||
|
@ -1411,7 +1411,7 @@ impl Step for Libunwind {
|
||||
}
|
||||
}
|
||||
}
|
||||
assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir);
|
||||
assert_eq!(cpp_len, count, "Can't get object files from {out_dir:?}");
|
||||
|
||||
cc_cfg.compile("unwind");
|
||||
out_dir
|
||||
|
@ -1414,6 +1414,19 @@ Executed at: {executed_at}"#,
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns whether it's requested that `wasm-component-ld` is built as part
|
||||
/// of the sysroot. This is done either with the `extended` key in
|
||||
/// `config.toml` or with the `tools` set.
|
||||
fn build_wasm_component_ld(&self) -> bool {
|
||||
if self.config.extended {
|
||||
return true;
|
||||
}
|
||||
match &self.config.tools {
|
||||
Some(set) => set.contains("wasm-component-ld"),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the root of the "rootfs" image that this target will be using,
|
||||
/// if one was configured.
|
||||
///
|
||||
|
@ -142,15 +142,15 @@ pub fn find_target(build: &Build, target: TargetSelection) {
|
||||
build.cxx.borrow_mut().insert(target, compiler);
|
||||
}
|
||||
|
||||
build.verbose(|| println!("CC_{} = {:?}", &target.triple, build.cc(target)));
|
||||
build.verbose(|| println!("CFLAGS_{} = {:?}", &target.triple, cflags));
|
||||
build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target)));
|
||||
build.verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple));
|
||||
if let Ok(cxx) = build.cxx(target) {
|
||||
let cxxflags = build.cflags(target, GitRepo::Rustc, CLang::Cxx);
|
||||
build.verbose(|| println!("CXX_{} = {:?}", &target.triple, cxx));
|
||||
build.verbose(|| println!("CXXFLAGS_{} = {:?}", &target.triple, cxxflags));
|
||||
build.verbose(|| println!("CXX_{} = {cxx:?}", target.triple));
|
||||
build.verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple));
|
||||
}
|
||||
if let Some(ar) = ar {
|
||||
build.verbose(|| println!("AR_{} = {:?}", &target.triple, ar));
|
||||
build.verbose(|| println!("AR_{} = {ar:?}", target.triple));
|
||||
build.ar.borrow_mut().insert(target, ar);
|
||||
}
|
||||
|
||||
|
@ -205,4 +205,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
|
||||
severity: ChangeSeverity::Warning,
|
||||
summary: "`debug-logging` option has been removed from the default `tools` profile.",
|
||||
},
|
||||
ChangeInfo {
|
||||
change_id: 127866,
|
||||
severity: ChangeSeverity::Info,
|
||||
summary: "the `wasm-component-ld` tool is now built as part of `build.extended` and can be a member of `build.tools`",
|
||||
},
|
||||
];
|
||||
|
@ -244,7 +244,7 @@ impl<'a> Tarball<'a> {
|
||||
cmd.arg("generate")
|
||||
.arg("--image-dir")
|
||||
.arg(&this.image_dir)
|
||||
.arg(format!("--component-name={}", &component_name));
|
||||
.arg(format!("--component-name={component_name}"));
|
||||
|
||||
if let Some((dir, dirs)) = this.bulk_dirs.split_first() {
|
||||
let mut arg = dir.as_os_str().to_os_string();
|
||||
|
@ -850,7 +850,7 @@ fn resolved_path<'cx>(
|
||||
}
|
||||
}
|
||||
if w.alternate() {
|
||||
write!(w, "{}{:#}", &last.name, last.args.print(cx))?;
|
||||
write!(w, "{}{:#}", last.name, last.args.print(cx))?;
|
||||
} else {
|
||||
let path = if use_absolute {
|
||||
if let Ok((_, _, fqp)) = href(did, cx) {
|
||||
|
@ -9,7 +9,6 @@ run-make/cat-and-grep-sanity-check/Makefile
|
||||
run-make/cdylib-dylib-linkage/Makefile
|
||||
run-make/compiler-lookup-paths-2/Makefile
|
||||
run-make/compiler-rt-works-on-mingw/Makefile
|
||||
run-make/crate-hash-rustc-version/Makefile
|
||||
run-make/cross-lang-lto-clang/Makefile
|
||||
run-make/cross-lang-lto-pgo-smoketest/Makefile
|
||||
run-make/cross-lang-lto-upstream-rlibs/Makefile
|
||||
|
@ -1,38 +0,0 @@
|
||||
# ignore-cross-compile
|
||||
include ../tools.mk
|
||||
|
||||
# Ensure that crates compiled with different rustc versions cannot
|
||||
# be dynamically linked.
|
||||
|
||||
FLAGS := -Cprefer-dynamic -Csymbol-mangling-version=v0
|
||||
UNAME := $(shell uname)
|
||||
ifeq ($(UNAME),Linux)
|
||||
EXT=".so"
|
||||
NM_CMD := nm -D
|
||||
endif
|
||||
ifeq ($(UNAME),Darwin)
|
||||
EXT=".dylib"
|
||||
NM_CMD := nm
|
||||
endif
|
||||
|
||||
ifndef NM_CMD
|
||||
all:
|
||||
exit 0
|
||||
else
|
||||
all:
|
||||
# a.rs is a dylib
|
||||
$(RUSTC) a.rs --crate-type=dylib $(FLAGS)
|
||||
# Write symbols to disk.
|
||||
$(NM_CMD) $(call DYLIB,a) > $(TMPDIR)/symbolsbefore
|
||||
# b.rs is a binary
|
||||
$(RUSTC) b.rs --extern a=$(TMPDIR)/liba$(EXT) --crate-type=bin -Crpath $(FLAGS)
|
||||
$(call RUN,b)
|
||||
# Now re-compile a.rs with another rustc version
|
||||
RUSTC_FORCE_RUSTC_VERSION=deadfeed $(RUSTC) a.rs --crate-type=dylib $(FLAGS)
|
||||
# After compiling with a different rustc version, write symbols to disk again.
|
||||
$(NM_CMD) $(call DYLIB,a) > $(TMPDIR)/symbolsafter
|
||||
# As a sanity check, test if the symbols changed:
|
||||
# If the symbols are identical, there's been an error.
|
||||
if diff $(TMPDIR)/symbolsbefore $(TMPDIR)/symbolsafter; then exit 1; fi
|
||||
$(call FAIL,b)
|
||||
endif
|
57
tests/run-make/crate-hash-rustc-version/rmake.rs
Normal file
57
tests/run-make/crate-hash-rustc-version/rmake.rs
Normal file
@ -0,0 +1,57 @@
|
||||
// Ensure that crates compiled with different rustc versions cannot
|
||||
// be dynamically linked.
|
||||
|
||||
//@ ignore-cross-compile
|
||||
//@ only-unix
|
||||
|
||||
use run_make_support::llvm;
|
||||
use run_make_support::{diff, dynamic_lib_name, is_darwin, run, run_fail, rustc};
|
||||
|
||||
fn llvm_readobj() -> llvm::LlvmReadobj {
|
||||
let mut cmd = llvm::llvm_readobj();
|
||||
if is_darwin() {
|
||||
cmd.symbols();
|
||||
} else {
|
||||
cmd.dynamic_table();
|
||||
}
|
||||
cmd
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let flags = ["-Cprefer-dynamic", "-Csymbol-mangling-version=v0"];
|
||||
|
||||
// a.rs is compiled to a dylib
|
||||
rustc().input("a.rs").crate_type("dylib").args(&flags).run();
|
||||
|
||||
// Store symbols
|
||||
let symbols_before = llvm_readobj().arg(dynamic_lib_name("a")).run().stdout_utf8();
|
||||
|
||||
// b.rs is compiled to a binary
|
||||
rustc()
|
||||
.input("b.rs")
|
||||
.extern_("a", dynamic_lib_name("a"))
|
||||
.crate_type("bin")
|
||||
.arg("-Crpath")
|
||||
.args(&flags)
|
||||
.run();
|
||||
run("b");
|
||||
|
||||
// Now re-compile a.rs with another rustc version
|
||||
rustc()
|
||||
.env("RUSTC_FORCE_RUSTC_VERSION", "deadfeed")
|
||||
.input("a.rs")
|
||||
.crate_type("dylib")
|
||||
.args(&flags)
|
||||
.run();
|
||||
|
||||
// After compiling with a different rustc version, store symbols again.
|
||||
let symbols_after = llvm_readobj().arg(dynamic_lib_name("a")).run().stdout_utf8();
|
||||
|
||||
// As a sanity check, test if the symbols changed:
|
||||
// If the symbols are identical, there's been an error.
|
||||
diff()
|
||||
.expected_text("symbols_before", symbols_before)
|
||||
.actual_text("symbols_after", symbols_after)
|
||||
.run_fail();
|
||||
run_fail("b");
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
extern "C" {
|
||||
fn rust_interesting_average(_: i64, ...) -> f64;
|
||||
}
|
||||
|
||||
fn test<T, U>(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 {
|
||||
unsafe {
|
||||
rust_interesting_average(
|
||||
6, a as f64, b, b as f64, f, c as f64, d, d as f64, e, e as f64, f, g, //~ ERROR use of moved value: `f` [E0382]
|
||||
) as i64
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,25 @@
|
||||
error[E0382]: use of moved value: `f`
|
||||
--> $DIR/move-error-suggest-clone-panic-issue-127915.rs:10:78
|
||||
|
|
||||
LL | fn test<T, U>(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 {
|
||||
| - move occurs because `f` has type `T`, which does not implement the `Copy` trait
|
||||
...
|
||||
LL | 6, a as f64, b, b as f64, f, c as f64, d, d as f64, e, e as f64, f, g,
|
||||
| - value moved here ^ value used here after move
|
||||
|
|
||||
help: if `T` implemented `Clone`, you could clone the value
|
||||
--> $DIR/move-error-suggest-clone-panic-issue-127915.rs:7:9
|
||||
|
|
||||
LL | fn test<T, U>(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 {
|
||||
| ^ consider constraining this type parameter with `Clone`
|
||||
...
|
||||
LL | 6, a as f64, b, b as f64, f, c as f64, d, d as f64, e, e as f64, f, g,
|
||||
| - you could clone this value
|
||||
help: consider restricting type parameter `T`
|
||||
|
|
||||
LL | fn test<T: Copy, U>(a: i64, b: i64, c: i64, d: i64, e: i64, f: T, g: U) -> i64 {
|
||||
| ++++++
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0382`.
|
@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn foo() -> dyn Trait { Struct }
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
||||
|
|
||||
LL | fn foo() -> impl Trait { Struct }
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn foo() -> Box<dyn Trait> { Box::new(Struct) }
|
||||
| ++++ + +++++++++ +
|
||||
@ -19,10 +19,7 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bar() -> dyn Trait {
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn bar() -> impl Trait {
|
||||
| ~~~~
|
||||
= help: if there were a single returned type, you could use `impl Trait` instead
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn bar() -> Box<dyn Trait> {
|
||||
|
@ -48,10 +48,14 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bap() -> Trait { Struct }
|
||||
| ^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
||||
|
|
||||
LL | fn bap() -> Box<Trait> { Box::new(Struct) }
|
||||
| ++++ + +++++++++ +
|
||||
LL | fn bap() -> impl Trait { Struct }
|
||||
| ++++
|
||||
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn bap() -> Box<dyn Trait> { Box::new(Struct) }
|
||||
| +++++++ + +++++++++ +
|
||||
|
||||
error[E0746]: return type cannot have an unboxed trait object
|
||||
--> $DIR/dyn-trait-return-should-be-impl-trait.rs:15:13
|
||||
@ -59,11 +63,11 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn ban() -> dyn Trait { Struct }
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
||||
|
|
||||
LL | fn ban() -> impl Trait { Struct }
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn ban() -> Box<dyn Trait> { Box::new(Struct) }
|
||||
| ++++ + +++++++++ +
|
||||
@ -74,11 +78,11 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bak() -> dyn Trait { unimplemented!() }
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
||||
|
|
||||
LL | fn bak() -> impl Trait { unimplemented!() }
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn bak() -> Box<dyn Trait> { Box::new(unimplemented!()) }
|
||||
| ++++ + +++++++++ +
|
||||
@ -89,10 +93,7 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bal() -> dyn Trait {
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn bal() -> impl Trait {
|
||||
| ~~~~
|
||||
= help: if there were a single returned type, you could use `impl Trait` instead
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn bal() -> Box<dyn Trait> {
|
||||
@ -108,10 +109,7 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bax() -> dyn Trait {
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn bax() -> impl Trait {
|
||||
| ~~~~
|
||||
= help: if there were a single returned type, you could use `impl Trait` instead
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn bax() -> Box<dyn Trait> {
|
||||
@ -263,10 +261,7 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bat() -> dyn Trait {
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn bat() -> impl Trait {
|
||||
| ~~~~
|
||||
= help: if there were a single returned type, you could use `impl Trait` instead
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn bat() -> Box<dyn Trait> {
|
||||
@ -282,10 +277,7 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn bay() -> dyn Trait {
|
||||
| ^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn bay() -> impl Trait {
|
||||
| ~~~~
|
||||
= help: if there were a single returned type, you could use `impl Trait` instead
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn bay() -> Box<dyn Trait> {
|
||||
|
@ -54,10 +54,7 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn car() -> dyn NotObjectSafe {
|
||||
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn car() -> impl NotObjectSafe {
|
||||
| ~~~~
|
||||
= help: if there were a single returned type, you could use `impl Trait` instead
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn car() -> Box<dyn NotObjectSafe> {
|
||||
|
@ -171,11 +171,11 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn hat() -> dyn std::fmt::Display {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
||||
|
|
||||
LL | fn hat() -> impl std::fmt::Display {
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn hat() -> Box<dyn std::fmt::Display> {
|
||||
LL | match 13 {
|
||||
@ -192,11 +192,11 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn pug() -> dyn std::fmt::Display {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
||||
|
|
||||
LL | fn pug() -> impl std::fmt::Display {
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn pug() -> Box<dyn std::fmt::Display> {
|
||||
LL | match 13 {
|
||||
@ -211,10 +211,7 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn man() -> dyn std::fmt::Display {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
|
|
||||
LL | fn man() -> impl std::fmt::Display {
|
||||
| ~~~~
|
||||
= help: if there were a single returned type, you could use `impl Trait` instead
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn man() -> Box<dyn std::fmt::Display> {
|
||||
|
@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | dyn AbstractRenderer
|
||||
| ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
||||
|
|
||||
LL | impl AbstractRenderer
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ Box<dyn AbstractRenderer>
|
||||
LL |
|
||||
|
@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> dyn Fn() + 'a {
|
||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
||||
|
|
||||
LL | fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> impl Fn() + 'a {
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL ~ fn print_on_or_the_other<'a>(a: i32, b: &'a String) -> Box<dyn Fn() + 'a> {
|
||||
LL |
|
||||
|
@ -4,10 +4,14 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Validator<'a> {
|
||||
| ^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
||||
|
|
||||
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box<Validator<'a>> {
|
||||
| ++++ +
|
||||
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> impl Validator<'a> {
|
||||
| ++++
|
||||
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn or<'a>(first: &'static Validator<'a>, second: &'static Validator<'a>) -> Box<dyn Validator<'a>> {
|
||||
| +++++++ +
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
@ -4,11 +4,11 @@ error[E0746]: return type cannot have an unboxed trait object
|
||||
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> dyn Foo<'a> {
|
||||
| ^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
||||
help: return an `impl Trait` instead of a `dyn Trait`, if all returned values are the same type
|
||||
help: consider returning an `impl Trait` instead of a `dyn Trait`
|
||||
|
|
||||
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> impl Foo<'a> {
|
||||
| ~~~~
|
||||
help: box the return type, and wrap all of the returned values in `Box::new`
|
||||
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
|
||||
|
|
||||
LL | fn or<'a>(first: &'static dyn Foo<'a>) -> Box<dyn Foo<'a>> {
|
||||
| ++++ +
|
||||
|
Loading…
Reference in New Issue
Block a user