Auto merge of #144692 - samueltardieu:rollup-0j1y08x, r=samueltardieu
Rollup of 4 pull requests Successful merges: - rust-lang/rust#143465 (Support multiple crate versions in --extern-html-root-url) - rust-lang/rust#144308 ([rustdoc] Display total time and compilation time of merged doctests) - rust-lang/rust#144655 (clean up codegen fn attrs) - rust-lang/rust#144675 (Reject running `compiletest` self-tests against stage 0 rustc unless explicitly allowed) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
3048886e59
49 changed files with 684 additions and 397 deletions
|
|
@ -465,6 +465,11 @@
|
|||
# What custom diff tool to use for displaying compiletest tests.
|
||||
#build.compiletest-diff-tool = <none>
|
||||
|
||||
# Whether to allow `compiletest` self-tests and `compiletest`-managed test
|
||||
# suites to be run against the stage 0 rustc. This is only intended to be used
|
||||
# when the stage 0 compiler is actually built from in-tree sources.
|
||||
#build.compiletest-allow-stage0 = false
|
||||
|
||||
# Whether to use the precompiled stage0 libtest with compiletest.
|
||||
#build.compiletest-use-stage0-libtest = true
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ rustc = "$(pwd)/../dist/bin/rustc-clif"
|
|||
cargo = "$(rustup which cargo)"
|
||||
full-bootstrap = true
|
||||
local-rebuild = true
|
||||
compiletest-allow-stage0 = true
|
||||
|
||||
[rust]
|
||||
download-rustc = false
|
||||
|
|
|
|||
|
|
@ -166,5 +166,5 @@ index 073116933bd..c3e4578204d 100644
|
|||
EOF
|
||||
|
||||
echo "[TEST] rustc test suite"
|
||||
COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,ui,incremental}
|
||||
./x.py test --stage 0 --test-args=--no-capture tests/{codegen-units,run-make,ui,incremental}
|
||||
popd
|
||||
|
|
|
|||
|
|
@ -561,8 +561,6 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("[TEST] rustc asm test suite");
|
||||
|
||||
env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
|
||||
|
||||
let codegen_backend_path = format!(
|
||||
"{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}",
|
||||
pwd = std::env::current_dir()
|
||||
|
|
@ -588,6 +586,8 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
|
|||
&"always",
|
||||
&"--stage",
|
||||
&"0",
|
||||
&"--set",
|
||||
&"build.compiletest-allow-stage0=true",
|
||||
&"tests/assembly-llvm/asm",
|
||||
&"--compiletest-rustc-args",
|
||||
&rustc_args,
|
||||
|
|
@ -1047,7 +1047,6 @@ where
|
|||
|
||||
// FIXME: create a function "display_if_not_quiet" or something along the line.
|
||||
println!("[TEST] rustc {test_type} test suite");
|
||||
env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
|
||||
|
||||
let extra =
|
||||
if args.is_using_gcc_master_branch() { "" } else { " -Csymbol-mangling-version=v0" };
|
||||
|
|
@ -1070,6 +1069,8 @@ where
|
|||
&"always",
|
||||
&"--stage",
|
||||
&"0",
|
||||
&"--set",
|
||||
&"build.compiletest-allow-stage0=true",
|
||||
&format!("tests/{test_type}"),
|
||||
&"--compiletest-rustc-args",
|
||||
&rustc_args,
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ use rustc_abi::{Align, ExternAbi};
|
|||
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
|
||||
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
|
||||
use rustc_attr_data_structures::{
|
||||
AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, UsedBy, find_attr,
|
||||
AttributeKind, InlineAttr, InstructionSetAttr, UsedBy, find_attr,
|
||||
};
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
|
||||
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
|
||||
use rustc_hir::{self as hir, LangItem, lang_items};
|
||||
use rustc_hir::{self as hir, Attribute, LangItem, lang_items};
|
||||
use rustc_middle::middle::codegen_fn_attrs::{
|
||||
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
|
||||
};
|
||||
|
|
@ -53,77 +53,196 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
|
|||
}
|
||||
}
|
||||
|
||||
fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
if cfg!(debug_assertions) {
|
||||
let def_kind = tcx.def_kind(did);
|
||||
assert!(
|
||||
def_kind.has_codegen_attrs(),
|
||||
"unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
|
||||
);
|
||||
/// In some cases, attributes are only valid on functions, but it's the `check_attr`
|
||||
/// pass that checks that they aren't used anywhere else, rather than this module.
|
||||
/// In these cases, we bail from performing further checks that are only meaningful for
|
||||
/// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
|
||||
/// report a delayed bug, just in case `check_attr` isn't doing its job.
|
||||
fn try_fn_sig<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
did: LocalDefId,
|
||||
attr_span: Span,
|
||||
) -> Option<ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>>> {
|
||||
use DefKind::*;
|
||||
|
||||
let def_kind = tcx.def_kind(did);
|
||||
if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
|
||||
Some(tcx.fn_sig(did))
|
||||
} else {
|
||||
tcx.dcx().span_delayed_bug(attr_span, "this attribute can only be applied to functions");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(jdonszelmann): remove when instruction_set becomes a parsed attr
|
||||
fn parse_instruction_set_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option<InstructionSetAttr> {
|
||||
let list = attr.meta_item_list()?;
|
||||
|
||||
match &list[..] {
|
||||
[MetaItemInner::MetaItem(set)] => {
|
||||
let segments = set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
|
||||
match segments.as_slice() {
|
||||
[sym::arm, sym::a32 | sym::t32] if !tcx.sess.target.has_thumb_interworking => {
|
||||
tcx.dcx().emit_err(errors::UnsupportedInstructionSet { span: attr.span() });
|
||||
None
|
||||
}
|
||||
[sym::arm, sym::a32] => Some(InstructionSetAttr::ArmA32),
|
||||
[sym::arm, sym::t32] => Some(InstructionSetAttr::ArmT32),
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::InvalidInstructionSet { span: attr.span() });
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
[] => {
|
||||
tcx.dcx().emit_err(errors::BareInstructionSet { span: attr.span() });
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::MultipleInstructionSet { span: attr.span() });
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(jdonszelmann): remove when linkage becomes a parsed attr
|
||||
fn parse_linkage_attr(tcx: TyCtxt<'_>, did: LocalDefId, attr: &Attribute) -> Option<Linkage> {
|
||||
let val = attr.value_str()?;
|
||||
let linkage = linkage_by_name(tcx, did, val.as_str());
|
||||
Some(linkage)
|
||||
}
|
||||
|
||||
// FIXME(jdonszelmann): remove when no_sanitize becomes a parsed attr
|
||||
fn parse_no_sanitize_attr(tcx: TyCtxt<'_>, attr: &Attribute) -> Option<SanitizerSet> {
|
||||
let list = attr.meta_item_list()?;
|
||||
let mut sanitizer_set = SanitizerSet::empty();
|
||||
|
||||
for item in list.iter() {
|
||||
match item.name() {
|
||||
Some(sym::address) => {
|
||||
sanitizer_set |= SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
|
||||
}
|
||||
Some(sym::cfi) => sanitizer_set |= SanitizerSet::CFI,
|
||||
Some(sym::kcfi) => sanitizer_set |= SanitizerSet::KCFI,
|
||||
Some(sym::memory) => sanitizer_set |= SanitizerSet::MEMORY,
|
||||
Some(sym::memtag) => sanitizer_set |= SanitizerSet::MEMTAG,
|
||||
Some(sym::shadow_call_stack) => sanitizer_set |= SanitizerSet::SHADOWCALLSTACK,
|
||||
Some(sym::thread) => sanitizer_set |= SanitizerSet::THREAD,
|
||||
Some(sym::hwaddress) => sanitizer_set |= SanitizerSet::HWADDRESS,
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(did));
|
||||
let mut codegen_fn_attrs = CodegenFnAttrs::new();
|
||||
if tcx.should_inherit_track_caller(did) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
|
||||
}
|
||||
Some(sanitizer_set)
|
||||
}
|
||||
|
||||
// FIXME(jdonszelmann): remove when patchable_function_entry becomes a parsed attr
|
||||
fn parse_patchable_function_entry(
|
||||
tcx: TyCtxt<'_>,
|
||||
attr: &Attribute,
|
||||
) -> Option<PatchableFunctionEntry> {
|
||||
attr.meta_item_list().and_then(|l| {
|
||||
let mut prefix = None;
|
||||
let mut entry = None;
|
||||
for item in l {
|
||||
let Some(meta_item) = item.meta_item() else {
|
||||
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(name_value_lit) = meta_item.name_value_literal() else {
|
||||
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
|
||||
continue;
|
||||
};
|
||||
|
||||
let attrib_to_write = match meta_item.name() {
|
||||
Some(sym::prefix_nops) => &mut prefix,
|
||||
Some(sym::entry_nops) => &mut entry,
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::UnexpectedParameterName {
|
||||
span: item.span(),
|
||||
prefix_nops: sym::prefix_nops,
|
||||
entry_nops: sym::entry_nops,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else {
|
||||
tcx.dcx().emit_err(errors::InvalidLiteralValue { span: name_value_lit.span });
|
||||
continue;
|
||||
};
|
||||
|
||||
let Ok(val) = val.get().try_into() else {
|
||||
tcx.dcx().emit_err(errors::OutOfRangeInteger { span: name_value_lit.span });
|
||||
continue;
|
||||
};
|
||||
|
||||
*attrib_to_write = Some(val);
|
||||
}
|
||||
|
||||
if let (None, None) = (prefix, entry) {
|
||||
tcx.dcx().span_err(attr.span(), "must specify at least one parameter");
|
||||
}
|
||||
|
||||
Some(PatchableFunctionEntry::from_prefix_and_entry(prefix.unwrap_or(0), entry.unwrap_or(0)))
|
||||
})
|
||||
}
|
||||
|
||||
/// Spans that are collected when processing built-in attributes,
|
||||
/// that are useful for emitting diagnostics later.
|
||||
#[derive(Default)]
|
||||
struct InterestingAttributeDiagnosticSpans {
|
||||
link_ordinal: Option<Span>,
|
||||
no_sanitize: Option<Span>,
|
||||
inline: Option<Span>,
|
||||
no_mangle: Option<Span>,
|
||||
}
|
||||
|
||||
/// Process the builtin attrs ([`hir::Attribute`]) on the item.
|
||||
/// Many of them directly translate to codegen attrs.
|
||||
fn process_builtin_attrs(
|
||||
tcx: TyCtxt<'_>,
|
||||
did: LocalDefId,
|
||||
attrs: &[Attribute],
|
||||
codegen_fn_attrs: &mut CodegenFnAttrs,
|
||||
) -> InterestingAttributeDiagnosticSpans {
|
||||
let mut interesting_spans = InterestingAttributeDiagnosticSpans::default();
|
||||
let rust_target_features = tcx.rust_target_features(LOCAL_CRATE);
|
||||
|
||||
// If our rustc version supports autodiff/enzyme, then we call our handler
|
||||
// to check for any `#[rustc_autodiff(...)]` attributes.
|
||||
// FIXME(jdonszelmann): merge with loop below
|
||||
if cfg!(llvm_enzyme) {
|
||||
let ad = autodiff_attrs(tcx, did.into());
|
||||
codegen_fn_attrs.autodiff_item = ad;
|
||||
}
|
||||
|
||||
// When `no_builtins` is applied at the crate level, we should add the
|
||||
// `no-builtins` attribute to each function to ensure it takes effect in LTO.
|
||||
let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
|
||||
if no_builtins {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
|
||||
}
|
||||
|
||||
let rust_target_features = tcx.rust_target_features(LOCAL_CRATE);
|
||||
|
||||
let mut link_ordinal_span = None;
|
||||
let mut no_sanitize_span = None;
|
||||
|
||||
for attr in attrs.iter() {
|
||||
// In some cases, attribute are only valid on functions, but it's the `check_attr`
|
||||
// pass that check that they aren't used anywhere else, rather this module.
|
||||
// In these cases, we bail from performing further checks that are only meaningful for
|
||||
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
|
||||
// report a delayed bug, just in case `check_attr` isn't doing its job.
|
||||
let fn_sig = |attr_span| {
|
||||
use DefKind::*;
|
||||
|
||||
let def_kind = tcx.def_kind(did);
|
||||
if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
|
||||
Some(tcx.fn_sig(did))
|
||||
} else {
|
||||
tcx.dcx()
|
||||
.span_delayed_bug(attr_span, "this attribute can only be applied to functions");
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
if let hir::Attribute::Parsed(p) = attr {
|
||||
match p {
|
||||
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
|
||||
AttributeKind::ExportName { name, .. } => {
|
||||
codegen_fn_attrs.export_name = Some(*name);
|
||||
codegen_fn_attrs.export_name = Some(*name)
|
||||
}
|
||||
AttributeKind::Inline(inline, span) => {
|
||||
codegen_fn_attrs.inline = *inline;
|
||||
interesting_spans.inline = Some(*span);
|
||||
}
|
||||
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
|
||||
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
|
||||
AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name),
|
||||
AttributeKind::LinkOrdinal { ordinal, span } => {
|
||||
codegen_fn_attrs.link_ordinal = Some(*ordinal);
|
||||
link_ordinal_span = Some(*span);
|
||||
interesting_spans.link_ordinal = Some(*span);
|
||||
}
|
||||
AttributeKind::LinkSection { name, .. } => {
|
||||
codegen_fn_attrs.link_section = Some(*name)
|
||||
}
|
||||
AttributeKind::NoMangle(attr_span) => {
|
||||
interesting_spans.no_mangle = Some(*attr_span);
|
||||
if tcx.opt_item_name(did.to_def_id()).is_some() {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
|
||||
} else {
|
||||
|
|
@ -137,6 +256,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
});
|
||||
}
|
||||
}
|
||||
AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize,
|
||||
AttributeKind::TargetFeature(features, attr_span) => {
|
||||
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
|
||||
tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn");
|
||||
|
|
@ -184,7 +304,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
let is_closure = tcx.is_closure_like(did.to_def_id());
|
||||
|
||||
if !is_closure
|
||||
&& let Some(fn_sig) = fn_sig(*attr_span)
|
||||
&& let Some(fn_sig) = try_fn_sig(tcx, did, *attr_span)
|
||||
&& fn_sig.skip_binder().abi() != ExternAbi::Rust
|
||||
{
|
||||
tcx.dcx().emit_err(errors::RequiresRustAbi { span: *attr_span });
|
||||
|
|
@ -232,155 +352,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
sym::thread_local => codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL,
|
||||
sym::linkage => {
|
||||
if let Some(val) = attr.value_str() {
|
||||
let linkage = Some(linkage_by_name(tcx, did, val.as_str()));
|
||||
if tcx.is_foreign_item(did) {
|
||||
codegen_fn_attrs.import_linkage = linkage;
|
||||
let linkage = parse_linkage_attr(tcx, did, attr);
|
||||
|
||||
if tcx.is_mutable_static(did.into()) {
|
||||
let mut diag = tcx.dcx().struct_span_err(
|
||||
attr.span(),
|
||||
"extern mutable statics are not allowed with `#[linkage]`",
|
||||
);
|
||||
diag.note(
|
||||
"marking the extern static mutable would allow changing which \
|
||||
symbol the static references rather than make the target of the \
|
||||
symbol mutable",
|
||||
);
|
||||
diag.emit();
|
||||
}
|
||||
} else {
|
||||
codegen_fn_attrs.linkage = linkage;
|
||||
if tcx.is_foreign_item(did) {
|
||||
codegen_fn_attrs.import_linkage = linkage;
|
||||
|
||||
if tcx.is_mutable_static(did.into()) {
|
||||
let mut diag = tcx.dcx().struct_span_err(
|
||||
attr.span(),
|
||||
"extern mutable statics are not allowed with `#[linkage]`",
|
||||
);
|
||||
diag.note(
|
||||
"marking the extern static mutable would allow changing which \
|
||||
symbol the static references rather than make the target of the \
|
||||
symbol mutable",
|
||||
);
|
||||
diag.emit();
|
||||
}
|
||||
} else {
|
||||
codegen_fn_attrs.linkage = linkage;
|
||||
}
|
||||
}
|
||||
sym::no_sanitize => {
|
||||
no_sanitize_span = Some(attr.span());
|
||||
if let Some(list) = attr.meta_item_list() {
|
||||
for item in list.iter() {
|
||||
match item.name() {
|
||||
Some(sym::address) => {
|
||||
codegen_fn_attrs.no_sanitize |=
|
||||
SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
|
||||
}
|
||||
Some(sym::cfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI,
|
||||
Some(sym::kcfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI,
|
||||
Some(sym::memory) => {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY
|
||||
}
|
||||
Some(sym::memtag) => {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG
|
||||
}
|
||||
Some(sym::shadow_call_stack) => {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK
|
||||
}
|
||||
Some(sym::thread) => {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD
|
||||
}
|
||||
Some(sym::hwaddress) => {
|
||||
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS
|
||||
}
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
interesting_spans.no_sanitize = Some(attr.span());
|
||||
codegen_fn_attrs.no_sanitize |=
|
||||
parse_no_sanitize_attr(tcx, attr).unwrap_or_default();
|
||||
}
|
||||
sym::instruction_set => {
|
||||
codegen_fn_attrs.instruction_set =
|
||||
attr.meta_item_list().and_then(|l| match &l[..] {
|
||||
[MetaItemInner::MetaItem(set)] => {
|
||||
let segments =
|
||||
set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>();
|
||||
match segments.as_slice() {
|
||||
[sym::arm, sym::a32 | sym::t32]
|
||||
if !tcx.sess.target.has_thumb_interworking =>
|
||||
{
|
||||
tcx.dcx().emit_err(errors::UnsupportedInstructionSet {
|
||||
span: attr.span(),
|
||||
});
|
||||
None
|
||||
}
|
||||
[sym::arm, sym::a32] => Some(InstructionSetAttr::ArmA32),
|
||||
[sym::arm, sym::t32] => Some(InstructionSetAttr::ArmT32),
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::InvalidInstructionSet {
|
||||
span: attr.span(),
|
||||
});
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
[] => {
|
||||
tcx.dcx().emit_err(errors::BareInstructionSet { span: attr.span() });
|
||||
None
|
||||
}
|
||||
_ => {
|
||||
tcx.dcx()
|
||||
.emit_err(errors::MultipleInstructionSet { span: attr.span() });
|
||||
None
|
||||
}
|
||||
})
|
||||
codegen_fn_attrs.instruction_set = parse_instruction_set_attr(tcx, attr)
|
||||
}
|
||||
sym::patchable_function_entry => {
|
||||
codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| {
|
||||
let mut prefix = None;
|
||||
let mut entry = None;
|
||||
for item in l {
|
||||
let Some(meta_item) = item.meta_item() else {
|
||||
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
|
||||
continue;
|
||||
};
|
||||
|
||||
let Some(name_value_lit) = meta_item.name_value_literal() else {
|
||||
tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() });
|
||||
continue;
|
||||
};
|
||||
|
||||
let attrib_to_write = match meta_item.name() {
|
||||
Some(sym::prefix_nops) => &mut prefix,
|
||||
Some(sym::entry_nops) => &mut entry,
|
||||
_ => {
|
||||
tcx.dcx().emit_err(errors::UnexpectedParameterName {
|
||||
span: item.span(),
|
||||
prefix_nops: sym::prefix_nops,
|
||||
entry_nops: sym::entry_nops,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else {
|
||||
tcx.dcx().emit_err(errors::InvalidLiteralValue {
|
||||
span: name_value_lit.span,
|
||||
});
|
||||
continue;
|
||||
};
|
||||
|
||||
let Ok(val) = val.get().try_into() else {
|
||||
tcx.dcx()
|
||||
.emit_err(errors::OutOfRangeInteger { span: name_value_lit.span });
|
||||
continue;
|
||||
};
|
||||
|
||||
*attrib_to_write = Some(val);
|
||||
}
|
||||
|
||||
if let (None, None) = (prefix, entry) {
|
||||
tcx.dcx().span_err(attr.span(), "must specify at least one parameter");
|
||||
}
|
||||
|
||||
Some(PatchableFunctionEntry::from_prefix_and_entry(
|
||||
prefix.unwrap_or(0),
|
||||
entry.unwrap_or(0),
|
||||
))
|
||||
})
|
||||
codegen_fn_attrs.patchable_function_entry =
|
||||
parse_patchable_function_entry(tcx, attr);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
interesting_spans
|
||||
}
|
||||
|
||||
/// Applies overrides for codegen fn attrs. These often have a specific reason why they're necessary.
|
||||
/// Please comment why when adding a new one!
|
||||
fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut CodegenFnAttrs) {
|
||||
// Apply the minimum function alignment here. This ensures that a function's alignment is
|
||||
// determined by the `-C` flags of the crate it is defined in, not the `-C` flags of the crate
|
||||
// it happens to be codegen'd (or const-eval'd) in.
|
||||
|
|
@ -390,15 +404,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
// On trait methods, inherit the `#[align]` of the trait's method prototype.
|
||||
codegen_fn_attrs.alignment = Ord::max(codegen_fn_attrs.alignment, tcx.inherited_align(did));
|
||||
|
||||
let inline_span;
|
||||
(codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) =
|
||||
find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span))
|
||||
{
|
||||
(inline_attr, Some(span))
|
||||
} else {
|
||||
(InlineAttr::None, None)
|
||||
};
|
||||
|
||||
// naked function MUST NOT be inlined! This attribute is required for the rust compiler itself,
|
||||
// but not for the code generation backend because at that point the naked function will just be
|
||||
// a declaration, with a definition provided in global assembly.
|
||||
|
|
@ -406,9 +411,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
codegen_fn_attrs.inline = InlineAttr::Never;
|
||||
}
|
||||
|
||||
codegen_fn_attrs.optimize =
|
||||
find_attr!(attrs, AttributeKind::Optimize(i, _) => *i).unwrap_or(OptimizeAttr::Default);
|
||||
|
||||
// #73631: closures inherit `#[target_feature]` annotations
|
||||
//
|
||||
// If this closure is marked `#[inline(always)]`, simply skip adding `#[target_feature]`.
|
||||
|
|
@ -431,6 +433,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
}
|
||||
}
|
||||
|
||||
// When `no_builtins` is applied at the crate level, we should add the
|
||||
// `no-builtins` attribute to each function to ensure it takes effect in LTO.
|
||||
let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID);
|
||||
let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins);
|
||||
if no_builtins {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS;
|
||||
}
|
||||
|
||||
// inherit track-caller properly
|
||||
if tcx.should_inherit_track_caller(did) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
|
||||
}
|
||||
}
|
||||
|
||||
fn check_result(
|
||||
tcx: TyCtxt<'_>,
|
||||
did: LocalDefId,
|
||||
interesting_spans: InterestingAttributeDiagnosticSpans,
|
||||
codegen_fn_attrs: &CodegenFnAttrs,
|
||||
) {
|
||||
// If a function uses `#[target_feature]` it can't be inlined into general
|
||||
// purpose functions as they wouldn't have the right target features
|
||||
// enabled. For that reason we also forbid `#[inline(always)]` as it can't be
|
||||
|
|
@ -446,14 +468,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
// llvm/llvm-project#70563).
|
||||
if !codegen_fn_attrs.target_features.is_empty()
|
||||
&& matches!(codegen_fn_attrs.inline, InlineAttr::Always)
|
||||
&& let Some(span) = inline_span
|
||||
&& let Some(span) = interesting_spans.inline
|
||||
{
|
||||
tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`");
|
||||
}
|
||||
|
||||
// warn that inline has no effect when no_sanitize is present
|
||||
if !codegen_fn_attrs.no_sanitize.is_empty()
|
||||
&& codegen_fn_attrs.inline.always()
|
||||
&& let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span)
|
||||
&& let (Some(no_sanitize_span), Some(inline_span)) =
|
||||
(interesting_spans.no_sanitize, interesting_spans.inline)
|
||||
{
|
||||
let hir_id = tcx.local_def_id_to_hir_id(did);
|
||||
tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, |lint| {
|
||||
|
|
@ -462,51 +486,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
})
|
||||
}
|
||||
|
||||
// Weak lang items have the same semantics as "std internal" symbols in the
|
||||
// sense that they're preserved through all our LTO passes and only
|
||||
// strippable by the linker.
|
||||
//
|
||||
// Additionally weak lang items have predetermined symbol names.
|
||||
if let Some((name, _)) = lang_items::extract(attrs)
|
||||
&& let Some(lang_item) = LangItem::from_name(name)
|
||||
// error when specifying link_name together with link_ordinal
|
||||
if let Some(_) = codegen_fn_attrs.link_name
|
||||
&& let Some(_) = codegen_fn_attrs.link_ordinal
|
||||
{
|
||||
if WEAK_LANG_ITEMS.contains(&lang_item) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
|
||||
let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
|
||||
if let Some(span) = interesting_spans.link_ordinal {
|
||||
tcx.dcx().span_err(span, msg);
|
||||
} else {
|
||||
tcx.dcx().err(msg);
|
||||
}
|
||||
if let Some(link_name) = lang_item.link_name() {
|
||||
codegen_fn_attrs.export_name = Some(link_name);
|
||||
codegen_fn_attrs.link_name = Some(link_name);
|
||||
}
|
||||
}
|
||||
check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
|
||||
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
&& codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
|
||||
{
|
||||
let no_mangle_span =
|
||||
find_attr!(attrs, AttributeKind::NoMangle(no_mangle_span) => *no_mangle_span)
|
||||
.unwrap_or_default();
|
||||
let lang_item =
|
||||
lang_items::extract(attrs).map_or(None, |(name, _span)| LangItem::from_name(name));
|
||||
let mut err = tcx
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
no_mangle_span,
|
||||
"`#[no_mangle]` cannot be used on internal language items",
|
||||
)
|
||||
.with_note("Rustc requires this item to have a specific mangled name.")
|
||||
.with_span_label(tcx.def_span(did), "should be the internal language item");
|
||||
if let Some(lang_item) = lang_item
|
||||
&& let Some(link_name) = lang_item.link_name()
|
||||
{
|
||||
err = err
|
||||
.with_note("If you are trying to prevent mangling to ease debugging, many")
|
||||
.with_note(format!("debuggers support a command such as `rbreak {link_name}` to"))
|
||||
.with_note(format!(
|
||||
"match `.*{link_name}.*` instead of `break {link_name}` on a specific name"
|
||||
))
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
|
||||
if let Some(features) = check_tied_features(
|
||||
|
|
@ -529,6 +518,84 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
|||
})
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_lang_items(
|
||||
tcx: TyCtxt<'_>,
|
||||
did: LocalDefId,
|
||||
interesting_spans: &InterestingAttributeDiagnosticSpans,
|
||||
attrs: &[Attribute],
|
||||
codegen_fn_attrs: &mut CodegenFnAttrs,
|
||||
) {
|
||||
// Weak lang items have the same semantics as "std internal" symbols in the
|
||||
// sense that they're preserved through all our LTO passes and only
|
||||
// strippable by the linker.
|
||||
//
|
||||
// Additionally weak lang items have predetermined symbol names.
|
||||
if let Some((name, _)) = lang_items::extract(attrs)
|
||||
&& let Some(lang_item) = LangItem::from_name(name)
|
||||
{
|
||||
if WEAK_LANG_ITEMS.contains(&lang_item) {
|
||||
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
|
||||
}
|
||||
if let Some(link_name) = lang_item.link_name() {
|
||||
codegen_fn_attrs.export_name = Some(link_name);
|
||||
codegen_fn_attrs.link_name = Some(link_name);
|
||||
}
|
||||
}
|
||||
|
||||
// error when using no_mangle on a lang item item
|
||||
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
|
||||
&& codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
|
||||
{
|
||||
let lang_item =
|
||||
lang_items::extract(attrs).map_or(None, |(name, _span)| LangItem::from_name(name));
|
||||
let mut err = tcx
|
||||
.dcx()
|
||||
.struct_span_err(
|
||||
interesting_spans.no_mangle.unwrap_or_default(),
|
||||
"`#[no_mangle]` cannot be used on internal language items",
|
||||
)
|
||||
.with_note("Rustc requires this item to have a specific mangled name.")
|
||||
.with_span_label(tcx.def_span(did), "should be the internal language item");
|
||||
if let Some(lang_item) = lang_item
|
||||
&& let Some(link_name) = lang_item.link_name()
|
||||
{
|
||||
err = err
|
||||
.with_note("If you are trying to prevent mangling to ease debugging, many")
|
||||
.with_note(format!("debuggers support a command such as `rbreak {link_name}` to"))
|
||||
.with_note(format!(
|
||||
"match `.*{link_name}.*` instead of `break {link_name}` on a specific name"
|
||||
))
|
||||
}
|
||||
err.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the [`CodegenFnAttrs`] for an item (identified by the [`LocalDefId`]).
|
||||
///
|
||||
/// This happens in 4 stages:
|
||||
/// - apply built-in attributes that directly translate to codegen attributes.
|
||||
/// - handle lang items. These have special codegen attrs applied to them.
|
||||
/// - apply overrides, like minimum requirements for alignment and other settings that don't rely directly the built-in attrs on the item.
|
||||
/// overrides come after applying built-in attributes since they may only apply when certain attributes were already set in the stage before.
|
||||
/// - check that the result is valid. There's various ways in which this may not be the case, such as certain combinations of attrs.
|
||||
fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
|
||||
if cfg!(debug_assertions) {
|
||||
let def_kind = tcx.def_kind(did);
|
||||
assert!(
|
||||
def_kind.has_codegen_attrs(),
|
||||
"unexpected `def_kind` in `codegen_fn_attrs`: {def_kind:?}",
|
||||
);
|
||||
}
|
||||
|
||||
let mut codegen_fn_attrs = CodegenFnAttrs::new();
|
||||
let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(did));
|
||||
|
||||
let interesting_spans = process_builtin_attrs(tcx, did, attrs, &mut codegen_fn_attrs);
|
||||
handle_lang_items(tcx, did, &interesting_spans, attrs, &mut codegen_fn_attrs);
|
||||
apply_overrides(tcx, did, &mut codegen_fn_attrs);
|
||||
check_result(tcx, did, interesting_spans, &codegen_fn_attrs);
|
||||
|
||||
codegen_fn_attrs
|
||||
}
|
||||
|
|
@ -555,27 +622,12 @@ fn inherited_align<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Align> {
|
|||
tcx.codegen_fn_attrs(opt_trait_item(tcx, def_id)?).alignment
|
||||
}
|
||||
|
||||
fn check_link_name_xor_ordinal(
|
||||
tcx: TyCtxt<'_>,
|
||||
codegen_fn_attrs: &CodegenFnAttrs,
|
||||
inline_span: Option<Span>,
|
||||
) {
|
||||
if codegen_fn_attrs.link_name.is_none() || codegen_fn_attrs.link_ordinal.is_none() {
|
||||
return;
|
||||
}
|
||||
let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
|
||||
if let Some(span) = inline_span {
|
||||
tcx.dcx().span_err(span, msg);
|
||||
} else {
|
||||
tcx.dcx().err(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// We now check the #\[rustc_autodiff\] attributes which we generated from the #[autodiff(...)]
|
||||
/// macros. There are two forms. The pure one without args to mark primal functions (the functions
|
||||
/// being differentiated). The other form is #[rustc_autodiff(Mode, ActivityList)] on top of the
|
||||
/// placeholder functions. We wrote the rustc_autodiff attributes ourself, so this should never
|
||||
/// panic, unless we introduced a bug when parsing the autodiff macro.
|
||||
//FIXME(jdonszelmann): put in the main loop. No need to have two..... :/ Let's do that when we make autodiff parsed.
|
||||
fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
|
||||
let attrs = tcx.get_attrs(id, sym::rustc_autodiff);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_data_structures::owned_slice::OwnedSlice;
|
||||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard};
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_expand::base::SyntaxExtension;
|
||||
use rustc_fs_util::try_canonicalize;
|
||||
use rustc_hir as hir;
|
||||
|
|
@ -69,6 +70,9 @@ pub struct CStore {
|
|||
/// This crate has a `#[alloc_error_handler]` item.
|
||||
has_alloc_error_handler: bool,
|
||||
|
||||
/// Names that were used to load the crates via `extern crate` or paths.
|
||||
resolved_externs: UnordMap<Symbol, CrateNum>,
|
||||
|
||||
/// Unused externs of the crate
|
||||
unused_externs: Vec<Symbol>,
|
||||
|
||||
|
|
@ -249,6 +253,22 @@ impl CStore {
|
|||
self.metas[cnum] = Some(Box::new(data));
|
||||
}
|
||||
|
||||
/// Save the name used to resolve the extern crate in the local crate
|
||||
///
|
||||
/// The name isn't always the crate's own name, because `sess.opts.externs` can assign it another name.
|
||||
/// It's also not always the same as the `DefId`'s symbol due to renames `extern crate resolved_name as defid_name`.
|
||||
pub(crate) fn set_resolved_extern_crate_name(&mut self, name: Symbol, extern_crate: CrateNum) {
|
||||
self.resolved_externs.insert(name, extern_crate);
|
||||
}
|
||||
|
||||
/// Crate resolved and loaded via the given extern name
|
||||
/// (corresponds to names in `sess.opts.externs`)
|
||||
///
|
||||
/// May be `None` if the crate wasn't used
|
||||
pub fn resolved_extern_crate(&self, externs_name: Symbol) -> Option<CrateNum> {
|
||||
self.resolved_externs.get(&externs_name).copied()
|
||||
}
|
||||
|
||||
pub(crate) fn iter_crate_data(&self) -> impl Iterator<Item = (CrateNum, &CrateMetadata)> {
|
||||
self.metas
|
||||
.iter_enumerated()
|
||||
|
|
@ -475,6 +495,7 @@ impl CStore {
|
|||
alloc_error_handler_kind: None,
|
||||
has_global_allocator: false,
|
||||
has_alloc_error_handler: false,
|
||||
resolved_externs: UnordMap::default(),
|
||||
unused_externs: Vec::new(),
|
||||
used_extern_options: Default::default(),
|
||||
}
|
||||
|
|
@ -511,7 +532,7 @@ impl CStore {
|
|||
// We're also sure to compare *paths*, not actual byte slices. The
|
||||
// `source` stores paths which are normalized which may be different
|
||||
// from the strings on the command line.
|
||||
let source = self.get_crate_data(cnum).cdata.source();
|
||||
let source = data.source();
|
||||
if let Some(entry) = externs.get(name.as_str()) {
|
||||
// Only use `--extern crate_name=path` here, not `--extern crate_name`.
|
||||
if let Some(mut files) = entry.files() {
|
||||
|
|
@ -1308,6 +1329,7 @@ impl CStore {
|
|||
let path_len = definitions.def_path(def_id).data.len();
|
||||
self.update_extern_crate(
|
||||
cnum,
|
||||
name,
|
||||
ExternCrate {
|
||||
src: ExternCrateSource::Extern(def_id.to_def_id()),
|
||||
span: item.span,
|
||||
|
|
@ -1332,6 +1354,7 @@ impl CStore {
|
|||
|
||||
self.update_extern_crate(
|
||||
cnum,
|
||||
name,
|
||||
ExternCrate {
|
||||
src: ExternCrateSource::Path,
|
||||
span,
|
||||
|
|
|
|||
|
|
@ -1937,9 +1937,13 @@ impl CrateMetadata {
|
|||
self.root.decode_target_modifiers(&self.blob).collect()
|
||||
}
|
||||
|
||||
pub(crate) fn update_extern_crate(&mut self, new_extern_crate: ExternCrate) -> bool {
|
||||
/// Keep `new_extern_crate` if it looks better in diagnostics
|
||||
pub(crate) fn update_extern_crate_diagnostics(
|
||||
&mut self,
|
||||
new_extern_crate: ExternCrate,
|
||||
) -> bool {
|
||||
let update =
|
||||
Some(new_extern_crate.rank()) > self.extern_crate.as_ref().map(ExternCrate::rank);
|
||||
self.extern_crate.as_ref().is_none_or(|old| old.rank() < new_extern_crate.rank());
|
||||
if update {
|
||||
self.extern_crate = Some(new_extern_crate);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -627,14 +627,37 @@ impl CStore {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn update_extern_crate(&mut self, cnum: CrateNum, extern_crate: ExternCrate) {
|
||||
/// Track how an extern crate has been loaded. Called after resolving an import in the local crate.
|
||||
///
|
||||
/// * the `name` is for [`Self::set_resolved_extern_crate_name`] saving `--extern name=`
|
||||
/// * `extern_crate` is for diagnostics
|
||||
pub(crate) fn update_extern_crate(
|
||||
&mut self,
|
||||
cnum: CrateNum,
|
||||
name: Symbol,
|
||||
extern_crate: ExternCrate,
|
||||
) {
|
||||
debug_assert_eq!(
|
||||
extern_crate.dependency_of, LOCAL_CRATE,
|
||||
"this function should not be called on transitive dependencies"
|
||||
);
|
||||
self.set_resolved_extern_crate_name(name, cnum);
|
||||
self.update_transitive_extern_crate_diagnostics(cnum, extern_crate);
|
||||
}
|
||||
|
||||
/// `CrateMetadata` uses `ExternCrate` only for diagnostics
|
||||
fn update_transitive_extern_crate_diagnostics(
|
||||
&mut self,
|
||||
cnum: CrateNum,
|
||||
extern_crate: ExternCrate,
|
||||
) {
|
||||
let cmeta = self.get_crate_data_mut(cnum);
|
||||
if cmeta.update_extern_crate(extern_crate) {
|
||||
if cmeta.update_extern_crate_diagnostics(extern_crate) {
|
||||
// Propagate the extern crate info to dependencies if it was updated.
|
||||
let extern_crate = ExternCrate { dependency_of: cnum, ..extern_crate };
|
||||
let dependencies = mem::take(&mut cmeta.dependencies);
|
||||
for &dep_cnum in &dependencies {
|
||||
self.update_extern_crate(dep_cnum, extern_crate);
|
||||
self.update_transitive_extern_crate_diagnostics(dep_cnum, extern_crate);
|
||||
}
|
||||
self.get_crate_data_mut(cnum).dependencies = dependencies;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ use std::ffi::{OsStr, OsString};
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::{env, fs, iter};
|
||||
|
||||
#[cfg(feature = "tracing")]
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::core::build_steps::compile::{Std, run_cargo};
|
||||
use crate::core::build_steps::doc::DocumentationFormat;
|
||||
use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
|
||||
|
|
@ -30,7 +33,7 @@ use crate::utils::helpers::{
|
|||
linker_flags, t, target_supports_cranelift_backend, up_to_date,
|
||||
};
|
||||
use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
|
||||
use crate::{CLang, DocTests, GitRepo, Mode, PathSet, envify};
|
||||
use crate::{CLang, DocTests, GitRepo, Mode, PathSet, debug, envify};
|
||||
|
||||
const ADB_TEST_DIR: &str = "/data/local/tmp/work";
|
||||
|
||||
|
|
@ -713,9 +716,23 @@ impl Step for CompiletestTest {
|
|||
}
|
||||
|
||||
/// Runs `cargo test` for compiletest.
|
||||
#[cfg_attr(
|
||||
feature = "tracing",
|
||||
instrument(level = "debug", name = "CompiletestTest::run", skip_all)
|
||||
)]
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let host = self.host;
|
||||
|
||||
if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
|
||||
eprintln!("\
|
||||
ERROR: `--stage 0` runs compiletest self-tests against the stage0 (precompiled) compiler, not the in-tree compiler, and will almost always cause tests to fail
|
||||
NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`."
|
||||
);
|
||||
crate::exit!(1);
|
||||
}
|
||||
|
||||
let compiler = builder.compiler(builder.top_stage, host);
|
||||
debug!(?compiler);
|
||||
|
||||
// We need `ToolStd` for the locally-built sysroot because
|
||||
// compiletest uses unstable features of the `test` crate.
|
||||
|
|
@ -723,8 +740,8 @@ impl Step for CompiletestTest {
|
|||
let mut cargo = tool::prepare_tool_cargo(
|
||||
builder,
|
||||
compiler,
|
||||
// compiletest uses libtest internals; make it use the in-tree std to make sure it never breaks
|
||||
// when std sources change.
|
||||
// compiletest uses libtest internals; make it use the in-tree std to make sure it never
|
||||
// breaks when std sources change.
|
||||
Mode::ToolStd,
|
||||
host,
|
||||
Kind::Test,
|
||||
|
|
@ -1612,12 +1629,11 @@ impl Step for Compiletest {
|
|||
return;
|
||||
}
|
||||
|
||||
if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() {
|
||||
if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 {
|
||||
eprintln!("\
|
||||
ERROR: `--stage 0` runs compiletest on the stage0 (precompiled) compiler, not your local changes, and will almost always cause tests to fail
|
||||
HELP: to test the compiler, use `--stage 1` instead
|
||||
HELP: to test the standard library, use `--stage 0 library/std` instead
|
||||
NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`."
|
||||
HELP: to test the compiler or standard library, omit the stage or explicitly use `--stage 1` instead
|
||||
NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`."
|
||||
);
|
||||
crate::exit!(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -298,8 +298,16 @@ pub struct Config {
|
|||
/// Command for visual diff display, e.g. `diff-tool --color=always`.
|
||||
pub compiletest_diff_tool: Option<String>,
|
||||
|
||||
/// Whether to allow running both `compiletest` self-tests and `compiletest`-managed test suites
|
||||
/// against the stage 0 (rustc, std).
|
||||
///
|
||||
/// This is only intended to be used when the stage 0 compiler is actually built from in-tree
|
||||
/// sources.
|
||||
pub compiletest_allow_stage0: bool,
|
||||
|
||||
/// Whether to use the precompiled stage0 libtest with compiletest.
|
||||
pub compiletest_use_stage0_libtest: bool,
|
||||
|
||||
/// Default value for `--extra-checks`
|
||||
pub tidy_extra_checks: Option<String>,
|
||||
pub is_running_on_ci: bool,
|
||||
|
|
@ -749,6 +757,7 @@ impl Config {
|
|||
optimized_compiler_builtins,
|
||||
jobs,
|
||||
compiletest_diff_tool,
|
||||
compiletest_allow_stage0,
|
||||
compiletest_use_stage0_libtest,
|
||||
tidy_extra_checks,
|
||||
ccache,
|
||||
|
|
@ -1020,8 +1029,12 @@ impl Config {
|
|||
|
||||
config.optimized_compiler_builtins =
|
||||
optimized_compiler_builtins.unwrap_or(config.channel != "dev");
|
||||
|
||||
config.compiletest_diff_tool = compiletest_diff_tool;
|
||||
|
||||
config.compiletest_allow_stage0 = compiletest_allow_stage0.unwrap_or(false);
|
||||
config.compiletest_use_stage0_libtest = compiletest_use_stage0_libtest.unwrap_or(true);
|
||||
|
||||
config.tidy_extra_checks = tidy_extra_checks;
|
||||
|
||||
let download_rustc = config.download_rustc_commit.is_some();
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ define_config! {
|
|||
optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
|
||||
jobs: Option<u32> = "jobs",
|
||||
compiletest_diff_tool: Option<String> = "compiletest-diff-tool",
|
||||
compiletest_allow_stage0: Option<bool> = "compiletest-allow-stage0",
|
||||
compiletest_use_stage0_libtest: Option<bool> = "compiletest-use-stage0-libtest",
|
||||
tidy_extra_checks: Option<String> = "tidy-extra-checks",
|
||||
ccache: Option<StringOrBool> = "ccache",
|
||||
|
|
|
|||
|
|
@ -486,4 +486,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
|
|||
severity: ChangeSeverity::Warning,
|
||||
summary: "Removed `rust.description` and `llvm.ccache` as it was deprecated in #137723 and #136941 long time ago.",
|
||||
},
|
||||
ChangeInfo {
|
||||
change_id: 144675,
|
||||
severity: ChangeSeverity::Warning,
|
||||
summary: "Added `build.compiletest-allow-stage0` flag instead of `COMPILETEST_FORCE_STAGE0` env var, and reject running `compiletest` self tests against stage 0 rustc unless explicitly allowed.",
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ ENV SCRIPT \
|
|||
python3 ../x.py check bootstrap && \
|
||||
/scripts/check-default-config-profiles.sh && \
|
||||
python3 ../x.py build src/tools/build-manifest && \
|
||||
python3 ../x.py test --stage 0 src/tools/compiletest && \
|
||||
python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
|
||||
python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
|
||||
python3 ../x.py check --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ ENV SCRIPT \
|
|||
python3 ../x.py check && \
|
||||
python3 ../x.py clippy ci && \
|
||||
python3 ../x.py test --stage 1 core alloc std test proc_macro && \
|
||||
python3 ../x.py test --stage 1 src/tools/compiletest && \
|
||||
python3 ../x.py doc --stage 0 bootstrap && \
|
||||
# Build both public and internal documentation.
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 0 compiler && \
|
||||
|
|
@ -37,6 +38,6 @@ ENV SCRIPT \
|
|||
mkdir -p /checkout/obj/staging/doc && \
|
||||
cp -r build/x86_64-unknown-linux-gnu/doc /checkout/obj/staging && \
|
||||
RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 1 library/test && \
|
||||
# The BOOTSTRAP_TRACING flag is added to verify whether the
|
||||
# The BOOTSTRAP_TRACING flag is added to verify whether the
|
||||
# bootstrap process compiles successfully with this flag enabled.
|
||||
BOOTSTRAP_TRACING=1 python3 ../x.py --help
|
||||
|
|
|
|||
|
|
@ -395,6 +395,12 @@ flags to control that behavior. When the `--extern-html-root-url` flag is given
|
|||
one of your dependencies, rustdoc use that URL for those docs. Keep in mind that if those docs exist
|
||||
in the output directory, those local docs will still override this flag.
|
||||
|
||||
The names in this flag are first matched against the names given in the `--extern name=` flags,
|
||||
which allows selecting between multiple crates with the same name (e.g. multiple versions of
|
||||
the same crate). For transitive dependencies that haven't been loaded via an `--extern` flag, matching
|
||||
falls backs to using crate names only, without ability to distinguish between multiple crates with
|
||||
the same name.
|
||||
|
||||
## `-Z force-unstable-if-unmarked`
|
||||
|
||||
Using this flag looks like this:
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ use std::path::{Path, PathBuf};
|
|||
use std::process::{self, Command, Stdio};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{panic, str};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{fmt, panic, str};
|
||||
|
||||
pub(crate) use make::{BuildDocTestBuilder, DocTestBuilder};
|
||||
pub(crate) use markdown::test as test_markdown;
|
||||
|
|
@ -36,6 +37,50 @@ use crate::config::{Options as RustdocOptions, OutputFormat};
|
|||
use crate::html::markdown::{ErrorCodes, Ignore, LangString, MdRelLine};
|
||||
use crate::lint::init_lints;
|
||||
|
||||
/// Type used to display times (compilation and total) information for merged doctests.
|
||||
struct MergedDoctestTimes {
|
||||
total_time: Instant,
|
||||
/// Total time spent compiling all merged doctests.
|
||||
compilation_time: Duration,
|
||||
/// This field is used to keep track of how many merged doctests we (tried to) compile.
|
||||
added_compilation_times: usize,
|
||||
}
|
||||
|
||||
impl MergedDoctestTimes {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
total_time: Instant::now(),
|
||||
compilation_time: Duration::default(),
|
||||
added_compilation_times: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn add_compilation_time(&mut self, duration: Duration) {
|
||||
self.compilation_time += duration;
|
||||
self.added_compilation_times += 1;
|
||||
}
|
||||
|
||||
fn display_times(&self) {
|
||||
// If no merged doctest was compiled, then there is nothing to display since the numbers
|
||||
// displayed by `libtest` for standalone tests are already accurate (they include both
|
||||
// compilation and runtime).
|
||||
if self.added_compilation_times > 0 {
|
||||
println!("{self}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MergedDoctestTimes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"all doctests ran in {:.2}s; merged doctests compilation took {:.2}s",
|
||||
self.total_time.elapsed().as_secs_f64(),
|
||||
self.compilation_time.as_secs_f64(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`).
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct GlobalTestOptions {
|
||||
|
|
@ -295,6 +340,7 @@ pub(crate) fn run_tests(
|
|||
|
||||
let mut nb_errors = 0;
|
||||
let mut ran_edition_tests = 0;
|
||||
let mut times = MergedDoctestTimes::new();
|
||||
let target_str = rustdoc_options.target.to_string();
|
||||
|
||||
for (MergeableTestKey { edition, global_crate_attrs_hash }, mut doctests) in mergeable_tests {
|
||||
|
|
@ -314,13 +360,15 @@ pub(crate) fn run_tests(
|
|||
for (doctest, scraped_test) in &doctests {
|
||||
tests_runner.add_test(doctest, scraped_test, &target_str);
|
||||
}
|
||||
if let Ok(success) = tests_runner.run_merged_tests(
|
||||
let (duration, ret) = tests_runner.run_merged_tests(
|
||||
rustdoc_test_options,
|
||||
edition,
|
||||
&opts,
|
||||
&test_args,
|
||||
rustdoc_options,
|
||||
) {
|
||||
);
|
||||
times.add_compilation_time(duration);
|
||||
if let Ok(success) = ret {
|
||||
ran_edition_tests += 1;
|
||||
if !success {
|
||||
nb_errors += 1;
|
||||
|
|
@ -354,11 +402,13 @@ pub(crate) fn run_tests(
|
|||
test::test_main_with_exit_callback(&test_args, standalone_tests, None, || {
|
||||
// We ensure temp dir destructor is called.
|
||||
std::mem::drop(temp_dir.take());
|
||||
times.display_times();
|
||||
});
|
||||
}
|
||||
if nb_errors != 0 {
|
||||
// We ensure temp dir destructor is called.
|
||||
std::mem::drop(temp_dir);
|
||||
times.display_times();
|
||||
// libtest::ERROR_EXIT_CODE is not public but it's the same value.
|
||||
std::process::exit(101);
|
||||
}
|
||||
|
|
@ -496,16 +546,19 @@ impl RunnableDocTest {
|
|||
///
|
||||
/// This is the function that calculates the compiler command line, invokes the compiler, then
|
||||
/// invokes the test or tests in a separate executable (if applicable).
|
||||
///
|
||||
/// Returns a tuple containing the `Duration` of the compilation and the `Result` of the test.
|
||||
fn run_test(
|
||||
doctest: RunnableDocTest,
|
||||
rustdoc_options: &RustdocOptions,
|
||||
supports_color: bool,
|
||||
report_unused_externs: impl Fn(UnusedExterns),
|
||||
) -> Result<(), TestFailure> {
|
||||
) -> (Duration, Result<(), TestFailure>) {
|
||||
let langstr = &doctest.langstr;
|
||||
// Make sure we emit well-formed executable names for our target.
|
||||
let rust_out = add_exe_suffix("rust_out".to_owned(), &rustdoc_options.target);
|
||||
let output_file = doctest.test_opts.outdir.path().join(rust_out);
|
||||
let instant = Instant::now();
|
||||
|
||||
// Common arguments used for compiling the doctest runner.
|
||||
// On merged doctests, the compiler is invoked twice: once for the test code itself,
|
||||
|
|
@ -589,7 +642,7 @@ fn run_test(
|
|||
if std::fs::write(&input_file, &doctest.full_test_code).is_err() {
|
||||
// If we cannot write this file for any reason, we leave. All combined tests will be
|
||||
// tested as standalone tests.
|
||||
return Err(TestFailure::CompileError);
|
||||
return (Duration::default(), Err(TestFailure::CompileError));
|
||||
}
|
||||
if !rustdoc_options.nocapture {
|
||||
// If `nocapture` is disabled, then we don't display rustc's output when compiling
|
||||
|
|
@ -660,7 +713,7 @@ fn run_test(
|
|||
if std::fs::write(&runner_input_file, merged_test_code).is_err() {
|
||||
// If we cannot write this file for any reason, we leave. All combined tests will be
|
||||
// tested as standalone tests.
|
||||
return Err(TestFailure::CompileError);
|
||||
return (instant.elapsed(), Err(TestFailure::CompileError));
|
||||
}
|
||||
if !rustdoc_options.nocapture {
|
||||
// If `nocapture` is disabled, then we don't display rustc's output when compiling
|
||||
|
|
@ -713,7 +766,7 @@ fn run_test(
|
|||
let _bomb = Bomb(&out);
|
||||
match (output.status.success(), langstr.compile_fail) {
|
||||
(true, true) => {
|
||||
return Err(TestFailure::UnexpectedCompilePass);
|
||||
return (instant.elapsed(), Err(TestFailure::UnexpectedCompilePass));
|
||||
}
|
||||
(true, false) => {}
|
||||
(false, true) => {
|
||||
|
|
@ -729,17 +782,18 @@ fn run_test(
|
|||
.collect();
|
||||
|
||||
if !missing_codes.is_empty() {
|
||||
return Err(TestFailure::MissingErrorCodes(missing_codes));
|
||||
return (instant.elapsed(), Err(TestFailure::MissingErrorCodes(missing_codes)));
|
||||
}
|
||||
}
|
||||
}
|
||||
(false, false) => {
|
||||
return Err(TestFailure::CompileError);
|
||||
return (instant.elapsed(), Err(TestFailure::CompileError));
|
||||
}
|
||||
}
|
||||
|
||||
let duration = instant.elapsed();
|
||||
if doctest.no_run {
|
||||
return Ok(());
|
||||
return (duration, Ok(()));
|
||||
}
|
||||
|
||||
// Run the code!
|
||||
|
|
@ -771,17 +825,17 @@ fn run_test(
|
|||
cmd.output()
|
||||
};
|
||||
match result {
|
||||
Err(e) => return Err(TestFailure::ExecutionError(e)),
|
||||
Err(e) => return (duration, Err(TestFailure::ExecutionError(e))),
|
||||
Ok(out) => {
|
||||
if langstr.should_panic && out.status.success() {
|
||||
return Err(TestFailure::UnexpectedRunPass);
|
||||
return (duration, Err(TestFailure::UnexpectedRunPass));
|
||||
} else if !langstr.should_panic && !out.status.success() {
|
||||
return Err(TestFailure::ExecutionFailure(out));
|
||||
return (duration, Err(TestFailure::ExecutionFailure(out)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
(duration, Ok(()))
|
||||
}
|
||||
|
||||
/// Converts a path intended to use as a command to absolute if it is
|
||||
|
|
@ -1071,7 +1125,7 @@ fn doctest_run_fn(
|
|||
no_run: scraped_test.no_run(&rustdoc_options),
|
||||
merged_test_code: None,
|
||||
};
|
||||
let res =
|
||||
let (_, res) =
|
||||
run_test(runnable_test, &rustdoc_options, doctest.supports_color, report_unused_externs);
|
||||
|
||||
if let Err(err) = res {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use std::fmt::Write;
|
||||
use std::time::Duration;
|
||||
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_span::edition::Edition;
|
||||
|
|
@ -67,6 +68,10 @@ impl DocTestRunner {
|
|||
self.nb_tests += 1;
|
||||
}
|
||||
|
||||
/// Returns a tuple containing the `Duration` of the compilation and the `Result` of the test.
|
||||
///
|
||||
/// If compilation failed, it will return `Err`, otherwise it will return `Ok` containing if
|
||||
/// the test ran successfully.
|
||||
pub(crate) fn run_merged_tests(
|
||||
&mut self,
|
||||
test_options: IndividualTestOptions,
|
||||
|
|
@ -74,7 +79,7 @@ impl DocTestRunner {
|
|||
opts: &GlobalTestOptions,
|
||||
test_args: &[String],
|
||||
rustdoc_options: &RustdocOptions,
|
||||
) -> Result<bool, ()> {
|
||||
) -> (Duration, Result<bool, ()>) {
|
||||
let mut code = "\
|
||||
#![allow(unused_extern_crates)]
|
||||
#![allow(internal_features)]
|
||||
|
|
@ -204,9 +209,9 @@ std::process::Termination::report(test::test_main(test_args, tests, None))
|
|||
no_run: false,
|
||||
merged_test_code: Some(code),
|
||||
};
|
||||
let ret =
|
||||
let (duration, ret) =
|
||||
run_test(runnable_test, rustdoc_options, self.supports_color, |_: UnusedExterns| {});
|
||||
if let Err(TestFailure::CompileError) = ret { Err(()) } else { Ok(ret.is_ok()) }
|
||||
(duration, if let Err(TestFailure::CompileError) = ret { Err(()) } else { Ok(ret.is_ok()) })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ use rustc_ast::join_path_syms;
|
|||
use rustc_attr_data_structures::StabilityLevel;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIdSet};
|
||||
use rustc_metadata::creader::CStore;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::Symbol;
|
||||
use tracing::debug;
|
||||
|
|
@ -158,18 +159,33 @@ impl Cache {
|
|||
assert!(cx.external_traits.is_empty());
|
||||
cx.cache.traits = mem::take(&mut krate.external_traits);
|
||||
|
||||
let render_options = &cx.render_options;
|
||||
let extern_url_takes_precedence = render_options.extern_html_root_takes_precedence;
|
||||
let dst = &render_options.output;
|
||||
|
||||
// Make `--extern-html-root-url` support the same names as `--extern` whenever possible
|
||||
let cstore = CStore::from_tcx(tcx);
|
||||
for (name, extern_url) in &render_options.extern_html_root_urls {
|
||||
if let Some(crate_num) = cstore.resolved_extern_crate(Symbol::intern(name)) {
|
||||
let e = ExternalCrate { crate_num };
|
||||
let location = e.location(Some(extern_url), extern_url_takes_precedence, dst, tcx);
|
||||
cx.cache.extern_locations.insert(e.crate_num, location);
|
||||
}
|
||||
}
|
||||
|
||||
// Cache where all our extern crates are located
|
||||
// FIXME: this part is specific to HTML so it'd be nice to remove it from the common code
|
||||
// This is also used in the JSON output.
|
||||
for &crate_num in tcx.crates(()) {
|
||||
let e = ExternalCrate { crate_num };
|
||||
|
||||
let name = e.name(tcx);
|
||||
let render_options = &cx.render_options;
|
||||
let extern_url = render_options.extern_html_root_urls.get(name.as_str()).map(|u| &**u);
|
||||
let extern_url_takes_precedence = render_options.extern_html_root_takes_precedence;
|
||||
let dst = &render_options.output;
|
||||
let location = e.location(extern_url, extern_url_takes_precedence, dst, tcx);
|
||||
cx.cache.extern_locations.insert(e.crate_num, location);
|
||||
cx.cache.extern_locations.entry(e.crate_num).or_insert_with(|| {
|
||||
// falls back to matching by crates' own names, because
|
||||
// transitive dependencies and injected crates may be loaded without `--extern`
|
||||
let extern_url =
|
||||
render_options.extern_html_root_urls.get(name.as_str()).map(|u| &**u);
|
||||
e.location(extern_url, extern_url_takes_precedence, dst, tcx)
|
||||
});
|
||||
cx.cache.external_paths.insert(e.def_id(), (vec![name], ItemType::Module));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ lld = false
|
|||
rustc = "{rustc}"
|
||||
cargo = "{cargo}"
|
||||
local-rebuild = true
|
||||
compiletest-allow-stage0=true
|
||||
|
||||
[target.{host_triple}]
|
||||
llvm-config = "{llvm_config}"
|
||||
|
|
@ -117,7 +118,6 @@ llvm-config = "{llvm_config}"
|
|||
args.extend(["--skip", test_path]);
|
||||
}
|
||||
cmd(&args)
|
||||
.env("COMPILETEST_FORCE_STAGE0", "1")
|
||||
// Also run dist-only tests
|
||||
.env("COMPILETEST_ENABLE_DIST_TESTS", "1")
|
||||
.run()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
//@ compile-flags: --test --test-args=--test-threads=1
|
||||
//@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
|
||||
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
|
||||
running 1 test
|
||||
test $DIR/2024-doctests-checks.rs - Foo (line 8) ... ok
|
||||
test $DIR/2024-doctests-checks.rs - Foo (line 10) ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
|
||||
running 1 test
|
||||
test $DIR/2024-doctests-checks.rs - Foo (line 15) ... ok
|
||||
test $DIR/2024-doctests-checks.rs - Foo (line 17) ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
//@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
|
||||
/// This doctest is used to ensure that if a crate attribute is present,
|
||||
/// it will not be part of the merged doctests.
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
|
||||
running 1 test
|
||||
test $DIR/2024-doctests-crate-attribute.rs - Foo (line 20) ... ok
|
||||
test $DIR/2024-doctests-crate-attribute.rs - Foo (line 22) ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
|
||||
running 1 test
|
||||
test $DIR/2024-doctests-crate-attribute.rs - Foo (line 11) ... ok
|
||||
test $DIR/2024-doctests-crate-attribute.rs - Foo (line 13) ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
//@ compile-flags:--test
|
||||
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
//@ failure-status: 101
|
||||
|
||||
#![doc(test(attr(allow(unused_variables), deny(warnings))))]
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
|
||||
running 1 test
|
||||
test $DIR/dead-code-2024.rs - f (line 13) - compile ... FAILED
|
||||
test $DIR/dead-code-2024.rs - f (line 15) - compile ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- $DIR/dead-code-2024.rs - f (line 13) stdout ----
|
||||
---- $DIR/dead-code-2024.rs - f (line 15) stdout ----
|
||||
error: trait `T` is never used
|
||||
--> $DIR/dead-code-2024.rs:14:7
|
||||
--> $DIR/dead-code-2024.rs:16:7
|
||||
|
|
||||
LL | trait T { fn f(); }
|
||||
| ^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/dead-code-2024.rs:12:9
|
||||
--> $DIR/dead-code-2024.rs:14:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
|
|
@ -23,7 +23,8 @@ error: aborting due to 1 previous error
|
|||
Couldn't compile the test.
|
||||
|
||||
failures:
|
||||
$DIR/dead-code-2024.rs - f (line 13)
|
||||
$DIR/dead-code-2024.rs - f (line 15)
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
//@ compile-flags:--test --test-args=--test-threads=1
|
||||
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
//@ failure-status: 101
|
||||
|
||||
#![doc(test(attr(deny(warnings))))]
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
|
||||
running 13 tests
|
||||
test $DIR/dead-code-items.rs - A (line 32) - compile ... ok
|
||||
test $DIR/dead-code-items.rs - A (line 88) - compile ... ok
|
||||
test $DIR/dead-code-items.rs - A::field (line 39) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - A::method (line 94) - compile ... ok
|
||||
test $DIR/dead-code-items.rs - C (line 22) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - Enum (line 70) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - Enum::Variant1 (line 77) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - MyTrait (line 103) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - S (line 14) - compile ... ok
|
||||
test $DIR/dead-code-items.rs - U (line 48) - compile ... ok
|
||||
test $DIR/dead-code-items.rs - U::field (line 55) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - U::field2 (line 61) - compile ... ok
|
||||
test $DIR/dead-code-items.rs - A (line 34) - compile ... ok
|
||||
test $DIR/dead-code-items.rs - A (line 90) - compile ... ok
|
||||
test $DIR/dead-code-items.rs - A::field (line 41) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - A::method (line 96) - compile ... ok
|
||||
test $DIR/dead-code-items.rs - C (line 24) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - Enum (line 72) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - Enum::Variant1 (line 79) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - MyTrait (line 105) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 112) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - S (line 16) - compile ... ok
|
||||
test $DIR/dead-code-items.rs - U (line 50) - compile ... ok
|
||||
test $DIR/dead-code-items.rs - U::field (line 57) - compile ... FAILED
|
||||
test $DIR/dead-code-items.rs - U::field2 (line 63) - compile ... ok
|
||||
|
||||
failures:
|
||||
|
||||
---- $DIR/dead-code-items.rs - A::field (line 39) stdout ----
|
||||
---- $DIR/dead-code-items.rs - A::field (line 41) stdout ----
|
||||
error: trait `DeadCodeInField` is never used
|
||||
--> $DIR/dead-code-items.rs:40:7
|
||||
--> $DIR/dead-code-items.rs:42:7
|
||||
|
|
||||
LL | trait DeadCodeInField {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/dead-code-items.rs:38:9
|
||||
--> $DIR/dead-code-items.rs:40:9
|
||||
|
|
||||
LL | #![deny(dead_code)]
|
||||
| ^^^^^^^^^
|
||||
|
|
@ -32,15 +32,15 @@ LL | #![deny(dead_code)]
|
|||
error: aborting due to 1 previous error
|
||||
|
||||
Couldn't compile the test.
|
||||
---- $DIR/dead-code-items.rs - C (line 22) stdout ----
|
||||
---- $DIR/dead-code-items.rs - C (line 24) stdout ----
|
||||
error: unused variable: `unused_error`
|
||||
--> $DIR/dead-code-items.rs:23:5
|
||||
--> $DIR/dead-code-items.rs:25:5
|
||||
|
|
||||
LL | let unused_error = 5;
|
||||
| ^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_error`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/dead-code-items.rs:20:9
|
||||
--> $DIR/dead-code-items.rs:22:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
|
|
@ -49,15 +49,15 @@ LL | #![deny(warnings)]
|
|||
error: aborting due to 1 previous error
|
||||
|
||||
Couldn't compile the test.
|
||||
---- $DIR/dead-code-items.rs - Enum (line 70) stdout ----
|
||||
---- $DIR/dead-code-items.rs - Enum (line 72) stdout ----
|
||||
error: unused variable: `not_dead_code_but_unused`
|
||||
--> $DIR/dead-code-items.rs:71:5
|
||||
--> $DIR/dead-code-items.rs:73:5
|
||||
|
|
||||
LL | let not_dead_code_but_unused = 5;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_not_dead_code_but_unused`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/dead-code-items.rs:68:9
|
||||
--> $DIR/dead-code-items.rs:70:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
|
|
@ -66,15 +66,15 @@ LL | #![deny(warnings)]
|
|||
error: aborting due to 1 previous error
|
||||
|
||||
Couldn't compile the test.
|
||||
---- $DIR/dead-code-items.rs - Enum::Variant1 (line 77) stdout ----
|
||||
---- $DIR/dead-code-items.rs - Enum::Variant1 (line 79) stdout ----
|
||||
error: unused variable: `unused_in_variant`
|
||||
--> $DIR/dead-code-items.rs:80:17
|
||||
--> $DIR/dead-code-items.rs:82:17
|
||||
|
|
||||
LL | fn main() { let unused_in_variant = 5; }
|
||||
| ^^^^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_in_variant`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/dead-code-items.rs:75:9
|
||||
--> $DIR/dead-code-items.rs:77:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
|
|
@ -83,15 +83,15 @@ LL | #![deny(warnings)]
|
|||
error: aborting due to 1 previous error
|
||||
|
||||
Couldn't compile the test.
|
||||
---- $DIR/dead-code-items.rs - MyTrait (line 103) stdout ----
|
||||
---- $DIR/dead-code-items.rs - MyTrait (line 105) stdout ----
|
||||
error: trait `StillDeadCodeAtMyTrait` is never used
|
||||
--> $DIR/dead-code-items.rs:104:7
|
||||
--> $DIR/dead-code-items.rs:106:7
|
||||
|
|
||||
LL | trait StillDeadCodeAtMyTrait { }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/dead-code-items.rs:102:9
|
||||
--> $DIR/dead-code-items.rs:104:9
|
||||
|
|
||||
LL | #![deny(dead_code)]
|
||||
| ^^^^^^^^^
|
||||
|
|
@ -99,15 +99,15 @@ LL | #![deny(dead_code)]
|
|||
error: aborting due to 1 previous error
|
||||
|
||||
Couldn't compile the test.
|
||||
---- $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110) stdout ----
|
||||
---- $DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 112) stdout ----
|
||||
error: unused variable: `unused_in_impl`
|
||||
--> $DIR/dead-code-items.rs:113:17
|
||||
--> $DIR/dead-code-items.rs:115:17
|
||||
|
|
||||
LL | fn main() { let unused_in_impl = 5; }
|
||||
| ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused_in_impl`
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/dead-code-items.rs:108:9
|
||||
--> $DIR/dead-code-items.rs:110:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
|
|
@ -116,15 +116,15 @@ LL | #![deny(warnings)]
|
|||
error: aborting due to 1 previous error
|
||||
|
||||
Couldn't compile the test.
|
||||
---- $DIR/dead-code-items.rs - U::field (line 55) stdout ----
|
||||
---- $DIR/dead-code-items.rs - U::field (line 57) stdout ----
|
||||
error: trait `DeadCodeInUnionField` is never used
|
||||
--> $DIR/dead-code-items.rs:56:7
|
||||
--> $DIR/dead-code-items.rs:58:7
|
||||
|
|
||||
LL | trait DeadCodeInUnionField {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/dead-code-items.rs:54:9
|
||||
--> $DIR/dead-code-items.rs:56:9
|
||||
|
|
||||
LL | #![deny(dead_code)]
|
||||
| ^^^^^^^^^
|
||||
|
|
@ -134,13 +134,14 @@ error: aborting due to 1 previous error
|
|||
Couldn't compile the test.
|
||||
|
||||
failures:
|
||||
$DIR/dead-code-items.rs - A::field (line 39)
|
||||
$DIR/dead-code-items.rs - C (line 22)
|
||||
$DIR/dead-code-items.rs - Enum (line 70)
|
||||
$DIR/dead-code-items.rs - Enum::Variant1 (line 77)
|
||||
$DIR/dead-code-items.rs - MyTrait (line 103)
|
||||
$DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 110)
|
||||
$DIR/dead-code-items.rs - U::field (line 55)
|
||||
$DIR/dead-code-items.rs - A::field (line 41)
|
||||
$DIR/dead-code-items.rs - C (line 24)
|
||||
$DIR/dead-code-items.rs - Enum (line 72)
|
||||
$DIR/dead-code-items.rs - Enum::Variant1 (line 79)
|
||||
$DIR/dead-code-items.rs - MyTrait (line 105)
|
||||
$DIR/dead-code-items.rs - MyTrait::my_trait_fn (line 112)
|
||||
$DIR/dead-code-items.rs - U::field (line 57)
|
||||
|
||||
test result: FAILED. 6 passed; 7 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
//@ compile-flags:--test
|
||||
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
//@ failure-status: 101
|
||||
|
||||
#![doc(test(attr(allow(unused_variables))))]
|
||||
|
|
|
|||
|
|
@ -1,24 +1,24 @@
|
|||
|
||||
running 1 test
|
||||
test $DIR/dead-code-module-2.rs - g (line 24) - compile ... ok
|
||||
test $DIR/dead-code-module-2.rs - g (line 26) - compile ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
|
||||
running 1 test
|
||||
test $DIR/dead-code-module-2.rs - my_mod::f (line 16) - compile ... FAILED
|
||||
test $DIR/dead-code-module-2.rs - my_mod::f (line 18) - compile ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- $DIR/dead-code-module-2.rs - my_mod::f (line 16) stdout ----
|
||||
---- $DIR/dead-code-module-2.rs - my_mod::f (line 18) stdout ----
|
||||
error: trait `T` is never used
|
||||
--> $DIR/dead-code-module-2.rs:17:7
|
||||
--> $DIR/dead-code-module-2.rs:19:7
|
||||
|
|
||||
LL | trait T { fn f(); }
|
||||
| ^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/dead-code-module-2.rs:15:9
|
||||
--> $DIR/dead-code-module-2.rs:17:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
|
|
@ -29,7 +29,8 @@ error: aborting due to 1 previous error
|
|||
Couldn't compile the test.
|
||||
|
||||
failures:
|
||||
$DIR/dead-code-module-2.rs - my_mod::f (line 16)
|
||||
$DIR/dead-code-module-2.rs - my_mod::f (line 18)
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
//@ compile-flags:--test
|
||||
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
//@ failure-status: 101
|
||||
|
||||
mod my_mod {
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
|
||||
running 1 test
|
||||
test $DIR/dead-code-module.rs - my_mod::f (line 14) - compile ... FAILED
|
||||
test $DIR/dead-code-module.rs - my_mod::f (line 16) - compile ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- $DIR/dead-code-module.rs - my_mod::f (line 14) stdout ----
|
||||
---- $DIR/dead-code-module.rs - my_mod::f (line 16) stdout ----
|
||||
error: trait `T` is never used
|
||||
--> $DIR/dead-code-module.rs:15:7
|
||||
--> $DIR/dead-code-module.rs:17:7
|
||||
|
|
||||
LL | trait T { fn f(); }
|
||||
| ^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> $DIR/dead-code-module.rs:13:9
|
||||
--> $DIR/dead-code-module.rs:15:9
|
||||
|
|
||||
LL | #![deny(warnings)]
|
||||
| ^^^^^^^^
|
||||
|
|
@ -23,7 +23,8 @@ error: aborting due to 1 previous error
|
|||
Couldn't compile the test.
|
||||
|
||||
failures:
|
||||
$DIR/dead-code-module.rs - my_mod::f (line 14)
|
||||
$DIR/dead-code-module.rs - my_mod::f (line 16)
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
//@ compile-flags:--test --test-args=--test-threads=1
|
||||
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
//@ failure-status: 101
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/130470
|
||||
|
|
|
|||
|
|
@ -22,3 +22,4 @@ failures:
|
|||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
|
||||
//@ normalize-stdout: "panicked at .+rs:" -> "panicked at $$TMP:"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
//@ rustc-env:RUST_BACKTRACE=0
|
||||
//@ failure-status: 101
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
running 1 test
|
||||
test $DIR/edition-2024-error-output.rs - (line 12) ... FAILED
|
||||
test $DIR/edition-2024-error-output.rs - (line 14) ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- $DIR/edition-2024-error-output.rs - (line 12) stdout ----
|
||||
---- $DIR/edition-2024-error-output.rs - (line 14) stdout ----
|
||||
Test executable failed (exit status: 101).
|
||||
|
||||
stderr:
|
||||
|
|
@ -18,7 +18,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
|||
|
||||
|
||||
failures:
|
||||
$DIR/edition-2024-error-output.rs - (line 12)
|
||||
$DIR/edition-2024-error-output.rs - (line 14)
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
//@ compile-flags:--test
|
||||
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
//@ failure-status: 101
|
||||
|
||||
/// ```should_panic
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
|
||||
running 1 test
|
||||
test $DIR/failed-doctest-should-panic.rs - Foo (line 10) - should panic ... FAILED
|
||||
test $DIR/failed-doctest-should-panic.rs - Foo (line 12) - should panic ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- $DIR/failed-doctest-should-panic.rs - Foo (line 10) stdout ----
|
||||
note: test did not panic as expected at $DIR/failed-doctest-should-panic.rs:10:0
|
||||
---- $DIR/failed-doctest-should-panic.rs - Foo (line 12) stdout ----
|
||||
note: test did not panic as expected at $DIR/failed-doctest-should-panic.rs:12:0
|
||||
|
||||
failures:
|
||||
$DIR/failed-doctest-should-panic.rs - Foo (line 10)
|
||||
$DIR/failed-doctest-should-panic.rs - Foo (line 12)
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
|
||||
running 1 test
|
||||
test $DIR/failed-doctest-test-crate.rs - m (line 14) ... FAILED
|
||||
test $DIR/failed-doctest-test-crate.rs - m (line 16) ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- $DIR/failed-doctest-test-crate.rs - m (line 14) stdout ----
|
||||
---- $DIR/failed-doctest-test-crate.rs - m (line 16) stdout ----
|
||||
error[E0432]: unresolved import `test`
|
||||
--> $DIR/failed-doctest-test-crate.rs:15:5
|
||||
--> $DIR/failed-doctest-test-crate.rs:17:5
|
||||
|
|
||||
LL | use test::*;
|
||||
| ^^^^ use of unresolved module or unlinked crate `test`
|
||||
|
|
@ -22,7 +22,7 @@ For more information about this error, try `rustc --explain E0432`.
|
|||
Couldn't compile the test.
|
||||
|
||||
failures:
|
||||
$DIR/failed-doctest-test-crate.rs - m (line 14)
|
||||
$DIR/failed-doctest-test-crate.rs - m (line 16)
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
|
||||
running 1 test
|
||||
test $DIR/failed-doctest-test-crate.rs - m (line 14) ... FAILED
|
||||
test $DIR/failed-doctest-test-crate.rs - m (line 16) ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- $DIR/failed-doctest-test-crate.rs - m (line 14) stdout ----
|
||||
---- $DIR/failed-doctest-test-crate.rs - m (line 16) stdout ----
|
||||
error[E0432]: unresolved import `test`
|
||||
--> $DIR/failed-doctest-test-crate.rs:15:5
|
||||
--> $DIR/failed-doctest-test-crate.rs:17:5
|
||||
|
|
||||
LL | use test::*;
|
||||
| ^^^^ use of unresolved module or unlinked crate `test`
|
||||
|
|
@ -19,7 +19,8 @@ For more information about this error, try `rustc --explain E0432`.
|
|||
Couldn't compile the test.
|
||||
|
||||
failures:
|
||||
$DIR/failed-doctest-test-crate.rs - m (line 14)
|
||||
$DIR/failed-doctest-test-crate.rs - m (line 16)
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
//@ compile-flags:--test
|
||||
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
//@ failure-status: 101
|
||||
|
||||
/// <https://github.com/rust-lang/rust/pull/137899#discussion_r1976743383>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
|
||||
running 1 test
|
||||
test $DIR/relative-path-include-bytes-132203.rs - (line 18) ... FAILED
|
||||
test $DIR/relative-path-include-bytes-132203.rs - (line 20) ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- $DIR/relative-path-include-bytes-132203.rs - (line 18) stdout ----
|
||||
---- $DIR/relative-path-include-bytes-132203.rs - (line 20) stdout ----
|
||||
error: couldn't read `$DIR/relative-dir-empty-file`: $FILE_NOT_FOUND_MSG (os error 2)
|
||||
--> $DIR/relative-path-include-bytes-132203.rs:19:9
|
||||
--> $DIR/relative-path-include-bytes-132203.rs:21:9
|
||||
|
|
||||
LL | let x = include_bytes!("relative-dir-empty-file");
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -16,7 +16,7 @@ error: aborting due to 1 previous error
|
|||
Couldn't compile the test.
|
||||
|
||||
failures:
|
||||
$DIR/relative-path-include-bytes-132203.rs - (line 18)
|
||||
$DIR/relative-path-include-bytes-132203.rs - (line 20)
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
|
|
|
|||
|
|
@ -4,3 +4,4 @@ test $DIR/auxiliary/relative-dir.md - (line 1) ... ok
|
|||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
//@ normalize-stdout: "tests.rustdoc-ui.doctest." -> "$$DIR/"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: "`: .* \(os error 2\)" -> "`: $$FILE_NOT_FOUND_MSG (os error 2)"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/132203
|
||||
// This version, because it's edition2024, passes thanks to the new
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: "panicked at .+rs:" -> "panicked at $$TMP:"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
//@ failure-status: 101
|
||||
//@ rustc-env:RUST_BACKTRACE=0
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
|
||||
running 3 tests
|
||||
test $DIR/stdout-and-stderr.rs - (line 15) ... FAILED
|
||||
test $DIR/stdout-and-stderr.rs - (line 20) ... FAILED
|
||||
test $DIR/stdout-and-stderr.rs - (line 24) ... FAILED
|
||||
test $DIR/stdout-and-stderr.rs - (line 17) ... FAILED
|
||||
test $DIR/stdout-and-stderr.rs - (line 22) ... FAILED
|
||||
test $DIR/stdout-and-stderr.rs - (line 26) ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- $DIR/stdout-and-stderr.rs - (line 15) stdout ----
|
||||
---- $DIR/stdout-and-stderr.rs - (line 17) stdout ----
|
||||
Test executable failed (exit status: 101).
|
||||
|
||||
stdout:
|
||||
|
|
@ -21,7 +21,7 @@ assertion `left == right` failed
|
|||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
|
||||
|
||||
---- $DIR/stdout-and-stderr.rs - (line 20) stdout ----
|
||||
---- $DIR/stdout-and-stderr.rs - (line 22) stdout ----
|
||||
Test executable failed (exit status: 101).
|
||||
|
||||
stderr:
|
||||
|
|
@ -33,14 +33,15 @@ assertion `left == right` failed
|
|||
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
|
||||
|
||||
|
||||
---- $DIR/stdout-and-stderr.rs - (line 24) stdout ----
|
||||
---- $DIR/stdout-and-stderr.rs - (line 26) stdout ----
|
||||
Test executable failed (exit status: 1).
|
||||
|
||||
|
||||
failures:
|
||||
$DIR/stdout-and-stderr.rs - (line 15)
|
||||
$DIR/stdout-and-stderr.rs - (line 20)
|
||||
$DIR/stdout-and-stderr.rs - (line 24)
|
||||
$DIR/stdout-and-stderr.rs - (line 17)
|
||||
$DIR/stdout-and-stderr.rs - (line 22)
|
||||
$DIR/stdout-and-stderr.rs - (line 26)
|
||||
|
||||
test result: FAILED. 0 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
|
||||
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
|
||||
//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
|
||||
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
|
||||
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
|
||||
//@ failure-status: 101
|
||||
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
|
||||
running 1 test
|
||||
test $DIR/wrong-ast-2024.rs - three (line 18) - should panic ... ok
|
||||
test $DIR/wrong-ast-2024.rs - three (line 20) - should panic ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
|
||||
running 2 tests
|
||||
test $DIR/wrong-ast-2024.rs - one (line 8) ... FAILED
|
||||
test $DIR/wrong-ast-2024.rs - two (line 13) ... FAILED
|
||||
test $DIR/wrong-ast-2024.rs - one (line 10) ... FAILED
|
||||
test $DIR/wrong-ast-2024.rs - two (line 15) ... FAILED
|
||||
|
||||
failures:
|
||||
|
||||
---- $DIR/wrong-ast-2024.rs - one (line 8) stdout ----
|
||||
---- $DIR/wrong-ast-2024.rs - one (line 10) stdout ----
|
||||
error[E0758]: unterminated block comment
|
||||
--> $DIR/wrong-ast-2024.rs:$LINE:$COL
|
||||
|
|
||||
|
|
@ -22,7 +22,7 @@ error: aborting due to 1 previous error
|
|||
|
||||
For more information about this error, try `rustc --explain E0758`.
|
||||
Couldn't compile the test.
|
||||
---- $DIR/wrong-ast-2024.rs - two (line 13) stdout ----
|
||||
---- $DIR/wrong-ast-2024.rs - two (line 15) stdout ----
|
||||
error: unexpected closing delimiter: `}`
|
||||
--> $DIR/wrong-ast-2024.rs:$LINE:$COL
|
||||
|
|
||||
|
|
@ -34,8 +34,9 @@ error: aborting due to 1 previous error
|
|||
Couldn't compile the test.
|
||||
|
||||
failures:
|
||||
$DIR/wrong-ast-2024.rs - one (line 8)
|
||||
$DIR/wrong-ast-2024.rs - two (line 13)
|
||||
$DIR/wrong-ast-2024.rs - one (line 10)
|
||||
$DIR/wrong-ast-2024.rs - two (line 15)
|
||||
|
||||
test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
|
||||
|
||||
all doctests ran in $TIME; merged doctests compilation took $TIME
|
||||
|
|
|
|||
9
tests/rustdoc/extern/extern-html-alias.rs
vendored
Normal file
9
tests/rustdoc/extern/extern-html-alias.rs
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
//@ compile-flags:-Z unstable-options --extern-html-root-url externs_name=https://renamed.example.com --extern-html-root-url empty=https://bad.invalid
|
||||
//@ aux-crate:externs_name=empty.rs
|
||||
//@ edition: 2018
|
||||
|
||||
extern crate externs_name as renamed;
|
||||
|
||||
//@ has extern_html_alias/index.html
|
||||
//@ has - '//a/@href' 'https://renamed.example.com/empty/index.html'
|
||||
pub use renamed as yet_different_name;
|
||||
14
tests/rustdoc/extern/extern-html-fallback.rs
vendored
Normal file
14
tests/rustdoc/extern/extern-html-fallback.rs
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//@ compile-flags:-Z unstable-options --extern-html-root-url yet_another_name=https://bad.invalid --extern-html-root-url renamed_privately=https://bad.invalid --extern-html-root-url renamed_locally=https://bad.invalid --extern-html-root-url empty=https://localhost
|
||||
//@ aux-crate:externs_name=empty.rs
|
||||
//@ edition: 2018
|
||||
|
||||
mod m {
|
||||
pub extern crate externs_name as renamed_privately;
|
||||
}
|
||||
|
||||
// renaming within the crate's source code is not supposed to affect CLI flags
|
||||
extern crate externs_name as renamed_locally;
|
||||
|
||||
//@ has extern_html_fallback/index.html
|
||||
//@ has - '//a/@href' 'https://localhost/empty/index.html'
|
||||
pub use crate::renamed_locally as yet_another_name;
|
||||
Loading…
Add table
Add a link
Reference in a new issue