mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-24 07:44:10 +00:00
Auto merge of #132035 - matthiaskrgr:rollup-ty1e4q0, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #125205 (Fixup Windows verbatim paths when used with the `include!` macro) - #131049 (Validate args are correct for `UnevaluatedConst`, `ExistentialTraitRef`/`ExistentialProjection`) - #131549 (Add a note for `?` on a `impl Future<Output = Result<..>>` in sync function) - #131731 (add `TestFloatParse` to `tools.rs` for bootstrap) - #131732 (Add doc(plugins), doc(passes), etc. to INVALID_DOC_ATTRIBUTES) - #132006 (don't stage-off to previous compiler when CI rustc is available) - #132022 (Move `cmp_in_dominator_order` out of graph dominator computation) - #132033 (compiletest: Make `line_directive` return a `DirectiveLine`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
86d69c705a
@ -9,8 +9,6 @@
|
||||
//! Thomas Lengauer and Robert Endre Tarjan.
|
||||
//! <https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf>
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||
|
||||
use super::ControlFlowGraph;
|
||||
@ -64,9 +62,6 @@ fn is_small_path_graph<G: ControlFlowGraph>(g: &G) -> bool {
|
||||
}
|
||||
|
||||
fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
|
||||
// compute the post order index (rank) for each node
|
||||
let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
|
||||
|
||||
// We allocate capacity for the full set of nodes, because most of the time
|
||||
// most of the nodes *are* reachable.
|
||||
let mut parent: IndexVec<PreorderIndex, PreorderIndex> =
|
||||
@ -83,12 +78,10 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
|
||||
pre_order_to_real.push(graph.start_node());
|
||||
parent.push(PreorderIndex::ZERO); // the parent of the root node is the root for now.
|
||||
real_to_pre_order[graph.start_node()] = Some(PreorderIndex::ZERO);
|
||||
let mut post_order_idx = 0;
|
||||
|
||||
// Traverse the graph, collecting a number of things:
|
||||
//
|
||||
// * Preorder mapping (to it, and back to the actual ordering)
|
||||
// * Postorder mapping (used exclusively for `cmp_in_dominator_order` on the final product)
|
||||
// * Parents for each vertex in the preorder tree
|
||||
//
|
||||
// These are all done here rather than through one of the 'standard'
|
||||
@ -104,8 +97,6 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
|
||||
continue 'recurse;
|
||||
}
|
||||
}
|
||||
post_order_rank[pre_order_to_real[frame.pre_order_idx]] = post_order_idx;
|
||||
post_order_idx += 1;
|
||||
|
||||
stack.pop();
|
||||
}
|
||||
@ -282,7 +273,7 @@ fn dominators_impl<G: ControlFlowGraph>(graph: &G) -> Inner<G::Node> {
|
||||
|
||||
let time = compute_access_time(start_node, &immediate_dominators);
|
||||
|
||||
Inner { post_order_rank, immediate_dominators, time }
|
||||
Inner { immediate_dominators, time }
|
||||
}
|
||||
|
||||
/// Evaluate the link-eval virtual forest, providing the currently minimum semi
|
||||
@ -348,7 +339,6 @@ fn compress(
|
||||
/// Tracks the list of dominators for each node.
|
||||
#[derive(Clone, Debug)]
|
||||
struct Inner<N: Idx> {
|
||||
post_order_rank: IndexVec<N, usize>,
|
||||
// Even though we track only the immediate dominator of each node, it's
|
||||
// possible to get its full list of dominators by looking up the dominator
|
||||
// of each dominator.
|
||||
@ -379,17 +369,6 @@ impl<Node: Idx> Dominators<Node> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
|
||||
/// relationship, the dominator will always precede the dominated. (The relative ordering
|
||||
/// of two unrelated nodes will also be consistent, but otherwise the order has no
|
||||
/// meaning.) This method cannot be used to determine if either Node dominates the other.
|
||||
pub fn cmp_in_dominator_order(&self, lhs: Node, rhs: Node) -> Ordering {
|
||||
match &self.kind {
|
||||
Kind::Path => lhs.index().cmp(&rhs.index()),
|
||||
Kind::General(g) => g.post_order_rank[rhs].cmp(&g.post_order_rank[lhs]),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if `a` dominates `b`.
|
||||
///
|
||||
/// # Panics
|
||||
|
@ -1,5 +1,6 @@
|
||||
use std::default::Default;
|
||||
use std::iter;
|
||||
use std::path::Component::Prefix;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -1293,7 +1294,12 @@ pub fn resolve_path(sess: &Session, path: impl Into<PathBuf>, span: Span) -> PRe
|
||||
base_path.push(path);
|
||||
Ok(base_path)
|
||||
} else {
|
||||
Ok(path)
|
||||
// This ensures that Windows verbatim paths are fixed if mixed path separators are used,
|
||||
// which can happen when `concat!` is used to join paths.
|
||||
match path.components().next() {
|
||||
Some(Prefix(prefix)) if prefix.kind().is_verbatim() => Ok(path.components().collect()),
|
||||
_ => Ok(path),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,7 +259,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
let args = tcx.mk_args(&args);
|
||||
|
||||
let span = i.bottom().1;
|
||||
let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
|
||||
@ -292,7 +291,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
||||
.emit();
|
||||
}
|
||||
|
||||
ty::ExistentialTraitRef { def_id: trait_ref.def_id, args }
|
||||
ty::ExistentialTraitRef::new(tcx, trait_ref.def_id, args)
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -10,7 +10,8 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{
|
||||
Applicability, Diag, ErrorGuaranteed, StashKey, Subdiagnostic, pluralize, struct_span_code_err,
|
||||
Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, pluralize,
|
||||
struct_span_code_err,
|
||||
};
|
||||
use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -2763,12 +2764,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
field_ident.span,
|
||||
"field not available in `impl Future`, but it is available in its `Output`",
|
||||
);
|
||||
err.span_suggestion_verbose(
|
||||
base.span.shrink_to_hi(),
|
||||
"consider `await`ing on the `Future` and access the field of its `Output`",
|
||||
".await",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
match self.tcx.coroutine_kind(self.body_id) {
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
|
||||
err.span_suggestion_verbose(
|
||||
base.span.shrink_to_hi(),
|
||||
"consider `await`ing on the `Future` to access the field",
|
||||
".await",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
let mut span: MultiSpan = base.span.into();
|
||||
span.push_span_label(self.tcx.def_span(self.body_id), "this is not `async`");
|
||||
err.span_note(
|
||||
span,
|
||||
"this implements `Future` and its output type has the field, \
|
||||
but the future cannot be awaited in a synchronous function",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ban_nonexisting_field(
|
||||
|
@ -109,6 +109,7 @@ impl<'tcx> Const<'tcx> {
|
||||
|
||||
#[inline]
|
||||
pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> {
|
||||
tcx.debug_assert_args_compatible(uv.def, uv.args);
|
||||
Const::new(tcx, ty::ConstKind::Unevaluated(uv))
|
||||
}
|
||||
|
||||
|
@ -279,6 +279,26 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
|
||||
self.debug_assert_args_compatible(def_id, args);
|
||||
}
|
||||
|
||||
/// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection`
|
||||
/// are compatible with the `DefId`. Since we're missing a `Self` type, stick on
|
||||
/// a dummy self type and forward to `debug_assert_args_compatible`.
|
||||
fn debug_assert_existential_args_compatible(
|
||||
self,
|
||||
def_id: Self::DefId,
|
||||
args: Self::GenericArgs,
|
||||
) {
|
||||
// FIXME: We could perhaps add a `skip: usize` to `debug_assert_args_compatible`
|
||||
// to avoid needing to reintern the set of args...
|
||||
if cfg!(debug_assertions) {
|
||||
self.debug_assert_args_compatible(
|
||||
def_id,
|
||||
self.mk_args_from_iter(
|
||||
[self.types.trait_object_dummy_self.into()].into_iter().chain(args.iter()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
|
@ -21,6 +21,10 @@ pub(crate) struct CoverageGraph {
|
||||
pub(crate) successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
|
||||
pub(crate) predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
|
||||
dominators: Option<Dominators<BasicCoverageBlock>>,
|
||||
/// Allows nodes to be compared in some total order such that _if_
|
||||
/// `a` dominates `b`, then `a < b`. If neither node dominates the other,
|
||||
/// their relative order is consistent but arbitrary.
|
||||
dominator_order_rank: IndexVec<BasicCoverageBlock, u32>,
|
||||
}
|
||||
|
||||
impl CoverageGraph {
|
||||
@ -54,10 +58,27 @@ impl CoverageGraph {
|
||||
}
|
||||
}
|
||||
|
||||
let mut this = Self { bcbs, bb_to_bcb, successors, predecessors, dominators: None };
|
||||
let num_nodes = bcbs.len();
|
||||
let mut this = Self {
|
||||
bcbs,
|
||||
bb_to_bcb,
|
||||
successors,
|
||||
predecessors,
|
||||
dominators: None,
|
||||
dominator_order_rank: IndexVec::from_elem_n(0, num_nodes),
|
||||
};
|
||||
assert_eq!(num_nodes, this.num_nodes());
|
||||
|
||||
this.dominators = Some(dominators::dominators(&this));
|
||||
|
||||
// The dominator rank of each node is just its index in a reverse-postorder traversal.
|
||||
let reverse_post_order = graph::iterate::reverse_post_order(&this, this.start_node());
|
||||
// The coverage graph is created by traversal, so all nodes are reachable.
|
||||
assert_eq!(reverse_post_order.len(), this.num_nodes());
|
||||
for (rank, bcb) in (0u32..).zip(reverse_post_order) {
|
||||
this.dominator_order_rank[bcb] = rank;
|
||||
}
|
||||
|
||||
// The coverage graph's entry-point node (bcb0) always starts with bb0,
|
||||
// which never has predecessors. Any other blocks merged into bcb0 can't
|
||||
// have multiple (coverage-relevant) predecessors, so bcb0 always has
|
||||
@ -162,7 +183,7 @@ impl CoverageGraph {
|
||||
a: BasicCoverageBlock,
|
||||
b: BasicCoverageBlock,
|
||||
) -> Ordering {
|
||||
self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b)
|
||||
self.dominator_order_rank[a].cmp(&self.dominator_order_rank[b])
|
||||
}
|
||||
|
||||
/// Returns the source of this node's sole in-edge, if it has exactly one.
|
||||
|
@ -245,6 +245,19 @@ passes_doc_test_unknown_include =
|
||||
unknown `doc` attribute `{$path}`
|
||||
.suggestion = use `doc = include_str!` instead
|
||||
|
||||
passes_doc_test_unknown_passes =
|
||||
unknown `doc` attribute `{$path}`
|
||||
.note = `doc` attribute `{$path}` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136>
|
||||
.label = no longer functions
|
||||
.help = you may want to use `doc(document_private_items)`
|
||||
.no_op_note = `doc({$path})` is now a no-op
|
||||
|
||||
passes_doc_test_unknown_plugins =
|
||||
unknown `doc` attribute `{$path}`
|
||||
.note = `doc` attribute `{$path}` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136> and CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>
|
||||
.label = no longer functions
|
||||
.no_op_note = `doc({$path})` is now a no-op
|
||||
|
||||
passes_doc_test_unknown_spotlight =
|
||||
unknown `doc` attribute `{$path}`
|
||||
.note = `doc(spotlight)` was renamed to `doc(notable_trait)`
|
||||
|
@ -1183,15 +1183,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
|
||||
sym::masked => self.check_doc_masked(attr, meta, hir_id, target),
|
||||
|
||||
// no_default_passes: deprecated
|
||||
// passes: deprecated
|
||||
// plugins: removed, but rustdoc warns about it itself
|
||||
sym::cfg
|
||||
| sym::hidden
|
||||
| sym::no_default_passes
|
||||
| sym::notable_trait
|
||||
| sym::passes
|
||||
| sym::plugins => {}
|
||||
sym::cfg | sym::hidden | sym::notable_trait => {}
|
||||
|
||||
sym::rust_logo => {
|
||||
if self.check_attr_crate_level(attr, meta, hir_id)
|
||||
@ -1240,6 +1232,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
||||
sugg: (attr.meta().unwrap().span, applicability),
|
||||
},
|
||||
);
|
||||
} else if i_meta.has_name(sym::passes)
|
||||
|| i_meta.has_name(sym::no_default_passes)
|
||||
{
|
||||
self.tcx.emit_node_span_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
i_meta.span,
|
||||
errors::DocTestUnknownPasses { path, span: i_meta.span },
|
||||
);
|
||||
} else if i_meta.has_name(sym::plugins) {
|
||||
self.tcx.emit_node_span_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
hir_id,
|
||||
i_meta.span,
|
||||
errors::DocTestUnknownPlugins { path, span: i_meta.span },
|
||||
);
|
||||
} else {
|
||||
self.tcx.emit_node_span_lint(
|
||||
INVALID_DOC_ATTRIBUTES,
|
||||
|
@ -323,6 +323,27 @@ pub(crate) struct DocTestUnknownSpotlight {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_doc_test_unknown_passes)]
|
||||
#[note]
|
||||
#[help]
|
||||
#[note(passes_no_op_note)]
|
||||
pub(crate) struct DocTestUnknownPasses {
|
||||
pub path: String,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_doc_test_unknown_plugins)]
|
||||
#[note]
|
||||
#[note(passes_no_op_note)]
|
||||
pub(crate) struct DocTestUnknownPlugins {
|
||||
pub path: String,
|
||||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(passes_doc_test_unknown_include)]
|
||||
pub(crate) struct DocTestUnknownInclude {
|
||||
|
@ -322,7 +322,7 @@ impl<'tcx> ReachableContext<'tcx> {
|
||||
self.visit(ty);
|
||||
// Manually visit to actually see the trait's `DefId`. Type visitors won't see it
|
||||
if let Some(trait_ref) = dyn_ty.principal() {
|
||||
let ExistentialTraitRef { def_id, args } = trait_ref.skip_binder();
|
||||
let ExistentialTraitRef { def_id, args, .. } = trait_ref.skip_binder();
|
||||
self.visit_def_id(def_id, "", &"");
|
||||
self.visit(args);
|
||||
}
|
||||
|
@ -32,8 +32,8 @@ use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility,
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
||||
use rustc_middle::ty::{
|
||||
self, Const, GenericArgs, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitor,
|
||||
self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitor,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::lint;
|
||||
@ -246,10 +246,10 @@ where
|
||||
ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
|
||||
ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
|
||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
||||
ty::ExistentialTraitRef { def_id, args: GenericArgs::empty() }
|
||||
ty::ExistentialTraitRef::new(tcx, def_id, ty::GenericArgs::empty())
|
||||
}
|
||||
};
|
||||
let ty::ExistentialTraitRef { def_id, args: _ } = trait_ref;
|
||||
let ty::ExistentialTraitRef { def_id, .. } = trait_ref;
|
||||
try_visit!(self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref));
|
||||
}
|
||||
}
|
||||
|
@ -245,11 +245,15 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
|
||||
alias_ty.to_ty(tcx),
|
||||
);
|
||||
debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx));
|
||||
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
|
||||
def_id: assoc_ty.def_id,
|
||||
args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args,
|
||||
term: resolved.into(),
|
||||
})
|
||||
ty::ExistentialPredicate::Projection(
|
||||
ty::ExistentialProjection::erase_self_ty(
|
||||
tcx,
|
||||
ty::ProjectionPredicate {
|
||||
projection_term: alias_ty.into(),
|
||||
term: resolved.into(),
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -318,10 +322,11 @@ pub(crate) fn transform_instance<'tcx>(
|
||||
.lang_items()
|
||||
.drop_trait()
|
||||
.unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item"));
|
||||
let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef {
|
||||
let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new_from_args(
|
||||
tcx,
|
||||
def_id,
|
||||
args: List::empty(),
|
||||
});
|
||||
ty::List::empty(),
|
||||
));
|
||||
let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
|
||||
let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
|
||||
instance.args = tcx.mk_args_trait(self_ty, List::empty());
|
||||
|
@ -380,11 +380,12 @@ impl RustcInternal for ExistentialProjection {
|
||||
type T<'tcx> = rustc_ty::ExistentialProjection<'tcx>;
|
||||
|
||||
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
|
||||
rustc_ty::ExistentialProjection {
|
||||
def_id: self.def_id.0.internal(tables, tcx),
|
||||
args: self.generic_args.internal(tables, tcx),
|
||||
term: self.term.internal(tables, tcx),
|
||||
}
|
||||
rustc_ty::ExistentialProjection::new_from_args(
|
||||
tcx,
|
||||
self.def_id.0.internal(tables, tcx),
|
||||
self.generic_args.internal(tables, tcx),
|
||||
self.term.internal(tables, tcx),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -403,10 +404,11 @@ impl RustcInternal for ExistentialTraitRef {
|
||||
type T<'tcx> = rustc_ty::ExistentialTraitRef<'tcx>;
|
||||
|
||||
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
|
||||
rustc_ty::ExistentialTraitRef {
|
||||
def_id: self.def_id.0.internal(tables, tcx),
|
||||
args: self.generic_args.internal(tables, tcx),
|
||||
}
|
||||
rustc_ty::ExistentialTraitRef::new_from_args(
|
||||
tcx,
|
||||
self.def_id.0.internal(tables, tcx),
|
||||
self.generic_args.internal(tables, tcx),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialTraitRef<'tcx> {
|
||||
type T = stable_mir::ty::ExistentialTraitRef;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
let ty::ExistentialTraitRef { def_id, args } = self;
|
||||
let ty::ExistentialTraitRef { def_id, args, .. } = self;
|
||||
stable_mir::ty::ExistentialTraitRef {
|
||||
def_id: tables.trait_def(*def_id),
|
||||
generic_args: args.stable(tables),
|
||||
@ -95,7 +95,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> {
|
||||
type T = stable_mir::ty::ExistentialProjection;
|
||||
|
||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
||||
let ty::ExistentialProjection { def_id, args, term } = self;
|
||||
let ty::ExistentialProjection { def_id, args, term, .. } = self;
|
||||
stable_mir::ty::ExistentialProjection {
|
||||
def_id: tables.trait_def(*def_id),
|
||||
generic_args: args.stable(tables),
|
||||
|
@ -3594,52 +3594,64 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||
span: Span,
|
||||
) {
|
||||
if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) =
|
||||
self.tcx.coroutine_kind(obligation.cause.body_id)
|
||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||
|
||||
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
|
||||
let impls_future = self.type_implements_trait(
|
||||
future_trait,
|
||||
[self.tcx.instantiate_bound_regions_with_erased(self_ty)],
|
||||
obligation.param_env,
|
||||
);
|
||||
if !impls_future.must_apply_modulo_regions() {
|
||||
return;
|
||||
}
|
||||
|
||||
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
|
||||
// `<T as Future>::Output`
|
||||
let projection_ty = trait_pred.map_bound(|trait_pred| {
|
||||
Ty::new_projection(
|
||||
self.tcx,
|
||||
item_def_id,
|
||||
// Future::Output has no args
|
||||
[trait_pred.self_ty()],
|
||||
)
|
||||
});
|
||||
let InferOk { value: projection_ty, .. } =
|
||||
self.at(&obligation.cause, obligation.param_env).normalize(projection_ty);
|
||||
|
||||
debug!(
|
||||
normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
|
||||
);
|
||||
let try_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
|
||||
);
|
||||
debug!(try_trait_obligation = ?try_obligation);
|
||||
if self.predicate_may_hold(&try_obligation)
|
||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
&& snippet.ends_with('?')
|
||||
{
|
||||
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||
|
||||
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
|
||||
let impls_future = self.type_implements_trait(
|
||||
future_trait,
|
||||
[self.tcx.instantiate_bound_regions_with_erased(self_ty)],
|
||||
obligation.param_env,
|
||||
);
|
||||
if !impls_future.must_apply_modulo_regions() {
|
||||
return;
|
||||
}
|
||||
|
||||
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
|
||||
// `<T as Future>::Output`
|
||||
let projection_ty = trait_pred.map_bound(|trait_pred| {
|
||||
Ty::new_projection(
|
||||
self.tcx,
|
||||
item_def_id,
|
||||
// Future::Output has no args
|
||||
[trait_pred.self_ty()],
|
||||
)
|
||||
});
|
||||
let InferOk { value: projection_ty, .. } =
|
||||
self.at(&obligation.cause, obligation.param_env).normalize(projection_ty);
|
||||
|
||||
debug!(
|
||||
normalized_projection_type = ?self.resolve_vars_if_possible(projection_ty)
|
||||
);
|
||||
let try_obligation = self.mk_trait_obligation_with_new_self_ty(
|
||||
obligation.param_env,
|
||||
trait_pred.map_bound(|trait_pred| (trait_pred, projection_ty.skip_binder())),
|
||||
);
|
||||
debug!(try_trait_obligation = ?try_obligation);
|
||||
if self.predicate_may_hold(&try_obligation)
|
||||
&& let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
|
||||
&& snippet.ends_with('?')
|
||||
{
|
||||
err.span_suggestion_verbose(
|
||||
span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
|
||||
"consider `await`ing on the `Future`",
|
||||
".await",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
match self.tcx.coroutine_kind(obligation.cause.body_id) {
|
||||
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
|
||||
err.span_suggestion_verbose(
|
||||
span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
|
||||
"consider `await`ing on the `Future`",
|
||||
".await",
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
let mut span: MultiSpan = span.with_lo(span.hi() - BytePos(1)).into();
|
||||
span.push_span_label(
|
||||
self.tcx.def_span(obligation.cause.body_id),
|
||||
"this is not `async`",
|
||||
);
|
||||
err.span_note(
|
||||
span,
|
||||
"this implements `Future` and its output type supports \
|
||||
`?`, but the future cannot be awaited in a synchronous function",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,9 +15,7 @@ use crate::solve::{
|
||||
CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode,
|
||||
};
|
||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||
use crate::{
|
||||
search_graph, {self as ty},
|
||||
};
|
||||
use crate::{self as ty, search_graph};
|
||||
|
||||
pub trait Interner:
|
||||
Sized
|
||||
@ -173,6 +171,10 @@ pub trait Interner:
|
||||
|
||||
fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs);
|
||||
|
||||
/// Assert that the args from an `ExistentialTraitRef` or `ExistentialProjection`
|
||||
/// are compatible with the `DefId`.
|
||||
fn debug_assert_existential_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs);
|
||||
|
||||
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
|
@ -289,9 +289,26 @@ impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
|
||||
pub struct ExistentialTraitRef<I: Interner> {
|
||||
pub def_id: I::DefId,
|
||||
pub args: I::GenericArgs,
|
||||
/// This field exists to prevent the creation of `ExistentialTraitRef` without
|
||||
/// calling [`ExistentialTraitRef::new_from_args`].
|
||||
_use_existential_trait_ref_new_instead: (),
|
||||
}
|
||||
|
||||
impl<I: Interner> ExistentialTraitRef<I> {
|
||||
pub fn new_from_args(interner: I, trait_def_id: I::DefId, args: I::GenericArgs) -> Self {
|
||||
interner.debug_assert_existential_args_compatible(trait_def_id, args);
|
||||
Self { def_id: trait_def_id, args, _use_existential_trait_ref_new_instead: () }
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
interner: I,
|
||||
trait_def_id: I::DefId,
|
||||
args: impl IntoIterator<Item: Into<I::GenericArg>>,
|
||||
) -> Self {
|
||||
let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
|
||||
Self::new_from_args(interner, trait_def_id, args)
|
||||
}
|
||||
|
||||
pub fn erase_self_ty(interner: I, trait_ref: TraitRef<I>) -> ExistentialTraitRef<I> {
|
||||
// Assert there is a Self.
|
||||
trait_ref.args.type_at(0);
|
||||
@ -299,6 +316,7 @@ impl<I: Interner> ExistentialTraitRef<I> {
|
||||
ExistentialTraitRef {
|
||||
def_id: trait_ref.def_id,
|
||||
args: interner.mk_args(&trait_ref.args.as_slice()[1..]),
|
||||
_use_existential_trait_ref_new_instead: (),
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,9 +354,33 @@ pub struct ExistentialProjection<I: Interner> {
|
||||
pub def_id: I::DefId,
|
||||
pub args: I::GenericArgs,
|
||||
pub term: I::Term,
|
||||
|
||||
/// This field exists to prevent the creation of `ExistentialProjection`
|
||||
/// without using [`ExistentialProjection::new_from_args`].
|
||||
use_existential_projection_new_instead: (),
|
||||
}
|
||||
|
||||
impl<I: Interner> ExistentialProjection<I> {
|
||||
pub fn new_from_args(
|
||||
interner: I,
|
||||
def_id: I::DefId,
|
||||
args: I::GenericArgs,
|
||||
term: I::Term,
|
||||
) -> ExistentialProjection<I> {
|
||||
interner.debug_assert_existential_args_compatible(def_id, args);
|
||||
Self { def_id, args, term, use_existential_projection_new_instead: () }
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
interner: I,
|
||||
def_id: I::DefId,
|
||||
args: impl IntoIterator<Item: Into<I::GenericArg>>,
|
||||
term: I::Term,
|
||||
) -> ExistentialProjection<I> {
|
||||
let args = interner.mk_args_from_iter(args.into_iter().map(Into::into));
|
||||
Self::new_from_args(interner, def_id, args, term)
|
||||
}
|
||||
|
||||
/// Extracts the underlying existential trait reference from this projection.
|
||||
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
|
||||
/// then this function would return an `exists T. T: Iterator` existential trait
|
||||
@ -347,7 +389,7 @@ impl<I: Interner> ExistentialProjection<I> {
|
||||
let def_id = interner.parent(self.def_id);
|
||||
let args_count = interner.generics_of(def_id).count() - 1;
|
||||
let args = interner.mk_args(&self.args.as_slice()[..args_count]);
|
||||
ExistentialTraitRef { def_id, args }
|
||||
ExistentialTraitRef { def_id, args, _use_existential_trait_ref_new_instead: () }
|
||||
}
|
||||
|
||||
pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
|
||||
@ -372,6 +414,7 @@ impl<I: Interner> ExistentialProjection<I> {
|
||||
def_id: projection_predicate.projection_term.def_id,
|
||||
args: interner.mk_args(&projection_predicate.projection_term.args.as_slice()[1..]),
|
||||
term: projection_predicate.term,
|
||||
use_existential_projection_new_instead: (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -333,7 +333,7 @@ impl<I: Interner> Relate<I> for ty::ExistentialProjection<I> {
|
||||
a.args,
|
||||
b.args,
|
||||
)?;
|
||||
Ok(ty::ExistentialProjection { def_id: a.def_id, args, term })
|
||||
Ok(ty::ExistentialProjection::new_from_args(relation.cx(), a.def_id, args, term))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -373,7 +373,7 @@ impl<I: Interner> Relate<I> for ty::ExistentialTraitRef<I> {
|
||||
}))
|
||||
} else {
|
||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
||||
Ok(ty::ExistentialTraitRef { def_id: a.def_id, args })
|
||||
Ok(ty::ExistentialTraitRef::new_from_args(relation.cx(), a.def_id, args))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1734,13 +1734,15 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
|
||||
} else {
|
||||
// We need to properly build cargo using the suitable stage compiler.
|
||||
|
||||
// HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if
|
||||
// you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built
|
||||
// and produce a cargo built with stage 2 rustc. To fix this, we need to chop off
|
||||
// the compiler stage by 1 to align with expected `./x test run-make --stage N`
|
||||
// behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri
|
||||
// which does a similar hack.
|
||||
let compiler = builder.compiler(builder.top_stage - 1, compiler.host);
|
||||
let compiler = builder.download_rustc().then_some(compiler).unwrap_or_else(||
|
||||
// HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if
|
||||
// you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built
|
||||
// and produce a cargo built with stage 2 rustc. To fix this, we need to chop off
|
||||
// the compiler stage by 1 to align with expected `./x test run-make --stage N`
|
||||
// behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri
|
||||
// which does a similar hack.
|
||||
builder.compiler(builder.top_stage - 1, compiler.host));
|
||||
|
||||
builder.ensure(tool::Cargo { compiler, target: compiler.host })
|
||||
};
|
||||
|
||||
@ -3549,9 +3551,7 @@ impl Step for TestFloatParse {
|
||||
let path = self.path.to_str().unwrap();
|
||||
let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap();
|
||||
|
||||
if !builder.download_rustc() {
|
||||
builder.ensure(compile::Std::new(compiler, self.host));
|
||||
}
|
||||
builder.ensure(tool::TestFloatParse { host: self.host });
|
||||
|
||||
// Run any unit tests in the crate
|
||||
let cargo_test = tool::prepare_tool_cargo(
|
||||
|
@ -1097,6 +1097,38 @@ tool_extended!((self, builder),
|
||||
Rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, add_bins_to_sysroot = ["rustfmt", "cargo-fmt"];
|
||||
);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct TestFloatParse {
|
||||
pub host: TargetSelection,
|
||||
}
|
||||
|
||||
impl Step for TestFloatParse {
|
||||
type Output = ();
|
||||
const ONLY_HOSTS: bool = true;
|
||||
const DEFAULT: bool = false;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/etc/test-float-parse")
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) {
|
||||
let bootstrap_host = builder.config.build;
|
||||
let compiler = builder.compiler(builder.top_stage, bootstrap_host);
|
||||
|
||||
builder.ensure(ToolBuild {
|
||||
compiler,
|
||||
target: bootstrap_host,
|
||||
tool: "test-float-parse",
|
||||
mode: Mode::ToolStd,
|
||||
path: "src/etc/test-float-parse",
|
||||
source_type: SourceType::InTree,
|
||||
extra_features: Vec::new(),
|
||||
allow_features: "",
|
||||
cargo_args: Vec::new(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Builder<'_> {
|
||||
/// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for
|
||||
/// `host`.
|
||||
|
@ -8,7 +8,7 @@ use rustc_data_structures::unord::UnordSet;
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::emitter::{DynEmitter, HumanEmitter, stderr_destination};
|
||||
use rustc_errors::json::JsonEmitter;
|
||||
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, TerminalUrl};
|
||||
use rustc_errors::{ErrorGuaranteed, TerminalUrl};
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
|
||||
@ -21,8 +21,8 @@ use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
|
||||
use rustc_session::config::{self, CrateType, ErrorOutputType, Input, ResolveDocLinks};
|
||||
pub(crate) use rustc_session::config::{Options, UnstableOptions};
|
||||
use rustc_session::{Session, lint};
|
||||
use rustc_span::source_map;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, source_map};
|
||||
use tracing::{debug, info};
|
||||
|
||||
use crate::clean::inline::build_external_trait;
|
||||
@ -381,45 +381,10 @@ pub(crate) fn run_global_ctxt(
|
||||
);
|
||||
}
|
||||
|
||||
fn report_deprecated_attr(name: &str, dcx: DiagCtxtHandle<'_>, sp: Span) {
|
||||
let mut msg =
|
||||
dcx.struct_span_warn(sp, format!("the `#![doc({name})]` attribute is deprecated"));
|
||||
msg.note(
|
||||
"see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
|
||||
for more information",
|
||||
);
|
||||
|
||||
if name == "no_default_passes" {
|
||||
msg.help("`#![doc(no_default_passes)]` no longer functions; you may want to use `#![doc(document_private_items)]`");
|
||||
} else if name.starts_with("passes") {
|
||||
msg.help("`#![doc(passes = \"...\")]` no longer functions; you may want to use `#![doc(document_private_items)]`");
|
||||
} else if name.starts_with("plugins") {
|
||||
msg.warn("`#![doc(plugins = \"...\")]` no longer functions; see CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>");
|
||||
}
|
||||
|
||||
msg.emit();
|
||||
}
|
||||
|
||||
// Process all of the crate attributes, extracting plugin metadata along
|
||||
// with the passes which we are supposed to run.
|
||||
for attr in krate.module.attrs.lists(sym::doc) {
|
||||
let dcx = ctxt.sess().dcx();
|
||||
|
||||
let name = attr.name_or_empty();
|
||||
// `plugins = "..."`, `no_default_passes`, and `passes = "..."` have no effect
|
||||
if attr.is_word() && name == sym::no_default_passes {
|
||||
report_deprecated_attr("no_default_passes", dcx, attr.span());
|
||||
} else if attr.value_str().is_some() {
|
||||
match name {
|
||||
sym::passes => {
|
||||
report_deprecated_attr("passes = \"...\"", dcx, attr.span());
|
||||
}
|
||||
sym::plugins => {
|
||||
report_deprecated_attr("plugins = \"...\"", dcx, attr.span());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
if attr.is_word() && name == sym::document_private_items {
|
||||
ctxt.render_options.document_private = true;
|
||||
|
@ -57,7 +57,7 @@ impl EarlyProps {
|
||||
&mut poisoned,
|
||||
testfile,
|
||||
rdr,
|
||||
&mut |DirectiveLine { directive: ln, .. }| {
|
||||
&mut |DirectiveLine { raw_directive: ln, .. }| {
|
||||
parse_and_update_aux(config, ln, &mut props.aux);
|
||||
config.parse_and_update_revisions(testfile, ln, &mut props.revisions);
|
||||
},
|
||||
@ -344,8 +344,8 @@ impl TestProps {
|
||||
&mut poisoned,
|
||||
testfile,
|
||||
file,
|
||||
&mut |DirectiveLine { header_revision, directive: ln, .. }| {
|
||||
if header_revision.is_some() && header_revision != test_revision {
|
||||
&mut |directive @ DirectiveLine { raw_directive: ln, .. }| {
|
||||
if !directive.applies_to_test_revision(test_revision) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -678,28 +678,35 @@ impl TestProps {
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract an `(Option<line_revision>, directive)` directive from a line if comment is present.
|
||||
///
|
||||
/// See [`DirectiveLine`] for a diagram.
|
||||
pub fn line_directive<'line>(
|
||||
/// If the given line begins with the appropriate comment prefix for a directive,
|
||||
/// returns a struct containing various parts of the directive.
|
||||
fn line_directive<'line>(
|
||||
line_number: usize,
|
||||
comment: &str,
|
||||
original_line: &'line str,
|
||||
) -> Option<(Option<&'line str>, &'line str)> {
|
||||
) -> Option<DirectiveLine<'line>> {
|
||||
// Ignore lines that don't start with the comment prefix.
|
||||
let after_comment = original_line.trim_start().strip_prefix(comment)?.trim_start();
|
||||
|
||||
let revision;
|
||||
let raw_directive;
|
||||
|
||||
if let Some(after_open_bracket) = after_comment.strip_prefix('[') {
|
||||
// A comment like `//@[foo]` only applies to revision `foo`.
|
||||
let Some((line_revision, directive)) = after_open_bracket.split_once(']') else {
|
||||
let Some((line_revision, after_close_bracket)) = after_open_bracket.split_once(']') else {
|
||||
panic!(
|
||||
"malformed condition directive: expected `{comment}[foo]`, found `{original_line}`"
|
||||
)
|
||||
};
|
||||
|
||||
Some((Some(line_revision), directive.trim_start()))
|
||||
revision = Some(line_revision);
|
||||
raw_directive = after_close_bracket.trim_start();
|
||||
} else {
|
||||
Some((None, after_comment))
|
||||
}
|
||||
revision = None;
|
||||
raw_directive = after_comment;
|
||||
};
|
||||
|
||||
Some(DirectiveLine { line_number, revision, raw_directive })
|
||||
}
|
||||
|
||||
// To prevent duplicating the list of commmands between `compiletest`,`htmldocck` and `jsondocck`,
|
||||
@ -730,28 +737,37 @@ const KNOWN_HTMLDOCCK_DIRECTIVE_NAMES: &[&str] = &[
|
||||
const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
|
||||
&["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
|
||||
|
||||
/// The broken-down contents of a line containing a test header directive,
|
||||
/// The (partly) broken-down contents of a line containing a test directive,
|
||||
/// which [`iter_header`] passes to its callback function.
|
||||
///
|
||||
/// For example:
|
||||
///
|
||||
/// ```text
|
||||
/// //@ compile-flags: -O
|
||||
/// ^^^^^^^^^^^^^^^^^ directive
|
||||
/// ^^^^^^^^^^^^^^^^^ raw_directive
|
||||
///
|
||||
/// //@ [foo] compile-flags: -O
|
||||
/// ^^^ header_revision
|
||||
/// ^^^^^^^^^^^^^^^^^ directive
|
||||
/// ^^^ revision
|
||||
/// ^^^^^^^^^^^^^^^^^ raw_directive
|
||||
/// ```
|
||||
struct DirectiveLine<'ln> {
|
||||
line_number: usize,
|
||||
/// Some header directives start with a revision name in square brackets
|
||||
/// Some test directives start with a revision name in square brackets
|
||||
/// (e.g. `[foo]`), and only apply to that revision of the test.
|
||||
/// If present, this field contains the revision name (e.g. `foo`).
|
||||
header_revision: Option<&'ln str>,
|
||||
/// The main part of the header directive, after removing the comment prefix
|
||||
revision: Option<&'ln str>,
|
||||
/// The main part of the directive, after removing the comment prefix
|
||||
/// and the optional revision specifier.
|
||||
directive: &'ln str,
|
||||
///
|
||||
/// This is "raw" because the directive's name and colon-separated value
|
||||
/// (if present) have not yet been extracted or checked.
|
||||
raw_directive: &'ln str,
|
||||
}
|
||||
|
||||
impl<'ln> DirectiveLine<'ln> {
|
||||
fn applies_to_test_revision(&self, test_revision: Option<&str>) -> bool {
|
||||
self.revision.is_none() || self.revision == test_revision
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct CheckDirectiveResult<'ln> {
|
||||
@ -819,8 +835,8 @@ fn iter_header(
|
||||
"ignore-cross-compile",
|
||||
];
|
||||
// Process the extra implied directives, with a dummy line number of 0.
|
||||
for directive in extra_directives {
|
||||
it(DirectiveLine { line_number: 0, header_revision: None, directive });
|
||||
for raw_directive in extra_directives {
|
||||
it(DirectiveLine { line_number: 0, revision: None, raw_directive });
|
||||
}
|
||||
}
|
||||
|
||||
@ -847,24 +863,21 @@ fn iter_header(
|
||||
return;
|
||||
}
|
||||
|
||||
let Some((header_revision, non_revisioned_directive_line)) = line_directive(comment, ln)
|
||||
else {
|
||||
let Some(directive_line) = line_directive(line_number, comment, ln) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// Perform unknown directive check on Rust files.
|
||||
if testfile.extension().map(|e| e == "rs").unwrap_or(false) {
|
||||
let directive_ln = non_revisioned_directive_line.trim();
|
||||
|
||||
let CheckDirectiveResult { is_known_directive, trailing_directive } =
|
||||
check_directive(directive_ln, mode, ln);
|
||||
check_directive(directive_line.raw_directive, mode, ln);
|
||||
|
||||
if !is_known_directive {
|
||||
*poisoned = true;
|
||||
|
||||
eprintln!(
|
||||
"error: detected unknown compiletest test directive `{}` in {}:{}",
|
||||
directive_ln,
|
||||
directive_line.raw_directive,
|
||||
testfile.display(),
|
||||
line_number,
|
||||
);
|
||||
@ -888,11 +901,7 @@ fn iter_header(
|
||||
}
|
||||
}
|
||||
|
||||
it(DirectiveLine {
|
||||
line_number,
|
||||
header_revision,
|
||||
directive: non_revisioned_directive_line,
|
||||
});
|
||||
it(directive_line);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1292,8 +1301,8 @@ pub fn make_test_description<R: Read>(
|
||||
&mut local_poisoned,
|
||||
path,
|
||||
src,
|
||||
&mut |DirectiveLine { header_revision, directive: ln, line_number }| {
|
||||
if header_revision.is_some() && header_revision != test_revision {
|
||||
&mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
|
||||
if !directive.applies_to_test_revision(test_revision) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,6 @@ use std::io::{BufRead, BufReader};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::common::Config;
|
||||
use crate::header::line_directive;
|
||||
use crate::runtest::ProcRes;
|
||||
|
||||
/// Representation of information to invoke a debugger and check its output
|
||||
@ -24,7 +23,6 @@ impl DebuggerCommands {
|
||||
file: &Path,
|
||||
config: &Config,
|
||||
debugger_prefixes: &[&str],
|
||||
rev: Option<&str>,
|
||||
) -> Result<Self, String> {
|
||||
let directives = debugger_prefixes
|
||||
.iter()
|
||||
@ -39,17 +37,16 @@ impl DebuggerCommands {
|
||||
for (line_no, line) in reader.lines().enumerate() {
|
||||
counter += 1;
|
||||
let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?;
|
||||
let (lnrev, line) = line_directive("//", &line).unwrap_or((None, &line));
|
||||
|
||||
// Skip any revision specific directive that doesn't match the current
|
||||
// revision being tested
|
||||
if lnrev.is_some() && lnrev != rev {
|
||||
// Breakpoints appear on lines with actual code, typically at the end of the line.
|
||||
if line.contains("#break") {
|
||||
breakpoint_lines.push(counter);
|
||||
continue;
|
||||
}
|
||||
|
||||
if line.contains("#break") {
|
||||
breakpoint_lines.push(counter);
|
||||
}
|
||||
let Some(line) = line.trim_start().strip_prefix("//").map(str::trim_start) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
for &(ref command_directive, ref check_directive) in &directives {
|
||||
config
|
||||
|
@ -66,13 +66,8 @@ impl TestCx<'_> {
|
||||
};
|
||||
|
||||
// Parse debugger commands etc from test files
|
||||
let dbg_cmds = DebuggerCommands::parse_from(
|
||||
&self.testpaths.file,
|
||||
self.config,
|
||||
prefixes,
|
||||
self.revision,
|
||||
)
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes)
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
|
||||
let mut script_str = String::with_capacity(2048);
|
||||
@ -142,13 +137,8 @@ impl TestCx<'_> {
|
||||
}
|
||||
|
||||
fn run_debuginfo_gdb_test_no_opt(&self) {
|
||||
let dbg_cmds = DebuggerCommands::parse_from(
|
||||
&self.testpaths.file,
|
||||
self.config,
|
||||
&["gdb"],
|
||||
self.revision,
|
||||
)
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["gdb"])
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
let mut cmds = dbg_cmds.commands.join("\n");
|
||||
|
||||
// compile test file (it should have 'compile-flags:-g' in the header)
|
||||
@ -413,13 +403,8 @@ impl TestCx<'_> {
|
||||
}
|
||||
|
||||
// Parse debugger commands etc from test files
|
||||
let dbg_cmds = DebuggerCommands::parse_from(
|
||||
&self.testpaths.file,
|
||||
self.config,
|
||||
&["lldb"],
|
||||
self.revision,
|
||||
)
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["lldb"])
|
||||
.unwrap_or_else(|e| self.fatal(&e));
|
||||
|
||||
// Write debugger script:
|
||||
// We don't want to hang when calling `quit` while the process is still running
|
||||
|
1
tests/run-make/import-macro-verbatim/include/include.txt
Normal file
1
tests/run-make/import-macro-verbatim/include/include.txt
Normal file
@ -0,0 +1 @@
|
||||
static TEST: &str = "Hello World!";
|
8
tests/run-make/import-macro-verbatim/rmake.rs
Normal file
8
tests/run-make/import-macro-verbatim/rmake.rs
Normal file
@ -0,0 +1,8 @@
|
||||
//@ only-windows other platforms do not have Windows verbatim paths
|
||||
use run_make_support::rustc;
|
||||
fn main() {
|
||||
// Canonicalizing the path ensures that it's verbatim (i.e. starts with `\\?\`)
|
||||
let mut path = std::fs::canonicalize(file!()).unwrap();
|
||||
path.pop();
|
||||
rustc().input("verbatim.rs").env("VERBATIM_DIR", path).run();
|
||||
}
|
12
tests/run-make/import-macro-verbatim/verbatim.rs
Normal file
12
tests/run-make/import-macro-verbatim/verbatim.rs
Normal file
@ -0,0 +1,12 @@
|
||||
//! Include a file by concating the verbatim path using `/` instead of `\`
|
||||
|
||||
include!(concat!(env!("VERBATIM_DIR"), "/include/include.txt"));
|
||||
fn main() {
|
||||
assert_eq!(TEST, "Hello World!");
|
||||
|
||||
let s = include_str!(concat!(env!("VERBATIM_DIR"), "/include/include.txt"));
|
||||
assert_eq!(s, "static TEST: &str = \"Hello World!\";\n");
|
||||
|
||||
let b = include_bytes!(concat!(env!("VERBATIM_DIR"), "/include/include.txt"));
|
||||
assert_eq!(b, b"static TEST: &str = \"Hello World!\";\n");
|
||||
}
|
@ -1,16 +1,21 @@
|
||||
//@ check-pass
|
||||
//@ compile-flags: --passes unknown-pass
|
||||
//@ error-pattern: the `passes` flag no longer functions
|
||||
|
||||
#![doc(no_default_passes)]
|
||||
//~^ WARNING attribute is deprecated
|
||||
//~^ ERROR unknown `doc` attribute `no_default_passes`
|
||||
//~| NOTE no longer functions
|
||||
//~| NOTE see issue #44136
|
||||
//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]`
|
||||
//~| HELP you may want to use `doc(document_private_items)`
|
||||
//~| NOTE `doc(no_default_passes)` is now a no-op
|
||||
//~| NOTE `#[deny(invalid_doc_attributes)]` on by default
|
||||
#![doc(passes = "collapse-docs unindent-comments")]
|
||||
//~^ WARNING attribute is deprecated
|
||||
//~^ ERROR unknown `doc` attribute `passes`
|
||||
//~| NOTE no longer functions
|
||||
//~| NOTE see issue #44136
|
||||
//~| HELP no longer functions; you may want to use `#![doc(document_private_items)]`
|
||||
//~| HELP you may want to use `doc(document_private_items)`
|
||||
//~| NOTE `doc(passes)` is now a no-op
|
||||
#![doc(plugins = "xxx")]
|
||||
//~^ WARNING attribute is deprecated
|
||||
//~^ ERROR unknown `doc` attribute `plugins`
|
||||
//~| NOTE see issue #44136
|
||||
//~| WARNING no longer functions; see CVE
|
||||
//~| NOTE no longer functions
|
||||
//~| NOTE `doc(plugins)` is now a no-op
|
||||
|
@ -3,32 +3,35 @@ warning: the `passes` flag no longer functions
|
||||
= note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
|
||||
= help: you may want to use --document-private-items
|
||||
|
||||
warning: the `#![doc(no_default_passes)]` attribute is deprecated
|
||||
--> $DIR/deprecated-attrs.rs:5:8
|
||||
error: unknown `doc` attribute `no_default_passes`
|
||||
--> $DIR/deprecated-attrs.rs:4:8
|
||||
|
|
||||
LL | #![doc(no_default_passes)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^ no longer functions
|
||||
|
|
||||
= note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
|
||||
= help: `#![doc(no_default_passes)]` no longer functions; you may want to use `#![doc(document_private_items)]`
|
||||
= note: `doc` attribute `no_default_passes` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136>
|
||||
= help: you may want to use `doc(document_private_items)`
|
||||
= note: `doc(no_default_passes)` is now a no-op
|
||||
= note: `#[deny(invalid_doc_attributes)]` on by default
|
||||
|
||||
warning: the `#![doc(passes = "...")]` attribute is deprecated
|
||||
--> $DIR/deprecated-attrs.rs:9:8
|
||||
error: unknown `doc` attribute `passes`
|
||||
--> $DIR/deprecated-attrs.rs:11:8
|
||||
|
|
||||
LL | #![doc(passes = "collapse-docs unindent-comments")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no longer functions
|
||||
|
|
||||
= note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
|
||||
= help: `#![doc(passes = "...")]` no longer functions; you may want to use `#![doc(document_private_items)]`
|
||||
= note: `doc` attribute `passes` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136>
|
||||
= help: you may want to use `doc(document_private_items)`
|
||||
= note: `doc(passes)` is now a no-op
|
||||
|
||||
warning: the `#![doc(plugins = "...")]` attribute is deprecated
|
||||
--> $DIR/deprecated-attrs.rs:13:8
|
||||
error: unknown `doc` attribute `plugins`
|
||||
--> $DIR/deprecated-attrs.rs:17:8
|
||||
|
|
||||
LL | #![doc(plugins = "xxx")]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^ no longer functions
|
||||
|
|
||||
= note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
|
||||
= warning: `#![doc(plugins = "...")]` no longer functions; see CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>
|
||||
= note: `doc` attribute `plugins` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136> and CVE-2018-1000622 <https://nvd.nist.gov/vuln/detail/CVE-2018-1000622>
|
||||
= note: `doc(plugins)` is now a no-op
|
||||
|
||||
warning: 3 warnings emitted
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
|
13
tests/ui/async-await/field-in-sync.rs
Normal file
13
tests/ui/async-await/field-in-sync.rs
Normal file
@ -0,0 +1,13 @@
|
||||
//@ edition: 2021
|
||||
|
||||
struct S {
|
||||
field: (),
|
||||
}
|
||||
|
||||
async fn foo() -> S { todo!() }
|
||||
|
||||
fn main() -> Result<(), ()> {
|
||||
foo().field;
|
||||
//~^ ERROR no field `field` on type `impl Future<Output = S>`
|
||||
Ok(())
|
||||
}
|
17
tests/ui/async-await/field-in-sync.stderr
Normal file
17
tests/ui/async-await/field-in-sync.stderr
Normal file
@ -0,0 +1,17 @@
|
||||
error[E0609]: no field `field` on type `impl Future<Output = S>`
|
||||
--> $DIR/field-in-sync.rs:10:11
|
||||
|
|
||||
LL | foo().field;
|
||||
| ^^^^^ field not available in `impl Future`, but it is available in its `Output`
|
||||
|
|
||||
note: this implements `Future` and its output type has the field, but the future cannot be awaited in a synchronous function
|
||||
--> $DIR/field-in-sync.rs:10:5
|
||||
|
|
||||
LL | fn main() -> Result<(), ()> {
|
||||
| --------------------------- this is not `async`
|
||||
LL | foo().field;
|
||||
| ^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0609`.
|
@ -28,7 +28,7 @@ error[E0609]: no field `0` on type `impl Future<Output = Tuple>`
|
||||
LL | let _: i32 = tuple().0;
|
||||
| ^ field not available in `impl Future`, but it is available in its `Output`
|
||||
|
|
||||
help: consider `await`ing on the `Future` and access the field of its `Output`
|
||||
help: consider `await`ing on the `Future` to access the field
|
||||
|
|
||||
LL | let _: i32 = tuple().await.0;
|
||||
| ++++++
|
||||
@ -39,7 +39,7 @@ error[E0609]: no field `a` on type `impl Future<Output = Struct>`
|
||||
LL | let _: i32 = struct_().a;
|
||||
| ^ field not available in `impl Future`, but it is available in its `Output`
|
||||
|
|
||||
help: consider `await`ing on the `Future` and access the field of its `Output`
|
||||
help: consider `await`ing on the `Future` to access the field
|
||||
|
|
||||
LL | let _: i32 = struct_().await.a;
|
||||
| ++++++
|
||||
|
9
tests/ui/async-await/try-in-sync.rs
Normal file
9
tests/ui/async-await/try-in-sync.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//@ edition: 2021
|
||||
|
||||
async fn foo() -> Result<(), ()> { todo!() }
|
||||
|
||||
fn main() -> Result<(), ()> {
|
||||
foo()?;
|
||||
//~^ ERROR the `?` operator can only be applied to values that implement `Try`
|
||||
Ok(())
|
||||
}
|
18
tests/ui/async-await/try-in-sync.stderr
Normal file
18
tests/ui/async-await/try-in-sync.stderr
Normal file
@ -0,0 +1,18 @@
|
||||
error[E0277]: the `?` operator can only be applied to values that implement `Try`
|
||||
--> $DIR/try-in-sync.rs:6:5
|
||||
|
|
||||
LL | foo()?;
|
||||
| ^^^^^^ the `?` operator cannot be applied to type `impl Future<Output = Result<(), ()>>`
|
||||
|
|
||||
= help: the trait `Try` is not implemented for `impl Future<Output = Result<(), ()>>`
|
||||
note: this implements `Future` and its output type supports `?`, but the future cannot be awaited in a synchronous function
|
||||
--> $DIR/try-in-sync.rs:6:10
|
||||
|
|
||||
LL | fn main() -> Result<(), ()> {
|
||||
| --------------------------- this is not `async`
|
||||
LL | foo()?;
|
||||
| ^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user