Merge pull request #4102 from rust-lang/rustup-2024-12-21
Automatic Rustup
This commit is contained in:
commit
268a5f423e
94 changed files with 1150 additions and 774 deletions
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
|
@ -46,7 +46,7 @@ jobs:
|
|||
# If you want to modify CI jobs, take a look at src/ci/github-actions/jobs.yml.
|
||||
calculate_matrix:
|
||||
name: Calculate job matrix
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
outputs:
|
||||
jobs: ${{ steps.jobs.outputs.jobs }}
|
||||
run_type: ${{ steps.jobs.outputs.run_type }}
|
||||
|
|
@ -243,7 +243,7 @@ jobs:
|
|||
# when a workflow is successful listening to webhooks only in our current bors implementation (homu).
|
||||
outcome:
|
||||
name: bors build finished
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
needs: [ calculate_matrix, job ]
|
||||
# !cancelled() executes the job regardless of whether the previous jobs passed or failed
|
||||
if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }}
|
||||
|
|
|
|||
6
.github/workflows/dependencies.yml
vendored
6
.github/workflows/dependencies.yml
vendored
|
|
@ -27,7 +27,7 @@ jobs:
|
|||
not-waiting-on-bors:
|
||||
if: github.repository_owner == 'rust-lang'
|
||||
name: skip if S-waiting-on-bors
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -47,7 +47,7 @@ jobs:
|
|||
if: github.repository_owner == 'rust-lang'
|
||||
name: update dependencies
|
||||
needs: not-waiting-on-bors
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: checkout the source code
|
||||
uses: actions/checkout@v4
|
||||
|
|
@ -94,7 +94,7 @@ jobs:
|
|||
if: github.repository_owner == 'rust-lang'
|
||||
name: amend PR
|
||||
needs: update
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
|
|
|||
|
|
@ -3722,6 +3722,7 @@ dependencies = [
|
|||
"rustc_fluent_macro",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_lexer",
|
||||
"rustc_lint_defs",
|
||||
"rustc_macros",
|
||||
"rustc_serialize",
|
||||
|
|
|
|||
|
|
@ -1322,11 +1322,15 @@ impl Expr {
|
|||
}
|
||||
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
match self.kind {
|
||||
ExprKind::Closure(..) => ExprPrecedence::Closure,
|
||||
match &self.kind {
|
||||
ExprKind::Closure(closure) => {
|
||||
match closure.fn_decl.output {
|
||||
FnRetTy::Default(_) => ExprPrecedence::Jump,
|
||||
FnRetTy::Ty(_) => ExprPrecedence::Unambiguous,
|
||||
}
|
||||
}
|
||||
|
||||
ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Yeet(..)
|
||||
|
|
@ -1360,6 +1364,7 @@ impl Expr {
|
|||
| ExprKind::Block(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::ConstBlock(_)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Field(..)
|
||||
| ExprKind::ForLoop { .. }
|
||||
| ExprKind::FormatArgs(..)
|
||||
|
|
|
|||
|
|
@ -231,8 +231,7 @@ impl AssocOp {
|
|||
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd)]
|
||||
pub enum ExprPrecedence {
|
||||
Closure,
|
||||
// return, break, yield
|
||||
// return, break, yield, closures
|
||||
Jump,
|
||||
// = += -= *= /= %= &= |= ^= <<= >>=
|
||||
Assign,
|
||||
|
|
|
|||
|
|
@ -795,7 +795,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
|
||||
// If the member region lives in a higher universe, we currently choose
|
||||
// the most conservative option by leaving it unchanged.
|
||||
|
||||
if !self.constraint_sccs().annotation(scc).min_universe().is_root() {
|
||||
return;
|
||||
}
|
||||
|
|
@ -823,12 +822,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
}
|
||||
debug!(?choice_regions, "after ub");
|
||||
|
||||
// At this point we can pick any member of `choice_regions`, but to avoid potential
|
||||
// non-determinism we will pick the *unique minimum* choice.
|
||||
// At this point we can pick any member of `choice_regions` and would like to choose
|
||||
// it to be a small as possible. To avoid potential non-determinism we will pick the
|
||||
// smallest such choice.
|
||||
//
|
||||
// Because universal regions are only partially ordered (i.e, not every two regions are
|
||||
// comparable), we will ignore any region that doesn't compare to all others when picking
|
||||
// the minimum choice.
|
||||
//
|
||||
// For example, consider `choice_regions = ['static, 'a, 'b, 'c, 'd, 'e]`, where
|
||||
// `'static: 'a, 'static: 'b, 'a: 'c, 'b: 'c, 'c: 'd, 'c: 'e`.
|
||||
// `['d, 'e]` are ignored because they do not compare - the same goes for `['a, 'b]`.
|
||||
|
|
@ -853,6 +854,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
|
|||
return;
|
||||
};
|
||||
|
||||
// As we require `'scc: 'min_choice`, we have definitely already computed
|
||||
// its `scc_values` at this point.
|
||||
let min_choice_scc = self.constraint_sccs.scc(min_choice);
|
||||
debug!(?min_choice, ?min_choice_scc);
|
||||
if self.scc_values.add_region(scc, min_choice_scc) {
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ fn dep_symbol_lookup_fn(
|
|||
// search path.
|
||||
for &cnum in crate_info.used_crates.iter().rev() {
|
||||
let src = &crate_info.used_crate_source[&cnum];
|
||||
match data[cnum.as_usize() - 1] {
|
||||
match data[cnum] {
|
||||
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
|
||||
Linkage::Static => {
|
||||
let name = crate_info.crate_name[&cnum];
|
||||
|
|
|
|||
|
|
@ -56,25 +56,6 @@ pub enum LLVMRustResult {
|
|||
Failure,
|
||||
}
|
||||
|
||||
// Rust version of the C struct with the same name in rustc_llvm/llvm-wrapper/RustWrapper.cpp.
|
||||
#[repr(C)]
|
||||
pub struct LLVMRustCOFFShortExport {
|
||||
pub name: *const c_char,
|
||||
pub ordinal_present: bool,
|
||||
/// value of `ordinal` only important when `ordinal_present` is true
|
||||
pub ordinal: u16,
|
||||
}
|
||||
|
||||
impl LLVMRustCOFFShortExport {
|
||||
pub fn new(name: *const c_char, ordinal: Option<u16>) -> LLVMRustCOFFShortExport {
|
||||
LLVMRustCOFFShortExport {
|
||||
name,
|
||||
ordinal_present: ordinal.is_some(),
|
||||
ordinal: ordinal.unwrap_or(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Translation of LLVM's MachineTypes enum, defined in llvm\include\llvm\BinaryFormat\COFF.h.
|
||||
///
|
||||
/// We include only architectures supported on Windows.
|
||||
|
|
@ -2347,15 +2328,6 @@ unsafe extern "C" {
|
|||
) -> &'a mut RustArchiveMember<'a>;
|
||||
pub fn LLVMRustArchiveMemberFree<'a>(Member: &'a mut RustArchiveMember<'a>);
|
||||
|
||||
pub fn LLVMRustWriteImportLibrary(
|
||||
ImportName: *const c_char,
|
||||
Path: *const c_char,
|
||||
Exports: *const LLVMRustCOFFShortExport,
|
||||
NumExports: usize,
|
||||
Machine: u16,
|
||||
MinGW: bool,
|
||||
) -> LLVMRustResult;
|
||||
|
||||
pub fn LLVMRustSetDataLayoutFromTargetMachine<'a>(M: &'a Module, TM: &'a TargetMachine);
|
||||
|
||||
pub fn LLVMRustPositionBuilderAtStart<'a>(B: &Builder<'a>, BB: &'a BasicBlock);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use rustc_ast::CRATE_NODE_ID;
|
|||
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||
use rustc_errors::{DiagCtxtHandle, FatalError};
|
||||
use rustc_errors::DiagCtxtHandle;
|
||||
use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file};
|
||||
|
|
@ -234,8 +234,6 @@ pub fn each_linked_rlib(
|
|||
crate_type: Option<CrateType>,
|
||||
f: &mut dyn FnMut(CrateNum, &Path),
|
||||
) -> Result<(), errors::LinkRlibError> {
|
||||
let crates = info.used_crates.iter();
|
||||
|
||||
let fmts = if let Some(crate_type) = crate_type {
|
||||
let Some(fmts) = info.dependency_formats.get(&crate_type) else {
|
||||
return Err(errors::LinkRlibError::MissingFormat);
|
||||
|
|
@ -261,8 +259,9 @@ pub fn each_linked_rlib(
|
|||
info.dependency_formats.first().unwrap().1
|
||||
};
|
||||
|
||||
for &cnum in crates {
|
||||
match fmts.get(cnum.as_usize() - 1) {
|
||||
let used_dep_crates = info.used_crates.iter();
|
||||
for &cnum in used_dep_crates {
|
||||
match fmts.get(cnum) {
|
||||
Some(&Linkage::NotLinked | &Linkage::Dynamic | &Linkage::IncludedFromDylib) => continue,
|
||||
Some(_) => {}
|
||||
None => return Err(errors::LinkRlibError::MissingFormat),
|
||||
|
|
@ -624,7 +623,7 @@ fn link_staticlib(
|
|||
|
||||
let mut all_rust_dylibs = vec![];
|
||||
for &cnum in crates {
|
||||
match fmts.get(cnum.as_usize() - 1) {
|
||||
match fmts.get(cnum) {
|
||||
Some(&Linkage::Dynamic) => {}
|
||||
_ => continue,
|
||||
}
|
||||
|
|
@ -1039,22 +1038,22 @@ fn link_natively(
|
|||
Err(e) => {
|
||||
let linker_not_found = e.kind() == io::ErrorKind::NotFound;
|
||||
|
||||
if linker_not_found {
|
||||
sess.dcx().emit_err(errors::LinkerNotFound { linker_path, error: e });
|
||||
let err = if linker_not_found {
|
||||
sess.dcx().emit_err(errors::LinkerNotFound { linker_path, error: e })
|
||||
} else {
|
||||
sess.dcx().emit_err(errors::UnableToExeLinker {
|
||||
linker_path,
|
||||
error: e,
|
||||
command_formatted: format!("{cmd:?}"),
|
||||
});
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
if sess.target.is_like_msvc && linker_not_found {
|
||||
sess.dcx().emit_note(errors::MsvcMissingLinker);
|
||||
sess.dcx().emit_note(errors::CheckInstalledVisualStudio);
|
||||
sess.dcx().emit_note(errors::InsufficientVSCodeProduct);
|
||||
}
|
||||
FatalError.raise();
|
||||
err.raise_fatal();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2361,8 +2360,8 @@ fn linker_with_args(
|
|||
.crate_info
|
||||
.native_libraries
|
||||
.iter()
|
||||
.filter_map(|(cnum, libraries)| {
|
||||
(dependency_linkage[cnum.as_usize() - 1] != Linkage::Static).then_some(libraries)
|
||||
.filter_map(|(&cnum, libraries)| {
|
||||
(dependency_linkage[cnum] != Linkage::Static).then_some(libraries)
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<_>>();
|
||||
|
|
@ -2754,7 +2753,7 @@ fn add_upstream_rust_crates(
|
|||
// (e.g. `libstd` when `-C prefer-dynamic` is used).
|
||||
// FIXME: `dependency_formats` can report `profiler_builtins` as `NotLinked` for some
|
||||
// reason, it shouldn't do that because `profiler_builtins` should indeed be linked.
|
||||
let linkage = data[cnum.as_usize() - 1];
|
||||
let linkage = data[cnum];
|
||||
let link_static_crate = linkage == Linkage::Static
|
||||
|| (linkage == Linkage::IncludedFromDylib || linkage == Linkage::NotLinked)
|
||||
&& (codegen_results.crate_info.compiler_builtins == Some(cnum)
|
||||
|
|
|
|||
|
|
@ -1744,15 +1744,10 @@ fn for_each_exported_symbols_include_dep<'tcx>(
|
|||
crate_type: CrateType,
|
||||
mut callback: impl FnMut(ExportedSymbol<'tcx>, SymbolExportInfo, CrateNum),
|
||||
) {
|
||||
for &(symbol, info) in tcx.exported_symbols(LOCAL_CRATE).iter() {
|
||||
callback(symbol, info, LOCAL_CRATE);
|
||||
}
|
||||
|
||||
let formats = tcx.dependency_formats(());
|
||||
let deps = &formats[&crate_type];
|
||||
|
||||
for (index, dep_format) in deps.iter().enumerate() {
|
||||
let cnum = CrateNum::new(index + 1);
|
||||
for (cnum, dep_format) in deps.iter_enumerated() {
|
||||
// For each dependency that we are linking to statically ...
|
||||
if *dep_format == Linkage::Static {
|
||||
for &(symbol, info) in tcx.exported_symbols(cnum).iter() {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ use std::cell::Cell;
|
|||
use std::fmt::Write;
|
||||
|
||||
use rustc_ast_pretty::pprust as pprust_ast;
|
||||
use rustc_errors::FatalError;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
|
|
@ -311,9 +310,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
|
|||
let tcx = ex.tcx();
|
||||
let mut out = String::new();
|
||||
rustc_hir_analysis::check_crate(tcx);
|
||||
if tcx.dcx().has_errors().is_some() {
|
||||
FatalError.raise();
|
||||
}
|
||||
tcx.dcx().abort_if_errors();
|
||||
debug!("pretty printing THIR tree");
|
||||
for did in tcx.hir().body_owners() {
|
||||
let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_tree(did));
|
||||
|
|
@ -324,9 +321,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) {
|
|||
let tcx = ex.tcx();
|
||||
let mut out = String::new();
|
||||
rustc_hir_analysis::check_crate(tcx);
|
||||
if tcx.dcx().has_errors().is_some() {
|
||||
FatalError.raise();
|
||||
}
|
||||
tcx.dcx().abort_if_errors();
|
||||
debug!("pretty printing THIR flat");
|
||||
for did in tcx.hir().body_owners() {
|
||||
let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_flat(did));
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ rustc_error_messages = { path = "../rustc_error_messages" }
|
|||
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
|
||||
rustc_hir = { path = "../rustc_hir" }
|
||||
rustc_index = { path = "../rustc_index" }
|
||||
rustc_lexer = { path = "../rustc_lexer" }
|
||||
rustc_lint_defs = { path = "../rustc_lint_defs" }
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
rustc_serialize = { path = "../rustc_serialize" }
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ use derive_setters::Setters;
|
|||
use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
|
||||
use rustc_data_structures::sync::{DynSend, IntoDynSyncSend, Lrc};
|
||||
use rustc_error_messages::{FluentArgs, SpanLabel};
|
||||
use rustc_lexer;
|
||||
use rustc_lint_defs::pluralize;
|
||||
use rustc_span::hygiene::{ExpnKind, MacroKind};
|
||||
use rustc_span::source_map::SourceMap;
|
||||
|
|
@ -1698,9 +1699,14 @@ impl HumanEmitter {
|
|||
if let Some(source_string) =
|
||||
line.line_index.checked_sub(1).and_then(|l| file.get_line(l))
|
||||
{
|
||||
// Whitespace can only be removed (aka considered leading)
|
||||
// if the lexer considers it whitespace.
|
||||
// non-rustc_lexer::is_whitespace() chars are reported as an
|
||||
// error (ex. no-break-spaces \u{a0}), and thus can't be considered
|
||||
// for removal during error reporting.
|
||||
let leading_whitespace = source_string
|
||||
.chars()
|
||||
.take_while(|c| c.is_whitespace())
|
||||
.take_while(|c| rustc_lexer::is_whitespace(*c))
|
||||
.map(|c| {
|
||||
match c {
|
||||
// Tabs are displayed as 4 spaces
|
||||
|
|
@ -1709,7 +1715,7 @@ impl HumanEmitter {
|
|||
}
|
||||
})
|
||||
.sum();
|
||||
if source_string.chars().any(|c| !c.is_whitespace()) {
|
||||
if source_string.chars().any(|c| !rustc_lexer::is_whitespace(c)) {
|
||||
whitespace_margin = min(whitespace_margin, leading_whitespace);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -912,11 +912,20 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
rustc_attr!(
|
||||
rustc_deny_explicit_impl,
|
||||
AttributeType::Normal,
|
||||
template!(List: "implement_via_object = (true|false)"),
|
||||
template!(Word),
|
||||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_do_not_implement_via_object,
|
||||
AttributeType::Normal,
|
||||
template!(Word),
|
||||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"#[rustc_do_not_implement_via_object] opts out of the automatic trait impl for trait objects \
|
||||
(`impl Trait for dyn Trait`)"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
|
||||
ErrorFollowing, EncodeCrossCrate::Yes,
|
||||
|
|
|
|||
|
|
@ -1943,11 +1943,15 @@ pub struct Expr<'hir> {
|
|||
|
||||
impl Expr<'_> {
|
||||
pub fn precedence(&self) -> ExprPrecedence {
|
||||
match self.kind {
|
||||
ExprKind::Closure { .. } => ExprPrecedence::Closure,
|
||||
match &self.kind {
|
||||
ExprKind::Closure(closure) => {
|
||||
match closure.fn_decl.output {
|
||||
FnRetTy::DefaultReturn(_) => ExprPrecedence::Jump,
|
||||
FnRetTy::Return(_) => ExprPrecedence::Unambiguous,
|
||||
}
|
||||
}
|
||||
|
||||
ExprKind::Break(..)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Ret(..)
|
||||
| ExprKind::Yield(..)
|
||||
| ExprKind::Become(..) => ExprPrecedence::Jump,
|
||||
|
|
@ -1973,6 +1977,7 @@ impl Expr<'_> {
|
|||
| ExprKind::Block(..)
|
||||
| ExprKind::Call(..)
|
||||
| ExprKind::ConstBlock(_)
|
||||
| ExprKind::Continue(..)
|
||||
| ExprKind::Field(..)
|
||||
| ExprKind::If(..)
|
||||
| ExprKind::Index(..)
|
||||
|
|
@ -1990,7 +1995,7 @@ impl Expr<'_> {
|
|||
| ExprKind::UnsafeBinderCast(..)
|
||||
| ExprKind::Err(_) => ExprPrecedence::Unambiguous,
|
||||
|
||||
ExprKind::DropTemps(ref expr, ..) => expr.precedence(),
|
||||
ExprKind::DropTemps(expr, ..) => expr.precedence(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -206,7 +206,9 @@ fn check_object_overlap<'tcx>(
|
|||
// so this is valid.
|
||||
} else {
|
||||
let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id);
|
||||
if supertrait_def_ids.any(|d| d == trait_def_id) {
|
||||
if supertrait_def_ids
|
||||
.any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object)
|
||||
{
|
||||
let span = tcx.def_span(impl_def_id);
|
||||
return Err(struct_span_code_err!(
|
||||
tcx.dcx(),
|
||||
|
|
|
|||
|
|
@ -1261,49 +1261,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
|
|||
no_dups.then_some(list)
|
||||
});
|
||||
|
||||
let mut deny_explicit_impl = false;
|
||||
let mut implement_via_object = true;
|
||||
if let Some(attr) = tcx.get_attr(def_id, sym::rustc_deny_explicit_impl) {
|
||||
deny_explicit_impl = true;
|
||||
let mut seen_attr = false;
|
||||
for meta in attr.meta_item_list().iter().flatten() {
|
||||
if let Some(meta) = meta.meta_item()
|
||||
&& meta.name_or_empty() == sym::implement_via_object
|
||||
&& let Some(lit) = meta.name_value_literal()
|
||||
{
|
||||
if seen_attr {
|
||||
tcx.dcx().span_err(meta.span, "duplicated `implement_via_object` meta item");
|
||||
}
|
||||
seen_attr = true;
|
||||
|
||||
match lit.symbol {
|
||||
kw::True => {
|
||||
implement_via_object = true;
|
||||
}
|
||||
kw::False => {
|
||||
implement_via_object = false;
|
||||
}
|
||||
_ => {
|
||||
tcx.dcx().span_err(
|
||||
meta.span,
|
||||
format!(
|
||||
"unknown literal passed to `implement_via_object` attribute: {}",
|
||||
lit.symbol
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tcx.dcx().span_err(
|
||||
meta.span(),
|
||||
format!("unknown meta item passed to `rustc_deny_explicit_impl` {meta:?}"),
|
||||
);
|
||||
}
|
||||
}
|
||||
if !seen_attr {
|
||||
tcx.dcx().span_err(attr.span, "missing `implement_via_object` meta item");
|
||||
}
|
||||
}
|
||||
let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl);
|
||||
let implement_via_object = !tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object);
|
||||
|
||||
ty::TraitDef {
|
||||
def_id: def_id.to_def_id(),
|
||||
|
|
|
|||
|
|
@ -1329,6 +1329,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
|
|||
mutbl: hir::Mutability,
|
||||
track_unstable_candidates: bool,
|
||||
) -> Result<(), MethodError<'tcx>> {
|
||||
// The errors emitted by this function are part of
|
||||
// the arbitrary self types work, and should not impact
|
||||
// other users.
|
||||
if !self.tcx.features().arbitrary_self_types()
|
||||
&& !self.tcx.features().arbitrary_self_types_pointers()
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// We don't want to remember any of the diagnostic hints from this
|
||||
// shadow search, but we do need to provide Some/None for the
|
||||
// unstable_candidates in order to reflect the behavior of the
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use rustc_incremental::setup_dep_graph;
|
|||
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store};
|
||||
use rustc_metadata::creader::CStore;
|
||||
use rustc_middle::arena::Arena;
|
||||
use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
|
||||
use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt};
|
||||
use rustc_middle::util::Providers;
|
||||
use rustc_parse::{
|
||||
new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr,
|
||||
|
|
@ -770,15 +770,14 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
|
|||
// subtyping for GlobalCtxt::enter to be allowed.
|
||||
let inner: Box<
|
||||
dyn for<'tcx> FnOnce(
|
||||
&'tcx Compiler,
|
||||
&'tcx Session,
|
||||
CurrentGcx,
|
||||
&'tcx OnceLock<GlobalCtxt<'tcx>>,
|
||||
&'tcx WorkerLocal<Arena<'tcx>>,
|
||||
&'tcx WorkerLocal<rustc_hir::Arena<'tcx>>,
|
||||
F,
|
||||
) -> T,
|
||||
> = Box::new(move |compiler, gcx_cell, arena, hir_arena, f| {
|
||||
let sess = &compiler.sess;
|
||||
|
||||
> = Box::new(move |sess, current_gcx, gcx_cell, arena, hir_arena, f| {
|
||||
TyCtxt::create_global_ctxt(
|
||||
gcx_cell,
|
||||
sess,
|
||||
|
|
@ -796,7 +795,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
|
|||
incremental,
|
||||
),
|
||||
providers.hooks,
|
||||
compiler.current_gcx.clone(),
|
||||
current_gcx,
|
||||
|tcx| {
|
||||
let feed = tcx.create_crate_num(stable_crate_id).unwrap();
|
||||
assert_eq!(feed.key(), LOCAL_CRATE);
|
||||
|
|
@ -804,7 +803,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
|
|||
|
||||
let feed = tcx.feed_unit_query();
|
||||
feed.features_query(tcx.arena.alloc(rustc_expand::config::features(
|
||||
sess,
|
||||
tcx.sess,
|
||||
&pre_configured_attrs,
|
||||
crate_name,
|
||||
)));
|
||||
|
|
@ -819,7 +818,7 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
|
|||
)
|
||||
});
|
||||
|
||||
inner(compiler, &gcx_cell, &arena, &hir_arena, f)
|
||||
inner(&compiler.sess, compiler.current_gcx.clone(), &gcx_cell, &arena, &hir_arena, f)
|
||||
}
|
||||
|
||||
/// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use std::ops::ControlFlow;
|
|||
use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, Variants, WrappingRange};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::DiagMessage;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_hir::{Expr, ExprKind, LangItem};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
|
||||
use rustc_middle::ty::{
|
||||
|
|
@ -444,7 +444,25 @@ fn lint_fn_pointer<'tcx>(
|
|||
let (l_ty, l_ty_refs) = peel_refs(l_ty);
|
||||
let (r_ty, r_ty_refs) = peel_refs(r_ty);
|
||||
|
||||
if !l_ty.is_fn() || !r_ty.is_fn() {
|
||||
if l_ty.is_fn() && r_ty.is_fn() {
|
||||
// both operands are function pointers, fallthrough
|
||||
} else if let ty::Adt(l_def, l_args) = l_ty.kind()
|
||||
&& let ty::Adt(r_def, r_args) = r_ty.kind()
|
||||
&& cx.tcx.is_lang_item(l_def.did(), LangItem::Option)
|
||||
&& cx.tcx.is_lang_item(r_def.did(), LangItem::Option)
|
||||
&& let Some(l_some_arg) = l_args.get(0)
|
||||
&& let Some(r_some_arg) = r_args.get(0)
|
||||
&& l_some_arg.expect_ty().is_fn()
|
||||
&& r_some_arg.expect_ty().is_fn()
|
||||
{
|
||||
// both operands are `Option<{function ptr}>`
|
||||
return cx.emit_span_lint(
|
||||
UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
|
||||
e.span,
|
||||
UnpredictableFunctionPointerComparisons::Warn,
|
||||
);
|
||||
} else {
|
||||
// types are not function pointers, nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1796,56 +1796,6 @@ extern "C" LLVMValueRef LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS,
|
|||
return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS), unwrap(RHS)));
|
||||
}
|
||||
|
||||
// This struct contains all necessary info about a symbol exported from a DLL.
|
||||
struct LLVMRustCOFFShortExport {
|
||||
const char *name;
|
||||
bool ordinal_present;
|
||||
// The value of `ordinal` is only meaningful if `ordinal_present` is true.
|
||||
uint16_t ordinal;
|
||||
};
|
||||
|
||||
// Machine must be a COFF machine type, as defined in PE specs.
|
||||
extern "C" LLVMRustResult
|
||||
LLVMRustWriteImportLibrary(const char *ImportName, const char *Path,
|
||||
const LLVMRustCOFFShortExport *Exports,
|
||||
size_t NumExports, uint16_t Machine, bool MinGW) {
|
||||
std::vector<llvm::object::COFFShortExport> ConvertedExports;
|
||||
ConvertedExports.reserve(NumExports);
|
||||
|
||||
for (size_t i = 0; i < NumExports; ++i) {
|
||||
bool ordinal_present = Exports[i].ordinal_present;
|
||||
uint16_t ordinal = ordinal_present ? Exports[i].ordinal : 0;
|
||||
ConvertedExports.push_back(llvm::object::COFFShortExport{
|
||||
Exports[i].name, // Name
|
||||
std::string{}, // ExtName
|
||||
std::string{}, // SymbolName
|
||||
std::string{}, // AliasTarget
|
||||
#if LLVM_VERSION_GE(19, 0)
|
||||
std::string{}, // ExportAs
|
||||
#endif
|
||||
ordinal, // Ordinal
|
||||
ordinal_present, // Noname
|
||||
false, // Data
|
||||
false, // Private
|
||||
false // Constant
|
||||
});
|
||||
}
|
||||
|
||||
auto Error = llvm::object::writeImportLibrary(
|
||||
ImportName, Path, ConvertedExports,
|
||||
static_cast<llvm::COFF::MachineTypes>(Machine), MinGW);
|
||||
if (Error) {
|
||||
std::string errorString;
|
||||
auto stream = llvm::raw_string_ostream(errorString);
|
||||
stream << Error;
|
||||
stream.flush();
|
||||
LLVMRustSetLastError(errorString.c_str());
|
||||
return LLVMRustResult::Failure;
|
||||
} else {
|
||||
return LLVMRustResult::Success;
|
||||
}
|
||||
}
|
||||
|
||||
// Transfers ownership of DiagnosticHandler unique_ptr to the caller.
|
||||
extern "C" DiagnosticHandler *
|
||||
LLVMRustContextGetDiagnosticHandler(LLVMContextRef C) {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@
|
|||
//! than finding a number of solutions (there are normally quite a few).
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
|
@ -84,7 +85,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
let sess = &tcx.sess;
|
||||
|
||||
if !sess.opts.output_types.should_codegen() {
|
||||
return Vec::new();
|
||||
return IndexVec::new();
|
||||
}
|
||||
|
||||
let preferred_linkage = match ty {
|
||||
|
|
@ -131,7 +132,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
|
||||
match preferred_linkage {
|
||||
// If the crate is not linked, there are no link-time dependencies.
|
||||
Linkage::NotLinked => return Vec::new(),
|
||||
Linkage::NotLinked => return IndexVec::new(),
|
||||
Linkage::Static => {
|
||||
// Attempt static linkage first. For dylibs and executables, we may be
|
||||
// able to retry below with dynamic linkage.
|
||||
|
|
@ -156,7 +157,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
}
|
||||
sess.dcx().emit_err(RlibRequired { crate_name: tcx.crate_name(cnum) });
|
||||
}
|
||||
return Vec::new();
|
||||
return IndexVec::new();
|
||||
}
|
||||
}
|
||||
Linkage::Dynamic | Linkage::IncludedFromDylib => {}
|
||||
|
|
@ -210,19 +211,32 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
|
||||
// Collect what we've got so far in the return vector.
|
||||
let last_crate = tcx.crates(()).len();
|
||||
let mut ret = (1..last_crate + 1)
|
||||
.map(|cnum| match formats.get(&CrateNum::new(cnum)) {
|
||||
Some(&RequireDynamic) => Linkage::Dynamic,
|
||||
Some(&RequireStatic) => Linkage::IncludedFromDylib,
|
||||
None => Linkage::NotLinked,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut ret = IndexVec::new();
|
||||
|
||||
// We need to fill in something for LOCAL_CRATE as IndexVec is a dense map.
|
||||
// Linkage::Static semantically the most correct thing to use as the local
|
||||
// crate is always statically linked into the linker output, even when
|
||||
// linking a dylib. Using Linkage::Static also allow avoiding special cases
|
||||
// for LOCAL_CRATE in some places.
|
||||
assert_eq!(ret.push(Linkage::Static), LOCAL_CRATE);
|
||||
|
||||
for cnum in 1..last_crate + 1 {
|
||||
let cnum = CrateNum::new(cnum);
|
||||
assert_eq!(
|
||||
ret.push(match formats.get(&cnum) {
|
||||
Some(&RequireDynamic) => Linkage::Dynamic,
|
||||
Some(&RequireStatic) => Linkage::IncludedFromDylib,
|
||||
None => Linkage::NotLinked,
|
||||
}),
|
||||
cnum
|
||||
);
|
||||
}
|
||||
|
||||
// Run through the dependency list again, and add any missing libraries as
|
||||
// static libraries.
|
||||
//
|
||||
// If the crate hasn't been included yet and it's not actually required
|
||||
// (e.g., it's an allocator) then we skip it here as well.
|
||||
// (e.g., it's a panic runtime) then we skip it here as well.
|
||||
for &cnum in tcx.crates(()).iter() {
|
||||
let src = tcx.used_crate_source(cnum);
|
||||
if src.dylib.is_none()
|
||||
|
|
@ -232,7 +246,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
assert!(src.rlib.is_some() || src.rmeta.is_some());
|
||||
info!("adding staticlib: {}", tcx.crate_name(cnum));
|
||||
add_library(tcx, cnum, RequireStatic, &mut formats, &mut unavailable_as_static);
|
||||
ret[cnum.as_usize() - 1] = Linkage::Static;
|
||||
ret[cnum] = Linkage::Static;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -240,8 +254,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
// artifact which means that we may need to inject dependencies of some
|
||||
// form.
|
||||
//
|
||||
// Things like allocators and panic runtimes may not have been activated
|
||||
// quite yet, so do so here.
|
||||
// Things like panic runtimes may not have been activated quite yet, so do so here.
|
||||
activate_injected_dep(CStore::from_tcx(tcx).injected_panic_runtime(), &mut ret, &|cnum| {
|
||||
tcx.is_panic_runtime(cnum)
|
||||
});
|
||||
|
|
@ -252,8 +265,10 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
|
|||
//
|
||||
// For situations like this, we perform one last pass over the dependencies,
|
||||
// making sure that everything is available in the requested format.
|
||||
for (cnum, kind) in ret.iter().enumerate() {
|
||||
let cnum = CrateNum::new(cnum + 1);
|
||||
for (cnum, kind) in ret.iter_enumerated() {
|
||||
if cnum == LOCAL_CRATE {
|
||||
continue;
|
||||
}
|
||||
let src = tcx.used_crate_source(cnum);
|
||||
match *kind {
|
||||
Linkage::NotLinked | Linkage::IncludedFromDylib => {}
|
||||
|
|
@ -334,18 +349,21 @@ fn attempt_static(tcx: TyCtxt<'_>, unavailable: &mut Vec<CrateNum>) -> Option<De
|
|||
|
||||
// All crates are available in an rlib format, so we're just going to link
|
||||
// everything in explicitly so long as it's actually required.
|
||||
let mut ret = tcx
|
||||
.crates(())
|
||||
.iter()
|
||||
.map(|&cnum| match tcx.dep_kind(cnum) {
|
||||
CrateDepKind::Explicit => Linkage::Static,
|
||||
CrateDepKind::MacrosOnly | CrateDepKind::Implicit => Linkage::NotLinked,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let mut ret = IndexVec::new();
|
||||
assert_eq!(ret.push(Linkage::Static), LOCAL_CRATE);
|
||||
for &cnum in tcx.crates(()) {
|
||||
assert_eq!(
|
||||
ret.push(match tcx.dep_kind(cnum) {
|
||||
CrateDepKind::Explicit => Linkage::Static,
|
||||
CrateDepKind::MacrosOnly | CrateDepKind::Implicit => Linkage::NotLinked,
|
||||
}),
|
||||
cnum
|
||||
);
|
||||
}
|
||||
|
||||
// Our allocator/panic runtime may not have been linked above if it wasn't
|
||||
// explicitly linked, which is the case for any injected dependency. Handle
|
||||
// that here and activate them.
|
||||
// Our panic runtime may not have been linked above if it wasn't explicitly
|
||||
// linked, which is the case for any injected dependency. Handle that here
|
||||
// and activate it.
|
||||
activate_injected_dep(CStore::from_tcx(tcx).injected_panic_runtime(), &mut ret, &|cnum| {
|
||||
tcx.is_panic_runtime(cnum)
|
||||
});
|
||||
|
|
@ -367,8 +385,7 @@ fn activate_injected_dep(
|
|||
list: &mut DependencyList,
|
||||
replaces_injected: &dyn Fn(CrateNum) -> bool,
|
||||
) {
|
||||
for (i, slot) in list.iter().enumerate() {
|
||||
let cnum = CrateNum::new(i + 1);
|
||||
for (cnum, slot) in list.iter_enumerated() {
|
||||
if !replaces_injected(cnum) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -377,25 +394,23 @@ fn activate_injected_dep(
|
|||
}
|
||||
}
|
||||
if let Some(injected) = injected {
|
||||
let idx = injected.as_usize() - 1;
|
||||
assert_eq!(list[idx], Linkage::NotLinked);
|
||||
list[idx] = Linkage::Static;
|
||||
assert_eq!(list[injected], Linkage::NotLinked);
|
||||
list[injected] = Linkage::Static;
|
||||
}
|
||||
}
|
||||
|
||||
// After the linkage for a crate has been determined we need to verify that
|
||||
// there's only going to be one allocator in the output.
|
||||
fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
|
||||
/// After the linkage for a crate has been determined we need to verify that
|
||||
/// there's only going to be one panic runtime in the output.
|
||||
fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) {
|
||||
let sess = &tcx.sess;
|
||||
if list.is_empty() {
|
||||
return;
|
||||
}
|
||||
let mut panic_runtime = None;
|
||||
for (i, linkage) in list.iter().enumerate() {
|
||||
for (cnum, linkage) in list.iter_enumerated() {
|
||||
if let Linkage::NotLinked = *linkage {
|
||||
continue;
|
||||
}
|
||||
let cnum = CrateNum::new(i + 1);
|
||||
|
||||
if tcx.is_panic_runtime(cnum) {
|
||||
if let Some((prev, _)) = panic_runtime {
|
||||
|
|
@ -431,11 +446,10 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
|
|||
// strategy. If the dep isn't linked, we ignore it, and if our strategy
|
||||
// is abort then it's compatible with everything. Otherwise all crates'
|
||||
// panic strategy must match our own.
|
||||
for (i, linkage) in list.iter().enumerate() {
|
||||
for (cnum, linkage) in list.iter_enumerated() {
|
||||
if let Linkage::NotLinked = *linkage {
|
||||
continue;
|
||||
}
|
||||
let cnum = CrateNum::new(i + 1);
|
||||
if cnum == runtime_cnum || tcx.is_compiler_builtins(cnum) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -450,13 +464,16 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
|
|||
});
|
||||
}
|
||||
|
||||
let found_drop_strategy = tcx.panic_in_drop_strategy(cnum);
|
||||
if tcx.sess.opts.unstable_opts.panic_in_drop != found_drop_strategy {
|
||||
sess.dcx().emit_err(IncompatiblePanicInDropStrategy {
|
||||
crate_name: tcx.crate_name(cnum),
|
||||
found_strategy: found_drop_strategy,
|
||||
desired_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
|
||||
});
|
||||
// panic_in_drop_strategy isn't allowed for LOCAL_CRATE
|
||||
if cnum != LOCAL_CRATE {
|
||||
let found_drop_strategy = tcx.panic_in_drop_strategy(cnum);
|
||||
if tcx.sess.opts.unstable_opts.panic_in_drop != found_drop_strategy {
|
||||
sess.dcx().emit_err(IncompatiblePanicInDropStrategy {
|
||||
crate_name: tcx.crate_name(cnum),
|
||||
found_strategy: found_drop_strategy,
|
||||
desired_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1474,7 +1474,7 @@ impl<'a> CrateMetadataRef<'a> {
|
|||
) -> &'tcx [(CrateNum, LinkagePreference)] {
|
||||
tcx.arena.alloc_from_iter(
|
||||
self.root.dylib_dependency_formats.decode(self).enumerate().flat_map(|(i, link)| {
|
||||
let cnum = CrateNum::new(i + 1);
|
||||
let cnum = CrateNum::new(i + 1); // We skipped LOCAL_CRATE when encoding
|
||||
link.map(|link| (self.cnum_map[cnum], link))
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2165,12 +2165,14 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||
empty_proc_macro!(self);
|
||||
let formats = self.tcx.dependency_formats(());
|
||||
if let Some(arr) = formats.get(&CrateType::Dylib) {
|
||||
return self.lazy_array(arr.iter().map(|slot| match *slot {
|
||||
Linkage::NotLinked | Linkage::IncludedFromDylib => None,
|
||||
return self.lazy_array(arr.iter().skip(1 /* skip LOCAL_CRATE */).map(
|
||||
|slot| match *slot {
|
||||
Linkage::NotLinked | Linkage::IncludedFromDylib => None,
|
||||
|
||||
Linkage::Dynamic => Some(LinkagePreference::RequireDynamic),
|
||||
Linkage::Static => Some(LinkagePreference::RequireStatic),
|
||||
}));
|
||||
Linkage::Dynamic => Some(LinkagePreference::RequireDynamic),
|
||||
Linkage::Static => Some(LinkagePreference::RequireStatic),
|
||||
},
|
||||
));
|
||||
}
|
||||
LazyArray::default()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@
|
|||
// this will introduce circular dependency between rustc_metadata and rustc_middle
|
||||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir::def_id::CrateNum;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_macros::{Decodable, Encodable, HashStable};
|
||||
use rustc_session::config::CrateType;
|
||||
|
||||
/// A list of dependencies for a certain crate type.
|
||||
///
|
||||
/// The length of this vector is the same as the number of external crates used.
|
||||
pub type DependencyList = Vec<Linkage>;
|
||||
pub type DependencyList = IndexVec<CrateNum, Linkage>;
|
||||
|
||||
/// A mapping of all required dependencies for a particular flavor of output.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -70,12 +70,12 @@ pub struct TraitDef {
|
|||
|
||||
/// Whether to add a builtin `dyn Trait: Trait` implementation.
|
||||
/// This is enabled for all traits except ones marked with
|
||||
/// `#[rustc_deny_explicit_impl(implement_via_object = false)]`.
|
||||
/// `#[rustc_do_not_implement_via_object]`.
|
||||
pub implement_via_object: bool,
|
||||
|
||||
/// Whether a trait is fully built-in, and any implementation is disallowed.
|
||||
/// This only applies to built-in traits, and is marked via
|
||||
/// `#[rustc_deny_explicit_impl(implement_via_object = ...)]`.
|
||||
/// `#[rustc_deny_explicit_impl]`.
|
||||
pub deny_explicit_impl: bool,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
mir_body: &mir::Body<'tcx>,
|
||||
hir_info: &ExtractedHirInfo,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
graph: &CoverageGraph,
|
||||
) -> ExtractedMappings {
|
||||
let mut code_mappings = vec![];
|
||||
let mut branch_pairs = vec![];
|
||||
|
|
@ -102,23 +102,23 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>(
|
|||
}
|
||||
} else {
|
||||
// Extract coverage spans from MIR statements/terminators as normal.
|
||||
extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
|
||||
extract_refined_covspans(mir_body, hir_info, graph, &mut code_mappings);
|
||||
}
|
||||
|
||||
branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks));
|
||||
branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, graph));
|
||||
|
||||
extract_mcdc_mappings(
|
||||
mir_body,
|
||||
tcx,
|
||||
hir_info.body_span,
|
||||
basic_coverage_blocks,
|
||||
graph,
|
||||
&mut mcdc_bitmap_bits,
|
||||
&mut mcdc_degraded_branches,
|
||||
&mut mcdc_mappings,
|
||||
);
|
||||
|
||||
ExtractedMappings {
|
||||
num_bcbs: basic_coverage_blocks.num_nodes(),
|
||||
num_bcbs: graph.num_nodes(),
|
||||
code_mappings,
|
||||
branch_pairs,
|
||||
mcdc_bitmap_bits,
|
||||
|
|
@ -211,7 +211,7 @@ fn resolve_block_markers(
|
|||
pub(super) fn extract_branch_pairs(
|
||||
mir_body: &mir::Body<'_>,
|
||||
hir_info: &ExtractedHirInfo,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
graph: &CoverageGraph,
|
||||
) -> Vec<BranchPair> {
|
||||
let Some(coverage_info_hi) = mir_body.coverage_info_hi.as_deref() else { return vec![] };
|
||||
|
||||
|
|
@ -228,8 +228,7 @@ pub(super) fn extract_branch_pairs(
|
|||
}
|
||||
let span = unexpand_into_body_span(raw_span, hir_info.body_span)?;
|
||||
|
||||
let bcb_from_marker =
|
||||
|marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?);
|
||||
let bcb_from_marker = |marker: BlockMarkerId| graph.bcb_from_bb(block_markers[marker]?);
|
||||
|
||||
let true_bcb = bcb_from_marker(true_marker)?;
|
||||
let false_bcb = bcb_from_marker(false_marker)?;
|
||||
|
|
@ -243,7 +242,7 @@ pub(super) fn extract_mcdc_mappings(
|
|||
mir_body: &mir::Body<'_>,
|
||||
tcx: TyCtxt<'_>,
|
||||
body_span: Span,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
graph: &CoverageGraph,
|
||||
mcdc_bitmap_bits: &mut usize,
|
||||
mcdc_degraded_branches: &mut impl Extend<MCDCBranch>,
|
||||
mcdc_mappings: &mut impl Extend<(MCDCDecision, Vec<MCDCBranch>)>,
|
||||
|
|
@ -252,8 +251,7 @@ pub(super) fn extract_mcdc_mappings(
|
|||
|
||||
let block_markers = resolve_block_markers(coverage_info_hi, mir_body);
|
||||
|
||||
let bcb_from_marker =
|
||||
|marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?);
|
||||
let bcb_from_marker = |marker: BlockMarkerId| graph.bcb_from_bb(block_markers[marker]?);
|
||||
|
||||
let check_branch_bcb =
|
||||
|raw_span: Span, true_marker: BlockMarkerId, false_marker: BlockMarkerId| {
|
||||
|
|
|
|||
|
|
@ -71,16 +71,15 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
|
|||
let _span = debug_span!("instrument_function_for_coverage", ?def_id).entered();
|
||||
|
||||
let hir_info = extract_hir_info(tcx, def_id.expect_local());
|
||||
let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
|
||||
|
||||
// Build the coverage graph, which is a simplified view of the MIR control-flow
|
||||
// graph that ignores some details not relevant to coverage instrumentation.
|
||||
let graph = CoverageGraph::from_mir(mir_body);
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Extract coverage spans and other mapping info from MIR.
|
||||
let extracted_mappings = mappings::extract_all_mapping_info_from_mir(
|
||||
tcx,
|
||||
mir_body,
|
||||
&hir_info,
|
||||
&basic_coverage_blocks,
|
||||
);
|
||||
let extracted_mappings =
|
||||
mappings::extract_all_mapping_info_from_mir(tcx, mir_body, &hir_info, &graph);
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
|
||||
|
|
@ -94,7 +93,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
|
|||
}
|
||||
|
||||
let coverage_counters =
|
||||
CoverageCounters::make_bcb_counters(&basic_coverage_blocks, &bcbs_with_counter_mappings);
|
||||
CoverageCounters::make_bcb_counters(&graph, &bcbs_with_counter_mappings);
|
||||
|
||||
let mappings = create_mappings(&extracted_mappings, &coverage_counters);
|
||||
if mappings.is_empty() {
|
||||
|
|
@ -103,14 +102,9 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
|
|||
return;
|
||||
}
|
||||
|
||||
inject_coverage_statements(
|
||||
mir_body,
|
||||
&basic_coverage_blocks,
|
||||
&extracted_mappings,
|
||||
&coverage_counters,
|
||||
);
|
||||
inject_coverage_statements(mir_body, &graph, &extracted_mappings, &coverage_counters);
|
||||
|
||||
inject_mcdc_statements(mir_body, &basic_coverage_blocks, &extracted_mappings);
|
||||
inject_mcdc_statements(mir_body, &graph, &extracted_mappings);
|
||||
|
||||
let mcdc_num_condition_bitmaps = extracted_mappings
|
||||
.mcdc_mappings
|
||||
|
|
@ -243,7 +237,7 @@ fn create_mappings(
|
|||
/// inject any necessary coverage statements into MIR.
|
||||
fn inject_coverage_statements<'tcx>(
|
||||
mir_body: &mut mir::Body<'tcx>,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
graph: &CoverageGraph,
|
||||
extracted_mappings: &ExtractedMappings,
|
||||
coverage_counters: &CoverageCounters,
|
||||
) {
|
||||
|
|
@ -253,12 +247,12 @@ fn inject_coverage_statements<'tcx>(
|
|||
// For BCB nodes this is just their first block, but for edges we need
|
||||
// to create a new block between the two BCBs, and inject into that.
|
||||
let target_bb = match site {
|
||||
Site::Node { bcb } => basic_coverage_blocks[bcb].leader_bb(),
|
||||
Site::Node { bcb } => graph[bcb].leader_bb(),
|
||||
Site::Edge { from_bcb, to_bcb } => {
|
||||
// Create a new block between the last block of `from_bcb` and
|
||||
// the first block of `to_bcb`.
|
||||
let from_bb = basic_coverage_blocks[from_bcb].last_bb();
|
||||
let to_bb = basic_coverage_blocks[to_bcb].leader_bb();
|
||||
let from_bb = graph[from_bcb].last_bb();
|
||||
let to_bb = graph[to_bcb].leader_bb();
|
||||
|
||||
let new_bb = inject_edge_counter_basic_block(mir_body, from_bb, to_bb);
|
||||
debug!(
|
||||
|
|
@ -291,7 +285,7 @@ fn inject_coverage_statements<'tcx>(
|
|||
inject_statement(
|
||||
mir_body,
|
||||
CoverageKind::ExpressionUsed { id: expression_id },
|
||||
basic_coverage_blocks[bcb].leader_bb(),
|
||||
graph[bcb].leader_bb(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -300,13 +294,13 @@ fn inject_coverage_statements<'tcx>(
|
|||
/// For each decision inject statements to update test vector bitmap after it has been evaluated.
|
||||
fn inject_mcdc_statements<'tcx>(
|
||||
mir_body: &mut mir::Body<'tcx>,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
graph: &CoverageGraph,
|
||||
extracted_mappings: &ExtractedMappings,
|
||||
) {
|
||||
for (decision, conditions) in &extracted_mappings.mcdc_mappings {
|
||||
// Inject test vector update first because `inject_statement` always insert new statement at head.
|
||||
for &end in &decision.end_bcbs {
|
||||
let end_bb = basic_coverage_blocks[end].leader_bb();
|
||||
let end_bb = graph[end].leader_bb();
|
||||
inject_statement(
|
||||
mir_body,
|
||||
CoverageKind::TestVectorBitmapUpdate {
|
||||
|
|
@ -327,7 +321,7 @@ fn inject_mcdc_statements<'tcx>(
|
|||
} in conditions
|
||||
{
|
||||
for (index, bcb) in [(false_index, false_bcb), (true_index, true_bcb)] {
|
||||
let bb = basic_coverage_blocks[bcb].leader_bb();
|
||||
let bb = graph[bcb].leader_bb();
|
||||
inject_statement(
|
||||
mir_body,
|
||||
CoverageKind::CondBitmapUpdate {
|
||||
|
|
|
|||
|
|
@ -17,14 +17,13 @@ mod from_mir;
|
|||
pub(super) fn extract_refined_covspans(
|
||||
mir_body: &mir::Body<'_>,
|
||||
hir_info: &ExtractedHirInfo,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
graph: &CoverageGraph,
|
||||
code_mappings: &mut impl Extend<mappings::CodeMapping>,
|
||||
) {
|
||||
let ExtractedCovspans { mut covspans } =
|
||||
extract_covspans_from_mir(mir_body, hir_info, basic_coverage_blocks);
|
||||
let ExtractedCovspans { mut covspans } = extract_covspans_from_mir(mir_body, hir_info, graph);
|
||||
|
||||
// First, perform the passes that need macro information.
|
||||
covspans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb));
|
||||
covspans.sort_by(|a, b| graph.cmp_in_dominator_order(a.bcb, b.bcb));
|
||||
remove_unwanted_expansion_spans(&mut covspans);
|
||||
split_visible_macro_spans(&mut covspans);
|
||||
|
||||
|
|
@ -34,7 +33,7 @@ pub(super) fn extract_refined_covspans(
|
|||
let compare_covspans = |a: &Covspan, b: &Covspan| {
|
||||
compare_spans(a.span, b.span)
|
||||
// After deduplication, we want to keep only the most-dominated BCB.
|
||||
.then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse())
|
||||
.then_with(|| graph.cmp_in_dominator_order(a.bcb, b.bcb).reverse())
|
||||
};
|
||||
covspans.sort_by(compare_covspans);
|
||||
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ pub(crate) struct ExtractedCovspans {
|
|||
pub(crate) fn extract_covspans_from_mir(
|
||||
mir_body: &mir::Body<'_>,
|
||||
hir_info: &ExtractedHirInfo,
|
||||
basic_coverage_blocks: &CoverageGraph,
|
||||
graph: &CoverageGraph,
|
||||
) -> ExtractedCovspans {
|
||||
let &ExtractedHirInfo { body_span, .. } = hir_info;
|
||||
|
||||
let mut covspans = vec![];
|
||||
|
||||
for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() {
|
||||
for (bcb, bcb_data) in graph.iter_enumerated() {
|
||||
bcb_to_initial_coverage_spans(mir_body, body_span, bcb, bcb_data, &mut covspans);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -223,16 +223,12 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_coverage_graphviz(
|
||||
name: &str,
|
||||
mir_body: &Body<'_>,
|
||||
basic_coverage_blocks: &graph::CoverageGraph,
|
||||
) {
|
||||
fn print_coverage_graphviz(name: &str, mir_body: &Body<'_>, graph: &graph::CoverageGraph) {
|
||||
if PRINT_GRAPHS {
|
||||
println!(
|
||||
"digraph {} {{\n{}\n}}",
|
||||
name,
|
||||
basic_coverage_blocks
|
||||
graph
|
||||
.iter_enumerated()
|
||||
.map(|(bcb, bcb_data)| {
|
||||
format!(
|
||||
|
|
@ -240,7 +236,7 @@ fn print_coverage_graphviz(
|
|||
bcb,
|
||||
bcb,
|
||||
mir_body[bcb_data.last_bb()].terminator().kind.name(),
|
||||
basic_coverage_blocks
|
||||
graph
|
||||
.successors(bcb)
|
||||
.map(|successor| { format!(" {:?} -> {:?};", bcb, successor) })
|
||||
.join("\n")
|
||||
|
|
@ -300,11 +296,11 @@ fn goto_switchint<'a>() -> Body<'a> {
|
|||
|
||||
#[track_caller]
|
||||
fn assert_successors(
|
||||
basic_coverage_blocks: &graph::CoverageGraph,
|
||||
graph: &graph::CoverageGraph,
|
||||
bcb: BasicCoverageBlock,
|
||||
expected_successors: &[BasicCoverageBlock],
|
||||
) {
|
||||
let mut successors = basic_coverage_blocks.successors[bcb].clone();
|
||||
let mut successors = graph.successors[bcb].clone();
|
||||
successors.sort_unstable();
|
||||
assert_eq!(successors, expected_successors);
|
||||
}
|
||||
|
|
@ -315,8 +311,8 @@ fn test_covgraph_goto_switchint() {
|
|||
if false {
|
||||
eprintln!("basic_blocks = {}", debug_basic_blocks(&mir_body));
|
||||
}
|
||||
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
|
||||
print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks);
|
||||
let graph = graph::CoverageGraph::from_mir(&mir_body);
|
||||
print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &graph);
|
||||
/*
|
||||
┌──────────────┐ ┌─────────────────┐
|
||||
│ bcb2: Return │ ◀── │ bcb0: SwitchInt │
|
||||
|
|
@ -328,16 +324,11 @@ fn test_covgraph_goto_switchint() {
|
|||
│ bcb1: Return │
|
||||
└─────────────────┘
|
||||
*/
|
||||
assert_eq!(
|
||||
basic_coverage_blocks.num_nodes(),
|
||||
3,
|
||||
"basic_coverage_blocks: {:?}",
|
||||
basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
|
||||
);
|
||||
assert_eq!(graph.num_nodes(), 3, "graph: {:?}", graph.iter_enumerated().collect::<Vec<_>>());
|
||||
|
||||
assert_successors(&basic_coverage_blocks, bcb(0), &[bcb(1), bcb(2)]);
|
||||
assert_successors(&basic_coverage_blocks, bcb(1), &[]);
|
||||
assert_successors(&basic_coverage_blocks, bcb(2), &[]);
|
||||
assert_successors(&graph, bcb(0), &[bcb(1), bcb(2)]);
|
||||
assert_successors(&graph, bcb(1), &[]);
|
||||
assert_successors(&graph, bcb(2), &[]);
|
||||
}
|
||||
|
||||
/// Create a mock `Body` with a loop.
|
||||
|
|
@ -383,12 +374,8 @@ fn switchint_then_loop_else_return<'a>() -> Body<'a> {
|
|||
#[test]
|
||||
fn test_covgraph_switchint_then_loop_else_return() {
|
||||
let mir_body = switchint_then_loop_else_return();
|
||||
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
|
||||
print_coverage_graphviz(
|
||||
"covgraph_switchint_then_loop_else_return",
|
||||
&mir_body,
|
||||
&basic_coverage_blocks,
|
||||
);
|
||||
let graph = graph::CoverageGraph::from_mir(&mir_body);
|
||||
print_coverage_graphviz("covgraph_switchint_then_loop_else_return", &mir_body, &graph);
|
||||
/*
|
||||
┌─────────────────┐
|
||||
│ bcb0: Call │
|
||||
|
|
@ -408,17 +395,12 @@ fn test_covgraph_switchint_then_loop_else_return() {
|
|||
│ │
|
||||
└─────────────────────────────────────┘
|
||||
*/
|
||||
assert_eq!(
|
||||
basic_coverage_blocks.num_nodes(),
|
||||
4,
|
||||
"basic_coverage_blocks: {:?}",
|
||||
basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
|
||||
);
|
||||
assert_eq!(graph.num_nodes(), 4, "graph: {:?}", graph.iter_enumerated().collect::<Vec<_>>());
|
||||
|
||||
assert_successors(&basic_coverage_blocks, bcb(0), &[bcb(1)]);
|
||||
assert_successors(&basic_coverage_blocks, bcb(1), &[bcb(2), bcb(3)]);
|
||||
assert_successors(&basic_coverage_blocks, bcb(2), &[]);
|
||||
assert_successors(&basic_coverage_blocks, bcb(3), &[bcb(1)]);
|
||||
assert_successors(&graph, bcb(0), &[bcb(1)]);
|
||||
assert_successors(&graph, bcb(1), &[bcb(2), bcb(3)]);
|
||||
assert_successors(&graph, bcb(2), &[]);
|
||||
assert_successors(&graph, bcb(3), &[bcb(1)]);
|
||||
}
|
||||
|
||||
/// Create a mock `Body` with nested loops.
|
||||
|
|
@ -494,11 +476,11 @@ fn switchint_loop_then_inner_loop_else_break<'a>() -> Body<'a> {
|
|||
#[test]
|
||||
fn test_covgraph_switchint_loop_then_inner_loop_else_break() {
|
||||
let mir_body = switchint_loop_then_inner_loop_else_break();
|
||||
let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
|
||||
let graph = graph::CoverageGraph::from_mir(&mir_body);
|
||||
print_coverage_graphviz(
|
||||
"covgraph_switchint_loop_then_inner_loop_else_break",
|
||||
&mir_body,
|
||||
&basic_coverage_blocks,
|
||||
&graph,
|
||||
);
|
||||
/*
|
||||
┌─────────────────┐
|
||||
|
|
@ -531,18 +513,13 @@ fn test_covgraph_switchint_loop_then_inner_loop_else_break() {
|
|||
│ │
|
||||
└────────────────────────────────────────────┘
|
||||
*/
|
||||
assert_eq!(
|
||||
basic_coverage_blocks.num_nodes(),
|
||||
7,
|
||||
"basic_coverage_blocks: {:?}",
|
||||
basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
|
||||
);
|
||||
assert_eq!(graph.num_nodes(), 7, "graph: {:?}", graph.iter_enumerated().collect::<Vec<_>>());
|
||||
|
||||
assert_successors(&basic_coverage_blocks, bcb(0), &[bcb(1)]);
|
||||
assert_successors(&basic_coverage_blocks, bcb(1), &[bcb(2), bcb(3)]);
|
||||
assert_successors(&basic_coverage_blocks, bcb(2), &[]);
|
||||
assert_successors(&basic_coverage_blocks, bcb(3), &[bcb(4)]);
|
||||
assert_successors(&basic_coverage_blocks, bcb(4), &[bcb(5), bcb(6)]);
|
||||
assert_successors(&basic_coverage_blocks, bcb(5), &[bcb(1)]);
|
||||
assert_successors(&basic_coverage_blocks, bcb(6), &[bcb(4)]);
|
||||
assert_successors(&graph, bcb(0), &[bcb(1)]);
|
||||
assert_successors(&graph, bcb(1), &[bcb(2), bcb(3)]);
|
||||
assert_successors(&graph, bcb(2), &[]);
|
||||
assert_successors(&graph, bcb(3), &[bcb(4)]);
|
||||
assert_successors(&graph, bcb(4), &[bcb(5), bcb(6)]);
|
||||
assert_successors(&graph, bcb(5), &[bcb(1)]);
|
||||
assert_successors(&graph, bcb(6), &[bcb(4)]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ use rustc_ast_pretty::pprust;
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, PResult, Subdiagnostic,
|
||||
Suggestions, pluralize,
|
||||
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, PResult, Subdiagnostic, Suggestions,
|
||||
pluralize,
|
||||
};
|
||||
use rustc_session::errors::ExprParenthesesNeeded;
|
||||
use rustc_span::edit_distance::find_best_match_for_name;
|
||||
|
|
@ -3023,17 +3023,10 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
pub(super) fn recover_vcs_conflict_marker(&mut self) {
|
||||
if let Err(err) = self.err_vcs_conflict_marker() {
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn err_vcs_conflict_marker(&mut self) -> PResult<'a, ()> {
|
||||
// <<<<<<<
|
||||
let Some(start) = self.conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt)
|
||||
else {
|
||||
return Ok(());
|
||||
return;
|
||||
};
|
||||
let mut spans = Vec::with_capacity(3);
|
||||
spans.push(start);
|
||||
|
|
@ -3063,7 +3056,7 @@ impl<'a> Parser<'a> {
|
|||
self.bump();
|
||||
}
|
||||
|
||||
let mut err = self.dcx().struct_span_err(spans, "encountered diff marker");
|
||||
let mut err = self.dcx().struct_span_fatal(spans, "encountered diff marker");
|
||||
match middlediff3 {
|
||||
// We're using diff3
|
||||
Some(middlediff3) => {
|
||||
|
|
@ -3106,7 +3099,7 @@ impl<'a> Parser<'a> {
|
|||
visit <https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_checking_out_conflicts>",
|
||||
);
|
||||
|
||||
Err(err)
|
||||
err.emit();
|
||||
}
|
||||
|
||||
/// Parse and throw away a parenthesized comma separated
|
||||
|
|
|
|||
|
|
@ -597,8 +597,7 @@ impl<'a> Parser<'a> {
|
|||
// When encountering severely malformed code where there are several levels of
|
||||
// nested unclosed angle args (`f::<f::<f::<f::<...`), we avoid severe O(n^2)
|
||||
// behavior by bailing out earlier (#117080).
|
||||
e.emit();
|
||||
rustc_errors::FatalError.raise();
|
||||
e.emit().raise_fatal();
|
||||
}
|
||||
Err(e) if is_first_invocation && self.unmatched_angle_bracket_count > 0 => {
|
||||
self.angle_bracket_nesting -= 1;
|
||||
|
|
|
|||
|
|
@ -566,6 +566,10 @@ passes_no_sanitize =
|
|||
`#[no_sanitize({$attr_str})]` should be applied to {$accepted_kind}
|
||||
.label = not {$accepted_kind}
|
||||
|
||||
passes_non_exaustive_with_default_field_values =
|
||||
`#[non_exhaustive]` can't be used to annotate items with default field values
|
||||
.label = this struct has default field values
|
||||
|
||||
passes_non_exported_macro_invalid_attrs =
|
||||
attribute should be applied to function or closure
|
||||
.label = not a function or closure
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
[sym::coverage, ..] => self.check_coverage(attr, span, target),
|
||||
[sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
|
||||
[sym::no_sanitize, ..] => self.check_no_sanitize(attr, span, target),
|
||||
[sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target),
|
||||
[sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item),
|
||||
[sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
|
||||
[sym::target_feature, ..] => {
|
||||
self.check_target_feature(hir_id, attr, span, target, attrs)
|
||||
|
|
@ -186,6 +186,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
[sym::rustc_coinductive, ..]
|
||||
| [sym::rustc_must_implement_one_of, ..]
|
||||
| [sym::rustc_deny_explicit_impl, ..]
|
||||
| [sym::rustc_do_not_implement_via_object, ..]
|
||||
| [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
|
||||
[sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
|
||||
[sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
|
||||
|
|
@ -684,9 +685,30 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
}
|
||||
|
||||
/// Checks if the `#[non_exhaustive]` attribute on an `item` is valid.
|
||||
fn check_non_exhaustive(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
|
||||
fn check_non_exhaustive(
|
||||
&self,
|
||||
hir_id: HirId,
|
||||
attr: &Attribute,
|
||||
span: Span,
|
||||
target: Target,
|
||||
item: Option<ItemLike<'_>>,
|
||||
) {
|
||||
match target {
|
||||
Target::Struct | Target::Enum | Target::Variant => {}
|
||||
Target::Struct => {
|
||||
if let Some(ItemLike::Item(hir::Item {
|
||||
kind: hir::ItemKind::Struct(hir::VariantData::Struct { fields, .. }, _),
|
||||
..
|
||||
})) = item
|
||||
&& !fields.is_empty()
|
||||
&& fields.iter().any(|f| f.default.is_some())
|
||||
{
|
||||
self.dcx().emit_err(errors::NonExhaustiveWithDefaultFieldValues {
|
||||
attr_span: attr.span,
|
||||
defn_span: span,
|
||||
});
|
||||
}
|
||||
}
|
||||
Target::Enum | Target::Variant => {}
|
||||
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
|
||||
// `#[non_exhaustive]` attribute with just a lint, because we previously
|
||||
// erroneously allowed it and some crates used it accidentally, to be compatible
|
||||
|
|
|
|||
|
|
@ -119,6 +119,15 @@ pub(crate) struct NonExhaustiveWrongLocation {
|
|||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_non_exaustive_with_default_field_values)]
|
||||
pub(crate) struct NonExhaustiveWithDefaultFieldValues {
|
||||
#[primary_span]
|
||||
pub attr_span: Span,
|
||||
#[label]
|
||||
pub defn_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(passes_should_be_applied_to_trait)]
|
||||
pub(crate) struct AttrShouldBeAppliedToTrait {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ pub enum CrateDepKind {
|
|||
/// A dependency that is only used for its macros.
|
||||
MacrosOnly,
|
||||
/// A dependency that is always injected into the dependency list and so
|
||||
/// doesn't need to be linked to an rlib, e.g., the injected allocator.
|
||||
/// doesn't need to be linked to an rlib, e.g., the injected panic runtime.
|
||||
Implicit,
|
||||
/// A dependency that is required by an rlib version of this crate.
|
||||
/// Ordinary `extern crate`s result in `Explicit` dependencies.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
use std::path::Path;
|
||||
|
||||
use rustc_ast::{self as ast, attr};
|
||||
use rustc_errors::FatalError;
|
||||
use rustc_span::{Span, Symbol, sym};
|
||||
|
||||
use crate::Session;
|
||||
|
|
@ -90,11 +89,10 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol {
|
|||
}
|
||||
|
||||
pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option<Span>) {
|
||||
let mut err_count = 0;
|
||||
let mut guar = None;
|
||||
{
|
||||
if s.is_empty() {
|
||||
err_count += 1;
|
||||
sess.dcx().emit_err(CrateNameEmpty { span: sp });
|
||||
guar = Some(sess.dcx().emit_err(CrateNameEmpty { span: sp }));
|
||||
}
|
||||
for c in s.as_str().chars() {
|
||||
if c.is_alphanumeric() {
|
||||
|
|
@ -103,8 +101,7 @@ pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option<Span>) {
|
|||
if c == '_' {
|
||||
continue;
|
||||
}
|
||||
err_count += 1;
|
||||
sess.dcx().emit_err(InvalidCharacterInCrateName {
|
||||
guar = Some(sess.dcx().emit_err(InvalidCharacterInCrateName {
|
||||
span: sp,
|
||||
character: c,
|
||||
crate_name: s,
|
||||
|
|
@ -113,12 +110,12 @@ pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option<Span>) {
|
|||
} else {
|
||||
None
|
||||
},
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
if err_count > 0 {
|
||||
FatalError.raise();
|
||||
if let Some(guar) = guar {
|
||||
guar.raise_fatal();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1717,6 +1717,7 @@ symbols! {
|
|||
rustc_diagnostic_macros,
|
||||
rustc_dirty,
|
||||
rustc_do_not_const_check,
|
||||
rustc_do_not_implement_via_object,
|
||||
rustc_doc_primitive,
|
||||
rustc_driver,
|
||||
rustc_dummy,
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
use std::fmt;
|
||||
|
||||
use rustc_errors::{
|
||||
Diag, E0275, EmissionGuarantee, ErrorGuaranteed, FatalError, struct_span_code_err,
|
||||
};
|
||||
use rustc_errors::{Diag, E0275, EmissionGuarantee, ErrorGuaranteed, struct_span_code_err};
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_hir::def_id::LOCAL_CRATE;
|
||||
use rustc_infer::traits::{Obligation, PredicateObligation};
|
||||
|
|
@ -52,8 +50,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
) -> ! {
|
||||
let mut err = self.build_overflow_error(cause, span, suggest_increasing_limit);
|
||||
mutate(&mut err);
|
||||
err.emit();
|
||||
FatalError.raise();
|
||||
err.emit().raise_fatal();
|
||||
}
|
||||
|
||||
pub fn build_overflow_error(
|
||||
|
|
|
|||
|
|
@ -133,7 +133,9 @@ pub trait AsyncDrop {
|
|||
}
|
||||
|
||||
#[lang = "async_destruct"]
|
||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
|
||||
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
|
||||
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
|
||||
trait AsyncDestruct {
|
||||
type AsyncDestructor: Future<Output = ()>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,7 +141,9 @@ unsafe impl<T: Sync + ?Sized> Send for &T {}
|
|||
)]
|
||||
#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable
|
||||
#[rustc_specialization_trait]
|
||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
|
||||
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
|
||||
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
|
||||
#[rustc_coinductive]
|
||||
pub trait Sized {
|
||||
// Empty.
|
||||
|
|
@ -181,7 +183,9 @@ pub trait Sized {
|
|||
/// [^1]: Formerly known as *object safe*.
|
||||
#[unstable(feature = "unsize", issue = "18598")]
|
||||
#[lang = "unsize"]
|
||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
|
||||
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
|
||||
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
|
||||
pub trait Unsize<T: ?Sized> {
|
||||
// Empty.
|
||||
}
|
||||
|
|
@ -815,7 +819,9 @@ impl<T: ?Sized> StructuralPartialEq for PhantomData<T> {}
|
|||
reason = "this trait is unlikely to ever be stabilized, use `mem::discriminant` instead"
|
||||
)]
|
||||
#[lang = "discriminant_kind"]
|
||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
|
||||
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
|
||||
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
|
||||
pub trait DiscriminantKind {
|
||||
/// The type of the discriminant, which must satisfy the trait
|
||||
/// bounds required by `mem::Discriminant`.
|
||||
|
|
@ -956,7 +962,9 @@ marker_impls! {
|
|||
#[unstable(feature = "const_destruct", issue = "133214")]
|
||||
#[lang = "destruct"]
|
||||
#[rustc_on_unimplemented(message = "can't drop `{Self}`", append_const_msg)]
|
||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
|
||||
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
|
||||
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
|
||||
#[cfg_attr(not(bootstrap), const_trait)]
|
||||
pub trait Destruct {}
|
||||
|
||||
|
|
@ -967,19 +975,22 @@ pub trait Destruct {}
|
|||
#[unstable(feature = "tuple_trait", issue = "none")]
|
||||
#[lang = "tuple_trait"]
|
||||
#[diagnostic::on_unimplemented(message = "`{Self}` is not a tuple")]
|
||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
|
||||
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
|
||||
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
|
||||
pub trait Tuple {}
|
||||
|
||||
/// A marker for pointer-like types.
|
||||
///
|
||||
/// All types that have the same size and alignment as a `usize` or
|
||||
/// `*const ()` automatically implement this trait.
|
||||
/// This trait can only be implemented for types that have the same size and alignment
|
||||
/// as a `usize` or `*const ()`.
|
||||
#[unstable(feature = "pointer_like_trait", issue = "none")]
|
||||
#[lang = "pointer_like"]
|
||||
#[diagnostic::on_unimplemented(
|
||||
message = "`{Self}` needs to have the same ABI as a pointer",
|
||||
label = "`{Self}` needs to be a pointer-like type"
|
||||
)]
|
||||
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
|
||||
pub trait PointerLike {}
|
||||
|
||||
#[cfg(not(bootstrap))]
|
||||
|
|
@ -1068,7 +1079,9 @@ marker_impls! {
|
|||
reason = "internal trait for implementing various traits for all function pointers"
|
||||
)]
|
||||
#[lang = "fn_ptr_trait"]
|
||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
|
||||
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
|
||||
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
|
||||
pub trait FnPtr: Copy + Clone {
|
||||
/// Returns the address of the function pointer.
|
||||
#[lang = "fn_ptr_addr"]
|
||||
|
|
|
|||
|
|
@ -84,7 +84,9 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy};
|
|||
/// `usize` is stable, but not portable.
|
||||
#[unstable(feature = "transmutability", issue = "99571")]
|
||||
#[lang = "transmute_trait"]
|
||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
|
||||
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
|
||||
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
|
||||
#[rustc_coinductive]
|
||||
pub unsafe trait TransmuteFrom<Src, const ASSUME: Assume = { Assume::NOTHING }>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -53,7 +53,9 @@ use crate::ptr::NonNull;
|
|||
///
|
||||
/// [`to_raw_parts`]: *const::to_raw_parts
|
||||
#[lang = "pointee_trait"]
|
||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||
#[cfg_attr(bootstrap, rustc_deny_explicit_impl(implement_via_object = false))]
|
||||
#[cfg_attr(not(bootstrap), rustc_deny_explicit_impl)]
|
||||
#[cfg_attr(not(bootstrap), rustc_do_not_implement_via_object)]
|
||||
pub trait Pointee {
|
||||
/// The type for metadata in pointers and references to `Self`.
|
||||
#[lang = "metadata_type"]
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ pub struct Iter<'a, T: 'a> {
|
|||
ptr: NonNull<T>,
|
||||
/// For non-ZSTs, the non-null pointer to the past-the-end element.
|
||||
///
|
||||
/// For ZSTs, this is `ptr::dangling(len)`.
|
||||
/// For ZSTs, this is `ptr::without_provenance_mut(len)`.
|
||||
end_or_len: *const T,
|
||||
_marker: PhantomData<&'a T>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@
|
|||
|
||||
#![stable(feature = "process_extensions", since = "1.2.0")]
|
||||
|
||||
use crate::ffi::OsStr;
|
||||
use crate::ffi::{OsStr, c_void};
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::os::windows::io::{
|
||||
AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
|
||||
};
|
||||
use crate::sealed::Sealed;
|
||||
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
|
||||
use crate::{process, sys};
|
||||
use crate::{io, marker, process, ptr, sys};
|
||||
|
||||
#[stable(feature = "process_extensions", since = "1.2.0")]
|
||||
impl FromRawHandle for process::Stdio {
|
||||
|
|
@ -295,41 +296,25 @@ pub trait CommandExt: Sealed {
|
|||
#[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
|
||||
fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
|
||||
|
||||
/// Set a raw attribute on the command, providing extended configuration options for Windows
|
||||
/// processes.
|
||||
/// Executes the command as a child process with the given
|
||||
/// [`ProcThreadAttributeList`], returning a handle to it.
|
||||
///
|
||||
/// This method allows you to specify custom attributes for a child process on Windows systems
|
||||
/// using raw attribute values. Raw attributes provide extended configurability for process
|
||||
/// creation, but their usage can be complex and potentially unsafe.
|
||||
///
|
||||
/// The `attribute` parameter specifies the raw attribute to be set, while the `value`
|
||||
/// parameter holds the value associated with that attribute. Please refer to the
|
||||
/// [`windows-rs` documentation] or the [Win32 API documentation] for detailed information
|
||||
/// about available attributes and their meanings.
|
||||
///
|
||||
/// [`windows-rs` documentation]: https://microsoft.github.io/windows-docs-rs/doc/windows/
|
||||
/// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute
|
||||
/// This method enables the customization of attributes for the spawned
|
||||
/// child process on Windows systems.
|
||||
/// Attributes offer extended configurability for process creation,
|
||||
/// but their usage can be intricate and potentially unsafe.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The maximum number of raw attributes is the value of [`u32::MAX`].
|
||||
/// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error`
|
||||
/// indicating that the maximum number of attributes has been exceeded.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The usage of raw attributes is potentially unsafe and should be done with caution.
|
||||
/// Incorrect attribute values or improper configuration can lead to unexpected behavior or
|
||||
/// errors.
|
||||
/// By default, stdin, stdout, and stderr are inherited from the parent
|
||||
/// process.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// The following example demonstrates how to create a child process with a specific parent
|
||||
/// process ID using a raw attribute.
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// #![feature(windows_process_extensions_raw_attribute)]
|
||||
/// use std::os::windows::{process::CommandExt, io::AsRawHandle};
|
||||
/// use std::os::windows::io::AsRawHandle;
|
||||
/// use std::os::windows::process::{CommandExt, ProcThreadAttributeList};
|
||||
/// use std::process::Command;
|
||||
///
|
||||
/// # struct ProcessDropGuard(std::process::Child);
|
||||
|
|
@ -338,36 +323,27 @@ pub trait CommandExt: Sealed {
|
|||
/// # let _ = self.0.kill();
|
||||
/// # }
|
||||
/// # }
|
||||
///
|
||||
/// let parent = Command::new("cmd").spawn()?;
|
||||
///
|
||||
/// let mut child_cmd = Command::new("cmd");
|
||||
///
|
||||
/// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
|
||||
///
|
||||
/// unsafe {
|
||||
/// child_cmd.raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.as_raw_handle() as isize);
|
||||
/// }
|
||||
/// #
|
||||
/// let parent = Command::new("cmd").spawn()?;
|
||||
/// let parent_process_handle = parent.as_raw_handle();
|
||||
/// # let parent = ProcessDropGuard(parent);
|
||||
///
|
||||
/// let mut child = child_cmd.spawn()?;
|
||||
/// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
|
||||
/// let mut attribute_list = ProcThreadAttributeList::build()
|
||||
/// .attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle)
|
||||
/// .finish()
|
||||
/// .unwrap();
|
||||
///
|
||||
/// let mut child = Command::new("cmd").spawn_with_attributes(&attribute_list)?;
|
||||
/// #
|
||||
/// # child.kill()?;
|
||||
/// # Ok::<(), std::io::Error>(())
|
||||
/// ```
|
||||
///
|
||||
/// # Safety Note
|
||||
///
|
||||
/// Remember that improper use of raw attributes can lead to undefined behavior or security
|
||||
/// vulnerabilities. Always consult the documentation and ensure proper attribute values are
|
||||
/// used.
|
||||
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
|
||||
unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
|
||||
fn spawn_with_attributes(
|
||||
&mut self,
|
||||
attribute: usize,
|
||||
value: T,
|
||||
) -> &mut process::Command;
|
||||
attribute_list: &ProcThreadAttributeList<'_>,
|
||||
) -> io::Result<process::Child>;
|
||||
}
|
||||
|
||||
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
|
||||
|
|
@ -401,13 +377,13 @@ impl CommandExt for process::Command {
|
|||
self
|
||||
}
|
||||
|
||||
unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
|
||||
fn spawn_with_attributes(
|
||||
&mut self,
|
||||
attribute: usize,
|
||||
value: T,
|
||||
) -> &mut process::Command {
|
||||
unsafe { self.as_inner_mut().raw_attribute(attribute, value) };
|
||||
self
|
||||
attribute_list: &ProcThreadAttributeList<'_>,
|
||||
) -> io::Result<process::Child> {
|
||||
self.as_inner_mut()
|
||||
.spawn_with_attributes(sys::process::Stdio::Inherit, true, Some(attribute_list))
|
||||
.map(process::Child::from_inner)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -447,3 +423,245 @@ impl ExitCodeExt for process::ExitCode {
|
|||
process::ExitCode::from_inner(From::from(raw))
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around windows [`ProcThreadAttributeList`][1].
|
||||
///
|
||||
/// [1]: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-initializeprocthreadattributelist>
|
||||
#[derive(Debug)]
|
||||
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
|
||||
pub struct ProcThreadAttributeList<'a> {
|
||||
attribute_list: Box<[MaybeUninit<u8>]>,
|
||||
_lifetime_marker: marker::PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
|
||||
impl<'a> ProcThreadAttributeList<'a> {
|
||||
/// Creates a new builder for constructing a [`ProcThreadAttributeList`].
|
||||
pub fn build() -> ProcThreadAttributeListBuilder<'a> {
|
||||
ProcThreadAttributeListBuilder::new()
|
||||
}
|
||||
|
||||
/// Returns a pointer to the underling attribute list.
|
||||
#[doc(hidden)]
|
||||
pub fn as_ptr(&self) -> *const MaybeUninit<u8> {
|
||||
self.attribute_list.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
|
||||
impl<'a> Drop for ProcThreadAttributeList<'a> {
|
||||
/// Deletes the attribute list.
|
||||
///
|
||||
/// This method calls [`DeleteProcThreadAttributeList`][1] to delete the
|
||||
/// underlying attribute list.
|
||||
///
|
||||
/// [1]: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-deleteprocthreadattributelist>
|
||||
fn drop(&mut self) {
|
||||
let lp_attribute_list = self.attribute_list.as_mut_ptr().cast::<c_void>();
|
||||
unsafe { sys::c::DeleteProcThreadAttributeList(lp_attribute_list) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Builder for constructing a [`ProcThreadAttributeList`].
|
||||
#[derive(Clone, Debug)]
|
||||
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
|
||||
pub struct ProcThreadAttributeListBuilder<'a> {
|
||||
attributes: alloc::collections::BTreeMap<usize, ProcThreadAttributeValue>,
|
||||
_lifetime_marker: marker::PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
#[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
|
||||
impl<'a> ProcThreadAttributeListBuilder<'a> {
|
||||
fn new() -> Self {
|
||||
ProcThreadAttributeListBuilder {
|
||||
attributes: alloc::collections::BTreeMap::new(),
|
||||
_lifetime_marker: marker::PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets an attribute on the attribute list.
|
||||
///
|
||||
/// The `attribute` parameter specifies the raw attribute to be set, while
|
||||
/// the `value` parameter holds the value associated with that attribute.
|
||||
/// Please refer to the [Windows documentation][1] for a list of valid attributes.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The maximum number of attributes is the value of [`u32::MAX`]. If this
|
||||
/// limit is exceeded, the call to [`Self::finish`] will return an `Error`
|
||||
/// indicating that the maximum number of attributes has been exceeded.
|
||||
///
|
||||
/// # Safety Note
|
||||
///
|
||||
/// Remember that improper use of attributes can lead to undefined behavior
|
||||
/// or security vulnerabilities. Always consult the documentation and ensure
|
||||
/// proper attribute values are used.
|
||||
///
|
||||
/// [1]: <https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute#parameters>
|
||||
pub fn attribute<T>(self, attribute: usize, value: &'a T) -> Self {
|
||||
unsafe {
|
||||
self.raw_attribute(
|
||||
attribute,
|
||||
ptr::addr_of!(*value).cast::<c_void>(),
|
||||
crate::mem::size_of::<T>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a raw attribute on the attribute list.
|
||||
///
|
||||
/// This function is useful for setting attributes with pointers or sizes
|
||||
/// that cannot be derived directly from their values.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is marked as `unsafe` because it deals with raw pointers
|
||||
/// and sizes. It is the responsibility of the caller to ensure the value
|
||||
/// lives longer than the resulting [`ProcThreadAttributeList`] as well as
|
||||
/// the validity of the size parameter.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(windows_process_extensions_raw_attribute)]
|
||||
/// use std::ffi::c_void;
|
||||
/// use std::os::windows::process::{CommandExt, ProcThreadAttributeList};
|
||||
/// use std::os::windows::raw::HANDLE;
|
||||
/// use std::process::Command;
|
||||
///
|
||||
/// #[repr(C)]
|
||||
/// pub struct COORD {
|
||||
/// pub X: i16,
|
||||
/// pub Y: i16,
|
||||
/// }
|
||||
///
|
||||
/// extern "system" {
|
||||
/// fn CreatePipe(
|
||||
/// hreadpipe: *mut HANDLE,
|
||||
/// hwritepipe: *mut HANDLE,
|
||||
/// lppipeattributes: *const c_void,
|
||||
/// nsize: u32,
|
||||
/// ) -> i32;
|
||||
/// fn CreatePseudoConsole(
|
||||
/// size: COORD,
|
||||
/// hinput: HANDLE,
|
||||
/// houtput: HANDLE,
|
||||
/// dwflags: u32,
|
||||
/// phpc: *mut isize,
|
||||
/// ) -> i32;
|
||||
/// fn CloseHandle(hobject: HANDLE) -> i32;
|
||||
/// }
|
||||
///
|
||||
/// let [mut input_read_side, mut output_write_side, mut output_read_side, mut input_write_side] =
|
||||
/// [unsafe { std::mem::zeroed::<HANDLE>() }; 4];
|
||||
///
|
||||
/// unsafe {
|
||||
/// CreatePipe(&mut input_read_side, &mut input_write_side, std::ptr::null(), 0);
|
||||
/// CreatePipe(&mut output_read_side, &mut output_write_side, std::ptr::null(), 0);
|
||||
/// }
|
||||
///
|
||||
/// let size = COORD { X: 60, Y: 40 };
|
||||
/// let mut h_pc = unsafe { std::mem::zeroed() };
|
||||
/// unsafe { CreatePseudoConsole(size, input_read_side, output_write_side, 0, &mut h_pc) };
|
||||
///
|
||||
/// unsafe { CloseHandle(input_read_side) };
|
||||
/// unsafe { CloseHandle(output_write_side) };
|
||||
///
|
||||
/// const PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE: usize = 131094;
|
||||
///
|
||||
/// let attribute_list = unsafe {
|
||||
/// ProcThreadAttributeList::build()
|
||||
/// .raw_attribute(
|
||||
/// PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
||||
/// h_pc as *const c_void,
|
||||
/// std::mem::size_of::<isize>(),
|
||||
/// )
|
||||
/// .finish()?
|
||||
/// };
|
||||
///
|
||||
/// let mut child = Command::new("cmd").spawn_with_attributes(&attribute_list)?;
|
||||
/// #
|
||||
/// # child.kill()?;
|
||||
/// # Ok::<(), std::io::Error>(())
|
||||
/// ```
|
||||
pub unsafe fn raw_attribute<T>(
|
||||
mut self,
|
||||
attribute: usize,
|
||||
value_ptr: *const T,
|
||||
value_size: usize,
|
||||
) -> Self {
|
||||
self.attributes.insert(attribute, ProcThreadAttributeValue {
|
||||
ptr: value_ptr.cast::<c_void>(),
|
||||
size: value_size,
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
/// Finalizes the construction of the `ProcThreadAttributeList`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the maximum number of attributes is exceeded
|
||||
/// or if there is an I/O error during initialization.
|
||||
pub fn finish(&self) -> io::Result<ProcThreadAttributeList<'a>> {
|
||||
// To initialize our ProcThreadAttributeList, we need to determine
|
||||
// how many bytes to allocate for it. The Windows API simplifies this
|
||||
// process by allowing us to call `InitializeProcThreadAttributeList`
|
||||
// with a null pointer to retrieve the required size.
|
||||
let mut required_size = 0;
|
||||
let Ok(attribute_count) = self.attributes.len().try_into() else {
|
||||
return Err(io::const_error!(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"maximum number of ProcThreadAttributes exceeded",
|
||||
));
|
||||
};
|
||||
unsafe {
|
||||
sys::c::InitializeProcThreadAttributeList(
|
||||
ptr::null_mut(),
|
||||
attribute_count,
|
||||
0,
|
||||
&mut required_size,
|
||||
)
|
||||
};
|
||||
|
||||
let mut attribute_list = vec![MaybeUninit::uninit(); required_size].into_boxed_slice();
|
||||
|
||||
// Once we've allocated the necessary memory, it's safe to invoke
|
||||
// `InitializeProcThreadAttributeList` to properly initialize the list.
|
||||
sys::cvt(unsafe {
|
||||
sys::c::InitializeProcThreadAttributeList(
|
||||
attribute_list.as_mut_ptr().cast::<c_void>(),
|
||||
attribute_count,
|
||||
0,
|
||||
&mut required_size,
|
||||
)
|
||||
})?;
|
||||
|
||||
// # Add our attributes to the buffer.
|
||||
// It's theoretically possible for the attribute count to exceed a u32
|
||||
// value. Therefore, we ensure that we don't add more attributes than
|
||||
// the buffer was initialized for.
|
||||
for (&attribute, value) in self.attributes.iter().take(attribute_count as usize) {
|
||||
sys::cvt(unsafe {
|
||||
sys::c::UpdateProcThreadAttribute(
|
||||
attribute_list.as_mut_ptr().cast::<c_void>(),
|
||||
0,
|
||||
attribute,
|
||||
value.ptr,
|
||||
value.size,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(ProcThreadAttributeList { attribute_list, _lifetime_marker: marker::PhantomData })
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around the value data to be used as a Process Thread Attribute.
|
||||
#[derive(Clone, Debug)]
|
||||
struct ProcThreadAttributeValue {
|
||||
ptr: *const c_void,
|
||||
size: usize,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ fn test_creation_flags() {
|
|||
fn test_proc_thread_attributes() {
|
||||
use crate::mem;
|
||||
use crate::os::windows::io::AsRawHandle;
|
||||
use crate::os::windows::process::CommandExt;
|
||||
use crate::os::windows::process::{CommandExt, ProcThreadAttributeList};
|
||||
use crate::sys::c::{BOOL, CloseHandle, HANDLE};
|
||||
use crate::sys::cvt;
|
||||
|
||||
|
|
@ -490,12 +490,14 @@ fn test_proc_thread_attributes() {
|
|||
|
||||
let mut child_cmd = Command::new("cmd");
|
||||
|
||||
unsafe {
|
||||
child_cmd
|
||||
.raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.0.as_raw_handle() as isize);
|
||||
}
|
||||
let parent_process_handle = parent.0.as_raw_handle();
|
||||
|
||||
let child = ProcessDropGuard(child_cmd.spawn().unwrap());
|
||||
let mut attribute_list = ProcThreadAttributeList::build()
|
||||
.attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &parent_process_handle)
|
||||
.finish()
|
||||
.unwrap();
|
||||
|
||||
let child = ProcessDropGuard(child_cmd.spawn_with_attributes(&mut attribute_list).unwrap());
|
||||
|
||||
let h_snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ unsafe impl Sync for Thread {}
|
|||
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
let p = Box::into_raw(Box::new(p));
|
||||
let mut native: libc::pthread_t = mem::zeroed();
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ use crate::collections::BTreeMap;
|
|||
use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX};
|
||||
use crate::ffi::{OsStr, OsString};
|
||||
use crate::io::{self, Error, ErrorKind};
|
||||
use crate::mem::MaybeUninit;
|
||||
use crate::num::NonZero;
|
||||
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
|
||||
use crate::os::windows::process::ProcThreadAttributeList;
|
||||
use crate::path::{Path, PathBuf};
|
||||
use crate::sync::Mutex;
|
||||
use crate::sys::args::{self, Arg};
|
||||
|
|
@ -162,7 +162,6 @@ pub struct Command {
|
|||
stdout: Option<Stdio>,
|
||||
stderr: Option<Stdio>,
|
||||
force_quotes_enabled: bool,
|
||||
proc_thread_attributes: BTreeMap<usize, ProcThreadAttributeValue>,
|
||||
}
|
||||
|
||||
pub enum Stdio {
|
||||
|
|
@ -194,7 +193,6 @@ impl Command {
|
|||
stdout: None,
|
||||
stderr: None,
|
||||
force_quotes_enabled: false,
|
||||
proc_thread_attributes: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -248,21 +246,19 @@ impl Command {
|
|||
self.cwd.as_ref().map(Path::new)
|
||||
}
|
||||
|
||||
pub unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
|
||||
&mut self,
|
||||
attribute: usize,
|
||||
value: T,
|
||||
) {
|
||||
self.proc_thread_attributes.insert(attribute, ProcThreadAttributeValue {
|
||||
size: mem::size_of::<T>(),
|
||||
data: Box::new(value),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn spawn(
|
||||
&mut self,
|
||||
default: Stdio,
|
||||
needs_stdin: bool,
|
||||
) -> io::Result<(Process, StdioPipes)> {
|
||||
self.spawn_with_attributes(default, needs_stdin, None)
|
||||
}
|
||||
|
||||
pub fn spawn_with_attributes(
|
||||
&mut self,
|
||||
default: Stdio,
|
||||
needs_stdin: bool,
|
||||
proc_thread_attribute_list: Option<&ProcThreadAttributeList<'_>>,
|
||||
) -> io::Result<(Process, StdioPipes)> {
|
||||
let maybe_env = self.env.capture_if_changed();
|
||||
|
||||
|
|
@ -355,18 +351,18 @@ impl Command {
|
|||
|
||||
let si_ptr: *mut c::STARTUPINFOW;
|
||||
|
||||
let mut proc_thread_attribute_list;
|
||||
let mut si_ex;
|
||||
|
||||
if !self.proc_thread_attributes.is_empty() {
|
||||
if let Some(proc_thread_attribute_list) = proc_thread_attribute_list {
|
||||
si.cb = mem::size_of::<c::STARTUPINFOEXW>() as u32;
|
||||
flags |= c::EXTENDED_STARTUPINFO_PRESENT;
|
||||
|
||||
proc_thread_attribute_list =
|
||||
make_proc_thread_attribute_list(&self.proc_thread_attributes)?;
|
||||
si_ex = c::STARTUPINFOEXW {
|
||||
StartupInfo: si,
|
||||
lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _,
|
||||
// SAFETY: Casting this `*const` pointer to a `*mut` pointer is "safe"
|
||||
// here because windows does not internally mutate the attribute list.
|
||||
// Ideally this should be reflected in the interface of the `windows-sys` crate.
|
||||
lpAttributeList: proc_thread_attribute_list.as_ptr().cast::<c_void>().cast_mut(),
|
||||
};
|
||||
si_ptr = (&raw mut si_ex) as _;
|
||||
} else {
|
||||
|
|
@ -896,79 +892,6 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
|
|||
}
|
||||
}
|
||||
|
||||
struct ProcThreadAttributeList(Box<[MaybeUninit<u8>]>);
|
||||
|
||||
impl Drop for ProcThreadAttributeList {
|
||||
fn drop(&mut self) {
|
||||
let lp_attribute_list = self.0.as_mut_ptr() as _;
|
||||
unsafe { c::DeleteProcThreadAttributeList(lp_attribute_list) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper around the value data to be used as a Process Thread Attribute.
|
||||
struct ProcThreadAttributeValue {
|
||||
data: Box<dyn Send + Sync>,
|
||||
size: usize,
|
||||
}
|
||||
|
||||
fn make_proc_thread_attribute_list(
|
||||
attributes: &BTreeMap<usize, ProcThreadAttributeValue>,
|
||||
) -> io::Result<ProcThreadAttributeList> {
|
||||
// To initialize our ProcThreadAttributeList, we need to determine
|
||||
// how many bytes to allocate for it. The Windows API simplifies this process
|
||||
// by allowing us to call `InitializeProcThreadAttributeList` with
|
||||
// a null pointer to retrieve the required size.
|
||||
let mut required_size = 0;
|
||||
let Ok(attribute_count) = attributes.len().try_into() else {
|
||||
return Err(io::const_error!(
|
||||
ErrorKind::InvalidInput,
|
||||
"maximum number of ProcThreadAttributes exceeded",
|
||||
));
|
||||
};
|
||||
unsafe {
|
||||
c::InitializeProcThreadAttributeList(
|
||||
ptr::null_mut(),
|
||||
attribute_count,
|
||||
0,
|
||||
&mut required_size,
|
||||
)
|
||||
};
|
||||
|
||||
let mut proc_thread_attribute_list =
|
||||
ProcThreadAttributeList(vec![MaybeUninit::uninit(); required_size].into_boxed_slice());
|
||||
|
||||
// Once we've allocated the necessary memory, it's safe to invoke
|
||||
// `InitializeProcThreadAttributeList` to properly initialize the list.
|
||||
cvt(unsafe {
|
||||
c::InitializeProcThreadAttributeList(
|
||||
proc_thread_attribute_list.0.as_mut_ptr() as *mut _,
|
||||
attribute_count,
|
||||
0,
|
||||
&mut required_size,
|
||||
)
|
||||
})?;
|
||||
|
||||
// # Add our attributes to the buffer.
|
||||
// It's theoretically possible for the attribute count to exceed a u32 value.
|
||||
// Therefore, we ensure that we don't add more attributes than the buffer was initialized for.
|
||||
for (&attribute, value) in attributes.iter().take(attribute_count as usize) {
|
||||
let value_ptr = (&raw const *value.data) as _;
|
||||
cvt(unsafe {
|
||||
c::UpdateProcThreadAttribute(
|
||||
proc_thread_attribute_list.0.as_mut_ptr() as _,
|
||||
0,
|
||||
attribute,
|
||||
value_ptr,
|
||||
value.size,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(proc_thread_attribute_list)
|
||||
}
|
||||
|
||||
pub struct CommandArgs<'a> {
|
||||
iter: crate::slice::Iter<'a, Arg>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ pub struct Thread {
|
|||
|
||||
impl Thread {
|
||||
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
|
||||
let p = Box::into_raw(Box::new(p));
|
||||
|
||||
|
|
|
|||
|
|
@ -391,6 +391,7 @@ impl Builder {
|
|||
/// handler.join().unwrap();
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
|
|
@ -458,6 +459,7 @@ impl Builder {
|
|||
///
|
||||
/// [`io::Result`]: crate::io::Result
|
||||
#[stable(feature = "thread_spawn_unchecked", since = "1.82.0")]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub unsafe fn spawn_unchecked<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
|
|
@ -467,6 +469,7 @@ impl Builder {
|
|||
Ok(JoinHandle(unsafe { self.spawn_unchecked_(f, None) }?))
|
||||
}
|
||||
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
unsafe fn spawn_unchecked_<'scope, F, T>(
|
||||
self,
|
||||
f: F,
|
||||
|
|
@ -721,6 +724,7 @@ impl Builder {
|
|||
/// [`join`]: JoinHandle::join
|
||||
/// [`Err`]: crate::result::Result::Err
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
|
||||
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ impl<'a> Renderer<'a> {
|
|||
for bench in &self.benches {
|
||||
rows.push((
|
||||
&bench.name,
|
||||
format!("{:.2?}/iter", bench.median),
|
||||
format!("{:.2?}ns/iter", bench.median),
|
||||
format!("+/- {:.2?}", bench.deviation),
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,99 +0,0 @@
|
|||
# We document platform support for minimum glibc 2.17 and kernel 3.2.
|
||||
# CentOS 7 has headers for kernel 3.10, but that's fine as long as we don't
|
||||
# actually use newer APIs in rustc or std without a fallback. It's more
|
||||
# important that we match glibc for ELF symbol versioning.
|
||||
FROM centos:7
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# CentOS 7 EOL is June 30, 2024, but the repos remain in the vault.
|
||||
RUN sed -i /etc/yum.repos.d/*.repo -e 's!^mirrorlist!#mirrorlist!' \
|
||||
-e 's!^#baseurl=http://mirror.centos.org/!baseurl=https://vault.centos.org/!'
|
||||
RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf
|
||||
|
||||
RUN yum upgrade -y && \
|
||||
yum install -y \
|
||||
automake \
|
||||
bzip2 \
|
||||
file \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
git \
|
||||
glibc-devel \
|
||||
libedit-devel \
|
||||
libstdc++-devel \
|
||||
make \
|
||||
ncurses-devel \
|
||||
openssl-devel \
|
||||
patch \
|
||||
perl \
|
||||
perl-core \
|
||||
pkgconfig \
|
||||
python3 \
|
||||
unzip \
|
||||
wget \
|
||||
xz \
|
||||
zlib-devel \
|
||||
&& yum clean all
|
||||
|
||||
RUN mkdir -p /rustroot/bin
|
||||
|
||||
ENV PATH=/rustroot/bin:$PATH
|
||||
ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
|
||||
ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
|
||||
WORKDIR /tmp
|
||||
RUN mkdir /home/user
|
||||
COPY scripts/shared.sh /tmp/
|
||||
|
||||
# Need at least GCC 5.1 to compile LLVM
|
||||
COPY scripts/build-gcc.sh /tmp/
|
||||
RUN ./build-gcc.sh && yum remove -y gcc gcc-c++
|
||||
|
||||
ENV CC=gcc CXX=g++
|
||||
|
||||
# LLVM 17 needs cmake 3.20 or higher.
|
||||
COPY scripts/cmake.sh /tmp/
|
||||
RUN ./cmake.sh
|
||||
|
||||
# Build LLVM+Clang
|
||||
COPY scripts/build-clang.sh /tmp/
|
||||
ENV LLVM_BUILD_TARGETS=AArch64
|
||||
RUN ./build-clang.sh
|
||||
ENV CC=clang CXX=clang++
|
||||
|
||||
# Build zstd to enable `llvm.libzstd`.
|
||||
COPY scripts/build-zstd.sh /tmp/
|
||||
RUN ./build-zstd.sh
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV PGO_HOST=aarch64-unknown-linux-gnu
|
||||
ENV HOSTS=aarch64-unknown-linux-gnu
|
||||
|
||||
ENV CPATH=/usr/include/aarch64-linux-gnu/:$CPATH
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS \
|
||||
--build=aarch64-unknown-linux-gnu \
|
||||
--enable-full-tools \
|
||||
--enable-profiler \
|
||||
--enable-sanitizers \
|
||||
--enable-compiler-docs \
|
||||
--set target.aarch64-unknown-linux-gnu.linker=clang \
|
||||
--set target.aarch64-unknown-linux-gnu.ar=/rustroot/bin/llvm-ar \
|
||||
--set target.aarch64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \
|
||||
--set llvm.link-shared=true \
|
||||
--set llvm.thin-lto=true \
|
||||
--set llvm.libzstd=true \
|
||||
--set llvm.ninja=false \
|
||||
--set rust.debug-assertions=false \
|
||||
--set rust.jemalloc \
|
||||
--set rust.use-lld=true \
|
||||
--set rust.codegen-units=1
|
||||
|
||||
ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
||||
ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=clang
|
||||
ENV DIST_SRC 1
|
||||
ENV LIBCURL_NO_PKG_CONFIG 1
|
||||
ENV DIST_REQUIRE_ALL_TOOLS 1
|
||||
32
src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
Normal file
32
src/ci/docker/host-x86_64/dist-aarch64-linux/Dockerfile
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
FROM ubuntu:22.04
|
||||
|
||||
COPY scripts/cross-apt-packages.sh /scripts/
|
||||
RUN sh /scripts/cross-apt-packages.sh
|
||||
|
||||
COPY scripts/crosstool-ng.sh /scripts/
|
||||
RUN sh /scripts/crosstool-ng.sh
|
||||
|
||||
COPY scripts/rustbuild-setup.sh /scripts/
|
||||
RUN sh /scripts/rustbuild-setup.sh
|
||||
WORKDIR /tmp
|
||||
|
||||
COPY scripts/crosstool-ng-build.sh /scripts/
|
||||
COPY host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.defconfig /tmp/crosstool.defconfig
|
||||
RUN /scripts/crosstool-ng-build.sh
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
RUN sh /scripts/sccache.sh
|
||||
|
||||
ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnu/bin
|
||||
|
||||
ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-gcc \
|
||||
AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-ar \
|
||||
CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnu-g++
|
||||
|
||||
ENV HOSTS=aarch64-unknown-linux-gnu
|
||||
|
||||
ENV RUST_CONFIGURE_ARGS \
|
||||
--enable-full-tools \
|
||||
--enable-profiler \
|
||||
--enable-sanitizers
|
||||
ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
CT_CONFIG_VERSION="4"
|
||||
CT_PREFIX_DIR="/x-tools/${CT_TARGET}"
|
||||
CT_USE_MIRROR=y
|
||||
CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc"
|
||||
CT_ARCH_ARM=y
|
||||
CT_ARCH_64=y
|
||||
CT_KERNEL_LINUX=y
|
||||
CT_LINUX_V_4_1=y
|
||||
CT_GLIBC_V_2_17=y
|
||||
CT_CC_LANG_CXX=y
|
||||
|
|
@ -46,11 +46,10 @@ ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
|
|||
ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
|
||||
WORKDIR /tmp
|
||||
RUN mkdir /home/user
|
||||
COPY scripts/shared.sh /tmp/
|
||||
COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
|
||||
|
||||
# Need at least GCC 5.1 to compile LLVM nowadays
|
||||
COPY scripts/build-gcc.sh /tmp/
|
||||
ENV GCC_BUILD_TARGET=i686
|
||||
COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
|
||||
RUN ./build-gcc.sh && yum remove -y gcc gcc-c++
|
||||
|
||||
COPY scripts/cmake.sh /tmp/
|
||||
|
|
@ -58,8 +57,7 @@ RUN ./cmake.sh
|
|||
|
||||
# Now build LLVM+Clang, afterwards configuring further compilations to use the
|
||||
# clang/clang++ compilers.
|
||||
COPY scripts/build-clang.sh /tmp/
|
||||
ENV LLVM_BUILD_TARGETS=X86
|
||||
COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/
|
||||
RUN ./build-clang.sh
|
||||
ENV CC=clang CXX=clang++
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ RUN /scripts/crosstool-ng-build.sh
|
|||
WORKDIR /build
|
||||
|
||||
RUN apt-get install -y --no-install-recommends rpm2cpio cpio
|
||||
COPY scripts/shared.sh host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh /build/
|
||||
COPY host-x86_64/dist-powerpc64le-linux/shared.sh host-x86_64/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh /build/
|
||||
RUN ./build-powerpc64le-toolchain.sh
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
|
|
|
|||
16
src/ci/docker/host-x86_64/dist-powerpc64le-linux/shared.sh
Normal file
16
src/ci/docker/host-x86_64/dist-powerpc64le-linux/shared.sh
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/sh
|
||||
hide_output() {
|
||||
set +x
|
||||
on_err="
|
||||
echo ERROR: An error was encountered with the build.
|
||||
cat /tmp/build.log
|
||||
exit 1
|
||||
"
|
||||
trap "$on_err" ERR
|
||||
bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
|
||||
PING_LOOP_PID=$!
|
||||
"$@" &> /tmp/build.log
|
||||
trap - ERR
|
||||
kill $PING_LOOP_PID
|
||||
set -x
|
||||
}
|
||||
|
|
@ -46,10 +46,10 @@ ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib32:/rustroot/lib
|
|||
ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
|
||||
WORKDIR /tmp
|
||||
RUN mkdir /home/user
|
||||
COPY scripts/shared.sh /tmp/
|
||||
COPY host-x86_64/dist-x86_64-linux/shared.sh /tmp/
|
||||
|
||||
# Need at least GCC 5.1 to compile LLVM nowadays
|
||||
COPY scripts/build-gcc.sh /tmp/
|
||||
COPY host-x86_64/dist-x86_64-linux/build-gcc.sh /tmp/
|
||||
RUN ./build-gcc.sh && yum remove -y gcc gcc-c++
|
||||
|
||||
# LLVM 17 needs cmake 3.20 or higher.
|
||||
|
|
@ -58,13 +58,12 @@ RUN ./cmake.sh
|
|||
|
||||
# Now build LLVM+Clang, afterwards configuring further compilations to use the
|
||||
# clang/clang++ compilers.
|
||||
COPY scripts/build-clang.sh /tmp/
|
||||
ENV LLVM_BUILD_TARGETS=X86
|
||||
COPY host-x86_64/dist-x86_64-linux/build-clang.sh /tmp/
|
||||
RUN ./build-clang.sh
|
||||
ENV CC=clang CXX=clang++
|
||||
|
||||
# Build zstd to enable `llvm.libzstd`.
|
||||
COPY scripts/build-zstd.sh /tmp/
|
||||
COPY host-x86_64/dist-x86_64-linux/build-zstd.sh /tmp/
|
||||
RUN ./build-zstd.sh
|
||||
|
||||
COPY scripts/sccache.sh /scripts/
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -exu
|
||||
set -ex
|
||||
|
||||
source shared.sh
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ hide_output \
|
|||
-DCOMPILER_RT_BUILD_XRAY=OFF \
|
||||
-DCOMPILER_RT_BUILD_MEMPROF=OFF \
|
||||
-DCOMPILER_RT_BUILD_CTX_PROFILE=OFF \
|
||||
-DLLVM_TARGETS_TO_BUILD=$LLVM_BUILD_TARGETS \
|
||||
-DLLVM_TARGETS_TO_BUILD=X86 \
|
||||
-DLLVM_INCLUDE_BENCHMARKS=OFF \
|
||||
-DLLVM_INCLUDE_TESTS=OFF \
|
||||
-DLLVM_INCLUDE_EXAMPLES=OFF \
|
||||
|
|
@ -50,9 +50,7 @@ cd ..
|
|||
rm -rf gcc-build
|
||||
rm -rf gcc-$GCC
|
||||
|
||||
if [[ $GCC_BUILD_TARGET == "i686" ]]; then
|
||||
# FIXME: clang doesn't find 32-bit libraries in /rustroot/lib,
|
||||
# but it does look all the way under /rustroot/lib/[...]/32,
|
||||
# so we can link stuff there to help it out.
|
||||
ln /rustroot/lib/*.{a,so} -rst /rustroot/lib/gcc/x86_64-pc-linux-gnu/$GCC/32/
|
||||
fi
|
||||
# FIXME: clang doesn't find 32-bit libraries in /rustroot/lib,
|
||||
# but it does look all the way under /rustroot/lib/[...]/32,
|
||||
# so we can link stuff there to help it out.
|
||||
ln /rustroot/lib/*.{a,so} -rst /rustroot/lib/gcc/x86_64-pc-linux-gnu/$GCC/32/
|
||||
16
src/ci/docker/host-x86_64/dist-x86_64-linux/shared.sh
Normal file
16
src/ci/docker/host-x86_64/dist-x86_64-linux/shared.sh
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#!/bin/sh
|
||||
hide_output() {
|
||||
set +x
|
||||
on_err="
|
||||
echo ERROR: An error was encountered with the build.
|
||||
cat /tmp/build.log
|
||||
exit 1
|
||||
"
|
||||
trap "$on_err" ERR
|
||||
bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
|
||||
PING_LOOP_PID=$!
|
||||
"$@" &> /tmp/build.log
|
||||
trap - ERR
|
||||
kill $PING_LOOP_PID
|
||||
set -x
|
||||
}
|
||||
|
|
@ -54,8 +54,8 @@ ENV RUST_CONFIGURE_ARGS \
|
|||
--set rust.randomize-layout=true \
|
||||
--set rust.thin-lto-import-instr-limit=10
|
||||
|
||||
COPY scripts/shared.sh /scripts/
|
||||
COPY scripts/build-gccjit.sh /scripts/
|
||||
COPY host-x86_64/dist-x86_64-linux/shared.sh /scripts/
|
||||
COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/
|
||||
|
||||
RUN /scripts/build-gccjit.sh /scripts
|
||||
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ ENV RUST_CONFIGURE_ARGS \
|
|||
--set rust.randomize-layout=true \
|
||||
--set rust.thin-lto-import-instr-limit=10
|
||||
|
||||
COPY scripts/shared.sh /scripts/
|
||||
COPY scripts/build-gccjit.sh /scripts/
|
||||
COPY host-x86_64/dist-x86_64-linux/shared.sh /scripts/
|
||||
COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/
|
||||
|
||||
RUN /scripts/build-gccjit.sh /scripts
|
||||
|
||||
|
|
|
|||
|
|
@ -89,8 +89,8 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu
|
|||
# assertions enabled! Therefore, we cannot force download CI rustc.
|
||||
#ENV FORCE_CI_RUSTC 1
|
||||
|
||||
COPY scripts/shared.sh /scripts/
|
||||
COPY scripts/build-gccjit.sh /scripts/
|
||||
COPY host-x86_64/dist-x86_64-linux/shared.sh /scripts/
|
||||
COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/
|
||||
|
||||
RUN /scripts/build-gccjit.sh /scripts
|
||||
|
||||
|
|
|
|||
|
|
@ -129,17 +129,17 @@ auto:
|
|||
- image: aarch64-gnu-debug
|
||||
<<: *job-linux-8c-aarch64
|
||||
|
||||
- image: dist-aarch64-linux
|
||||
env:
|
||||
CODEGEN_BACKENDS: llvm,cranelift
|
||||
<<: *job-linux-8c-aarch64
|
||||
|
||||
- image: arm-android
|
||||
<<: *job-linux-4c
|
||||
|
||||
- image: armhf-gnu
|
||||
<<: *job-linux-4c
|
||||
|
||||
- image: dist-aarch64-linux
|
||||
env:
|
||||
CODEGEN_BACKENDS: llvm,cranelift
|
||||
<<: *job-linux-4c
|
||||
|
||||
- image: dist-android
|
||||
<<: *job-linux-4c
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
8a1f8039a7ded79d3d4fe97b110016d89f2b11e2
|
||||
13170cd787cb733ed24842ee825bcbd98dc01476
|
||||
|
|
|
|||
|
|
@ -152,12 +152,14 @@ pub fn iter_exported_symbols<'tcx>(
|
|||
let dependency_format = dependency_formats
|
||||
.get(&CrateType::Executable)
|
||||
.expect("interpreting a non-executable crate");
|
||||
for cnum in dependency_format.iter().enumerate().filter_map(|(num, &linkage)| {
|
||||
// We add 1 to the number because that's what rustc also does everywhere it
|
||||
// calls `CrateNum::new`...
|
||||
#[expect(clippy::arithmetic_side_effects)]
|
||||
(linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1))
|
||||
}) {
|
||||
for cnum in dependency_format
|
||||
.iter_enumerated()
|
||||
.filter_map(|(num, &linkage)| (linkage != Linkage::NotLinked).then_some(num))
|
||||
{
|
||||
if cnum == LOCAL_CRATE {
|
||||
continue; // Already handled above
|
||||
}
|
||||
|
||||
// We can ignore `_export_info` here: we are a Rust crate, and everything is exported
|
||||
// from a Rust crate.
|
||||
for &(symbol, _export_info) in tcx.exported_symbols(cnum) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: aarch64 aarch64_fixed_x18 aarch64_no_x18 aarch64_reserve_x18 arm64ec
|
||||
//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
|
||||
//@[aarch64] needs-llvm-components: aarch64
|
||||
|
|
@ -14,16 +15,11 @@
|
|||
// ignore-tidy-linelength
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items)]
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// CHECK-LABEL: @cc_clobber
|
||||
// CHECK: call void asm sideeffect "", "~{cc}"()
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target avr-unknown-gnu-atmega328
|
||||
//@ needs-llvm-components: avr
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// CHECK-LABEL: @sreg_is_clobbered
|
||||
// CHECK: void asm sideeffect "", "~{sreg}"()
|
||||
|
|
|
|||
|
|
@ -1,19 +1,15 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: hexagon
|
||||
//@[hexagon] compile-flags: --target hexagon-unknown-linux-musl
|
||||
//@[hexagon] needs-llvm-components: hexagon
|
||||
//@ compile-flags: -Zmerge-functions=disabled
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// CHECK-LABEL: @flags_clobber
|
||||
// CHECK: call void asm sideeffect "", ""()
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: --target msp430-none-elf
|
||||
//@ needs-llvm-components: msp430
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// CHECK-LABEL: @sr_clobber
|
||||
// CHECK: call void asm sideeffect "", "~{sr}"()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: powerpc powerpc64 powerpc64le aix64
|
||||
//@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
|
||||
//@[powerpc] needs-llvm-components: powerpc
|
||||
|
|
@ -10,16 +11,11 @@
|
|||
// ignore-tidy-linelength
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// CHECK-LABEL: @cr_clobber
|
||||
// CHECK: call void asm sideeffect "", "~{cr}"()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ assembly-output: emit-asm
|
||||
//@ revisions: rv32i rv64i rv32e
|
||||
//@[rv32i] compile-flags: --target riscv32i-unknown-none-elf
|
||||
|
|
@ -9,16 +10,11 @@
|
|||
// ignore-tidy-linelength
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items)]
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// CHECK-LABEL: @flags_clobber
|
||||
// CHECK: call void asm sideeffect "", "~{vtype},~{vl},~{vxsat},~{vxrm}"()
|
||||
|
|
|
|||
|
|
@ -1,18 +1,14 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: s390x
|
||||
//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
|
||||
//@[s390x] needs-llvm-components: systemz
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items)]
|
||||
#![feature(no_core)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// CHECK-LABEL: @cc_clobber
|
||||
// CHECK: call void asm sideeffect "", "~{cc}"()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
// FIXME(nagisa): remove the flags below once all targets support `asm!`.
|
||||
//@ compile-flags: --target x86_64-unknown-linux-gnu -Copt-level=0
|
||||
//@ needs-llvm-components: x86
|
||||
|
|
@ -5,19 +6,12 @@
|
|||
// Verify we sanitize the special tokens for the LLVM inline-assembly, ensuring people won't
|
||||
// inadvertently rely on the LLVM-specific syntax and features.
|
||||
#![no_core]
|
||||
#![feature(no_core, lang_items, rustc_attrs)]
|
||||
#![feature(no_core)]
|
||||
#![crate_type = "rlib"]
|
||||
#![allow(named_asm_labels)]
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
pub unsafe fn we_escape_dollar_signs() {
|
||||
// CHECK: call void asm sideeffect alignstack inteldialect "banana$$:"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: sparc sparcv8plus sparc64
|
||||
//@[sparc] compile-flags: --target sparc-unknown-none-elf
|
||||
//@[sparc] needs-llvm-components: sparc
|
||||
|
|
@ -7,16 +8,11 @@
|
|||
//@[sparc64] needs-llvm-components: sparc
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(no_core, rustc_attrs, lang_items, asm_experimental_arch)]
|
||||
#![feature(no_core, asm_experimental_arch)]
|
||||
#![no_core]
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! asm {
|
||||
() => {};
|
||||
}
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// CHECK-LABEL: @cc_clobber
|
||||
// CHECK: call void asm sideeffect "", "~{icc},~{fcc0},~{fcc1},~{fcc2},~{fcc3}"()
|
||||
|
|
|
|||
|
|
@ -68,6 +68,12 @@ static EXPRS: &[&str] = &[
|
|||
// These mean different things.
|
||||
"return - 2",
|
||||
"(return) - 2",
|
||||
// Closures and jumps have equal precedence.
|
||||
"|| return break 2",
|
||||
"return break || 2",
|
||||
// Closures with a return type have especially high precedence.
|
||||
"|| -> T { x } + 1",
|
||||
"(|| { x }) + 1",
|
||||
// These mean different things.
|
||||
"if let _ = true && false {}",
|
||||
"if let _ = (true && false) {}",
|
||||
|
|
|
|||
23
tests/ui/dyn-star/dyn-pointer-like.rs
Normal file
23
tests/ui/dyn-star/dyn-pointer-like.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// Test that `dyn PointerLike` and `dyn* PointerLike` do not implement `PointerLike`.
|
||||
// This used to ICE during codegen.
|
||||
|
||||
#![crate_type = "lib"]
|
||||
|
||||
#![feature(pointer_like_trait, dyn_star)]
|
||||
#![feature(unsized_fn_params)]
|
||||
#![expect(incomplete_features)]
|
||||
#![expect(internal_features)]
|
||||
|
||||
use std::marker::PointerLike;
|
||||
|
||||
pub fn lol(x: dyn* PointerLike) {
|
||||
foo(x); //~ ERROR `dyn* PointerLike` needs to have the same ABI as a pointer
|
||||
}
|
||||
|
||||
pub fn uwu(x: dyn PointerLike) {
|
||||
foo(x); //~ ERROR `dyn PointerLike` needs to have the same ABI as a pointer
|
||||
}
|
||||
|
||||
fn foo<T: PointerLike + ?Sized>(x: T) {
|
||||
let _: dyn* PointerLike = x;
|
||||
}
|
||||
39
tests/ui/dyn-star/dyn-pointer-like.stderr
Normal file
39
tests/ui/dyn-star/dyn-pointer-like.stderr
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
error[E0277]: `dyn* PointerLike` needs to have the same ABI as a pointer
|
||||
--> $DIR/dyn-pointer-like.rs:14:9
|
||||
|
|
||||
LL | foo(x);
|
||||
| --- ^ the trait `PointerLike` is not implemented for `dyn* PointerLike`
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= note: the trait bound `dyn* PointerLike: PointerLike` is not satisfied
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/dyn-pointer-like.rs:21:11
|
||||
|
|
||||
LL | fn foo<T: PointerLike + ?Sized>(x: T) {
|
||||
| ^^^^^^^^^^^ required by this bound in `foo`
|
||||
help: consider borrowing here
|
||||
|
|
||||
LL | foo(&x);
|
||||
| +
|
||||
LL | foo(&mut x);
|
||||
| ++++
|
||||
|
||||
error[E0277]: `dyn PointerLike` needs to have the same ABI as a pointer
|
||||
--> $DIR/dyn-pointer-like.rs:18:9
|
||||
|
|
||||
LL | foo(x);
|
||||
| --- ^ `dyn PointerLike` needs to be a pointer-like type
|
||||
| |
|
||||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `PointerLike` is not implemented for `dyn PointerLike`
|
||||
note: required by a bound in `foo`
|
||||
--> $DIR/dyn-pointer-like.rs:21:11
|
||||
|
|
||||
LL | fn foo<T: PointerLike + ?Sized>(x: T) {
|
||||
| ^^^^^^^^^^^ required by this bound in `foo`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
11
tests/ui/errors/emitter-overflow-bad-whitespace.rs
Normal file
11
tests/ui/errors/emitter-overflow-bad-whitespace.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
// Invalid whitespace (not listed here: https://doc.rust-lang.org/reference/whitespace.html
|
||||
// e.g. \u{a0}) before any other syntax on the line should not cause any integer overflow
|
||||
// in the emitter, even when the terminal width causes the line to be truncated.
|
||||
//
|
||||
// issue #132918
|
||||
|
||||
//@ check-fail
|
||||
//@ needs-rustc-debug-assertions
|
||||
//@ compile-flags: --diagnostic-width=1
|
||||
fn main() { return; }
|
||||
//~^ ERROR unknown start of token: \u{a0}
|
||||
13
tests/ui/errors/emitter-overflow-bad-whitespace.stderr
Normal file
13
tests/ui/errors/emitter-overflow-bad-whitespace.stderr
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
error: unknown start of token: \u{a0}
|
||||
--> $DIR/emitter-overflow-bad-whitespace.rs:10:1
|
||||
|
|
||||
LL | ...
|
||||
| ^
|
||||
|
|
||||
help: Unicode character ' ' (No-Break Space) looks like ' ' (Space), but it is not
|
||||
|
|
||||
LL | fn main() { return; }
|
||||
| +
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
17
tests/ui/lint/fn-ptr-comparisons-some.rs
Normal file
17
tests/ui/lint/fn-ptr-comparisons-some.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// This test checks that we lint on Option of fn ptr.
|
||||
//
|
||||
// https://github.com/rust-lang/rust/issues/134527.
|
||||
//
|
||||
//@ check-pass
|
||||
|
||||
unsafe extern "C" fn func() {}
|
||||
|
||||
type FnPtr = unsafe extern "C" fn();
|
||||
|
||||
fn main() {
|
||||
let _ = Some::<FnPtr>(func) == Some(func as unsafe extern "C" fn());
|
||||
//~^ WARN function pointer comparisons
|
||||
|
||||
// Undecided as of https://github.com/rust-lang/rust/pull/134536
|
||||
assert_eq!(Some::<FnPtr>(func), Some(func as unsafe extern "C" fn()));
|
||||
}
|
||||
13
tests/ui/lint/fn-ptr-comparisons-some.stderr
Normal file
13
tests/ui/lint/fn-ptr-comparisons-some.stderr
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
|
||||
--> $DIR/fn-ptr-comparisons-some.rs:12:13
|
||||
|
|
||||
LL | let _ = Some::<FnPtr>(func) == Some(func as unsafe extern "C" fn());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: the address of the same function can vary between different codegen units
|
||||
= note: furthermore, different functions could have the same address after being merged together
|
||||
= note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
|
||||
= note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default
|
||||
|
||||
warning: 1 warning emitted
|
||||
|
||||
63
tests/ui/self/arbitrary_self_types_niche_deshadowing.rs
Normal file
63
tests/ui/self/arbitrary_self_types_niche_deshadowing.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
//@ run-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
#![feature(arbitrary_self_types)]
|
||||
#![feature(arbitrary_self_types_pointers)]
|
||||
#![feature(pin_ergonomics)]
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::pin::pin;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct A;
|
||||
|
||||
impl A {
|
||||
fn m(self: *const SmartPtr<Self>) -> usize { 2 }
|
||||
fn n(self: *const SmartPtr<Self>) -> usize { 2 }
|
||||
|
||||
fn o(self: Pin<&SmartPtr2<Self>>) -> usize { 2 }
|
||||
fn p(self: Pin<&SmartPtr2<Self>>) -> usize { 2 }
|
||||
}
|
||||
|
||||
struct SmartPtr<T>(T);
|
||||
|
||||
impl<T> core::ops::Receiver for SmartPtr<T> {
|
||||
type Target = *mut T;
|
||||
}
|
||||
|
||||
impl<T> SmartPtr<T> {
|
||||
// In general we try to detect cases where a method in a smart pointer
|
||||
// "shadows" a method in the referent (in this test, A).
|
||||
// This method "shadows" the 'n' method in the inner type A
|
||||
// We do not attempt to produce an error in these shadowing cases
|
||||
// since the type signature of this method and the corresponding
|
||||
// method in A are pretty unlikely to occur in practice,
|
||||
// and because it shows up conflicts between *const::cast and *mut::cast.
|
||||
fn n(self: *mut Self) -> usize { 1 }
|
||||
}
|
||||
|
||||
struct SmartPtr2<'a, T>(T, PhantomData<&'a T>);
|
||||
|
||||
impl<'a, T> core::ops::Receiver for SmartPtr2<'a, T> {
|
||||
type Target = Pin<&'a mut T>;
|
||||
}
|
||||
|
||||
impl<T> SmartPtr2<'_, T> {
|
||||
// Similarly, this method shadows the method in A
|
||||
// Can only happen with the unstable feature pin_ergonomics
|
||||
fn p(self: Pin<&mut Self>) -> usize { 1 }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut sm = SmartPtr(A);
|
||||
let smp: *mut SmartPtr<A> = &mut sm as *mut SmartPtr<A>;
|
||||
assert_eq!(smp.m(), 2);
|
||||
assert_eq!(smp.n(), 1);
|
||||
|
||||
let smp: Pin<&mut SmartPtr2<A>> = pin!(SmartPtr2(A, PhantomData));
|
||||
assert_eq!(smp.o(), 2);
|
||||
let smp: Pin<&mut SmartPtr2<A>> = pin!(SmartPtr2(A, PhantomData));
|
||||
assert_eq!(smp.p(), 1);
|
||||
}
|
||||
16
tests/ui/self/arbitrary_self_types_pin_getref.feature.stderr
Normal file
16
tests/ui/self/arbitrary_self_types_pin_getref.feature.stderr
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
error[E0034]: multiple applicable items in scope
|
||||
--> $DIR/arbitrary_self_types_pin_getref.rs:23:22
|
||||
|
|
||||
LL | let _ = pinned_a.get_ref();
|
||||
| ^^^^^^^ multiple `get_ref` found
|
||||
|
|
||||
note: candidate #1 is defined in an impl for the type `A`
|
||||
--> $DIR/arbitrary_self_types_pin_getref.rs:17:5
|
||||
|
|
||||
LL | fn get_ref(self: &Pin<&A>) {} // note &Pin
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: candidate #2 is defined in an impl for the type `Pin<&'a T>`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0034`.
|
||||
25
tests/ui/self/arbitrary_self_types_pin_getref.rs
Normal file
25
tests/ui/self/arbitrary_self_types_pin_getref.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// Confirms that Pin::get_ref can no longer shadow methods in pointees
|
||||
// once arbitrary_self_types is enabled.
|
||||
//
|
||||
//@ revisions: default feature
|
||||
#![cfg_attr(feature, feature(arbitrary_self_types))]
|
||||
|
||||
//@[default] check-pass
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::pin::Pin;
|
||||
use std::pin::pin;
|
||||
|
||||
struct A;
|
||||
|
||||
impl A {
|
||||
fn get_ref(self: &Pin<&A>) {} // note &Pin
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let pinned_a: Pin<&mut A> = pin!(A);
|
||||
let pinned_a: Pin<&A> = pinned_a.as_ref();
|
||||
let _ = pinned_a.get_ref();
|
||||
//[feature]~^ ERROR: multiple applicable items
|
||||
}
|
||||
18
tests/ui/structs/default-field-values-non_exhaustive.rs
Normal file
18
tests/ui/structs/default-field-values-non_exhaustive.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#![feature(default_field_values)]
|
||||
|
||||
#[derive(Default)]
|
||||
#[non_exhaustive] //~ ERROR `#[non_exhaustive]` can't be used to annotate items with default field values
|
||||
struct Foo {
|
||||
x: i32 = 42 + 3,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
enum Bar {
|
||||
#[non_exhaustive]
|
||||
#[default]
|
||||
Baz { //~ ERROR default variant must be exhaustive
|
||||
x: i32 = 42 + 3,
|
||||
}
|
||||
}
|
||||
|
||||
fn main () {}
|
||||
23
tests/ui/structs/default-field-values-non_exhaustive.stderr
Normal file
23
tests/ui/structs/default-field-values-non_exhaustive.stderr
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
error: default variant must be exhaustive
|
||||
--> $DIR/default-field-values-non_exhaustive.rs:13:5
|
||||
|
|
||||
LL | #[non_exhaustive]
|
||||
| ----------------- declared `#[non_exhaustive]` here
|
||||
LL | #[default]
|
||||
LL | Baz {
|
||||
| ^^^
|
||||
|
|
||||
= help: consider a manual implementation of `Default`
|
||||
|
||||
error: `#[non_exhaustive]` can't be used to annotate items with default field values
|
||||
--> $DIR/default-field-values-non_exhaustive.rs:4:1
|
||||
|
|
||||
LL | #[non_exhaustive]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
LL | / struct Foo {
|
||||
LL | | x: i32 = 42 + 3,
|
||||
LL | | }
|
||||
| |_- this struct has default field values
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
@ -1,20 +1,44 @@
|
|||
error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied
|
||||
--> $DIR/deny-builtin-object-impl.rs:19:23
|
||||
error[E0322]: explicit impls for the `NotImplYesObject` trait are not permitted
|
||||
--> $DIR/deny-builtin-object-impl.rs:20:1
|
||||
|
|
||||
LL | test_not_object::<dyn NotObject>();
|
||||
| ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject`
|
||||
LL | impl NotImplYesObject for () {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `NotImplYesObject` not allowed
|
||||
|
||||
error[E0277]: the trait bound `dyn NotImplNotObject: NotImplNotObject` is not satisfied
|
||||
--> $DIR/deny-builtin-object-impl.rs:37:32
|
||||
|
|
||||
LL | test_not_impl_not_object::<dyn NotImplNotObject>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^ the trait `NotImplNotObject` is not implemented for `dyn NotImplNotObject`
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/deny-builtin-object-impl.rs:11:1
|
||||
--> $DIR/deny-builtin-object-impl.rs:12:1
|
||||
|
|
||||
LL | trait NotObject {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `test_not_object`
|
||||
--> $DIR/deny-builtin-object-impl.rs:15:23
|
||||
LL | trait NotImplNotObject {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `test_not_impl_not_object`
|
||||
--> $DIR/deny-builtin-object-impl.rs:28:32
|
||||
|
|
||||
LL | fn test_not_object<T: NotObject + ?Sized>() {}
|
||||
| ^^^^^^^^^ required by this bound in `test_not_object`
|
||||
LL | fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
|
||||
| ^^^^^^^^^^^^^^^^ required by this bound in `test_not_impl_not_object`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0277]: the trait bound `dyn YesImplNotObject: YesImplNotObject` is not satisfied
|
||||
--> $DIR/deny-builtin-object-impl.rs:40:32
|
||||
|
|
||||
LL | test_yes_impl_not_object::<dyn YesImplNotObject>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^ the trait `YesImplNotObject` is not implemented for `dyn YesImplNotObject`
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/deny-builtin-object-impl.rs:15:1
|
||||
|
|
||||
LL | trait YesImplNotObject {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `test_yes_impl_not_object`
|
||||
--> $DIR/deny-builtin-object-impl.rs:30:32
|
||||
|
|
||||
LL | fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
|
||||
| ^^^^^^^^^^^^^^^^ required by this bound in `test_yes_impl_not_object`
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0322.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
|
|
|||
|
|
@ -1,20 +1,44 @@
|
|||
error[E0277]: the trait bound `dyn NotObject: NotObject` is not satisfied
|
||||
--> $DIR/deny-builtin-object-impl.rs:19:23
|
||||
error[E0322]: explicit impls for the `NotImplYesObject` trait are not permitted
|
||||
--> $DIR/deny-builtin-object-impl.rs:20:1
|
||||
|
|
||||
LL | test_not_object::<dyn NotObject>();
|
||||
| ^^^^^^^^^^^^^ the trait `NotObject` is not implemented for `dyn NotObject`
|
||||
LL | impl NotImplYesObject for () {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl of `NotImplYesObject` not allowed
|
||||
|
||||
error[E0277]: the trait bound `dyn NotImplNotObject: NotImplNotObject` is not satisfied
|
||||
--> $DIR/deny-builtin-object-impl.rs:37:32
|
||||
|
|
||||
LL | test_not_impl_not_object::<dyn NotImplNotObject>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^ the trait `NotImplNotObject` is not implemented for `dyn NotImplNotObject`
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/deny-builtin-object-impl.rs:11:1
|
||||
--> $DIR/deny-builtin-object-impl.rs:12:1
|
||||
|
|
||||
LL | trait NotObject {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `test_not_object`
|
||||
--> $DIR/deny-builtin-object-impl.rs:15:23
|
||||
LL | trait NotImplNotObject {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `test_not_impl_not_object`
|
||||
--> $DIR/deny-builtin-object-impl.rs:28:32
|
||||
|
|
||||
LL | fn test_not_object<T: NotObject + ?Sized>() {}
|
||||
| ^^^^^^^^^ required by this bound in `test_not_object`
|
||||
LL | fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
|
||||
| ^^^^^^^^^^^^^^^^ required by this bound in `test_not_impl_not_object`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
error[E0277]: the trait bound `dyn YesImplNotObject: YesImplNotObject` is not satisfied
|
||||
--> $DIR/deny-builtin-object-impl.rs:40:32
|
||||
|
|
||||
LL | test_yes_impl_not_object::<dyn YesImplNotObject>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^ the trait `YesImplNotObject` is not implemented for `dyn YesImplNotObject`
|
||||
|
|
||||
help: this trait has no implementations, consider adding one
|
||||
--> $DIR/deny-builtin-object-impl.rs:15:1
|
||||
|
|
||||
LL | trait YesImplNotObject {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: required by a bound in `test_yes_impl_not_object`
|
||||
--> $DIR/deny-builtin-object-impl.rs:30:32
|
||||
|
|
||||
LL | fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
|
||||
| ^^^^^^^^^^^^^^^^ required by this bound in `test_yes_impl_not_object`
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0322.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
||||
|
|
|
|||
|
|
@ -4,18 +4,41 @@
|
|||
|
||||
#![feature(rustc_attrs)]
|
||||
|
||||
#[rustc_deny_explicit_impl(implement_via_object = true)]
|
||||
trait YesObject {}
|
||||
#[rustc_deny_explicit_impl]
|
||||
trait NotImplYesObject {}
|
||||
|
||||
#[rustc_deny_explicit_impl(implement_via_object = false)]
|
||||
trait NotObject {}
|
||||
#[rustc_deny_explicit_impl]
|
||||
#[rustc_do_not_implement_via_object]
|
||||
trait NotImplNotObject {}
|
||||
|
||||
fn test_yes_object<T: YesObject + ?Sized>() {}
|
||||
#[rustc_do_not_implement_via_object]
|
||||
trait YesImplNotObject {}
|
||||
|
||||
fn test_not_object<T: NotObject + ?Sized>() {}
|
||||
#[rustc_do_not_implement_via_object]
|
||||
trait YesImplNotObject2 {}
|
||||
|
||||
impl NotImplYesObject for () {}
|
||||
//~^ ERROR explicit impls for the `NotImplYesObject` trait are not permitted
|
||||
|
||||
// If there is no automatic impl then we can add a manual impl:
|
||||
impl YesImplNotObject2 for dyn YesImplNotObject2 {}
|
||||
|
||||
fn test_not_impl_yes_object<T: NotImplYesObject + ?Sized>() {}
|
||||
|
||||
fn test_not_impl_not_object<T: NotImplNotObject + ?Sized>() {}
|
||||
|
||||
fn test_yes_impl_not_object<T: YesImplNotObject + ?Sized>() {}
|
||||
|
||||
fn test_yes_impl_not_object2<T: YesImplNotObject2 + ?Sized>() {}
|
||||
|
||||
fn main() {
|
||||
test_yes_object::<dyn YesObject>();
|
||||
test_not_object::<dyn NotObject>();
|
||||
//~^ ERROR the trait bound `dyn NotObject: NotObject` is not satisfied
|
||||
test_not_impl_yes_object::<dyn NotImplYesObject>();
|
||||
|
||||
test_not_impl_not_object::<dyn NotImplNotObject>();
|
||||
//~^ ERROR the trait bound `dyn NotImplNotObject: NotImplNotObject` is not satisfied
|
||||
|
||||
test_yes_impl_not_object::<dyn YesImplNotObject>();
|
||||
//~^ ERROR the trait bound `dyn YesImplNotObject: YesImplNotObject` is not satisfied
|
||||
|
||||
test_yes_impl_not_object2::<dyn YesImplNotObject2>();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue