Auto merge of #147220 - Zalathar:rollup-fubv0wy, r=Zalathar

Rollup of 11 pull requests

Successful merges:

 - rust-lang/rust#146918 (add regression test)
 - rust-lang/rust#146980 (simplify setup_constraining_predicates, and note it is potentially cubic)
 - rust-lang/rust#147170 (compiletest: Pass around `DirectiveLine` instead of bare strings)
 - rust-lang/rust#147180 (add tests)
 - rust-lang/rust#147188 (Remove usage of `compiletest-use-stage0-libtest` from CI)
 - rust-lang/rust#147189 (Replace `rustc_span::Span` with a stripped down version for librustdoc's highlighter)
 - rust-lang/rust#147199 (remove outdated comment in (inner) `InferCtxt`)
 - rust-lang/rust#147200 (Fix autodiff empty ret regression)
 - rust-lang/rust#147209 (Remove `no-remap-src-base` from tests)
 - rust-lang/rust#147213 (Fix broken STD build for ESP-IDF)
 - rust-lang/rust#147217 (Don't create a top-level `true` directory when running UI tests)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors
2025-10-01 14:36:51 +00:00
43 changed files with 419 additions and 267 deletions
-3
View File
@@ -476,9 +476,6 @@
# 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
# Default value for the `--extra-checks` flag of tidy.
#
# See `./x test tidy --help` for details.
@@ -378,5 +378,12 @@ pub(crate) fn generate_enzyme_call<'ll, 'tcx>(
let call = builder.call(enzyme_ty, None, None, ad_fn, &args, None, None);
builder.store_to_place(call, dest.val);
let fn_ret_ty = builder.cx.val_ty(call);
if fn_ret_ty != builder.cx.type_void() && fn_ret_ty != builder.cx.type_struct(&[], false) {
// If we return void or an empty struct, then our caller (due to how we generated it)
// does not expect a return value. As such, we have no pointer (or place) into which
// we could store our value, and would store into an undef, which would cause UB.
// As such, we just ignore the return value in those cases.
builder.store_to_place(call, dest.val);
}
}
@@ -167,15 +167,20 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
// which is `O(nt)` where `t` is the depth of type-parameter constraints,
// remembering that `t` should be less than 7 in practice.
//
// FIXME(hkBst): the big-O bound above would be accurate for the number
// of calls to `parameters_for`, which itself is some O(complexity of type).
// That would make this potentially cubic instead of merely quadratic...
// ...unless we cache those `parameters_for` calls.
//
// Basically, I iterate over all projections and swap every
// "ready" projection to the start of the list, such that
// all of the projections before `i` are topologically sorted
// and constrain all the parameters in `input_parameters`.
//
// In the example, `input_parameters` starts by containing `U` - which
// is constrained by the trait-ref - and so on the first pass we
// In the first example, `input_parameters` starts by containing `U`,
// which is constrained by the self type `U`. Then, on the first pass we
// observe that `<U as Iterator>::Item = T` is a "ready" projection that
// constrains `T` and swap it to front. As it is the sole projection,
// constrains `T` and swap it to the front. As it is the sole projection,
// no more swaps can take place afterwards, with the result being
// * <U as Iterator>::Item = T
// * T: Debug
@@ -193,33 +198,25 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
for j in i..predicates.len() {
// Note that we don't have to care about binders here,
// as the impl trait ref never contains any late-bound regions.
if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() {
// Special case: watch out for some kind of sneaky attempt
// to project out an associated type defined by this very
// trait.
let unbound_trait_ref = projection.projection_term.trait_ref(tcx);
if Some(unbound_trait_ref) == impl_trait_ref {
continue;
}
if let ty::ClauseKind::Projection(projection) = predicates[j].0.kind().skip_binder() &&
// A projection depends on its input types and determines its output
// type. For example, if we have
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
// Then the projection only applies if `T` is known, but it still
// does not determine `U`.
let inputs = parameters_for(tcx, projection.projection_term, true);
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
if !relies_only_on_inputs {
continue;
}
// Special case: watch out for some kind of sneaky attempt to
// project out an associated type defined by this very trait.
!impl_trait_ref.is_some_and(|t| t == projection.projection_term.trait_ref(tcx)) &&
// A projection depends on its input types and determines its output
// type. For example, if we have
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
// then the projection only applies if `T` is known, but it still
// does not determine `U`.
parameters_for(tcx, projection.projection_term, true).iter().all(|p| input_parameters.contains(p))
{
input_parameters.extend(parameters_for(tcx, projection.term, false));
} else {
continue;
predicates.swap(i, j);
i += 1;
changed = true;
}
// fancy control flow to bypass borrow checker
predicates.swap(i, j);
i += 1;
changed = true;
}
debug!(
"setup_constraining_predicates: predicates={:?} \
-17
View File
@@ -131,23 +131,6 @@ pub struct InferCtxtInner<'tcx> {
/// `$0: 'static`. This will get checked later by regionck. (We
/// can't generally check these things right away because we have
/// to wait until types are resolved.)
///
/// These are stored in a map keyed to the id of the innermost
/// enclosing fn body / static initializer expression. This is
/// because the location where the obligation was incurred can be
/// relevant with respect to which sublifetime assumptions are in
/// place. The reason that we store under the fn-id, and not
/// something more fine-grained, is so that it is easier for
/// regionck to be sure that it has found *all* the region
/// obligations (otherwise, it's easy to fail to walk to a
/// particular node-id).
///
/// Before running `resolve_regions_and_report_errors`, the creator
/// of the inference context is expected to invoke
/// [`InferCtxt::process_registered_region_obligations`]
/// for each body-id in this map, which will process the
/// obligations within. This is expected to be done 'late enough'
/// that all type inference variables have been bound and so forth.
region_obligations: Vec<TypeOutlivesConstraint<'tcx>>,
/// The outlives bounds that we assume must hold about placeholders that
@@ -473,7 +473,10 @@ pub(super) fn forced_ambiguity(
// fails to reach a fixpoint but ends up getting an error after
// running for some additional step.
//
// cc trait-system-refactor-initiative#105
// FIXME(@lcnr): While I believe an error here to be possible, we
// currently don't have any test which actually triggers it. @lqd
// created a minimization for an ICE in typenum, but that one no
// longer fails here. cc trait-system-refactor-initiative#105.
let source = CandidateSource::BuiltinImpl(BuiltinImplSource::Misc);
let certainty = Certainty::Maybe { cause, opaque_types_jank: OpaqueTypesJank::AllGood };
self.probe_trait_candidate(source)
@@ -77,6 +77,8 @@ impl<'tcx> InferCtxt<'tcx> {
///
/// Prefer this method over `resolve_regions_with_normalize`, unless you are
/// doing something specific for normalization.
///
/// This function assumes that all infer variables are already constrained.
fn resolve_regions(
&self,
body_id: LocalDefId,
+1 -1
View File
@@ -1,5 +1,5 @@
cfg_select! {
target_family = "unix" => {
all(target_family = "unix", not(target_os = "espidf")) => {
mod unix;
pub use unix::hostname;
}
@@ -7,8 +7,6 @@ test-stage = 2
doc-stage = 2
# When compiling from source, you usually want all tools.
extended = true
# Use libtest built from the source tree instead of the precompiled one from stage 0.
compiletest-use-stage0-libtest = false
# Most users installing from source want to build all parts of the project from source.
[llvm]
+1 -1
View File
@@ -1145,7 +1145,7 @@ macro_rules! describe {
test::RunMakeCargo,
),
Kind::Miri => describe!(test::Crate),
Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
Kind::Bench => describe!(test::Crate, test::CrateLibrustc, test::CrateRustdoc),
Kind::Doc => describe!(
doc::UnstableBook,
doc::UnstableBookGen,
+1 -1
View File
@@ -27,7 +27,7 @@ runners:
<<: *base-job
envs:
env-x86_64-apple-tests: &env-x86_64-apple-tests
SCRIPT: ./x.py check compiletest --set build.compiletest-use-stage0-libtest=true && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
SCRIPT: ./x.py check compiletest && ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact
RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc
RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
# Ensure that host tooling is tested on our minimum supported macOS version.
@@ -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 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 && \
/scripts/validate-toolstate.sh && \
@@ -90,5 +90,4 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu
COPY scripts/shared.sh /scripts/
ENV SCRIPT /tmp/checktools.sh ../x.py && \
python3 ../x.py check compiletest --set build.compiletest-use-stage0-libtest=true && \
python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--jobs 1'"
+2 -1
View File
@@ -12,15 +12,16 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind};
use rustc_span::BytePos;
use rustc_span::edition::Edition;
use rustc_span::symbol::Symbol;
use rustc_span::{BytePos, DUMMY_SP, Span};
use super::format;
use crate::clean::PrimitiveType;
use crate::display::Joined as _;
use crate::html::escape::EscapeBodyText;
use crate::html::macro_expansion::ExpandedCode;
use crate::html::render::span_map::{DUMMY_SP, Span};
use crate::html::render::{Context, LinkFromSrc};
/// This type is needed in case we want to render links on items to allow to go to their definition.
+14
View File
@@ -1,6 +1,7 @@
use expect_test::expect_file;
use rustc_data_structures::fx::FxIndexMap;
use rustc_span::create_default_session_globals_then;
use test::Bencher;
use super::{DecorationInfo, write_code};
@@ -81,3 +82,16 @@ fn test_decorations() {
expect_file!["fixtures/decorations.html"].assert_eq(&html);
});
}
#[bench]
fn bench_html_highlighting(b: &mut Bencher) {
let src = include_str!("../../../../compiler/rustc_ast/src/visit.rs");
create_default_session_globals_then(|| {
b.iter(|| {
let mut out = String::new();
write_code(&mut out, src, None, None, None);
out
});
});
}
+2 -1
View File
@@ -30,6 +30,7 @@
use crate::html::escape::Escape;
use crate::html::macro_expansion::ExpandedCode;
use crate::html::markdown::{self, ErrorCodes, IdMap, plain_text_summary};
use crate::html::render::span_map::Span;
use crate::html::render::write_shared::write_shared;
use crate::html::url_parts_builder::UrlPartsBuilder;
use crate::html::{layout, sources, static_files};
@@ -139,7 +140,7 @@ pub(crate) struct SharedContext<'tcx> {
/// Correspondence map used to link types used in the source code pages to allow to click on
/// links to jump to the type's definition.
pub(crate) span_correspondence_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
pub(crate) span_correspondence_map: FxHashMap<Span, LinkFromSrc>,
pub(crate) expanded_codes: FxHashMap<BytePos, Vec<ExpandedCode>>,
/// The [`Cache`] used during rendering.
pub(crate) cache: Cache,
+1 -1
View File
@@ -36,7 +36,7 @@
mod print_item;
pub(crate) mod sidebar;
mod sorted_template;
mod span_map;
pub(crate) mod span_map;
mod type_layout;
mod write_shared;
+54 -14
View File
@@ -8,11 +8,48 @@
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::TyCtxt;
use rustc_span::hygiene::MacroKind;
use rustc_span::{BytePos, ExpnKind, Span};
use rustc_span::{BytePos, ExpnKind};
use crate::clean::{self, PrimitiveType, rustc_span};
use crate::html::sources;
/// This is a stripped down version of [`rustc_span::Span`] that only contains the start and end byte positions of the span.
///
/// Profiling showed that the `Span` interner was taking up a lot of the run-time when highlighting, and since we
/// never actually use the context and parent that are stored in a normal `Span`, we can replace its usages with this
/// one, which is much cheaper to construct.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct Span {
lo: BytePos,
hi: BytePos,
}
impl From<rustc_span::Span> for Span {
fn from(value: rustc_span::Span) -> Self {
Self { lo: value.lo(), hi: value.hi() }
}
}
impl Span {
pub(crate) fn lo(self) -> BytePos {
self.lo
}
pub(crate) fn hi(self) -> BytePos {
self.hi
}
pub(crate) fn with_lo(self, lo: BytePos) -> Self {
Self { lo, hi: self.hi() }
}
pub(crate) fn with_hi(self, hi: BytePos) -> Self {
Self { lo: self.lo(), hi }
}
}
pub(crate) const DUMMY_SP: Span = Span { lo: BytePos(0), hi: BytePos(0) };
/// This enum allows us to store two different kinds of information:
///
/// In case the `span` definition comes from the same crate, we can simply get the `span` and use
@@ -96,7 +133,7 @@ fn handle_path(&mut self, path: &rustc_hir::Path<'_>, only_use_last_segment: boo
})
.unwrap_or(path.span)
};
self.matches.insert(span, link);
self.matches.insert(span.into(), link);
}
Res::Local(_) if let Some(span) = self.tcx.hir_res_span(path.res) => {
let path_span = if only_use_last_segment
@@ -106,11 +143,12 @@ fn handle_path(&mut self, path: &rustc_hir::Path<'_>, only_use_last_segment: boo
} else {
path.span
};
self.matches.insert(path_span, LinkFromSrc::Local(clean::Span::new(span)));
self.matches.insert(path_span.into(), LinkFromSrc::Local(clean::Span::new(span)));
}
Res::PrimTy(p) => {
// FIXME: Doesn't handle "path-like" primitives like arrays or tuples.
self.matches.insert(path.span, LinkFromSrc::Primitive(PrimitiveType::from(p)));
self.matches
.insert(path.span.into(), LinkFromSrc::Primitive(PrimitiveType::from(p)));
}
Res::Err => {}
_ => {}
@@ -127,7 +165,7 @@ pub(crate) fn extract_info_from_hir_id(&mut self, hir_id: HirId) {
if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE {
return;
}
self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id()));
self.matches.insert(span.into(), LinkFromSrc::Doc(item.owner_id.to_def_id()));
}
}
@@ -138,7 +176,7 @@ pub(crate) fn extract_info_from_hir_id(&mut self, hir_id: HirId) {
/// so, we loop until we find the macro definition by using `outer_expn_data` in a loop.
/// Finally, we get the information about the macro itself (`span` if "local", `DefId`
/// otherwise) and store it inside the span map.
fn handle_macro(&mut self, span: Span) -> bool {
fn handle_macro(&mut self, span: rustc_span::Span) -> bool {
if !span.from_expansion() {
return false;
}
@@ -176,7 +214,7 @@ fn handle_macro(&mut self, span: Span) -> bool {
// The "call_site" includes the whole macro with its "arguments". We only want
// the macro name.
let new_span = new_span.with_hi(new_span.lo() + BytePos(macro_name.len() as u32));
self.matches.insert(new_span, link_from_src);
self.matches.insert(new_span.into(), link_from_src);
true
}
@@ -233,7 +271,7 @@ fn visit_path(&mut self, path: &rustc_hir::Path<'tcx>, _id: HirId) {
intravisit::walk_path(self, path);
}
fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: Span) {
fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: rustc_span::Span) {
match *qpath {
QPath::TypeRelative(qself, path) => {
if matches!(path.res, Res::Err) {
@@ -249,7 +287,7 @@ fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: Span) {
self.handle_path(&path, false);
}
} else {
self.infer_id(path.hir_id, Some(id), path.ident.span);
self.infer_id(path.hir_id, Some(id), path.ident.span.into());
}
rustc_ast::visit::try_visit!(self.visit_ty_unambig(qself));
@@ -267,7 +305,7 @@ fn visit_qpath(&mut self, qpath: &QPath<'tcx>, id: HirId, _span: Span) {
}
}
fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) {
fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: rustc_span::Span, id: HirId) {
// To make the difference between "mod foo {}" and "mod foo;". In case we "import" another
// file, we want to link to it. Otherwise no need to create a link.
if !span.overlaps(m.spans.inner_span) {
@@ -275,8 +313,10 @@ fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) {
// name only and not all the "mod foo;".
if let Node::Item(item) = self.tcx.hir_node(id) {
let (ident, _) = item.expect_mod();
self.matches
.insert(ident.span, LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)));
self.matches.insert(
ident.span.into(),
LinkFromSrc::Local(clean::Span::new(m.spans.inner_span)),
);
}
} else {
// If it's a "mod foo {}", we want to look to its documentation page.
@@ -288,9 +328,9 @@ fn visit_mod(&mut self, m: &'tcx Mod<'tcx>, span: Span, id: HirId) {
fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
match expr.kind {
ExprKind::MethodCall(segment, ..) => {
self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span)
self.infer_id(segment.hir_id, Some(expr.hir_id), segment.ident.span.into())
}
ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span),
ExprKind::Call(call, ..) => self.infer_id(call.hir_id, None, call.span.into()),
_ => {
if self.handle_macro(expr.span) {
// We don't want to go deeper into the macro.
+6 -1
View File
@@ -348,7 +348,12 @@ pub(crate) fn print_src(
highlight::write_code(
fmt,
s,
Some(highlight::HrefContext { context, file_span, root_path, current_href }),
Some(highlight::HrefContext {
context,
file_span: file_span.into(),
root_path,
current_href,
}),
Some(decoration_info),
Some(line_info),
);
+84 -133
View File
@@ -63,9 +63,10 @@ pub fn from_reader<R: Read>(config: &Config, testfile: &Utf8Path, rdr: R) -> Sel
&mut poisoned,
testfile,
rdr,
&mut |DirectiveLine { line_number, raw_directive: ln, .. }| {
parse_and_update_aux(config, ln, testfile, line_number, &mut props.aux);
config.parse_and_update_revisions(testfile, line_number, ln, &mut props.revisions);
// (dummy comment to force args into vertical layout)
&mut |ref ln: DirectiveLine<'_>| {
parse_and_update_aux(config, ln, testfile, &mut props.aux);
config.parse_and_update_revisions(testfile, ln, &mut props.revisions);
},
);
@@ -367,8 +368,8 @@ fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config
&mut poisoned,
testfile,
file,
&mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
if !directive.applies_to_test_revision(test_revision) {
&mut |ref ln: DirectiveLine<'_>| {
if !ln.applies_to_test_revision(test_revision) {
return;
}
@@ -378,7 +379,6 @@ fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config
ln,
ERROR_PATTERN,
testfile,
line_number,
&mut self.error_patterns,
|r| r,
);
@@ -386,7 +386,6 @@ fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config
ln,
REGEX_ERROR_PATTERN,
testfile,
line_number,
&mut self.regex_error_patterns,
|r| r,
);
@@ -395,7 +394,6 @@ fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config
ln,
DOC_FLAGS,
testfile,
line_number,
&mut self.doc_flags,
|r| r,
);
@@ -414,7 +412,7 @@ fn split_flags(flags: &str) -> Vec<String> {
}
if let Some(flags) =
config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile, line_number)
config.parse_name_value_directive(ln, COMPILE_FLAGS, testfile)
{
let flags = split_flags(&flags);
for flag in &flags {
@@ -425,39 +423,28 @@ fn split_flags(flags: &str) -> Vec<String> {
self.compile_flags.extend(flags);
}
if config
.parse_name_value_directive(
ln,
INCORRECT_COMPILER_FLAGS,
testfile,
line_number,
)
.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS, testfile)
.is_some()
{
panic!("`compiler-flags` directive should be spelled `compile-flags`");
}
if let Some(edition) = config.parse_edition(ln, testfile, line_number) {
if let Some(edition) = config.parse_edition(ln, testfile) {
// The edition is added at the start, since flags from //@compile-flags must
// be passed to rustc last.
self.compile_flags.insert(0, format!("--edition={}", edition.trim()));
has_edition = true;
}
config.parse_and_update_revisions(
testfile,
line_number,
ln,
&mut self.revisions,
);
config.parse_and_update_revisions(testfile, ln, &mut self.revisions);
if let Some(flags) =
config.parse_name_value_directive(ln, RUN_FLAGS, testfile, line_number)
if let Some(flags) = config.parse_name_value_directive(ln, RUN_FLAGS, testfile)
{
self.run_flags.extend(split_flags(&flags));
}
if self.pp_exact.is_none() {
self.pp_exact = config.parse_pp_exact(ln, testfile, line_number);
self.pp_exact = config.parse_pp_exact(ln, testfile);
}
config.set_name_directive(ln, SHOULD_ICE, &mut self.should_ice);
@@ -479,9 +466,7 @@ fn split_flags(flags: &str) -> Vec<String> {
);
config.set_name_directive(ln, NO_PREFER_DYNAMIC, &mut self.no_prefer_dynamic);
if let Some(m) =
config.parse_name_value_directive(ln, PRETTY_MODE, testfile, line_number)
{
if let Some(m) = config.parse_name_value_directive(ln, PRETTY_MODE, testfile) {
self.pretty_mode = m;
}
@@ -492,13 +477,12 @@ fn split_flags(flags: &str) -> Vec<String> {
);
// Call a helper method to deal with aux-related directives.
parse_and_update_aux(config, ln, testfile, line_number, &mut self.aux);
parse_and_update_aux(config, ln, testfile, &mut self.aux);
config.push_name_value_directive(
ln,
EXEC_ENV,
testfile,
line_number,
&mut self.exec_env,
Config::parse_env,
);
@@ -506,7 +490,6 @@ fn split_flags(flags: &str) -> Vec<String> {
ln,
UNSET_EXEC_ENV,
testfile,
line_number,
&mut self.unset_exec_env,
|r| r.trim().to_owned(),
);
@@ -514,7 +497,6 @@ fn split_flags(flags: &str) -> Vec<String> {
ln,
RUSTC_ENV,
testfile,
line_number,
&mut self.rustc_env,
Config::parse_env,
);
@@ -522,7 +504,6 @@ fn split_flags(flags: &str) -> Vec<String> {
ln,
UNSET_RUSTC_ENV,
testfile,
line_number,
&mut self.unset_rustc_env,
|r| r.trim().to_owned(),
);
@@ -530,7 +511,6 @@ fn split_flags(flags: &str) -> Vec<String> {
ln,
FORBID_OUTPUT,
testfile,
line_number,
&mut self.forbid_output,
|r| r,
);
@@ -566,7 +546,7 @@ fn split_flags(flags: &str) -> Vec<String> {
}
if let Some(code) = config
.parse_name_value_directive(ln, FAILURE_STATUS, testfile, line_number)
.parse_name_value_directive(ln, FAILURE_STATUS, testfile)
.and_then(|code| code.trim().parse::<i32>().ok())
{
self.failure_status = Some(code);
@@ -588,7 +568,6 @@ fn split_flags(flags: &str) -> Vec<String> {
ln,
ASSEMBLY_OUTPUT,
testfile,
line_number,
&mut self.assembly_output,
|r| r.trim().to_string(),
);
@@ -602,7 +581,7 @@ fn split_flags(flags: &str) -> Vec<String> {
// Unlike the other `name_value_directive`s this needs to be handled manually,
// because it sets a `bool` flag.
if let Some(known_bug) =
config.parse_name_value_directive(ln, KNOWN_BUG, testfile, line_number)
config.parse_name_value_directive(ln, KNOWN_BUG, testfile)
{
let known_bug = known_bug.trim();
if known_bug == "unknown"
@@ -632,24 +611,20 @@ fn split_flags(flags: &str) -> Vec<String> {
ln,
TEST_MIR_PASS,
testfile,
line_number,
&mut self.mir_unit_test,
|s| s.trim().to_string(),
);
config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base);
if let Some(flags) =
config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile, line_number)
config.parse_name_value_directive(ln, LLVM_COV_FLAGS, testfile)
{
self.llvm_cov_flags.extend(split_flags(&flags));
}
if let Some(flags) = config.parse_name_value_directive(
ln,
FILECHECK_FLAGS,
testfile,
line_number,
) {
if let Some(flags) =
config.parse_name_value_directive(ln, FILECHECK_FLAGS, testfile)
{
self.filecheck_flags.extend(split_flags(&flags));
}
@@ -661,7 +636,6 @@ fn split_flags(flags: &str) -> Vec<String> {
ln,
directives::CORE_STUBS_COMPILE_FLAGS,
testfile,
line_number,
) {
let flags = split_flags(&flags);
for flag in &flags {
@@ -672,12 +646,9 @@ fn split_flags(flags: &str) -> Vec<String> {
self.core_stubs_compile_flags.extend(flags);
}
if let Some(err_kind) = config.parse_name_value_directive(
ln,
DONT_REQUIRE_ANNOTATIONS,
testfile,
line_number,
) {
if let Some(err_kind) =
config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS, testfile)
{
self.dont_require_annotations
.insert(ErrorKind::expect_from_user_str(err_kind.trim()));
}
@@ -734,7 +705,7 @@ fn split_flags(flags: &str) -> Vec<String> {
}
}
fn update_fail_mode(&mut self, ln: &str, config: &Config) {
fn update_fail_mode(&mut self, ln: &DirectiveLine<'_>, config: &Config) {
let check_ui = |mode: &str| {
// Mode::Crashes may need build-fail in order to trigger llvm errors or stack overflows
if config.mode != TestMode::Ui && config.mode != TestMode::Crashes {
@@ -769,7 +740,12 @@ fn update_fail_mode(&mut self, ln: &str, config: &Config) {
}
}
fn update_pass_mode(&mut self, ln: &str, revision: Option<&str>, config: &Config) {
fn update_pass_mode(
&mut self,
ln: &DirectiveLine<'_>,
revision: Option<&str>,
config: &Config,
) {
let check_no_run = |s| match (config.mode, s) {
(TestMode::Ui, _) => (),
(TestMode::Crashes, _) => (),
@@ -814,7 +790,7 @@ pub fn local_pass_mode(&self) -> Option<PassMode> {
self.pass_mode
}
pub fn update_add_core_stubs(&mut self, ln: &str, config: &Config) {
fn update_add_core_stubs(&mut self, ln: &DirectiveLine<'_>, config: &Config) {
let add_core_stubs = config.parse_name_directive(ln, directives::ADD_CORE_STUBS);
if add_core_stubs {
if !matches!(config.mode, TestMode::Ui | TestMode::Codegen | TestMode::Assembly) {
@@ -905,10 +881,12 @@ pub(crate) struct CheckDirectiveResult<'ln> {
trailing_directive: Option<&'ln str>,
}
pub(crate) fn check_directive<'a>(
directive_ln: &'a str,
fn check_directive<'a>(
directive_ln: &DirectiveLine<'a>,
mode: TestMode,
) -> CheckDirectiveResult<'a> {
let &DirectiveLine { raw_directive: directive_ln, .. } = directive_ln;
let (directive_name, post) = directive_ln.split_once([':', ' ']).unwrap_or((directive_ln, ""));
let is_known_directive = KNOWN_DIRECTIVE_NAMES.contains(&directive_name)
@@ -980,7 +958,7 @@ fn iter_directives(
// Perform unknown directive check on Rust files.
if testfile.extension() == Some("rs") {
let CheckDirectiveResult { is_known_directive, trailing_directive } =
check_directive(directive_line.raw_directive, mode);
check_directive(&directive_line, mode);
if !is_known_directive {
*poisoned = true;
@@ -1014,8 +992,7 @@ impl Config {
fn parse_and_update_revisions(
&self,
testfile: &Utf8Path,
line_number: usize,
line: &str,
line: &DirectiveLine<'_>,
existing: &mut Vec<String>,
) {
const FORBIDDEN_REVISION_NAMES: [&str; 2] = [
@@ -1028,8 +1005,7 @@ fn parse_and_update_revisions(
const FILECHECK_FORBIDDEN_REVISION_NAMES: [&str; 9] =
["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"];
if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile, line_number)
{
if let Some(raw) = self.parse_name_value_directive(line, "revisions", testfile) {
if self.mode == TestMode::RunMake {
panic!("`run-make` mode tests do not support revisions: {}", testfile);
}
@@ -1074,13 +1050,8 @@ fn parse_env(nv: String) -> (String, String) {
(name.to_owned(), value.to_owned())
}
fn parse_pp_exact(
&self,
line: &str,
testfile: &Utf8Path,
line_number: usize,
) -> Option<Utf8PathBuf> {
if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile, line_number) {
fn parse_pp_exact(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option<Utf8PathBuf> {
if let Some(s) = self.parse_name_value_directive(line, "pp-exact", testfile) {
Some(Utf8PathBuf::from(&s))
} else if self.parse_name_directive(line, "pp-exact") {
testfile.file_name().map(Utf8PathBuf::from)
@@ -1089,7 +1060,9 @@ fn parse_pp_exact(
}
}
fn parse_custom_normalization(&self, raw_directive: &str) -> Option<NormalizeRule> {
fn parse_custom_normalization(&self, line: &DirectiveLine<'_>) -> Option<NormalizeRule> {
let &DirectiveLine { raw_directive, .. } = line;
// FIXME(Zalathar): Integrate name/value splitting into `DirectiveLine`
// instead of doing it here.
let (directive_name, raw_value) = raw_directive.split_once(':')?;
@@ -1110,24 +1083,23 @@ fn parse_custom_normalization(&self, raw_directive: &str) -> Option<NormalizeRul
Some(NormalizeRule { kind, regex, replacement })
}
fn parse_name_directive(&self, line: &str, directive: &str) -> bool {
fn parse_name_directive(&self, line: &DirectiveLine<'_>, directive: &str) -> bool {
let &DirectiveLine { raw_directive: line, .. } = line;
// Ensure the directive is a whole word. Do not match "ignore-x86" when
// the line says "ignore-x86_64".
line.starts_with(directive)
&& matches!(line.as_bytes().get(directive.len()), None | Some(&b' ') | Some(&b':'))
}
fn parse_negative_name_directive(&self, line: &str, directive: &str) -> bool {
line.starts_with("no-") && self.parse_name_directive(&line[3..], directive)
}
pub fn parse_name_value_directive(
fn parse_name_value_directive(
&self,
line: &str,
line: &DirectiveLine<'_>,
directive: &str,
testfile: &Utf8Path,
line_number: usize,
) -> Option<String> {
let &DirectiveLine { line_number, raw_directive: line, .. } = line;
let colon = directive.len();
if line.starts_with(directive) && line.as_bytes().get(colon) == Some(&b':') {
let value = line[(colon + 1)..].to_owned();
@@ -1144,52 +1116,37 @@ pub fn parse_name_value_directive(
}
}
fn parse_edition(&self, line: &str, testfile: &Utf8Path, line_number: usize) -> Option<String> {
self.parse_name_value_directive(line, "edition", testfile, line_number)
fn parse_edition(&self, line: &DirectiveLine<'_>, testfile: &Utf8Path) -> Option<String> {
self.parse_name_value_directive(line, "edition", testfile)
}
fn set_name_directive(&self, line: &str, directive: &str, value: &mut bool) {
match value {
true => {
if self.parse_negative_name_directive(line, directive) {
*value = false;
}
}
false => {
if self.parse_name_directive(line, directive) {
*value = true;
}
}
}
fn set_name_directive(&self, line: &DirectiveLine<'_>, directive: &str, value: &mut bool) {
// If the flag is already true, don't bother looking at the directive.
*value = *value || self.parse_name_directive(line, directive);
}
fn set_name_value_directive<T>(
&self,
line: &str,
line: &DirectiveLine<'_>,
directive: &str,
testfile: &Utf8Path,
line_number: usize,
value: &mut Option<T>,
parse: impl FnOnce(String) -> T,
) {
if value.is_none() {
*value =
self.parse_name_value_directive(line, directive, testfile, line_number).map(parse);
*value = self.parse_name_value_directive(line, directive, testfile).map(parse);
}
}
fn push_name_value_directive<T>(
&self,
line: &str,
line: &DirectiveLine<'_>,
directive: &str,
testfile: &Utf8Path,
line_number: usize,
values: &mut Vec<T>,
parse: impl FnOnce(String) -> T,
) {
if let Some(value) =
self.parse_name_value_directive(line, directive, testfile, line_number).map(parse)
{
if let Some(value) = self.parse_name_value_directive(line, directive, testfile).map(parse) {
values.push(value);
}
}
@@ -1482,8 +1439,8 @@ pub(crate) fn make_test_description<R: Read>(
&mut local_poisoned,
path,
src,
&mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
if !directive.applies_to_test_revision(test_revision) {
&mut |ref ln @ DirectiveLine { line_number, .. }| {
if !ln.applies_to_test_revision(test_revision) {
return;
}
@@ -1507,9 +1464,9 @@ macro_rules! decision {
decision!(cfg::handle_ignore(config, ln));
decision!(cfg::handle_only(config, ln));
decision!(needs::handle_needs(&cache.needs, config, ln));
decision!(ignore_llvm(config, path, ln, line_number));
decision!(ignore_backends(config, path, ln, line_number));
decision!(needs_backends(config, path, ln, line_number));
decision!(ignore_llvm(config, path, ln));
decision!(ignore_backends(config, path, ln));
decision!(needs_backends(config, path, ln));
decision!(ignore_cdb(config, ln));
decision!(ignore_gdb(config, ln));
decision!(ignore_lldb(config, ln));
@@ -1549,7 +1506,9 @@ macro_rules! decision {
}
}
fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision {
fn ignore_cdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
let &DirectiveLine { raw_directive: line, .. } = line;
if config.debugger != Some(Debugger::Cdb) {
return IgnoreDecision::Continue;
}
@@ -1572,7 +1531,9 @@ fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision {
IgnoreDecision::Continue
}
fn ignore_gdb(config: &Config, line: &str) -> IgnoreDecision {
fn ignore_gdb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
let &DirectiveLine { raw_directive: line, .. } = line;
if config.debugger != Some(Debugger::Gdb) {
return IgnoreDecision::Continue;
}
@@ -1620,7 +1581,9 @@ fn ignore_gdb(config: &Config, line: &str) -> IgnoreDecision {
IgnoreDecision::Continue
}
fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
fn ignore_lldb(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
let &DirectiveLine { raw_directive: line, .. } = line;
if config.debugger != Some(Debugger::Lldb) {
return IgnoreDecision::Continue;
}
@@ -1642,14 +1605,9 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
IgnoreDecision::Continue
}
fn ignore_backends(
config: &Config,
path: &Utf8Path,
line: &str,
line_number: usize,
) -> IgnoreDecision {
fn ignore_backends(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision {
if let Some(backends_to_ignore) =
config.parse_name_value_directive(line, "ignore-backends", path, line_number)
config.parse_name_value_directive(line, "ignore-backends", path)
{
for backend in backends_to_ignore.split_whitespace().map(|backend| {
match CodegenBackend::try_from(backend) {
@@ -1669,15 +1627,8 @@ fn ignore_backends(
IgnoreDecision::Continue
}
fn needs_backends(
config: &Config,
path: &Utf8Path,
line: &str,
line_number: usize,
) -> IgnoreDecision {
if let Some(needed_backends) =
config.parse_name_value_directive(line, "needs-backends", path, line_number)
{
fn needs_backends(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision {
if let Some(needed_backends) = config.parse_name_value_directive(line, "needs-backends", path) {
if !needed_backends
.split_whitespace()
.map(|backend| match CodegenBackend::try_from(backend) {
@@ -1699,9 +1650,9 @@ fn needs_backends(
IgnoreDecision::Continue
}
fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize) -> IgnoreDecision {
fn ignore_llvm(config: &Config, path: &Utf8Path, line: &DirectiveLine<'_>) -> IgnoreDecision {
if let Some(needed_components) =
config.parse_name_value_directive(line, "needs-llvm-components", path, line_number)
config.parse_name_value_directive(line, "needs-llvm-components", path)
{
let components: HashSet<_> = config.llvm_components.split_whitespace().collect();
if let Some(missing_component) = needed_components
@@ -1723,7 +1674,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
// Note that these `min` versions will check for not just major versions.
if let Some(version_string) =
config.parse_name_value_directive(line, "min-llvm-version", path, line_number)
config.parse_name_value_directive(line, "min-llvm-version", path)
{
let min_version = extract_llvm_version(&version_string);
// Ignore if actual version is smaller than the minimum required version.
@@ -1735,7 +1686,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
};
}
} else if let Some(version_string) =
config.parse_name_value_directive(line, "max-llvm-major-version", path, line_number)
config.parse_name_value_directive(line, "max-llvm-major-version", path)
{
let max_version = extract_llvm_version(&version_string);
// Ignore if actual major version is larger than the maximum required major version.
@@ -1749,7 +1700,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
};
}
} else if let Some(version_string) =
config.parse_name_value_directive(line, "min-system-llvm-version", path, line_number)
config.parse_name_value_directive(line, "min-system-llvm-version", path)
{
let min_version = extract_llvm_version(&version_string);
// Ignore if using system LLVM and actual version
@@ -1762,7 +1713,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
};
}
} else if let Some(version_range) =
config.parse_name_value_directive(line, "ignore-llvm-version", path, line_number)
config.parse_name_value_directive(line, "ignore-llvm-version", path)
{
// Syntax is: "ignore-llvm-version: <version1> [- <version2>]"
let (v_min, v_max) =
@@ -1788,7 +1739,7 @@ fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str, line_number: usize)
}
}
} else if let Some(version_string) =
config.parse_name_value_directive(line, "exact-llvm-major-version", path, line_number)
config.parse_name_value_directive(line, "exact-llvm-major-version", path)
{
// Syntax is "exact-llvm-major-version: <version>"
let version = extract_llvm_version(&version_string);
@@ -7,6 +7,7 @@
use super::directives::{AUX_BIN, AUX_BUILD, AUX_CODEGEN_BACKEND, AUX_CRATE, PROC_MACRO};
use crate::common::Config;
use crate::directives::DirectiveLine;
/// Properties parsed from `aux-*` test directives.
#[derive(Clone, Debug, Default)]
@@ -45,40 +46,28 @@ pub(crate) fn all_aux_path_strings(&self) -> impl Iterator<Item = &str> {
/// and update [`AuxProps`] accordingly.
pub(super) fn parse_and_update_aux(
config: &Config,
ln: &str,
directive_line: &DirectiveLine<'_>,
testfile: &Utf8Path,
line_number: usize,
aux: &mut AuxProps,
) {
let &DirectiveLine { raw_directive: ln, .. } = directive_line;
if !(ln.starts_with("aux-") || ln.starts_with("proc-macro")) {
return;
}
config.push_name_value_directive(ln, AUX_BUILD, testfile, line_number, &mut aux.builds, |r| {
let ln = directive_line;
config.push_name_value_directive(ln, AUX_BUILD, testfile, &mut aux.builds, |r| {
r.trim().to_string()
});
config.push_name_value_directive(ln, AUX_BIN, testfile, line_number, &mut aux.bins, |r| {
config
.push_name_value_directive(ln, AUX_BIN, testfile, &mut aux.bins, |r| r.trim().to_string());
config.push_name_value_directive(ln, AUX_CRATE, testfile, &mut aux.crates, parse_aux_crate);
config.push_name_value_directive(ln, PROC_MACRO, testfile, &mut aux.proc_macros, |r| {
r.trim().to_string()
});
config.push_name_value_directive(
ln,
AUX_CRATE,
testfile,
line_number,
&mut aux.crates,
parse_aux_crate,
);
config.push_name_value_directive(
ln,
PROC_MACRO,
testfile,
line_number,
&mut aux.proc_macros,
|r| r.trim().to_string(),
);
if let Some(r) =
config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile, line_number)
{
if let Some(r) = config.parse_name_value_directive(ln, AUX_CODEGEN_BACKEND, testfile) {
aux.codegen_backend = Some(r.trim().to_owned());
}
}
+10 -4
View File
@@ -1,12 +1,14 @@
use std::collections::HashSet;
use crate::common::{CompareMode, Config, Debugger};
use crate::directives::IgnoreDecision;
use crate::directives::{DirectiveLine, IgnoreDecision};
const EXTRA_ARCHS: &[&str] = &["spirv"];
pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision {
pub(super) fn handle_ignore(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
let parsed = parse_cfg_name_directive(config, line, "ignore");
let &DirectiveLine { raw_directive: line, .. } = line;
match parsed.outcome {
MatchOutcome::NoMatch => IgnoreDecision::Continue,
MatchOutcome::Match => IgnoreDecision::Ignore {
@@ -21,8 +23,10 @@ pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision {
}
}
pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision {
pub(super) fn handle_only(config: &Config, line: &DirectiveLine<'_>) -> IgnoreDecision {
let parsed = parse_cfg_name_directive(config, line, "only");
let &DirectiveLine { raw_directive: line, .. } = line;
match parsed.outcome {
MatchOutcome::Match => IgnoreDecision::Continue,
MatchOutcome::NoMatch => IgnoreDecision::Ignore {
@@ -43,9 +47,11 @@ pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision {
/// or `only-windows`.
fn parse_cfg_name_directive<'a>(
config: &Config,
line: &'a str,
line: &'a DirectiveLine<'a>,
prefix: &str,
) -> ParsedNameDirective<'a> {
let &DirectiveLine { raw_directive: line, .. } = line;
if !line.as_bytes().starts_with(prefix.as_bytes()) {
return ParsedNameDirective::not_a_directive();
}
@@ -1,10 +1,10 @@
use crate::common::{Config, KNOWN_CRATE_TYPES, KNOWN_TARGET_HAS_ATOMIC_WIDTHS, Sanitizer};
use crate::directives::{IgnoreDecision, llvm_has_libzstd};
use crate::directives::{DirectiveLine, IgnoreDecision, llvm_has_libzstd};
pub(super) fn handle_needs(
cache: &CachedNeedsConditions,
config: &Config,
ln: &str,
ln: &DirectiveLine<'_>,
) -> IgnoreDecision {
// Note that we intentionally still put the needs- prefix here to make the file show up when
// grepping for a directive name, even though we could technically strip that.
@@ -181,6 +181,8 @@ pub(super) fn handle_needs(
},
];
let &DirectiveLine { raw_directive: ln, .. } = ln;
let (name, rest) = match ln.split_once([':', ' ']) {
Some((name, rest)) => (name, Some(rest)),
None => (ln, None),
+15 -12
View File
@@ -4,7 +4,6 @@
use camino::{Utf8Path, Utf8PathBuf};
use crate::common::Config;
use crate::runtest::ProcRes;
/// Representation of information to invoke a debugger and check its output
@@ -20,11 +19,7 @@ pub(super) struct DebuggerCommands {
}
impl DebuggerCommands {
pub fn parse_from(
file: &Utf8Path,
config: &Config,
debugger_prefix: &str,
) -> Result<Self, String> {
pub fn parse_from(file: &Utf8Path, debugger_prefix: &str) -> Result<Self, String> {
let command_directive = format!("{debugger_prefix}-command");
let check_directive = format!("{debugger_prefix}-check");
@@ -47,14 +42,10 @@ pub fn parse_from(
continue;
};
if let Some(command) =
config.parse_name_value_directive(&line, &command_directive, file, line_no)
{
if let Some(command) = parse_name_value(&line, &command_directive) {
commands.push(command);
}
if let Some(pattern) =
config.parse_name_value_directive(&line, &check_directive, file, line_no)
{
if let Some(pattern) = parse_name_value(&line, &check_directive) {
check_lines.push((line_no, pattern));
}
}
@@ -114,6 +105,18 @@ pub fn check_output(&self, debugger_run_result: &ProcRes) -> Result<(), String>
}
}
/// Split off from the main `parse_name_value_directive`, so that improvements
/// to directive handling aren't held back by debuginfo test commands.
fn parse_name_value(line: &str, name: &str) -> Option<String> {
if let Some(after_name) = line.strip_prefix(name)
&& let Some(value) = after_name.strip_prefix(':')
{
Some(value.to_owned())
} else {
None
}
}
/// Check that the pattern in `check_line` applies to `line`. Returns `true` if they do match.
fn check_single_line(line: &str, check_line: &str) -> bool {
// Allow check lines to leave parts unspecified (e.g., uninitialized
@@ -59,7 +59,7 @@ fn run_debuginfo_cdb_test_no_opt(&self) {
}
// Parse debugger commands etc from test files
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "cdb")
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "cdb")
.unwrap_or_else(|e| self.fatal(&e));
// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
@@ -130,7 +130,7 @@ fn run_debuginfo_gdb_test(&self) {
}
fn run_debuginfo_gdb_test_no_opt(&self) {
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "gdb")
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "gdb")
.unwrap_or_else(|e| self.fatal(&e));
let mut cmds = dbg_cmds.commands.join("\n");
@@ -397,7 +397,7 @@ fn run_debuginfo_lldb_test_no_opt(&self) {
}
// Parse debugger commands etc from test files
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, "lldb")
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, "lldb")
.unwrap_or_else(|e| self.fatal(&e));
// Write debugger script:
+2 -2
View File
@@ -1,7 +1,7 @@
//@ revisions: debug release
//@[debug] compile-flags: -Zautodiff=Enable -C opt-level=0 -Clto=fat
//@[release] compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat
//@[debug] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=0 -Clto=fat
//@[release] compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat
//@ no-prefer-dynamic
//@ needs-enzyme
+1 -1
View File
@@ -1,4 +1,4 @@
//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat
//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat
//@ no-prefer-dynamic
//@ needs-enzyme
//
+1 -1
View File
@@ -1,4 +1,4 @@
//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat
//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat
//@ no-prefer-dynamic
//@ needs-enzyme
#![feature(autodiff)]
+1 -1
View File
@@ -1,4 +1,4 @@
//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat
//@ compile-flags: -Zautodiff=Enable,NoTT -C opt-level=3 -Clto=fat
//@ no-prefer-dynamic
//@ needs-enzyme
+41
View File
@@ -0,0 +1,41 @@
//@ compile-flags: -Zautodiff=Enable,NoTT,NoPostopt -C no-prepopulate-passes -C opt-level=3 -Clto=fat
//@ no-prefer-dynamic
//@ needs-enzyme
#![feature(autodiff)]
use std::autodiff::*;
// Usually we would store the return value of the differentiated function.
// However, if the return type is void or an empty struct,
// we don't need to store anything. Verify this, since it caused a bug.
// CHECK:; void_ret::main
// CHECK-NEXT: ; Function Attrs:
// CHECK-NEXT: define internal
// CHECK-NOT: store {} undef, ptr undef
// CHECK: ret void
#[autodiff_reverse(bar, Duplicated, Duplicated)]
pub fn foo(r: &[f64; 10], res: &mut f64) {
let mut output = [0.0; 10];
output[0] = r[0];
output[1] = r[1] * r[2];
output[2] = r[4] * r[5];
output[3] = r[2] * r[6];
output[4] = r[1] * r[7];
output[5] = r[2] * r[8];
output[6] = r[1] * r[9];
output[7] = r[5] * r[6];
output[8] = r[5] * r[7];
output[9] = r[4] * r[8];
*res = output.iter().sum();
}
fn main() {
let inputs = Box::new([3.1; 10]);
let mut d_inputs = Box::new([0.0; 10]);
let mut res = Box::new(0.0);
let mut d_res = Box::new(1.0);
bar(&inputs, &mut d_inputs, &mut res, &mut d_res);
dbg!(&d_inputs);
}
@@ -2,7 +2,6 @@
// Testing that a librustc_ast can parse modules with canonicalized base path
//@ ignore-cross-compile
//@ ignore-remote
// no-remap-src-base: Reading `file!()` (expectedly) fails when enabled.
#![feature(rustc_private)]
@@ -1,5 +1,6 @@
//@ add-core-stubs
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib -Cincremental=true
//@ compile-flags: --target thumbv8m.main-none-eabi --crate-type lib
//@ incremental (required to trigger the bug)
//@ needs-llvm-components: arm
#![feature(abi_cmse_nonsecure_call, no_core)]
#![no_core]
@@ -8,7 +9,7 @@
use minicore::*;
// A regression test for https://github.com/rust-lang/rust/issues/131639.
// NOTE: -Cincremental=true was required for triggering the bug.
// NOTE: `-Cincremental` was required for triggering the bug.
fn foo() {
id::<extern "cmse-nonsecure-call" fn(&'a ())>(PhantomData);
@@ -1,5 +1,5 @@
error[E0261]: use of undeclared lifetime name `'a`
--> $DIR/undeclared-lifetime.rs:14:43
--> $DIR/undeclared-lifetime.rs:15:43
|
LL | id::<extern "cmse-nonsecure-call" fn(&'a ())>(PhantomData);
| ^^ undeclared lifetime
+1 -1
View File
@@ -1,4 +1,4 @@
//@ compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux
// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file.
// Manually remap, so the remapped path remains in .stderr file.
pub struct SomeStruct {} // This line should be show as part of the error.
@@ -1,5 +1,5 @@
error[E0423]: expected value, found struct `remapped_dep::SomeStruct`
--> $DIR/remap-path-prefix-reverse.rs:16:13
--> $DIR/remap-path-prefix-reverse.rs:15:13
|
LL | let _ = remapped_dep::SomeStruct;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}`
@@ -1,5 +1,5 @@
error[E0423]: expected value, found struct `remapped_dep::SomeStruct`
--> $DIR/remap-path-prefix-reverse.rs:16:13
--> $DIR/remap-path-prefix-reverse.rs:15:13
|
LL | let _ = remapped_dep::SomeStruct;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `remapped_dep::SomeStruct {}`
@@ -2,7 +2,6 @@
//@ compile-flags: --remap-path-prefix={{src-base}}/errors/auxiliary=remapped-aux
//@ revisions: local-self remapped-self
// [local-self] no-remap-src-base: The hack should work regardless of remapping.
//@ [remapped-self] remap-src-base
// Verify that the expected source code is shown.
+1 -1
View File
@@ -2,7 +2,7 @@
//@ compile-flags: --remap-path-prefix={{src-base}}=remapped
//@ [with-diagnostic-scope]compile-flags: -Zremap-path-scope=diagnostics
//@ [without-diagnostic-scope]compile-flags: -Zremap-path-scope=object
// no-remap-src-base: Manually remap, so the remapped path remains in .stderr file.
// Manually remap, so the remapped path remains in .stderr file.
// The remapped paths are not normalized by compiletest.
//@ normalize-stderr: "\\(errors)" -> "/$1"
@@ -0,0 +1,9 @@
// Regression test making sure that indexing fails with an ambiguity
// error if one of the deref-steps encounters an inference variable.
fn main() {
let x = &Default::default();
//~^ ERROR type annotations needed for `&_`
x[1];
let _: &Vec<()> = x;
}
@@ -0,0 +1,17 @@
error[E0282]: type annotations needed for `&_`
--> $DIR/ambiguity-after-deref-step.rs:5:9
|
LL | let x = &Default::default();
| ^
LL |
LL | x[1];
| - type must be known at this point
|
help: consider giving `x` an explicit type, where the placeholders `_` are specified
|
LL | let x: &_ = &Default::default();
| ++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0282`.
+30
View File
@@ -0,0 +1,30 @@
//@ check-pass
// Regression test for #128887.
#![allow(unconditional_recursion)]
trait Mappable<T> {
type Output;
}
trait Bound<T> {}
// Deleting this impl made it compile on beta
impl<T> Bound<T> for T {}
trait Generic<M> {}
// Deleting the `: Mappable<T>` already made it error on stable.
struct IndexWithIter<I, M: Mappable<T>, T>(I, M, T);
impl<I, M, T> IndexWithIter<I, M, T>
where
<M as Mappable<T>>::Output: Bound<T>,
// Flipping these where bounds causes this to succeed, even when removing
// the where-clause on the struct definition.
M: Mappable<T>,
I: Generic<M>,
{
fn new(x: I) {
IndexWithIter::<_, _, _>::new(x);
}
}
fn main() {}
+1 -1
View File
@@ -1,6 +1,6 @@
//@ proc-macro: expand-expr.rs
//@ ignore-backends: gcc
// no-remap-src-base: check_expand_expr_file!() fails when enabled.
// No `remap-src-base`, since `check_expand_expr_file!()` fails when enabled.
#![feature(concat_bytes)]
extern crate expand_expr;
@@ -1,7 +1,6 @@
//@ proc-macro: test-macros.rs
//@ compile-flags: -Z span-debug
//@ revisions: local remapped
// [local] no-remap-src-base: The hack should work regardless of remapping.
//@ [remapped] remap-src-base
#![no_std] // Don't load unnecessary hygiene information from std
@@ -0,0 +1,60 @@
//@ compile-flags: -Znext-solver
//@ check-pass
// Regression test for trait-system-refactor-initiative#105. We previously encountered
// an ICE in typenum as `forced_ambiguity` failed. While this test no longer causes
// `forced_ambiguity` to error, we still want to use it as a regression test.
pub struct UInt<U, B> {
_msb: U,
_lsb: B,
}
pub struct B1;
pub trait Sub<Rhs> {
type Output;
}
impl<U, B> Sub<B1> for UInt<UInt<U, B>, B1> {
type Output = ();
}
impl<U> Sub<B1> for UInt<U, ()>
where
U: Sub<B1>,
U::Output: Send,
{
type Output = ();
}
pub trait Op<N, R, I> {
fn op(&self) {
unimplemented!()
}
}
trait OpIf<N, R, I> {}
impl<N, Ur, Br, I> Op<N, UInt<Ur, Br>, I> for ()
where
N: Sub<I>,
(): OpIf<N, UInt<UInt<Ur, Br>, N::Output>, I>,
{
}
impl<N, R, Ui, Bi> OpIf<N, R, UInt<Ui, Bi>> for ()
where
UInt<Ui, Bi>: Sub<B1>,
(): Op<N, R, <UInt<Ui, Bi> as Sub<B1>>::Output>,
{
}
impl<N, R> OpIf<N, R, ()> for () where R: Sub<N> {}
pub trait Compute {
type Output;
}
pub fn repro<Ul, Bl>()
where
UInt<Ul, Bl>: Compute,
<UInt<Ul, Bl> as Compute>::Output: Sub<B1>,
(): Op<UInt<(), Bl>, (), ()>,
{
().op();
}
fn main() {}