mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-16 17:03:35 +00:00
Auto merge of #130237 - matthiaskrgr:rollup-qmgr8i7, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #129260 (Don't suggest adding return type for closures with default return type) - #129520 (Suggest the correct pattern syntax on usage of unit variant pattern for a struct variant) - #129866 (Clarify documentation labelling and definitions for std::collections) - #130123 (Report the `note` when specified in `diagnostic::on_unimplemented`) - #130161 (refactor merge base logic and fix `x fmt`) - #130206 (Map `WSAEDQUOT` to `ErrorKind::FilesystemQuotaExceeded`) - #130207 (Map `ERROR_CANT_RESOLVE_FILENAME` to `ErrorKind::FilesystemLoop`) - #130219 (Fix false positive with `missing_docs` and `#[test]`) - #130221 (Make SearchPath::new public) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
8d6b88b168
@ -277,6 +277,8 @@ pub(crate) fn expand_test_or_bench(
|
|||||||
cx.attr_nested_word(sym::cfg, sym::test, attr_sp),
|
cx.attr_nested_word(sym::cfg, sym::test, attr_sp),
|
||||||
// #[rustc_test_marker = "test_case_sort_key"]
|
// #[rustc_test_marker = "test_case_sort_key"]
|
||||||
cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp),
|
cx.attr_name_value_str(sym::rustc_test_marker, test_path_symbol, attr_sp),
|
||||||
|
// #[doc(hidden)]
|
||||||
|
cx.attr_nested_word(sym::doc, sym::hidden, attr_sp),
|
||||||
],
|
],
|
||||||
// const $ident: test::TestDescAndFn =
|
// const $ident: test::TestDescAndFn =
|
||||||
ast::ItemKind::Const(
|
ast::ItemKind::Const(
|
||||||
|
@ -326,8 +326,8 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
|
|||||||
let main_attr = ecx.attr_word(sym::rustc_main, sp);
|
let main_attr = ecx.attr_word(sym::rustc_main, sp);
|
||||||
// #[coverage(off)]
|
// #[coverage(off)]
|
||||||
let coverage_attr = ecx.attr_nested_word(sym::coverage, sym::off, sp);
|
let coverage_attr = ecx.attr_nested_word(sym::coverage, sym::off, sp);
|
||||||
// #[allow(missing_docs)]
|
// #[doc(hidden)]
|
||||||
let missing_docs_attr = ecx.attr_nested_word(sym::allow, sym::missing_docs, sp);
|
let doc_hidden_attr = ecx.attr_nested_word(sym::doc, sym::hidden, sp);
|
||||||
|
|
||||||
// pub fn main() { ... }
|
// pub fn main() { ... }
|
||||||
let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(ThinVec::new()));
|
let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(ThinVec::new()));
|
||||||
@ -357,7 +357,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
|
|||||||
|
|
||||||
let main = P(ast::Item {
|
let main = P(ast::Item {
|
||||||
ident: main_id,
|
ident: main_id,
|
||||||
attrs: thin_vec![main_attr, coverage_attr, missing_docs_attr],
|
attrs: thin_vec![main_attr, coverage_attr, doc_hidden_attr],
|
||||||
id: ast::DUMMY_NODE_ID,
|
id: ast::DUMMY_NODE_ID,
|
||||||
kind: main,
|
kind: main,
|
||||||
vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None },
|
vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None },
|
||||||
|
@ -389,7 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
{
|
{
|
||||||
// check that the `if` expr without `else` is the fn body's expr
|
// check that the `if` expr without `else` is the fn body's expr
|
||||||
if expr.span == sp {
|
if expr.span == sp {
|
||||||
return self.get_fn_decl(hir_id).map(|(_, fn_decl, _)| {
|
return self.get_fn_decl(hir_id).map(|(_, fn_decl)| {
|
||||||
let (ty, span) = match fn_decl.output {
|
let (ty, span) = match fn_decl.output {
|
||||||
hir::FnRetTy::DefaultReturn(span) => ("()".to_string(), span),
|
hir::FnRetTy::DefaultReturn(span) => ("()".to_string(), span),
|
||||||
hir::FnRetTy::Return(ty) => (ty_to_string(&self.tcx, ty), ty.span),
|
hir::FnRetTy::Return(ty) => (ty_to_string(&self.tcx, ty), ty.span),
|
||||||
|
@ -1860,10 +1860,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// If this is due to an explicit `return`, suggest adding a return type.
|
// If this is due to an explicit `return`, suggest adding a return type.
|
||||||
if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(block_or_return_id)
|
if let Some((fn_id, fn_decl)) = fcx.get_fn_decl(block_or_return_id)
|
||||||
&& !due_to_block
|
&& !due_to_block
|
||||||
{
|
{
|
||||||
fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, can_suggest, fn_id);
|
fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, fn_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is due to a block, then maybe we forgot a `return`/`break`.
|
// If this is due to a block, then maybe we forgot a `return`/`break`.
|
||||||
|
@ -774,7 +774,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
self.ret_coercion_span.set(Some(expr.span));
|
self.ret_coercion_span.set(Some(expr.span));
|
||||||
}
|
}
|
||||||
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
|
let cause = self.cause(expr.span, ObligationCauseCode::ReturnNoExpression);
|
||||||
if let Some((_, fn_decl, _)) = self.get_fn_decl(expr.hir_id) {
|
if let Some((_, fn_decl)) = self.get_fn_decl(expr.hir_id) {
|
||||||
coercion.coerce_forced_unit(
|
coercion.coerce_forced_unit(
|
||||||
self,
|
self,
|
||||||
&cause,
|
&cause,
|
||||||
|
@ -30,7 +30,7 @@ use rustc_middle::{bug, span_bug};
|
|||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::def_id::LocalDefId;
|
use rustc_span::def_id::LocalDefId;
|
||||||
use rustc_span::hygiene::DesugaringKind;
|
use rustc_span::hygiene::DesugaringKind;
|
||||||
use rustc_span::symbol::{kw, sym};
|
use rustc_span::symbol::kw;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::abi::FieldIdx;
|
use rustc_target::abi::FieldIdx;
|
||||||
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
|
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
|
||||||
@ -859,38 +859,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
|
/// Given a `HirId`, return the `HirId` of the enclosing function and its `FnDecl`.
|
||||||
/// suggestion can be made, `None` otherwise.
|
|
||||||
pub(crate) fn get_fn_decl(
|
pub(crate) fn get_fn_decl(
|
||||||
&self,
|
&self,
|
||||||
blk_id: HirId,
|
blk_id: HirId,
|
||||||
) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> {
|
) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>)> {
|
||||||
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
|
// Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
|
||||||
// `while` before reaching it, as block tail returns are not available in them.
|
// `while` before reaching it, as block tail returns are not available in them.
|
||||||
self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|item_id| {
|
self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|item_id| {
|
||||||
match self.tcx.hir_node(item_id) {
|
match self.tcx.hir_node(item_id) {
|
||||||
Node::Item(&hir::Item {
|
Node::Item(&hir::Item {
|
||||||
ident,
|
kind: hir::ItemKind::Fn(ref sig, ..), owner_id, ..
|
||||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
}) => Some((owner_id.def_id, sig.decl)),
|
||||||
owner_id,
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
// This is less than ideal, it will not suggest a return type span on any
|
|
||||||
// method called `main`, regardless of whether it is actually the entry point,
|
|
||||||
// but it will still present it as the reason for the expected type.
|
|
||||||
Some((owner_id.def_id, sig.decl, ident.name != sym::main))
|
|
||||||
}
|
|
||||||
Node::TraitItem(&hir::TraitItem {
|
Node::TraitItem(&hir::TraitItem {
|
||||||
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
||||||
owner_id,
|
owner_id,
|
||||||
..
|
..
|
||||||
}) => Some((owner_id.def_id, sig.decl, true)),
|
}) => Some((owner_id.def_id, sig.decl)),
|
||||||
// FIXME: Suggestable if this is not a trait implementation
|
|
||||||
Node::ImplItem(&hir::ImplItem {
|
Node::ImplItem(&hir::ImplItem {
|
||||||
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
||||||
owner_id,
|
owner_id,
|
||||||
..
|
..
|
||||||
}) => Some((owner_id.def_id, sig.decl, false)),
|
}) => Some((owner_id.def_id, sig.decl)),
|
||||||
Node::Expr(&hir::Expr {
|
Node::Expr(&hir::Expr {
|
||||||
hir_id,
|
hir_id,
|
||||||
kind: hir::ExprKind::Closure(&hir::Closure { def_id, kind, fn_decl, .. }),
|
kind: hir::ExprKind::Closure(&hir::Closure { def_id, kind, fn_decl, .. }),
|
||||||
@ -901,33 +891,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// FIXME(async_closures): Implement this.
|
// FIXME(async_closures): Implement this.
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
hir::ClosureKind::Closure => Some((def_id, fn_decl, true)),
|
hir::ClosureKind::Closure => Some((def_id, fn_decl)),
|
||||||
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
|
||||||
_,
|
_,
|
||||||
hir::CoroutineSource::Fn,
|
hir::CoroutineSource::Fn,
|
||||||
)) => {
|
)) => {
|
||||||
let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
|
let (sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
|
||||||
Node::Item(&hir::Item {
|
Node::Item(&hir::Item {
|
||||||
ident,
|
|
||||||
kind: hir::ItemKind::Fn(ref sig, ..),
|
kind: hir::ItemKind::Fn(ref sig, ..),
|
||||||
owner_id,
|
owner_id,
|
||||||
..
|
..
|
||||||
}) => (ident, sig, owner_id),
|
}) => (sig, owner_id),
|
||||||
Node::TraitItem(&hir::TraitItem {
|
Node::TraitItem(&hir::TraitItem {
|
||||||
ident,
|
|
||||||
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
kind: hir::TraitItemKind::Fn(ref sig, ..),
|
||||||
owner_id,
|
owner_id,
|
||||||
..
|
..
|
||||||
}) => (ident, sig, owner_id),
|
}) => (sig, owner_id),
|
||||||
Node::ImplItem(&hir::ImplItem {
|
Node::ImplItem(&hir::ImplItem {
|
||||||
ident,
|
|
||||||
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
kind: hir::ImplItemKind::Fn(ref sig, ..),
|
||||||
owner_id,
|
owner_id,
|
||||||
..
|
..
|
||||||
}) => (ident, sig, owner_id),
|
}) => (sig, owner_id),
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some((owner_id.def_id, sig.decl, ident.name != sym::main))
|
Some((owner_id.def_id, sig.decl))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -1873,7 +1873,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// that highlight errors inline.
|
// that highlight errors inline.
|
||||||
let mut sp = blk.span;
|
let mut sp = blk.span;
|
||||||
let mut fn_span = None;
|
let mut fn_span = None;
|
||||||
if let Some((fn_def_id, decl, _)) = self.get_fn_decl(blk.hir_id) {
|
if let Some((fn_def_id, decl)) = self.get_fn_decl(blk.hir_id) {
|
||||||
let ret_sp = decl.output.span();
|
let ret_sp = decl.output.span();
|
||||||
if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
|
if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
|
||||||
// HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
|
// HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
|
||||||
|
@ -79,9 +79,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// `break` type mismatches provide better context for tail `loop` expressions.
|
// `break` type mismatches provide better context for tail `loop` expressions.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
|
if let Some((fn_id, fn_decl)) = self.get_fn_decl(blk_id) {
|
||||||
pointing_at_return_type =
|
pointing_at_return_type =
|
||||||
self.suggest_missing_return_type(err, fn_decl, expected, found, can_suggest, fn_id);
|
self.suggest_missing_return_type(err, fn_decl, expected, found, fn_id);
|
||||||
self.suggest_missing_break_or_return_expr(
|
self.suggest_missing_break_or_return_expr(
|
||||||
err, expr, fn_decl, expected, found, blk_id, fn_id,
|
err, expr, fn_decl, expected, found, blk_id, fn_id,
|
||||||
);
|
);
|
||||||
@ -813,7 +813,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
fn_decl: &hir::FnDecl<'tcx>,
|
fn_decl: &hir::FnDecl<'tcx>,
|
||||||
expected: Ty<'tcx>,
|
expected: Ty<'tcx>,
|
||||||
found: Ty<'tcx>,
|
found: Ty<'tcx>,
|
||||||
can_suggest: bool,
|
|
||||||
fn_id: LocalDefId,
|
fn_id: LocalDefId,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Can't suggest `->` on a block-like coroutine
|
// Can't suggest `->` on a block-like coroutine
|
||||||
@ -826,28 +825,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let found =
|
let found =
|
||||||
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
|
self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
|
||||||
// Only suggest changing the return type for methods that
|
// Only suggest changing the return type for methods that
|
||||||
// haven't set a return type at all (and aren't `fn main()` or an impl).
|
// haven't set a return type at all (and aren't `fn main()`, impl or closure).
|
||||||
match &fn_decl.output {
|
match &fn_decl.output {
|
||||||
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() && !can_suggest => {
|
// For closure with default returns, don't suggest adding return type
|
||||||
// `fn main()` must return `()`, do not suggest changing return type
|
&hir::FnRetTy::DefaultReturn(_) if self.tcx.is_closure_like(fn_id.to_def_id()) => {}
|
||||||
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span });
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
|
&hir::FnRetTy::DefaultReturn(span) if expected.is_unit() => {
|
||||||
if let Some(found) = found.make_suggestable(self.tcx, false, None) {
|
if !self.can_add_return_type(fn_id) {
|
||||||
|
err.subdiagnostic(errors::ExpectedReturnTypeLabel::Unit { span });
|
||||||
|
} else if let Some(found) = found.make_suggestable(self.tcx, false, None) {
|
||||||
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
|
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add {
|
||||||
span,
|
span,
|
||||||
found: found.to_string(),
|
found: found.to_string(),
|
||||||
});
|
});
|
||||||
return true;
|
|
||||||
} else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) {
|
} else if let Some(sugg) = suggest_impl_trait(self, self.param_env, found) {
|
||||||
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: sugg });
|
err.subdiagnostic(errors::AddReturnTypeSuggestion::Add { span, found: sugg });
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
// FIXME: if `found` could be `impl Iterator` we should suggest that.
|
// FIXME: if `found` could be `impl Iterator` we should suggest that.
|
||||||
err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
|
err.subdiagnostic(errors::AddReturnTypeSuggestion::MissingHere { span });
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
hir::FnRetTy::Return(hir_ty) => {
|
hir::FnRetTy::Return(hir_ty) => {
|
||||||
if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
|
if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind
|
||||||
@ -905,6 +902,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks whether we can add a return type to a function.
|
||||||
|
/// Assumes given function doesn't have a explicit return type.
|
||||||
|
fn can_add_return_type(&self, fn_id: LocalDefId) -> bool {
|
||||||
|
match self.tcx.hir_node_by_def_id(fn_id) {
|
||||||
|
Node::Item(&hir::Item { ident, .. }) => {
|
||||||
|
// This is less than ideal, it will not suggest a return type span on any
|
||||||
|
// method called `main`, regardless of whether it is actually the entry point,
|
||||||
|
// but it will still present it as the reason for the expected type.
|
||||||
|
ident.name != sym::main
|
||||||
|
}
|
||||||
|
Node::ImplItem(item) => {
|
||||||
|
// If it doesn't impl a trait, we can add a return type
|
||||||
|
let Node::Item(&hir::Item {
|
||||||
|
kind: hir::ItemKind::Impl(&hir::Impl { of_trait, .. }),
|
||||||
|
..
|
||||||
|
}) = self.tcx.parent_hir_node(item.hir_id())
|
||||||
|
else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
|
||||||
|
of_trait.is_none()
|
||||||
|
}
|
||||||
|
_ => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn try_note_caller_chooses_ty_for_ty_param(
|
fn try_note_caller_chooses_ty_for_ty_param(
|
||||||
&self,
|
&self,
|
||||||
diag: &mut Diag<'_>,
|
diag: &mut Diag<'_>,
|
||||||
|
@ -43,7 +43,7 @@ pub use coercion::can_coerce;
|
|||||||
use fn_ctxt::FnCtxt;
|
use fn_ctxt::FnCtxt;
|
||||||
use rustc_data_structures::unord::UnordSet;
|
use rustc_data_structures::unord::UnordSet;
|
||||||
use rustc_errors::codes::*;
|
use rustc_errors::codes::*;
|
||||||
use rustc_errors::{struct_span_code_err, Applicability, ErrorGuaranteed};
|
use rustc_errors::{pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::intravisit::Visitor;
|
use rustc_hir::intravisit::Visitor;
|
||||||
@ -423,6 +423,36 @@ fn report_unexpected_variant_res(
|
|||||||
err.multipart_suggestion_verbose(descr, suggestion, Applicability::MaybeIncorrect);
|
err.multipart_suggestion_verbose(descr, suggestion, Applicability::MaybeIncorrect);
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
|
Res::Def(DefKind::Variant, _) if expr.is_none() => {
|
||||||
|
err.span_label(span, format!("not a {expected}"));
|
||||||
|
|
||||||
|
let fields = &tcx.expect_variant_res(res).fields.raw;
|
||||||
|
let span = qpath.span().shrink_to_hi().to(span.shrink_to_hi());
|
||||||
|
let (msg, sugg) = if fields.is_empty() {
|
||||||
|
("use the struct variant pattern syntax".to_string(), " {}".to_string())
|
||||||
|
} else {
|
||||||
|
let msg = format!(
|
||||||
|
"the struct variant's field{s} {are} being ignored",
|
||||||
|
s = pluralize!(fields.len()),
|
||||||
|
are = pluralize!("is", fields.len())
|
||||||
|
);
|
||||||
|
let fields = fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| format!("{}: _", field.name.to_ident_string()))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
|
let sugg = format!(" {{ {} }}", fields);
|
||||||
|
(msg, sugg)
|
||||||
|
};
|
||||||
|
|
||||||
|
err.span_suggestion_verbose(
|
||||||
|
qpath.span().shrink_to_hi().to(span.shrink_to_hi()),
|
||||||
|
msg,
|
||||||
|
sugg,
|
||||||
|
Applicability::HasPlaceholders,
|
||||||
|
);
|
||||||
|
err
|
||||||
|
}
|
||||||
_ => err.with_span_label(span, format!("not a {expected}")),
|
_ => err.with_span_label(span, format!("not a {expected}")),
|
||||||
}
|
}
|
||||||
.emit()
|
.emit()
|
||||||
|
@ -1317,7 +1317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
let actual_prefix = rcvr_ty.prefix_string(self.tcx);
|
let actual_prefix = rcvr_ty.prefix_string(self.tcx);
|
||||||
info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
|
info!("unimplemented_traits.len() == {}", unimplemented_traits.len());
|
||||||
let mut long_ty_file = None;
|
let mut long_ty_file = None;
|
||||||
let (primary_message, label) = if unimplemented_traits.len() == 1
|
let (primary_message, label, notes) = if unimplemented_traits.len() == 1
|
||||||
&& unimplemented_traits_only
|
&& unimplemented_traits_only
|
||||||
{
|
{
|
||||||
unimplemented_traits
|
unimplemented_traits
|
||||||
@ -1327,16 +1327,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
|
if trait_ref.self_ty().references_error() || rcvr_ty.references_error()
|
||||||
{
|
{
|
||||||
// Avoid crashing.
|
// Avoid crashing.
|
||||||
return (None, None);
|
return (None, None, Vec::new());
|
||||||
}
|
}
|
||||||
let OnUnimplementedNote { message, label, .. } = self
|
let OnUnimplementedNote { message, label, notes, .. } = self
|
||||||
.err_ctxt()
|
.err_ctxt()
|
||||||
.on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file);
|
.on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file);
|
||||||
(message, label)
|
(message, label, notes)
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
} else {
|
} else {
|
||||||
(None, None)
|
(None, None, Vec::new())
|
||||||
};
|
};
|
||||||
let primary_message = primary_message.unwrap_or_else(|| {
|
let primary_message = primary_message.unwrap_or_else(|| {
|
||||||
format!(
|
format!(
|
||||||
@ -1363,6 +1363,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
"the following trait bounds were not satisfied:\n{bound_list}"
|
"the following trait bounds were not satisfied:\n{bound_list}"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
for note in notes {
|
||||||
|
err.note(note);
|
||||||
|
}
|
||||||
|
|
||||||
suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates);
|
suggested_derive = self.suggest_derive(&mut err, unsatisfied_predicates);
|
||||||
|
|
||||||
unsatisfied_bounds = true;
|
unsatisfied_bounds = true;
|
||||||
|
@ -96,7 +96,7 @@ impl SearchPath {
|
|||||||
Self::new(PathKind::All, make_target_lib_path(sysroot, triple))
|
Self::new(PathKind::All, make_target_lib_path(sysroot, triple))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(kind: PathKind, dir: PathBuf) -> Self {
|
pub fn new(kind: PathKind, dir: PathBuf) -> Self {
|
||||||
// Get the files within the directory.
|
// Get the files within the directory.
|
||||||
let files = match std::fs::read_dir(&dir) {
|
let files = match std::fs::read_dir(&dir) {
|
||||||
Ok(files) => files
|
Ok(files) => files
|
||||||
|
@ -1236,7 +1236,6 @@ symbols! {
|
|||||||
mir_unwind_unreachable,
|
mir_unwind_unreachable,
|
||||||
mir_variant,
|
mir_variant,
|
||||||
miri,
|
miri,
|
||||||
missing_docs,
|
|
||||||
mmx_reg,
|
mmx_reg,
|
||||||
modifiers,
|
modifiers,
|
||||||
module,
|
module,
|
||||||
|
@ -79,42 +79,50 @@
|
|||||||
//! see each type's documentation, and note that the names of actual methods may
|
//! see each type's documentation, and note that the names of actual methods may
|
||||||
//! differ from the tables below on certain collections.
|
//! differ from the tables below on certain collections.
|
||||||
//!
|
//!
|
||||||
//! Throughout the documentation, we will follow a few conventions. For all
|
//! Throughout the documentation, we will adhere to the following conventions
|
||||||
//! operations, the collection's size is denoted by n. If another collection is
|
//! for operation notation:
|
||||||
//! involved in the operation, it contains m elements. Operations which have an
|
|
||||||
//! *amortized* cost are suffixed with a `*`. Operations with an *expected*
|
|
||||||
//! cost are suffixed with a `~`.
|
|
||||||
//!
|
//!
|
||||||
//! All amortized costs are for the potential need to resize when capacity is
|
//! * The collection's size is denoted by `n`.
|
||||||
//! exhausted. If a resize occurs it will take *O*(*n*) time. Our collections never
|
//! * If a second collection is involved, its size is denoted by `m`.
|
||||||
//! automatically shrink, so removal operations aren't amortized. Over a
|
//! * Item indices are denoted by `i`.
|
||||||
//! sufficiently large series of operations, the average cost per operation will
|
//! * Operations which have an *amortized* cost are suffixed with a `*`.
|
||||||
//! deterministically equal the given cost.
|
//! * Operations with an *expected* cost are suffixed with a `~`.
|
||||||
//!
|
//!
|
||||||
//! Only [`HashMap`] has expected costs, due to the probabilistic nature of hashing.
|
//! Calling operations that add to a collection will occasionally require a
|
||||||
//! It is theoretically possible, though very unlikely, for [`HashMap`] to
|
//! collection to be resized - an extra operation that takes *O*(*n*) time.
|
||||||
//! experience worse performance.
|
|
||||||
//!
|
//!
|
||||||
//! ## Sequences
|
//! *Amortized* costs are calculated to account for the time cost of such resize
|
||||||
|
//! operations *over a sufficiently large series of operations*. An individual
|
||||||
|
//! operation may be slower or faster due to the sporadic nature of collection
|
||||||
|
//! resizing, however the average cost per operation will approach the amortized
|
||||||
|
//! cost.
|
||||||
//!
|
//!
|
||||||
//! | | get(i) | insert(i) | remove(i) | append | split_off(i) |
|
//! Rust's collections never automatically shrink, so removal operations aren't
|
||||||
//! |----------------|------------------------|-------------------------|------------------------|-----------|------------------------|
|
//! amortized.
|
||||||
//! | [`Vec`] | *O*(1) | *O*(*n*-*i*)* | *O*(*n*-*i*) | *O*(*m*)* | *O*(*n*-*i*) |
|
|
||||||
//! | [`VecDeque`] | *O*(1) | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) |
|
|
||||||
//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(1) | *O*(min(*i*, *n*-*i*)) |
|
|
||||||
//!
|
//!
|
||||||
//! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and
|
//! [`HashMap`] uses *expected* costs. It is theoretically possible, though very
|
||||||
//! [`VecDeque`] is generally going to be faster than [`LinkedList`].
|
//! unlikely, for [`HashMap`] to experience significantly worse performance than
|
||||||
|
//! the expected cost. This is due to the probabilistic nature of hashing - i.e.
|
||||||
|
//! it is possible to generate a duplicate hash given some input key that will
|
||||||
|
//! requires extra computation to correct.
|
||||||
//!
|
//!
|
||||||
//! ## Maps
|
//! ## Cost of Collection Operations
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//! | | get(i) | insert(i) | remove(i) | append(Vec(m)) | split_off(i) | range | append |
|
||||||
|
//! |----------------|------------------------|-------------------------|------------------------|-------------------|------------------------|-----------------|--------------|
|
||||||
|
//! | [`Vec`] | *O*(1) | *O*(*n*-*i*)* | *O*(*n*-*i*) | *O*(*m*)* | *O*(*n*-*i*) | N/A | N/A |
|
||||||
|
//! | [`VecDeque`] | *O*(1) | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) | N/A | N/A |
|
||||||
|
//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*)) | *O*(1) | *O*(min(*i*, *n*-*i*)) | N/A | N/A |
|
||||||
|
//! | [`HashMap`] | *O*(1)~ | *O*(1)~* | *O*(1)~ | N/A | N/A | N/A | N/A |
|
||||||
|
//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | N/A | N/A | *O*(log(*n*)) | *O*(*n*+*m*) |
|
||||||
|
//!
|
||||||
|
//! Note that where ties occur, [`Vec`] is generally going to be faster than
|
||||||
|
//! [`VecDeque`], and [`VecDeque`] is generally going to be faster than
|
||||||
|
//! [`LinkedList`].
|
||||||
//!
|
//!
|
||||||
//! For Sets, all operations have the cost of the equivalent Map operation.
|
//! For Sets, all operations have the cost of the equivalent Map operation.
|
||||||
//!
|
//!
|
||||||
//! | | get | insert | remove | range | append |
|
|
||||||
//! |--------------|---------------|---------------|---------------|---------------|--------------|
|
|
||||||
//! | [`HashMap`] | *O*(1)~ | *O*(1)~* | *O*(1)~ | N/A | N/A |
|
|
||||||
//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(*n*+*m*) |
|
|
||||||
//!
|
|
||||||
//! # Correct and Efficient Usage of Collections
|
//! # Correct and Efficient Usage of Collections
|
||||||
//!
|
//!
|
||||||
//! Of course, knowing which collection is the right one for the job doesn't
|
//! Of course, knowing which collection is the right one for the job doesn't
|
||||||
|
@ -122,6 +122,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
|
|||||||
c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
|
c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
|
||||||
c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
|
c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
|
||||||
c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename,
|
c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename,
|
||||||
|
c::ERROR_CANT_RESOLVE_FILENAME => return FilesystemLoop,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,6 +140,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
|
|||||||
c::WSAEHOSTUNREACH => HostUnreachable,
|
c::WSAEHOSTUNREACH => HostUnreachable,
|
||||||
c::WSAENETDOWN => NetworkDown,
|
c::WSAENETDOWN => NetworkDown,
|
||||||
c::WSAENETUNREACH => NetworkUnreachable,
|
c::WSAENETUNREACH => NetworkUnreachable,
|
||||||
|
c::WSAEDQUOT => FilesystemQuotaExceeded,
|
||||||
|
|
||||||
_ => Uncategorized,
|
_ => Uncategorized,
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
use std::{env, fs, str};
|
use std::{env, fs, str};
|
||||||
|
|
||||||
|
use build_helper::git::get_closest_merge_commit;
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
use crate::core::build_steps::tool::SourceType;
|
use crate::core::build_steps::tool::SourceType;
|
||||||
@ -26,8 +27,7 @@ use crate::core::builder::{
|
|||||||
use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
|
use crate::core::config::{DebuginfoLevel, LlvmLibunwind, RustcLto, TargetSelection};
|
||||||
use crate::utils::exec::command;
|
use crate::utils::exec::command;
|
||||||
use crate::utils::helpers::{
|
use crate::utils::helpers::{
|
||||||
self, exe, get_clang_cl_resource_dir, get_closest_merge_base_commit, is_debug_info, is_dylib,
|
self, exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
|
||||||
symlink_dir, t, up_to_date,
|
|
||||||
};
|
};
|
||||||
use crate::{CLang, Compiler, DependencyType, GitRepo, Mode, LLVM_TOOLS};
|
use crate::{CLang, Compiler, DependencyType, GitRepo, Mode, LLVM_TOOLS};
|
||||||
|
|
||||||
@ -127,13 +127,9 @@ impl Step for Std {
|
|||||||
// the `rust.download-rustc=true` option.
|
// the `rust.download-rustc=true` option.
|
||||||
let force_recompile =
|
let force_recompile =
|
||||||
if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() {
|
if builder.rust_info().is_managed_git_subrepository() && builder.download_rustc() {
|
||||||
let closest_merge_commit = get_closest_merge_base_commit(
|
let closest_merge_commit =
|
||||||
Some(&builder.src),
|
get_closest_merge_commit(Some(&builder.src), &builder.config.git_config(), &[])
|
||||||
&builder.config.git_config(),
|
.unwrap();
|
||||||
&builder.config.stage0_metadata.config.git_merge_commit_email,
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Check if `library` has changes (returns false otherwise)
|
// Check if `library` has changes (returns false otherwise)
|
||||||
!t!(helpers::git(Some(&builder.src))
|
!t!(helpers::git(Some(&builder.src))
|
||||||
|
@ -200,6 +200,11 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
|
|||||||
adjective = Some("modified");
|
adjective = Some("modified");
|
||||||
match get_modified_rs_files(build) {
|
match get_modified_rs_files(build) {
|
||||||
Ok(Some(files)) => {
|
Ok(Some(files)) => {
|
||||||
|
if files.is_empty() {
|
||||||
|
println!("fmt info: No modified files detected for formatting.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for file in files {
|
for file in files {
|
||||||
override_builder.add(&format!("/{file}")).expect(&file);
|
override_builder.add(&format!("/{file}")).expect(&file);
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ use std::sync::OnceLock;
|
|||||||
use std::{env, io};
|
use std::{env, io};
|
||||||
|
|
||||||
use build_helper::ci::CiEnv;
|
use build_helper::ci::CiEnv;
|
||||||
|
use build_helper::git::get_closest_merge_commit;
|
||||||
|
|
||||||
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
|
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
|
||||||
use crate::core::config::{Config, TargetSelection};
|
use crate::core::config::{Config, TargetSelection};
|
||||||
@ -153,10 +154,9 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L
|
|||||||
/// This retrieves the LLVM sha we *want* to use, according to git history.
|
/// This retrieves the LLVM sha we *want* to use, according to git history.
|
||||||
pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
|
pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
|
||||||
let llvm_sha = if is_git {
|
let llvm_sha = if is_git {
|
||||||
helpers::get_closest_merge_base_commit(
|
get_closest_merge_commit(
|
||||||
Some(&config.src),
|
Some(&config.src),
|
||||||
&config.git_config(),
|
&config.git_config(),
|
||||||
&config.stage0_metadata.config.git_merge_commit_email,
|
|
||||||
&[
|
&[
|
||||||
config.src.join("src/llvm-project"),
|
config.src.join("src/llvm-project"),
|
||||||
config.src.join("src/bootstrap/download-ci-llvm-stamp"),
|
config.src.join("src/bootstrap/download-ci-llvm-stamp"),
|
||||||
|
@ -17,6 +17,7 @@ pub fn suggest(builder: &Builder<'_>, run: bool) {
|
|||||||
.tool_cmd(Tool::SuggestTests)
|
.tool_cmd(Tool::SuggestTests)
|
||||||
.env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository)
|
.env("SUGGEST_TESTS_GIT_REPOSITORY", git_config.git_repository)
|
||||||
.env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch)
|
.env("SUGGEST_TESTS_NIGHTLY_BRANCH", git_config.nightly_branch)
|
||||||
|
.env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL", git_config.git_merge_commit_email)
|
||||||
.run_capture_stdout(builder)
|
.run_capture_stdout(builder)
|
||||||
.stdout();
|
.stdout();
|
||||||
|
|
||||||
|
@ -2098,6 +2098,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
|
|||||||
let git_config = builder.config.git_config();
|
let git_config = builder.config.git_config();
|
||||||
cmd.arg("--git-repository").arg(git_config.git_repository);
|
cmd.arg("--git-repository").arg(git_config.git_repository);
|
||||||
cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
|
cmd.arg("--nightly-branch").arg(git_config.nightly_branch);
|
||||||
|
cmd.arg("--git-merge-commit-email").arg(git_config.git_merge_commit_email);
|
||||||
cmd.force_coloring_in_ci();
|
cmd.force_coloring_in_ci();
|
||||||
|
|
||||||
#[cfg(feature = "build-metrics")]
|
#[cfg(feature = "build-metrics")]
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
|
use build_helper::git::get_closest_merge_commit;
|
||||||
|
|
||||||
use crate::core::build_steps::compile;
|
use crate::core::build_steps::compile;
|
||||||
use crate::core::build_steps::toolstate::ToolState;
|
use crate::core::build_steps::toolstate::ToolState;
|
||||||
use crate::core::builder;
|
use crate::core::builder;
|
||||||
@ -8,7 +10,7 @@ use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun,
|
|||||||
use crate::core::config::TargetSelection;
|
use crate::core::config::TargetSelection;
|
||||||
use crate::utils::channel::GitInfo;
|
use crate::utils::channel::GitInfo;
|
||||||
use crate::utils::exec::{command, BootstrapCommand};
|
use crate::utils::exec::{command, BootstrapCommand};
|
||||||
use crate::utils::helpers::{add_dylib_path, exe, get_closest_merge_base_commit, git, t};
|
use crate::utils::helpers::{add_dylib_path, exe, git, t};
|
||||||
use crate::{gha, Compiler, Kind, Mode};
|
use crate::{gha, Compiler, Kind, Mode};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
@ -576,10 +578,9 @@ impl Step for Rustdoc {
|
|||||||
&& target_compiler.stage > 0
|
&& target_compiler.stage > 0
|
||||||
&& builder.rust_info().is_managed_git_subrepository()
|
&& builder.rust_info().is_managed_git_subrepository()
|
||||||
{
|
{
|
||||||
let commit = get_closest_merge_base_commit(
|
let commit = get_closest_merge_commit(
|
||||||
Some(&builder.config.src),
|
Some(&builder.config.src),
|
||||||
&builder.config.git_config(),
|
&builder.config.git_config(),
|
||||||
&builder.config.stage0_metadata.config.git_merge_commit_email,
|
|
||||||
&[],
|
&[],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -14,7 +14,7 @@ use std::sync::OnceLock;
|
|||||||
use std::{cmp, env, fs};
|
use std::{cmp, env, fs};
|
||||||
|
|
||||||
use build_helper::exit;
|
use build_helper::exit;
|
||||||
use build_helper::git::{output_result, GitConfig};
|
use build_helper::git::{get_closest_merge_commit, output_result, GitConfig};
|
||||||
use serde::{Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer};
|
||||||
use serde_derive::Deserialize;
|
use serde_derive::Deserialize;
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ pub use crate::core::config::flags::Subcommand;
|
|||||||
use crate::core::config::flags::{Color, Flags, Warnings};
|
use crate::core::config::flags::{Color, Flags, Warnings};
|
||||||
use crate::utils::cache::{Interned, INTERNER};
|
use crate::utils::cache::{Interned, INTERNER};
|
||||||
use crate::utils::channel::{self, GitInfo};
|
use crate::utils::channel::{self, GitInfo};
|
||||||
use crate::utils::helpers::{self, exe, get_closest_merge_base_commit, output, t};
|
use crate::utils::helpers::{self, exe, output, t};
|
||||||
|
|
||||||
macro_rules! check_ci_llvm {
|
macro_rules! check_ci_llvm {
|
||||||
($name:expr) => {
|
($name:expr) => {
|
||||||
@ -2512,6 +2512,7 @@ impl Config {
|
|||||||
GitConfig {
|
GitConfig {
|
||||||
git_repository: &self.stage0_metadata.config.git_repository,
|
git_repository: &self.stage0_metadata.config.git_repository,
|
||||||
nightly_branch: &self.stage0_metadata.config.nightly_branch,
|
nightly_branch: &self.stage0_metadata.config.nightly_branch,
|
||||||
|
git_merge_commit_email: &self.stage0_metadata.config.git_merge_commit_email,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2688,13 +2689,7 @@ impl Config {
|
|||||||
|
|
||||||
// Look for a version to compare to based on the current commit.
|
// Look for a version to compare to based on the current commit.
|
||||||
// Only commits merged by bors will have CI artifacts.
|
// Only commits merged by bors will have CI artifacts.
|
||||||
let commit = get_closest_merge_base_commit(
|
let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap();
|
||||||
Some(&self.src),
|
|
||||||
&self.git_config(),
|
|
||||||
&self.stage0_metadata.config.git_merge_commit_email,
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
if commit.is_empty() {
|
if commit.is_empty() {
|
||||||
println!("ERROR: could not find commit hash for downloading rustc");
|
println!("ERROR: could not find commit hash for downloading rustc");
|
||||||
println!("HELP: maybe your repository history is too shallow?");
|
println!("HELP: maybe your repository history is too shallow?");
|
||||||
@ -2786,13 +2781,7 @@ impl Config {
|
|||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
// Look for a version to compare to based on the current commit.
|
// Look for a version to compare to based on the current commit.
|
||||||
// Only commits merged by bors will have CI artifacts.
|
// Only commits merged by bors will have CI artifacts.
|
||||||
let commit = get_closest_merge_base_commit(
|
let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap();
|
||||||
Some(&self.src),
|
|
||||||
&self.git_config(),
|
|
||||||
&self.stage0_metadata.config.git_merge_commit_email,
|
|
||||||
&[],
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
if commit.is_empty() {
|
if commit.is_empty() {
|
||||||
println!("error: could not find commit hash for downloading components from CI");
|
println!("error: could not find commit hash for downloading components from CI");
|
||||||
println!("help: maybe your repository history is too shallow?");
|
println!("help: maybe your repository history is too shallow?");
|
||||||
|
@ -10,7 +10,6 @@ use std::sync::OnceLock;
|
|||||||
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
use std::time::{Instant, SystemTime, UNIX_EPOCH};
|
||||||
use std::{env, fs, io, str};
|
use std::{env, fs, io, str};
|
||||||
|
|
||||||
use build_helper::git::{get_git_merge_base, output_result, GitConfig};
|
|
||||||
use build_helper::util::fail;
|
use build_helper::util::fail;
|
||||||
|
|
||||||
use crate::core::builder::Builder;
|
use crate::core::builder::Builder;
|
||||||
@ -523,28 +522,6 @@ pub fn git(source_dir: Option<&Path>) -> BootstrapCommand {
|
|||||||
git
|
git
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the closest commit available from upstream for the given `author` and `target_paths`.
|
|
||||||
///
|
|
||||||
/// If it fails to find the commit from upstream using `git merge-base`, fallbacks to HEAD.
|
|
||||||
pub fn get_closest_merge_base_commit(
|
|
||||||
source_dir: Option<&Path>,
|
|
||||||
config: &GitConfig<'_>,
|
|
||||||
author: &str,
|
|
||||||
target_paths: &[PathBuf],
|
|
||||||
) -> Result<String, String> {
|
|
||||||
let mut git = git(source_dir);
|
|
||||||
|
|
||||||
let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into());
|
|
||||||
|
|
||||||
git.args(["rev-list", &format!("--author={author}"), "-n1", "--first-parent", &merge_base]);
|
|
||||||
|
|
||||||
if !target_paths.is_empty() {
|
|
||||||
git.arg("--").args(target_paths);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(output_result(git.as_command_mut())?.trim().to_owned())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the file times for a given file at `path`.
|
/// Sets the file times for a given file at `path`.
|
||||||
pub fn set_file_times<P: AsRef<Path>>(path: P, times: fs::FileTimes) -> io::Result<()> {
|
pub fn set_file_times<P: AsRef<Path>>(path: P, times: fs::FileTimes) -> io::Result<()> {
|
||||||
// Windows requires file to be writable to modify file times. But on Linux CI the file does not
|
// Windows requires file to be writable to modify file times. But on Linux CI the file does not
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use std::path::Path;
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
pub struct GitConfig<'a> {
|
pub struct GitConfig<'a> {
|
||||||
pub git_repository: &'a str,
|
pub git_repository: &'a str,
|
||||||
pub nightly_branch: &'a str,
|
pub nightly_branch: &'a str,
|
||||||
|
pub git_merge_commit_email: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Runs a command and returns the output
|
/// Runs a command and returns the output
|
||||||
@ -95,7 +96,11 @@ pub fn updated_master_branch(
|
|||||||
Err("Cannot find any suitable upstream master branch".to_owned())
|
Err("Cannot find any suitable upstream master branch".to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_git_merge_base(
|
/// Finds the nearest merge commit by comparing the local `HEAD` with the upstream branch's state.
|
||||||
|
/// To work correctly, the upstream remote must be properly configured using `git remote add <name> <url>`.
|
||||||
|
/// In most cases `get_closest_merge_commit` is the function you are looking for as it doesn't require remote
|
||||||
|
/// to be configured.
|
||||||
|
fn git_upstream_merge_base(
|
||||||
config: &GitConfig<'_>,
|
config: &GitConfig<'_>,
|
||||||
git_dir: Option<&Path>,
|
git_dir: Option<&Path>,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
@ -107,6 +112,38 @@ pub fn get_git_merge_base(
|
|||||||
Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned())
|
Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Searches for the nearest merge commit in the repository that also exists upstream.
|
||||||
|
///
|
||||||
|
/// If it fails to find the upstream remote, it then looks for the most recent commit made
|
||||||
|
/// by the merge bot by matching the author's email address with the merge bot's email.
|
||||||
|
pub fn get_closest_merge_commit(
|
||||||
|
git_dir: Option<&Path>,
|
||||||
|
config: &GitConfig<'_>,
|
||||||
|
target_paths: &[PathBuf],
|
||||||
|
) -> Result<String, String> {
|
||||||
|
let mut git = Command::new("git");
|
||||||
|
|
||||||
|
if let Some(git_dir) = git_dir {
|
||||||
|
git.current_dir(git_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
let merge_base = git_upstream_merge_base(config, git_dir).unwrap_or_else(|_| "HEAD".into());
|
||||||
|
|
||||||
|
git.args([
|
||||||
|
"rev-list",
|
||||||
|
&format!("--author={}", config.git_merge_commit_email),
|
||||||
|
"-n1",
|
||||||
|
"--first-parent",
|
||||||
|
&merge_base,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if !target_paths.is_empty() {
|
||||||
|
git.arg("--").args(target_paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(output_result(&mut git)?.trim().to_owned())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the files that have been modified in the current branch compared to the master branch.
|
/// Returns the files that have been modified in the current branch compared to the master branch.
|
||||||
/// The `extensions` parameter can be used to filter the files by their extension.
|
/// The `extensions` parameter can be used to filter the files by their extension.
|
||||||
/// Does not include removed files.
|
/// Does not include removed files.
|
||||||
@ -116,7 +153,7 @@ pub fn get_git_modified_files(
|
|||||||
git_dir: Option<&Path>,
|
git_dir: Option<&Path>,
|
||||||
extensions: &[&str],
|
extensions: &[&str],
|
||||||
) -> Result<Option<Vec<String>>, String> {
|
) -> Result<Option<Vec<String>>, String> {
|
||||||
let merge_base = get_git_merge_base(config, git_dir)?;
|
let merge_base = get_closest_merge_commit(git_dir, config, &[])?;
|
||||||
|
|
||||||
let mut git = Command::new("git");
|
let mut git = Command::new("git");
|
||||||
if let Some(git_dir) = git_dir {
|
if let Some(git_dir) = git_dir {
|
||||||
|
@ -384,6 +384,7 @@ pub struct Config {
|
|||||||
// Needed both to construct build_helper::git::GitConfig
|
// Needed both to construct build_helper::git::GitConfig
|
||||||
pub git_repository: String,
|
pub git_repository: String,
|
||||||
pub nightly_branch: String,
|
pub nightly_branch: String,
|
||||||
|
pub git_merge_commit_email: String,
|
||||||
|
|
||||||
/// True if the profiler runtime is enabled for this target.
|
/// True if the profiler runtime is enabled for this target.
|
||||||
/// Used by the "needs-profiler-support" header in test files.
|
/// Used by the "needs-profiler-support" header in test files.
|
||||||
@ -461,7 +462,11 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn git_config(&self) -> GitConfig<'_> {
|
pub fn git_config(&self) -> GitConfig<'_> {
|
||||||
GitConfig { git_repository: &self.git_repository, nightly_branch: &self.nightly_branch }
|
GitConfig {
|
||||||
|
git_repository: &self.git_repository,
|
||||||
|
nightly_branch: &self.nightly_branch,
|
||||||
|
git_merge_commit_email: &self.git_merge_commit_email,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +148,7 @@ impl ConfigBuilder {
|
|||||||
self.target.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
|
self.target.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
|
||||||
"--git-repository=",
|
"--git-repository=",
|
||||||
"--nightly-branch=",
|
"--nightly-branch=",
|
||||||
|
"--git-merge-commit-email=",
|
||||||
];
|
];
|
||||||
let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
|
let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
|
||||||
|
|
||||||
|
@ -163,7 +163,13 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||||||
)
|
)
|
||||||
.optopt("", "edition", "default Rust edition", "EDITION")
|
.optopt("", "edition", "default Rust edition", "EDITION")
|
||||||
.reqopt("", "git-repository", "name of the git repository", "ORG/REPO")
|
.reqopt("", "git-repository", "name of the git repository", "ORG/REPO")
|
||||||
.reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH");
|
.reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH")
|
||||||
|
.reqopt(
|
||||||
|
"",
|
||||||
|
"git-merge-commit-email",
|
||||||
|
"email address used for finding merge commits",
|
||||||
|
"EMAIL",
|
||||||
|
);
|
||||||
|
|
||||||
let (argv0, args_) = args.split_first().unwrap();
|
let (argv0, args_) = args.split_first().unwrap();
|
||||||
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
|
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
|
||||||
@ -346,6 +352,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
|
|||||||
|
|
||||||
git_repository: matches.opt_str("git-repository").unwrap(),
|
git_repository: matches.opt_str("git-repository").unwrap(),
|
||||||
nightly_branch: matches.opt_str("nightly-branch").unwrap(),
|
nightly_branch: matches.opt_str("nightly-branch").unwrap(),
|
||||||
|
git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(),
|
||||||
|
|
||||||
profiler_support: matches.opt_present("profiler-support"),
|
profiler_support: matches.opt_present("profiler-support"),
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ fn main() -> ExitCode {
|
|||||||
&GitConfig {
|
&GitConfig {
|
||||||
git_repository: &env("SUGGEST_TESTS_GIT_REPOSITORY"),
|
git_repository: &env("SUGGEST_TESTS_GIT_REPOSITORY"),
|
||||||
nightly_branch: &env("SUGGEST_TESTS_NIGHTLY_BRANCH"),
|
nightly_branch: &env("SUGGEST_TESTS_NIGHTLY_BRANCH"),
|
||||||
|
git_merge_commit_email: &env("SUGGEST_TESTS_MERGE_COMMIT_EMAIL"),
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
&Vec::new(),
|
&Vec::new(),
|
||||||
|
@ -12,6 +12,7 @@ extern crate std;
|
|||||||
extern crate test;
|
extern crate test;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[rustc_test_marker = "m_test"]
|
#[rustc_test_marker = "m_test"]
|
||||||
|
#[doc(hidden)]
|
||||||
pub const m_test: test::TestDescAndFn =
|
pub const m_test: test::TestDescAndFn =
|
||||||
test::TestDescAndFn {
|
test::TestDescAndFn {
|
||||||
desc: test::TestDesc {
|
desc: test::TestDesc {
|
||||||
@ -36,6 +37,7 @@ fn m_test() {}
|
|||||||
extern crate test;
|
extern crate test;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[rustc_test_marker = "z_test"]
|
#[rustc_test_marker = "z_test"]
|
||||||
|
#[doc(hidden)]
|
||||||
pub const z_test: test::TestDescAndFn =
|
pub const z_test: test::TestDescAndFn =
|
||||||
test::TestDescAndFn {
|
test::TestDescAndFn {
|
||||||
desc: test::TestDesc {
|
desc: test::TestDesc {
|
||||||
@ -61,6 +63,7 @@ fn z_test() {}
|
|||||||
extern crate test;
|
extern crate test;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[rustc_test_marker = "a_test"]
|
#[rustc_test_marker = "a_test"]
|
||||||
|
#[doc(hidden)]
|
||||||
pub const a_test: test::TestDescAndFn =
|
pub const a_test: test::TestDescAndFn =
|
||||||
test::TestDescAndFn {
|
test::TestDescAndFn {
|
||||||
desc: test::TestDesc {
|
desc: test::TestDesc {
|
||||||
@ -83,7 +86,7 @@ pub const a_test: test::TestDescAndFn =
|
|||||||
fn a_test() {}
|
fn a_test() {}
|
||||||
#[rustc_main]
|
#[rustc_main]
|
||||||
#[coverage(off)]
|
#[coverage(off)]
|
||||||
#[allow(missing_docs)]
|
#[doc(hidden)]
|
||||||
pub fn main() -> () {
|
pub fn main() -> () {
|
||||||
extern crate test;
|
extern crate test;
|
||||||
test::test_main_static(&[&a_test, &m_test, &z_test])
|
test::test_main_static(&[&a_test, &m_test, &z_test])
|
||||||
|
@ -8,5 +8,4 @@ fn main() {
|
|||||||
foo(|| bar())
|
foo(|| bar())
|
||||||
//~^ ERROR mismatched types [E0308]
|
//~^ ERROR mismatched types [E0308]
|
||||||
//~| HELP consider using a semicolon here
|
//~| HELP consider using a semicolon here
|
||||||
//~| HELP try adding a return type
|
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,6 @@ help: consider using a semicolon here
|
|||||||
|
|
|
|
||||||
LL | foo(|| { bar(); })
|
LL | foo(|| { bar(); })
|
||||||
| + +++
|
| + +++
|
||||||
help: try adding a return type
|
|
||||||
|
|
|
||||||
LL | foo(|| -> i32 bar())
|
|
||||||
| ++++++
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
@ -3,12 +3,22 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia
|
|||||||
|
|
|
|
||||||
LL | E::Empty3 => ()
|
LL | E::Empty3 => ()
|
||||||
| ^^^^^^^^^ not a unit struct, unit variant or constant
|
| ^^^^^^^^^ not a unit struct, unit variant or constant
|
||||||
|
|
|
||||||
|
help: use the struct variant pattern syntax
|
||||||
|
|
|
||||||
|
LL | E::Empty3 {} => ()
|
||||||
|
| ++
|
||||||
|
|
||||||
error[E0533]: expected unit struct, unit variant or constant, found struct variant `XE::XEmpty3`
|
error[E0533]: expected unit struct, unit variant or constant, found struct variant `XE::XEmpty3`
|
||||||
--> $DIR/empty-struct-braces-pat-1.rs:31:9
|
--> $DIR/empty-struct-braces-pat-1.rs:31:9
|
||||||
|
|
|
|
||||||
LL | XE::XEmpty3 => ()
|
LL | XE::XEmpty3 => ()
|
||||||
| ^^^^^^^^^^^ not a unit struct, unit variant or constant
|
| ^^^^^^^^^^^ not a unit struct, unit variant or constant
|
||||||
|
|
|
||||||
|
help: use the struct variant pattern syntax
|
||||||
|
|
|
||||||
|
LL | XE::XEmpty3 {} => ()
|
||||||
|
| ++
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -3,24 +3,44 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `E::E
|
|||||||
|
|
|
|
||||||
LL | E::Empty3() => ()
|
LL | E::Empty3() => ()
|
||||||
| ^^^^^^^^^^^ not a tuple struct or tuple variant
|
| ^^^^^^^^^^^ not a tuple struct or tuple variant
|
||||||
|
|
|
||||||
|
help: use the struct variant pattern syntax
|
||||||
|
|
|
||||||
|
LL | E::Empty3 {} => ()
|
||||||
|
| ~~
|
||||||
|
|
||||||
error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
|
error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
|
||||||
--> $DIR/empty-struct-braces-pat-3.rs:21:9
|
--> $DIR/empty-struct-braces-pat-3.rs:21:9
|
||||||
|
|
|
|
||||||
LL | XE::XEmpty3() => ()
|
LL | XE::XEmpty3() => ()
|
||||||
| ^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
| ^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
||||||
|
|
|
||||||
|
help: use the struct variant pattern syntax
|
||||||
|
|
|
||||||
|
LL | XE::XEmpty3 {} => ()
|
||||||
|
| ~~
|
||||||
|
|
||||||
error[E0164]: expected tuple struct or tuple variant, found struct variant `E::Empty3`
|
error[E0164]: expected tuple struct or tuple variant, found struct variant `E::Empty3`
|
||||||
--> $DIR/empty-struct-braces-pat-3.rs:25:9
|
--> $DIR/empty-struct-braces-pat-3.rs:25:9
|
||||||
|
|
|
|
||||||
LL | E::Empty3(..) => ()
|
LL | E::Empty3(..) => ()
|
||||||
| ^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
| ^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
||||||
|
|
|
||||||
|
help: use the struct variant pattern syntax
|
||||||
|
|
|
||||||
|
LL | E::Empty3 {} => ()
|
||||||
|
| ~~
|
||||||
|
|
||||||
error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
|
error[E0164]: expected tuple struct or tuple variant, found struct variant `XE::XEmpty3`
|
||||||
--> $DIR/empty-struct-braces-pat-3.rs:29:9
|
--> $DIR/empty-struct-braces-pat-3.rs:29:9
|
||||||
|
|
|
|
||||||
LL | XE::XEmpty3(..) => ()
|
LL | XE::XEmpty3(..) => ()
|
||||||
| ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
| ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
||||||
|
|
|
||||||
|
help: use the struct variant pattern syntax
|
||||||
|
|
|
||||||
|
LL | XE::XEmpty3 {} => ()
|
||||||
|
| ~~
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
@ -12,6 +12,11 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia
|
|||||||
|
|
|
|
||||||
LL | MyEnum::Struct => "",
|
LL | MyEnum::Struct => "",
|
||||||
| ^^^^^^^^^^^^^^ not a unit struct, unit variant or constant
|
| ^^^^^^^^^^^^^^ not a unit struct, unit variant or constant
|
||||||
|
|
|
||||||
|
help: the struct variant's field is being ignored
|
||||||
|
|
|
||||||
|
LL | MyEnum::Struct { s: _ } => "",
|
||||||
|
| ++++++++
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -2,4 +2,9 @@
|
|||||||
//! on the generated test harness.
|
//! on the generated test harness.
|
||||||
|
|
||||||
//@ check-pass
|
//@ check-pass
|
||||||
//@ compile-flags: --test -Dmissing_docs
|
//@ compile-flags: --test
|
||||||
|
|
||||||
|
#![forbid(missing_docs)]
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {}
|
||||||
|
@ -11,6 +11,7 @@ note: the method `to_string` exists on the type `&u8`
|
|||||||
= note: the following trait bounds were not satisfied:
|
= note: the following trait bounds were not satisfied:
|
||||||
`*const u8: std::fmt::Display`
|
`*const u8: std::fmt::Display`
|
||||||
which is required by `*const u8: ToString`
|
which is required by `*const u8: ToString`
|
||||||
|
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||||
|
|
||||||
error[E0599]: `*mut u8` doesn't implement `std::fmt::Display`
|
error[E0599]: `*mut u8` doesn't implement `std::fmt::Display`
|
||||||
--> $DIR/suggest-convert-ptr-to-ref.rs:8:22
|
--> $DIR/suggest-convert-ptr-to-ref.rs:8:22
|
||||||
@ -25,6 +26,7 @@ note: the method `to_string` exists on the type `&&mut u8`
|
|||||||
= note: the following trait bounds were not satisfied:
|
= note: the following trait bounds were not satisfied:
|
||||||
`*mut u8: std::fmt::Display`
|
`*mut u8: std::fmt::Display`
|
||||||
which is required by `*mut u8: ToString`
|
which is required by `*mut u8: ToString`
|
||||||
|
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
|
||||||
|
|
||||||
error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*mut u8` in the current scope
|
error[E0599]: no method named `make_ascii_lowercase` found for raw pointer `*mut u8` in the current scope
|
||||||
--> $DIR/suggest-convert-ptr-to-ref.rs:9:7
|
--> $DIR/suggest-convert-ptr-to-ref.rs:9:7
|
||||||
|
@ -19,6 +19,11 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `Enum
|
|||||||
|
|
|
|
||||||
LL | Enum::Foo(a, b) => {}
|
LL | Enum::Foo(a, b) => {}
|
||||||
| ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
| ^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
||||||
|
|
|
||||||
|
help: the struct variant's fields are being ignored
|
||||||
|
|
|
||||||
|
LL | Enum::Foo { a: _, b: _ } => {}
|
||||||
|
| ~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error[E0769]: tuple variant `Enum::Bar` written as struct variant
|
error[E0769]: tuple variant `Enum::Bar` written as struct variant
|
||||||
--> $DIR/recover-from-bad-variant.rs:12:9
|
--> $DIR/recover-from-bad-variant.rs:12:9
|
||||||
|
@ -12,6 +12,11 @@ error[E0164]: expected tuple struct or tuple variant, found struct variant `Farm
|
|||||||
|
|
|
|
||||||
LL | FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(),
|
LL | FarmAnimal::Chicken(_) => "cluck, cluck!".to_string(),
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
| ^^^^^^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
||||||
|
|
|
||||||
|
help: the struct variant's field is being ignored
|
||||||
|
|
|
||||||
|
LL | FarmAnimal::Chicken { num_eggs: _ } => "cluck, cluck!".to_string(),
|
||||||
|
| ~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
fn main() -> Result<(), ()> {
|
fn main() -> Result<(), ()> {
|
||||||
a(|| {
|
a(|| {
|
||||||
//~^ HELP: try adding a return type
|
|
||||||
b()
|
b()
|
||||||
//~^ ERROR: mismatched types [E0308]
|
//~^ ERROR: mismatched types [E0308]
|
||||||
//~| NOTE: expected `()`, found `i32`
|
//~| NOTE: expected `()`, found `i32`
|
||||||
|
@ -1,20 +1,13 @@
|
|||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/try-operator-dont-suggest-semicolon.rs:7:9
|
--> $DIR/try-operator-dont-suggest-semicolon.rs:6:9
|
||||||
|
|
|
|
||||||
LL | b()
|
LL | b()
|
||||||
| ^^^ expected `()`, found `i32`
|
| ^^^- help: consider using a semicolon here: `;`
|
||||||
|
|
| |
|
||||||
help: consider using a semicolon here
|
| expected `()`, found `i32`
|
||||||
|
|
|
||||||
LL | b();
|
|
||||||
| +
|
|
||||||
help: try adding a return type
|
|
||||||
|
|
|
||||||
LL | a(|| -> i32 {
|
|
||||||
| ++++++
|
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/try-operator-dont-suggest-semicolon.rs:17:9
|
--> $DIR/try-operator-dont-suggest-semicolon.rs:16:9
|
||||||
|
|
|
|
||||||
LL | / if true {
|
LL | / if true {
|
||||||
LL | |
|
LL | |
|
||||||
|
19
tests/ui/traits/custom-on-unimplemented-diagnostic.rs
Normal file
19
tests/ui/traits/custom-on-unimplemented-diagnostic.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#[diagnostic::on_unimplemented(message = "my message", label = "my label", note = "my note")]
|
||||||
|
pub trait ProviderLt {}
|
||||||
|
|
||||||
|
pub trait ProviderExt {
|
||||||
|
fn request<R>(&self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + ProviderLt> ProviderExt for T {}
|
||||||
|
|
||||||
|
struct B;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
B.request();
|
||||||
|
//~^ my message [E0599]
|
||||||
|
//~| my label
|
||||||
|
//~| my note
|
||||||
|
}
|
32
tests/ui/traits/custom-on-unimplemented-diagnostic.stderr
Normal file
32
tests/ui/traits/custom-on-unimplemented-diagnostic.stderr
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
error[E0599]: my message
|
||||||
|
--> $DIR/custom-on-unimplemented-diagnostic.rs:15:7
|
||||||
|
|
|
||||||
|
LL | struct B;
|
||||||
|
| -------- method `request` not found for this struct because it doesn't satisfy `B: ProviderExt` or `B: ProviderLt`
|
||||||
|
...
|
||||||
|
LL | B.request();
|
||||||
|
| ^^^^^^^ my label
|
||||||
|
|
|
||||||
|
note: trait bound `B: ProviderLt` was not satisfied
|
||||||
|
--> $DIR/custom-on-unimplemented-diagnostic.rs:10:18
|
||||||
|
|
|
||||||
|
LL | impl<T: ?Sized + ProviderLt> ProviderExt for T {}
|
||||||
|
| ^^^^^^^^^^ ----------- -
|
||||||
|
| |
|
||||||
|
| unsatisfied trait bound introduced here
|
||||||
|
= note: my note
|
||||||
|
note: the trait `ProviderLt` must be implemented
|
||||||
|
--> $DIR/custom-on-unimplemented-diagnostic.rs:2:1
|
||||||
|
|
|
||||||
|
LL | pub trait ProviderLt {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
= help: items from traits can only be used if the trait is implemented and in scope
|
||||||
|
note: `ProviderExt` defines an item `request`, perhaps you need to implement it
|
||||||
|
--> $DIR/custom-on-unimplemented-diagnostic.rs:4:1
|
||||||
|
|
|
||||||
|
LL | pub trait ProviderExt {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0599`.
|
@ -14,12 +14,22 @@ error[E0533]: expected unit struct, unit variant or constant, found struct varia
|
|||||||
|
|
|
|
||||||
LL | let Alias::Braced = panic!();
|
LL | let Alias::Braced = panic!();
|
||||||
| ^^^^^^^^^^^^^ not a unit struct, unit variant or constant
|
| ^^^^^^^^^^^^^ not a unit struct, unit variant or constant
|
||||||
|
|
|
||||||
|
help: use the struct variant pattern syntax
|
||||||
|
|
|
||||||
|
LL | let Alias::Braced {} = panic!();
|
||||||
|
| ++
|
||||||
|
|
||||||
error[E0164]: expected tuple struct or tuple variant, found struct variant `Alias::Braced`
|
error[E0164]: expected tuple struct or tuple variant, found struct variant `Alias::Braced`
|
||||||
--> $DIR/incorrect-variant-form-through-alias-caught.rs:12:9
|
--> $DIR/incorrect-variant-form-through-alias-caught.rs:12:9
|
||||||
|
|
|
|
||||||
LL | let Alias::Braced(..) = panic!();
|
LL | let Alias::Braced(..) = panic!();
|
||||||
| ^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
| ^^^^^^^^^^^^^^^^^ not a tuple struct or tuple variant
|
||||||
|
|
|
||||||
|
help: use the struct variant pattern syntax
|
||||||
|
|
|
||||||
|
LL | let Alias::Braced {} = panic!();
|
||||||
|
| ~~
|
||||||
|
|
||||||
error[E0618]: expected function, found enum variant `Alias::Unit`
|
error[E0618]: expected function, found enum variant `Alias::Unit`
|
||||||
--> $DIR/incorrect-variant-form-through-alias-caught.rs:15:5
|
--> $DIR/incorrect-variant-form-through-alias-caught.rs:15:5
|
||||||
|
@ -2,9 +2,7 @@ error[E0308]: mismatched types
|
|||||||
--> $DIR/issue-81943.rs:7:9
|
--> $DIR/issue-81943.rs:7:9
|
||||||
|
|
|
|
||||||
LL | f(|x| lib::d!(x));
|
LL | f(|x| lib::d!(x));
|
||||||
| -^^^^^^^^^^ expected `()`, found `i32`
|
| ^^^^^^^^^^ expected `()`, found `i32`
|
||||||
| |
|
|
||||||
| help: try adding a return type: `-> i32`
|
|
||||||
|
|
|
|
||||||
= note: this error originates in the macro `lib::d` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the macro `lib::d` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
@ -12,22 +10,28 @@ error[E0308]: mismatched types
|
|||||||
--> $DIR/issue-81943.rs:8:28
|
--> $DIR/issue-81943.rs:8:28
|
||||||
|
|
|
|
||||||
LL | f(|x| match x { tmp => { g(tmp) } });
|
LL | f(|x| match x { tmp => { g(tmp) } });
|
||||||
| ^^^^^^ expected `()`, found `i32`
|
| -------------------^^^^^^----
|
||||||
|
| | |
|
||||||
|
| | expected `()`, found `i32`
|
||||||
|
| expected this to be `()`
|
||||||
|
|
|
|
||||||
help: consider using a semicolon here
|
help: consider using a semicolon here
|
||||||
|
|
|
|
||||||
LL | f(|x| match x { tmp => { g(tmp); } });
|
LL | f(|x| match x { tmp => { g(tmp); } });
|
||||||
| +
|
| +
|
||||||
help: try adding a return type
|
help: consider using a semicolon here
|
||||||
|
|
|
|
||||||
LL | f(|x| -> i32 match x { tmp => { g(tmp) } });
|
LL | f(|x| match x { tmp => { g(tmp) } };);
|
||||||
| ++++++
|
| +
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/issue-81943.rs:10:38
|
--> $DIR/issue-81943.rs:10:38
|
||||||
|
|
|
|
||||||
LL | ($e:expr) => { match $e { x => { g(x) } } }
|
LL | ($e:expr) => { match $e { x => { g(x) } } }
|
||||||
| ^^^^ expected `()`, found `i32`
|
| ------------------^^^^----
|
||||||
|
| | |
|
||||||
|
| | expected `()`, found `i32`
|
||||||
|
| expected this to be `()`
|
||||||
LL | }
|
LL | }
|
||||||
LL | f(|x| d!(x));
|
LL | f(|x| d!(x));
|
||||||
| ----- in this macro invocation
|
| ----- in this macro invocation
|
||||||
@ -37,10 +41,10 @@ help: consider using a semicolon here
|
|||||||
|
|
|
|
||||||
LL | ($e:expr) => { match $e { x => { g(x); } } }
|
LL | ($e:expr) => { match $e { x => { g(x); } } }
|
||||||
| +
|
| +
|
||||||
help: try adding a return type
|
help: consider using a semicolon here
|
||||||
|
|
|
|
||||||
LL | f(|x| -> i32 d!(x));
|
LL | ($e:expr) => { match $e { x => { g(x) } }; }
|
||||||
| ++++++
|
| +
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user