mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-28 01:34:21 +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.
|
//! Thomas Lengauer and Robert Endre Tarjan.
|
||||||
//! <https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf>
|
//! <https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf>
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
|
|
||||||
use rustc_index::{Idx, IndexSlice, IndexVec};
|
use rustc_index::{Idx, IndexSlice, IndexVec};
|
||||||
|
|
||||||
use super::ControlFlowGraph;
|
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> {
|
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
|
// We allocate capacity for the full set of nodes, because most of the time
|
||||||
// most of the nodes *are* reachable.
|
// most of the nodes *are* reachable.
|
||||||
let mut parent: IndexVec<PreorderIndex, PreorderIndex> =
|
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());
|
pre_order_to_real.push(graph.start_node());
|
||||||
parent.push(PreorderIndex::ZERO); // the parent of the root node is the root for now.
|
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);
|
real_to_pre_order[graph.start_node()] = Some(PreorderIndex::ZERO);
|
||||||
let mut post_order_idx = 0;
|
|
||||||
|
|
||||||
// Traverse the graph, collecting a number of things:
|
// Traverse the graph, collecting a number of things:
|
||||||
//
|
//
|
||||||
// * Preorder mapping (to it, and back to the actual ordering)
|
// * 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
|
// * Parents for each vertex in the preorder tree
|
||||||
//
|
//
|
||||||
// These are all done here rather than through one of the 'standard'
|
// 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;
|
continue 'recurse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
post_order_rank[pre_order_to_real[frame.pre_order_idx]] = post_order_idx;
|
|
||||||
post_order_idx += 1;
|
|
||||||
|
|
||||||
stack.pop();
|
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);
|
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
|
/// 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.
|
/// Tracks the list of dominators for each node.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct Inner<N: Idx> {
|
struct Inner<N: Idx> {
|
||||||
post_order_rank: IndexVec<N, usize>,
|
|
||||||
// Even though we track only the immediate dominator of each node, it's
|
// 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
|
// possible to get its full list of dominators by looking up the dominator
|
||||||
// of each 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`.
|
/// Returns true if `a` dominates `b`.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
use std::path::Component::Prefix;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::rc::Rc;
|
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);
|
base_path.push(path);
|
||||||
Ok(base_path)
|
Ok(base_path)
|
||||||
} else {
|
} 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();
|
.collect();
|
||||||
let args = tcx.mk_args(&args);
|
|
||||||
|
|
||||||
let span = i.bottom().1;
|
let span = i.bottom().1;
|
||||||
let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
|
let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
|
||||||
@ -292,7 +291,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
|
|||||||
.emit();
|
.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_data_structures::unord::UnordMap;
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::{
|
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::{CtorKind, DefKind, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
@ -2763,12 +2764,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
field_ident.span,
|
field_ident.span,
|
||||||
"field not available in `impl Future`, but it is available in its `Output`",
|
"field not available in `impl Future`, but it is available in its `Output`",
|
||||||
);
|
);
|
||||||
err.span_suggestion_verbose(
|
match self.tcx.coroutine_kind(self.body_id) {
|
||||||
base.span.shrink_to_hi(),
|
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
|
||||||
"consider `await`ing on the `Future` and access the field of its `Output`",
|
err.span_suggestion_verbose(
|
||||||
".await",
|
base.span.shrink_to_hi(),
|
||||||
Applicability::MaybeIncorrect,
|
"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(
|
fn ban_nonexisting_field(
|
||||||
|
@ -109,6 +109,7 @@ impl<'tcx> Const<'tcx> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_unevaluated(tcx: TyCtxt<'tcx>, uv: ty::UnevaluatedConst<'tcx>) -> Const<'tcx> {
|
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))
|
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);
|
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
|
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
|
||||||
where
|
where
|
||||||
I: Iterator<Item = T>,
|
I: Iterator<Item = T>,
|
||||||
|
@ -21,6 +21,10 @@ pub(crate) struct CoverageGraph {
|
|||||||
pub(crate) successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
|
pub(crate) successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
|
||||||
pub(crate) predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
|
pub(crate) predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
|
||||||
dominators: Option<Dominators<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 {
|
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));
|
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,
|
// The coverage graph's entry-point node (bcb0) always starts with bb0,
|
||||||
// which never has predecessors. Any other blocks merged into bcb0 can't
|
// which never has predecessors. Any other blocks merged into bcb0 can't
|
||||||
// have multiple (coverage-relevant) predecessors, so bcb0 always has
|
// have multiple (coverage-relevant) predecessors, so bcb0 always has
|
||||||
@ -162,7 +183,7 @@ impl CoverageGraph {
|
|||||||
a: BasicCoverageBlock,
|
a: BasicCoverageBlock,
|
||||||
b: BasicCoverageBlock,
|
b: BasicCoverageBlock,
|
||||||
) -> Ordering {
|
) -> 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.
|
/// 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}`
|
unknown `doc` attribute `{$path}`
|
||||||
.suggestion = use `doc = include_str!` instead
|
.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 =
|
passes_doc_test_unknown_spotlight =
|
||||||
unknown `doc` attribute `{$path}`
|
unknown `doc` attribute `{$path}`
|
||||||
.note = `doc(spotlight)` was renamed to `doc(notable_trait)`
|
.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),
|
sym::masked => self.check_doc_masked(attr, meta, hir_id, target),
|
||||||
|
|
||||||
// no_default_passes: deprecated
|
sym::cfg | sym::hidden | sym::notable_trait => {}
|
||||||
// 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::rust_logo => {
|
sym::rust_logo => {
|
||||||
if self.check_attr_crate_level(attr, meta, hir_id)
|
if self.check_attr_crate_level(attr, meta, hir_id)
|
||||||
@ -1240,6 +1232,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||||||
sugg: (attr.meta().unwrap().span, applicability),
|
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 {
|
} else {
|
||||||
self.tcx.emit_node_span_lint(
|
self.tcx.emit_node_span_lint(
|
||||||
INVALID_DOC_ATTRIBUTES,
|
INVALID_DOC_ATTRIBUTES,
|
||||||
|
@ -323,6 +323,27 @@ pub(crate) struct DocTestUnknownSpotlight {
|
|||||||
pub span: Span,
|
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)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(passes_doc_test_unknown_include)]
|
#[diag(passes_doc_test_unknown_include)]
|
||||||
pub(crate) struct DocTestUnknownInclude {
|
pub(crate) struct DocTestUnknownInclude {
|
||||||
|
@ -322,7 +322,7 @@ impl<'tcx> ReachableContext<'tcx> {
|
|||||||
self.visit(ty);
|
self.visit(ty);
|
||||||
// Manually visit to actually see the trait's `DefId`. Type visitors won't see it
|
// Manually visit to actually see the trait's `DefId`. Type visitors won't see it
|
||||||
if let Some(trait_ref) = dyn_ty.principal() {
|
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_def_id(def_id, "", &"");
|
||||||
self.visit(args);
|
self.visit(args);
|
||||||
}
|
}
|
||||||
|
@ -32,8 +32,8 @@ use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility,
|
|||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
use rustc_middle::ty::print::PrintTraitRefExt as _;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, Const, GenericArgs, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
|
self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||||
TypeVisitable, TypeVisitor,
|
TypeVisitor,
|
||||||
};
|
};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
@ -246,10 +246,10 @@ where
|
|||||||
ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
|
ty::ExistentialPredicate::Trait(trait_ref) => trait_ref,
|
||||||
ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
|
ty::ExistentialPredicate::Projection(proj) => proj.trait_ref(tcx),
|
||||||
ty::ExistentialPredicate::AutoTrait(def_id) => {
|
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));
|
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),
|
alias_ty.to_ty(tcx),
|
||||||
);
|
);
|
||||||
debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx));
|
debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx));
|
||||||
ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
|
ty::ExistentialPredicate::Projection(
|
||||||
def_id: assoc_ty.def_id,
|
ty::ExistentialProjection::erase_self_ty(
|
||||||
args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args,
|
tcx,
|
||||||
term: resolved.into(),
|
ty::ProjectionPredicate {
|
||||||
})
|
projection_term: alias_ty.into(),
|
||||||
|
term: resolved.into(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -318,10 +322,11 @@ pub(crate) fn transform_instance<'tcx>(
|
|||||||
.lang_items()
|
.lang_items()
|
||||||
.drop_trait()
|
.drop_trait()
|
||||||
.unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item"));
|
.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,
|
def_id,
|
||||||
args: List::empty(),
|
ty::List::empty(),
|
||||||
});
|
));
|
||||||
let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]);
|
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);
|
let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn);
|
||||||
instance.args = tcx.mk_args_trait(self_ty, List::empty());
|
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>;
|
type T<'tcx> = rustc_ty::ExistentialProjection<'tcx>;
|
||||||
|
|
||||||
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
|
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
|
||||||
rustc_ty::ExistentialProjection {
|
rustc_ty::ExistentialProjection::new_from_args(
|
||||||
def_id: self.def_id.0.internal(tables, tcx),
|
tcx,
|
||||||
args: self.generic_args.internal(tables, tcx),
|
self.def_id.0.internal(tables, tcx),
|
||||||
term: self.term.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>;
|
type T<'tcx> = rustc_ty::ExistentialTraitRef<'tcx>;
|
||||||
|
|
||||||
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
|
fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
|
||||||
rustc_ty::ExistentialTraitRef {
|
rustc_ty::ExistentialTraitRef::new_from_args(
|
||||||
def_id: self.def_id.0.internal(tables, tcx),
|
tcx,
|
||||||
args: self.generic_args.internal(tables, 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;
|
type T = stable_mir::ty::ExistentialTraitRef;
|
||||||
|
|
||||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
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 {
|
stable_mir::ty::ExistentialTraitRef {
|
||||||
def_id: tables.trait_def(*def_id),
|
def_id: tables.trait_def(*def_id),
|
||||||
generic_args: args.stable(tables),
|
generic_args: args.stable(tables),
|
||||||
@ -95,7 +95,7 @@ impl<'tcx> Stable<'tcx> for ty::ExistentialProjection<'tcx> {
|
|||||||
type T = stable_mir::ty::ExistentialProjection;
|
type T = stable_mir::ty::ExistentialProjection;
|
||||||
|
|
||||||
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
|
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 {
|
stable_mir::ty::ExistentialProjection {
|
||||||
def_id: tables.trait_def(*def_id),
|
def_id: tables.trait_def(*def_id),
|
||||||
generic_args: args.stable(tables),
|
generic_args: args.stable(tables),
|
||||||
|
@ -3594,52 +3594,64 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
) {
|
) {
|
||||||
if let Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) =
|
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
|
||||||
self.tcx.coroutine_kind(obligation.cause.body_id)
|
|
||||||
|
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);
|
match self.tcx.coroutine_kind(obligation.cause.body_id) {
|
||||||
|
Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
|
||||||
let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
|
err.span_suggestion_verbose(
|
||||||
let impls_future = self.type_implements_trait(
|
span.with_hi(span.hi() - BytePos(1)).shrink_to_hi(),
|
||||||
future_trait,
|
"consider `await`ing on the `Future`",
|
||||||
[self.tcx.instantiate_bound_regions_with_erased(self_ty)],
|
".await",
|
||||||
obligation.param_env,
|
Applicability::MaybeIncorrect,
|
||||||
);
|
);
|
||||||
if !impls_future.must_apply_modulo_regions() {
|
}
|
||||||
return;
|
_ => {
|
||||||
}
|
let mut span: MultiSpan = span.with_lo(span.hi() - BytePos(1)).into();
|
||||||
|
span.push_span_label(
|
||||||
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
|
self.tcx.def_span(obligation.cause.body_id),
|
||||||
// `<T as Future>::Output`
|
"this is not `async`",
|
||||||
let projection_ty = trait_pred.map_bound(|trait_pred| {
|
);
|
||||||
Ty::new_projection(
|
err.span_note(
|
||||||
self.tcx,
|
span,
|
||||||
item_def_id,
|
"this implements `Future` and its output type supports \
|
||||||
// Future::Output has no args
|
`?`, but the future cannot be awaited in a synchronous function",
|
||||||
[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,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,7 @@ use crate::solve::{
|
|||||||
CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode,
|
CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult, SolverMode,
|
||||||
};
|
};
|
||||||
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
|
||||||
use crate::{
|
use crate::{self as ty, search_graph};
|
||||||
search_graph, {self as ty},
|
|
||||||
};
|
|
||||||
|
|
||||||
pub trait Interner:
|
pub trait Interner:
|
||||||
Sized
|
Sized
|
||||||
@ -173,6 +171,10 @@ pub trait Interner:
|
|||||||
|
|
||||||
fn debug_assert_args_compatible(self, def_id: Self::DefId, args: Self::GenericArgs);
|
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
|
fn mk_type_list_from_iter<I, T>(self, args: I) -> T::Output
|
||||||
where
|
where
|
||||||
I: Iterator<Item = T>,
|
I: Iterator<Item = T>,
|
||||||
|
@ -289,9 +289,26 @@ impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
|
|||||||
pub struct ExistentialTraitRef<I: Interner> {
|
pub struct ExistentialTraitRef<I: Interner> {
|
||||||
pub def_id: I::DefId,
|
pub def_id: I::DefId,
|
||||||
pub args: I::GenericArgs,
|
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> {
|
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> {
|
pub fn erase_self_ty(interner: I, trait_ref: TraitRef<I>) -> ExistentialTraitRef<I> {
|
||||||
// Assert there is a Self.
|
// Assert there is a Self.
|
||||||
trait_ref.args.type_at(0);
|
trait_ref.args.type_at(0);
|
||||||
@ -299,6 +316,7 @@ impl<I: Interner> ExistentialTraitRef<I> {
|
|||||||
ExistentialTraitRef {
|
ExistentialTraitRef {
|
||||||
def_id: trait_ref.def_id,
|
def_id: trait_ref.def_id,
|
||||||
args: interner.mk_args(&trait_ref.args.as_slice()[1..]),
|
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 def_id: I::DefId,
|
||||||
pub args: I::GenericArgs,
|
pub args: I::GenericArgs,
|
||||||
pub term: I::Term,
|
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> {
|
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.
|
/// Extracts the underlying existential trait reference from this projection.
|
||||||
/// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
|
/// 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
|
/// 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 def_id = interner.parent(self.def_id);
|
||||||
let args_count = interner.generics_of(def_id).count() - 1;
|
let args_count = interner.generics_of(def_id).count() - 1;
|
||||||
let args = interner.mk_args(&self.args.as_slice()[..args_count]);
|
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> {
|
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,
|
def_id: projection_predicate.projection_term.def_id,
|
||||||
args: interner.mk_args(&projection_predicate.projection_term.args.as_slice()[1..]),
|
args: interner.mk_args(&projection_predicate.projection_term.args.as_slice()[1..]),
|
||||||
term: projection_predicate.term,
|
term: projection_predicate.term,
|
||||||
|
use_existential_projection_new_instead: (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -333,7 +333,7 @@ impl<I: Interner> Relate<I> for ty::ExistentialProjection<I> {
|
|||||||
a.args,
|
a.args,
|
||||||
b.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 {
|
} else {
|
||||||
let args = relate_args_invariantly(relation, a.args, b.args)?;
|
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 {
|
} else {
|
||||||
// We need to properly build cargo using the suitable stage compiler.
|
// 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
|
let compiler = builder.download_rustc().then_some(compiler).unwrap_or_else(||
|
||||||
// you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built
|
// HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if
|
||||||
// and produce a cargo built with stage 2 rustc. To fix this, we need to chop off
|
// you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built
|
||||||
// the compiler stage by 1 to align with expected `./x test run-make --stage N`
|
// and produce a cargo built with stage 2 rustc. To fix this, we need to chop off
|
||||||
// behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri
|
// the compiler stage by 1 to align with expected `./x test run-make --stage N`
|
||||||
// which does a similar hack.
|
// behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri
|
||||||
let compiler = builder.compiler(builder.top_stage - 1, compiler.host);
|
// which does a similar hack.
|
||||||
|
builder.compiler(builder.top_stage - 1, compiler.host));
|
||||||
|
|
||||||
builder.ensure(tool::Cargo { compiler, target: 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 path = self.path.to_str().unwrap();
|
||||||
let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap();
|
let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap();
|
||||||
|
|
||||||
if !builder.download_rustc() {
|
builder.ensure(tool::TestFloatParse { host: self.host });
|
||||||
builder.ensure(compile::Std::new(compiler, self.host));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run any unit tests in the crate
|
// Run any unit tests in the crate
|
||||||
let cargo_test = tool::prepare_tool_cargo(
|
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"];
|
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<'_> {
|
impl Builder<'_> {
|
||||||
/// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for
|
/// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for
|
||||||
/// `host`.
|
/// `host`.
|
||||||
|
@ -8,7 +8,7 @@ use rustc_data_structures::unord::UnordSet;
|
|||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::emitter::{DynEmitter, HumanEmitter, stderr_destination};
|
use rustc_errors::emitter::{DynEmitter, HumanEmitter, stderr_destination};
|
||||||
use rustc_errors::json::JsonEmitter;
|
use rustc_errors::json::JsonEmitter;
|
||||||
use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, TerminalUrl};
|
use rustc_errors::{ErrorGuaranteed, TerminalUrl};
|
||||||
use rustc_feature::UnstableFeatures;
|
use rustc_feature::UnstableFeatures;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId};
|
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};
|
use rustc_session::config::{self, CrateType, ErrorOutputType, Input, ResolveDocLinks};
|
||||||
pub(crate) use rustc_session::config::{Options, UnstableOptions};
|
pub(crate) use rustc_session::config::{Options, UnstableOptions};
|
||||||
use rustc_session::{Session, lint};
|
use rustc_session::{Session, lint};
|
||||||
|
use rustc_span::source_map;
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{Span, source_map};
|
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info};
|
||||||
|
|
||||||
use crate::clean::inline::build_external_trait;
|
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
|
// Process all of the crate attributes, extracting plugin metadata along
|
||||||
// with the passes which we are supposed to run.
|
// with the passes which we are supposed to run.
|
||||||
for attr in krate.module.attrs.lists(sym::doc) {
|
for attr in krate.module.attrs.lists(sym::doc) {
|
||||||
let dcx = ctxt.sess().dcx();
|
|
||||||
|
|
||||||
let name = attr.name_or_empty();
|
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 {
|
if attr.is_word() && name == sym::document_private_items {
|
||||||
ctxt.render_options.document_private = true;
|
ctxt.render_options.document_private = true;
|
||||||
|
@ -57,7 +57,7 @@ impl EarlyProps {
|
|||||||
&mut poisoned,
|
&mut poisoned,
|
||||||
testfile,
|
testfile,
|
||||||
rdr,
|
rdr,
|
||||||
&mut |DirectiveLine { directive: ln, .. }| {
|
&mut |DirectiveLine { raw_directive: ln, .. }| {
|
||||||
parse_and_update_aux(config, ln, &mut props.aux);
|
parse_and_update_aux(config, ln, &mut props.aux);
|
||||||
config.parse_and_update_revisions(testfile, ln, &mut props.revisions);
|
config.parse_and_update_revisions(testfile, ln, &mut props.revisions);
|
||||||
},
|
},
|
||||||
@ -344,8 +344,8 @@ impl TestProps {
|
|||||||
&mut poisoned,
|
&mut poisoned,
|
||||||
testfile,
|
testfile,
|
||||||
file,
|
file,
|
||||||
&mut |DirectiveLine { header_revision, directive: ln, .. }| {
|
&mut |directive @ DirectiveLine { raw_directive: ln, .. }| {
|
||||||
if header_revision.is_some() && header_revision != test_revision {
|
if !directive.applies_to_test_revision(test_revision) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,28 +678,35 @@ impl TestProps {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extract an `(Option<line_revision>, directive)` directive from a line if comment is present.
|
/// If the given line begins with the appropriate comment prefix for a directive,
|
||||||
///
|
/// returns a struct containing various parts of the directive.
|
||||||
/// See [`DirectiveLine`] for a diagram.
|
fn line_directive<'line>(
|
||||||
pub fn line_directive<'line>(
|
line_number: usize,
|
||||||
comment: &str,
|
comment: &str,
|
||||||
original_line: &'line str,
|
original_line: &'line str,
|
||||||
) -> Option<(Option<&'line str>, &'line str)> {
|
) -> Option<DirectiveLine<'line>> {
|
||||||
// Ignore lines that don't start with the comment prefix.
|
// Ignore lines that don't start with the comment prefix.
|
||||||
let after_comment = original_line.trim_start().strip_prefix(comment)?.trim_start();
|
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('[') {
|
if let Some(after_open_bracket) = after_comment.strip_prefix('[') {
|
||||||
// A comment like `//@[foo]` only applies to revision `foo`.
|
// 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!(
|
panic!(
|
||||||
"malformed condition directive: expected `{comment}[foo]`, found `{original_line}`"
|
"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 {
|
} 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`,
|
// 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] =
|
const KNOWN_JSONDOCCK_DIRECTIVE_NAMES: &[&str] =
|
||||||
&["count", "!count", "has", "!has", "is", "!is", "ismany", "!ismany", "set", "!set"];
|
&["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.
|
/// which [`iter_header`] passes to its callback function.
|
||||||
///
|
///
|
||||||
/// For example:
|
/// For example:
|
||||||
///
|
///
|
||||||
/// ```text
|
/// ```text
|
||||||
/// //@ compile-flags: -O
|
/// //@ compile-flags: -O
|
||||||
/// ^^^^^^^^^^^^^^^^^ directive
|
/// ^^^^^^^^^^^^^^^^^ raw_directive
|
||||||
///
|
///
|
||||||
/// //@ [foo] compile-flags: -O
|
/// //@ [foo] compile-flags: -O
|
||||||
/// ^^^ header_revision
|
/// ^^^ revision
|
||||||
/// ^^^^^^^^^^^^^^^^^ directive
|
/// ^^^^^^^^^^^^^^^^^ raw_directive
|
||||||
/// ```
|
/// ```
|
||||||
struct DirectiveLine<'ln> {
|
struct DirectiveLine<'ln> {
|
||||||
line_number: usize,
|
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.
|
/// (e.g. `[foo]`), and only apply to that revision of the test.
|
||||||
/// If present, this field contains the revision name (e.g. `foo`).
|
/// If present, this field contains the revision name (e.g. `foo`).
|
||||||
header_revision: Option<&'ln str>,
|
revision: Option<&'ln str>,
|
||||||
/// The main part of the header directive, after removing the comment prefix
|
/// The main part of the directive, after removing the comment prefix
|
||||||
/// and the optional revision specifier.
|
/// 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> {
|
pub(crate) struct CheckDirectiveResult<'ln> {
|
||||||
@ -819,8 +835,8 @@ fn iter_header(
|
|||||||
"ignore-cross-compile",
|
"ignore-cross-compile",
|
||||||
];
|
];
|
||||||
// Process the extra implied directives, with a dummy line number of 0.
|
// Process the extra implied directives, with a dummy line number of 0.
|
||||||
for directive in extra_directives {
|
for raw_directive in extra_directives {
|
||||||
it(DirectiveLine { line_number: 0, header_revision: None, directive });
|
it(DirectiveLine { line_number: 0, revision: None, raw_directive });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -847,24 +863,21 @@ fn iter_header(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some((header_revision, non_revisioned_directive_line)) = line_directive(comment, ln)
|
let Some(directive_line) = line_directive(line_number, comment, ln) else {
|
||||||
else {
|
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Perform unknown directive check on Rust files.
|
// Perform unknown directive check on Rust files.
|
||||||
if testfile.extension().map(|e| e == "rs").unwrap_or(false) {
|
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 } =
|
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 {
|
if !is_known_directive {
|
||||||
*poisoned = true;
|
*poisoned = true;
|
||||||
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"error: detected unknown compiletest test directive `{}` in {}:{}",
|
"error: detected unknown compiletest test directive `{}` in {}:{}",
|
||||||
directive_ln,
|
directive_line.raw_directive,
|
||||||
testfile.display(),
|
testfile.display(),
|
||||||
line_number,
|
line_number,
|
||||||
);
|
);
|
||||||
@ -888,11 +901,7 @@ fn iter_header(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
it(DirectiveLine {
|
it(directive_line);
|
||||||
line_number,
|
|
||||||
header_revision,
|
|
||||||
directive: non_revisioned_directive_line,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1292,8 +1301,8 @@ pub fn make_test_description<R: Read>(
|
|||||||
&mut local_poisoned,
|
&mut local_poisoned,
|
||||||
path,
|
path,
|
||||||
src,
|
src,
|
||||||
&mut |DirectiveLine { header_revision, directive: ln, line_number }| {
|
&mut |directive @ DirectiveLine { line_number, raw_directive: ln, .. }| {
|
||||||
if header_revision.is_some() && header_revision != test_revision {
|
if !directive.applies_to_test_revision(test_revision) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ use std::io::{BufRead, BufReader};
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use crate::common::Config;
|
use crate::common::Config;
|
||||||
use crate::header::line_directive;
|
|
||||||
use crate::runtest::ProcRes;
|
use crate::runtest::ProcRes;
|
||||||
|
|
||||||
/// Representation of information to invoke a debugger and check its output
|
/// Representation of information to invoke a debugger and check its output
|
||||||
@ -24,7 +23,6 @@ impl DebuggerCommands {
|
|||||||
file: &Path,
|
file: &Path,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
debugger_prefixes: &[&str],
|
debugger_prefixes: &[&str],
|
||||||
rev: Option<&str>,
|
|
||||||
) -> Result<Self, String> {
|
) -> Result<Self, String> {
|
||||||
let directives = debugger_prefixes
|
let directives = debugger_prefixes
|
||||||
.iter()
|
.iter()
|
||||||
@ -39,17 +37,16 @@ impl DebuggerCommands {
|
|||||||
for (line_no, line) in reader.lines().enumerate() {
|
for (line_no, line) in reader.lines().enumerate() {
|
||||||
counter += 1;
|
counter += 1;
|
||||||
let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?;
|
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
|
// Breakpoints appear on lines with actual code, typically at the end of the line.
|
||||||
// revision being tested
|
if line.contains("#break") {
|
||||||
if lnrev.is_some() && lnrev != rev {
|
breakpoint_lines.push(counter);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if line.contains("#break") {
|
let Some(line) = line.trim_start().strip_prefix("//").map(str::trim_start) else {
|
||||||
breakpoint_lines.push(counter);
|
continue;
|
||||||
}
|
};
|
||||||
|
|
||||||
for &(ref command_directive, ref check_directive) in &directives {
|
for &(ref command_directive, ref check_directive) in &directives {
|
||||||
config
|
config
|
||||||
|
@ -66,13 +66,8 @@ impl TestCx<'_> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Parse debugger commands etc from test files
|
// Parse debugger commands etc from test files
|
||||||
let dbg_cmds = DebuggerCommands::parse_from(
|
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, prefixes)
|
||||||
&self.testpaths.file,
|
.unwrap_or_else(|e| self.fatal(&e));
|
||||||
self.config,
|
|
||||||
prefixes,
|
|
||||||
self.revision,
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| self.fatal(&e));
|
|
||||||
|
|
||||||
// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
|
// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugger-commands
|
||||||
let mut script_str = String::with_capacity(2048);
|
let mut script_str = String::with_capacity(2048);
|
||||||
@ -142,13 +137,8 @@ impl TestCx<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run_debuginfo_gdb_test_no_opt(&self) {
|
fn run_debuginfo_gdb_test_no_opt(&self) {
|
||||||
let dbg_cmds = DebuggerCommands::parse_from(
|
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["gdb"])
|
||||||
&self.testpaths.file,
|
.unwrap_or_else(|e| self.fatal(&e));
|
||||||
self.config,
|
|
||||||
&["gdb"],
|
|
||||||
self.revision,
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| self.fatal(&e));
|
|
||||||
let mut cmds = dbg_cmds.commands.join("\n");
|
let mut cmds = dbg_cmds.commands.join("\n");
|
||||||
|
|
||||||
// compile test file (it should have 'compile-flags:-g' in the header)
|
// 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
|
// Parse debugger commands etc from test files
|
||||||
let dbg_cmds = DebuggerCommands::parse_from(
|
let dbg_cmds = DebuggerCommands::parse_from(&self.testpaths.file, self.config, &["lldb"])
|
||||||
&self.testpaths.file,
|
.unwrap_or_else(|e| self.fatal(&e));
|
||||||
self.config,
|
|
||||||
&["lldb"],
|
|
||||||
self.revision,
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| self.fatal(&e));
|
|
||||||
|
|
||||||
// Write debugger script:
|
// Write debugger script:
|
||||||
// We don't want to hang when calling `quit` while the process is still running
|
// 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
|
//@ compile-flags: --passes unknown-pass
|
||||||
//@ error-pattern: the `passes` flag no longer functions
|
//@ error-pattern: the `passes` flag no longer functions
|
||||||
|
|
||||||
#![doc(no_default_passes)]
|
#![doc(no_default_passes)]
|
||||||
//~^ WARNING attribute is deprecated
|
//~^ ERROR unknown `doc` attribute `no_default_passes`
|
||||||
|
//~| NOTE no longer functions
|
||||||
//~| NOTE see issue #44136
|
//~| 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")]
|
#![doc(passes = "collapse-docs unindent-comments")]
|
||||||
//~^ WARNING attribute is deprecated
|
//~^ ERROR unknown `doc` attribute `passes`
|
||||||
|
//~| NOTE no longer functions
|
||||||
//~| NOTE see issue #44136
|
//~| 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")]
|
#![doc(plugins = "xxx")]
|
||||||
//~^ WARNING attribute is deprecated
|
//~^ ERROR unknown `doc` attribute `plugins`
|
||||||
//~| NOTE see issue #44136
|
//~| 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
|
= note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
|
||||||
= help: you may want to use --document-private-items
|
= help: you may want to use --document-private-items
|
||||||
|
|
||||||
warning: the `#![doc(no_default_passes)]` attribute is deprecated
|
error: unknown `doc` attribute `no_default_passes`
|
||||||
--> $DIR/deprecated-attrs.rs:5:8
|
--> $DIR/deprecated-attrs.rs:4:8
|
||||||
|
|
|
|
||||||
LL | #![doc(no_default_passes)]
|
LL | #![doc(no_default_passes)]
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^ no longer functions
|
||||||
|
|
|
|
||||||
= note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
|
= note: `doc` attribute `no_default_passes` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136>
|
||||||
= help: `#![doc(no_default_passes)]` 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
|
||||||
|
|
||||||
warning: the `#![doc(passes = "...")]` attribute is deprecated
|
error: unknown `doc` attribute `passes`
|
||||||
--> $DIR/deprecated-attrs.rs:9:8
|
--> $DIR/deprecated-attrs.rs:11:8
|
||||||
|
|
|
|
||||||
LL | #![doc(passes = "collapse-docs unindent-comments")]
|
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
|
= note: `doc` attribute `passes` no longer functions; see issue #44136 <https://github.com/rust-lang/rust/issues/44136>
|
||||||
= help: `#![doc(passes = "...")]` 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
|
||||||
|
|
||||||
warning: the `#![doc(plugins = "...")]` attribute is deprecated
|
error: unknown `doc` attribute `plugins`
|
||||||
--> $DIR/deprecated-attrs.rs:13:8
|
--> $DIR/deprecated-attrs.rs:17:8
|
||||||
|
|
|
|
||||||
LL | #![doc(plugins = "xxx")]
|
LL | #![doc(plugins = "xxx")]
|
||||||
| ^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^ no longer functions
|
||||||
|
|
|
|
||||||
= note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
|
= 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>
|
||||||
= warning: `#![doc(plugins = "...")]` no longer functions; see 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;
|
LL | let _: i32 = tuple().0;
|
||||||
| ^ field not available in `impl Future`, but it is available in its `Output`
|
| ^ 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;
|
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;
|
LL | let _: i32 = struct_().a;
|
||||||
| ^ field not available in `impl Future`, but it is available in its `Output`
|
| ^ 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;
|
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