mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
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:
@@ -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={:?} \
|
||||
|
||||
@@ -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,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]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'"
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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),
|
||||
);
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,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,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,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
|
||||
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
@@ -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`.
|
||||
@@ -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,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() {}
|
||||
Reference in New Issue
Block a user