Auto merge of #106588 - JohnTitor:rollup-4z80tjx, r=JohnTitor

Rollup of 8 pull requests

Successful merges:

 - #103104 (Stabilize `main_separator_str`)
 - #106410 (Suggest `mut self: &mut Self` for `?Sized` impls)
 - #106457 (Adjust comments about pre-push.sh hook)
 - #106546 (jsondoclint: Check local items in `paths` are also in `index`.)
 - #106557 (Add some UI tests and reword error-code docs)
 - #106562 (Clarify examples for `VecDeque::get/get_mut`)
 - #106580 (remove unreachable error code `E0313`)
 - #106581 (Do not emit wrong E0308 suggestion for closure mismatch)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-01-08 09:00:31 +00:00
commit 8ea62f6c30
22 changed files with 268 additions and 94 deletions

View file

@ -344,20 +344,25 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
} else {
err.span_help(source_info.span, "try removing `&mut` here");
}
} else if decl.mutability == Mutability::Not
&& !matches!(
} else if decl.mutability == Mutability::Not {
if matches!(
decl.local_info,
Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf(
hir::ImplicitSelfKind::MutRef
))))
)
{
err.span_suggestion_verbose(
decl.source_info.span.shrink_to_lo(),
"consider making the binding mutable",
"mut ",
Applicability::MachineApplicable,
);
),)))
) {
err.note(
"as `Self` may be unsized, this call attempts to take `&mut &mut self`",
);
err.note("however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably");
} else {
err.span_suggestion_verbose(
decl.source_info.span.shrink_to_lo(),
"consider making the binding mutable",
"mut ",
Applicability::MachineApplicable,
);
};
}
}

View file

@ -579,8 +579,7 @@ E0791: include_str!("./error_codes/E0791.md"),
// E0300, // unexpanded macro
// E0304, // expected signed integer constant
// E0305, // expected constant
E0313, // lifetime of borrowed pointer outlives lifetime of captured
// variable
// E0313, // removed: found unreachable
// E0314, // closure outlives stack frame
// E0315, // cannot invoke closure outside of its lifetime
// E0319, // trait impls for defaulted traits allowed just for structs/enums

View file

@ -1,5 +1,4 @@
A constant item was initialized with something that is not a constant
expression.
A non-`const` function was called in a `const` context.
Erroneous code example:
@ -8,26 +7,20 @@ fn create_some() -> Option<u8> {
Some(1)
}
const FOO: Option<u8> = create_some(); // error!
// error: cannot call non-const fn `create_some` in constants
const FOO: Option<u8> = create_some();
```
The only functions that can be called in static or constant expressions are
`const` functions, and struct/enum constructors.
All functions used in a `const` context (constant or static expression) must
be marked `const`.
To fix this error, you can declare `create_some` as a constant function:
```
const fn create_some() -> Option<u8> { // declared as a const function
// declared as a `const` function:
const fn create_some() -> Option<u8> {
Some(1)
}
const FOO: Option<u8> = create_some(); // ok!
// These are also working:
struct Bar {
x: u8,
}
const OTHER_FOO: Option<u8> = Some(1);
const BAR: Bar = Bar {x: 1};
const FOO: Option<u8> = create_some(); // no error!
```

View file

@ -1379,7 +1379,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
// If we've reached our target type with just removing `&`, then just print now.
if steps == 0 {
if steps == 0 && !remove.trim().is_empty() {
return Some((
prefix_span,
format!("consider removing the `{}`", remove.trim()),
@ -1438,6 +1438,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
(prefix_span, format!("{}{}", prefix, "*".repeat(steps)))
};
if suggestion.trim().is_empty() {
return None;
}
return Some((
span,

View file

@ -1,4 +1,3 @@
// ignore-tidy-filelength
//! Error Reporting Code for the inference engine
//!
//! Because of the way inference, and in particular region inference,

View file

@ -25,16 +25,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
infer::Reborrow(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
}
infer::ReborrowUpvar(span, ref upvar_id) => {
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
RegionOriginNote::WithName {
span,
msg: fluent::infer_reborrow,
name: &var_name.to_string(),
continues: false,
}
.add_to_diagnostic(err);
}
infer::RelateObjectBound(span) => {
RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
.add_to_diagnostic(err);
@ -162,33 +152,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
);
err
}
infer::ReborrowUpvar(span, ref upvar_id) => {
let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
let mut err = struct_span_err!(
self.tcx.sess,
span,
E0313,
"lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
var_name
);
note_and_explain_region(
self.tcx,
&mut err,
"...the borrowed pointer is valid for ",
sub,
"...",
None,
);
note_and_explain_region(
self.tcx,
&mut err,
&format!("...but `{}` is only valid for ", var_name),
sup,
"",
None,
);
err
}
infer::RelateObjectBound(span) => {
let mut err = struct_span_err!(
self.tcx.sess,

View file

@ -409,9 +409,6 @@ pub enum SubregionOrigin<'tcx> {
/// Creating a pointer `b` to contents of another reference
Reborrow(Span),
/// Creating a pointer `b` to contents of an upvar
ReborrowUpvar(Span, ty::UpvarId),
/// Data with type `Ty<'tcx>` was borrowed
DataBorrowed(Ty<'tcx>, Span),
@ -1954,7 +1951,6 @@ impl<'tcx> SubregionOrigin<'tcx> {
RelateParamBound(a, ..) => a,
RelateRegionParamBound(a) => a,
Reborrow(a) => a,
ReborrowUpvar(a, _) => a,
DataBorrowed(_, a) => a,
ReferenceOutlivesReferent(_, a) => a,
CompareImplItemObligation { span, .. } => span,

View file

@ -636,6 +636,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
/// buf.push_back(3);
/// buf.push_back(4);
/// buf.push_back(5);
/// buf.push_back(6);
/// assert_eq!(buf.get(1), Some(&4));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
@ -661,10 +662,11 @@ impl<T, A: Allocator> VecDeque<T, A> {
/// buf.push_back(3);
/// buf.push_back(4);
/// buf.push_back(5);
/// buf.push_back(6);
/// assert_eq!(buf[1], 4);
/// if let Some(elem) = buf.get_mut(1) {
/// *elem = 7;
/// }
///
/// assert_eq!(buf[1], 7);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]

View file

@ -271,7 +271,7 @@ pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP;
/// The primary separator of path components for the current platform.
///
/// For example, `/` on Unix and `\` on Windows.
#[unstable(feature = "main_separator_str", issue = "94071")]
#[stable(feature = "main_separator_str", since = "CURRENT_RUSTC_VERSION")]
pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR;
////////////////////////////////////////////////////////////////////////////////

View file

@ -351,7 +351,7 @@ pub fn interactive_path() -> io::Result<Profile> {
Ok(template)
}
// install a git hook to automatically run tidy --bless, if they want
// install a git hook to automatically run tidy, if they want
fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
let git = t!(config.git().args(&["rev-parse", "--git-common-dir"]).output().map(|output| {
assert!(output.status.success(), "failed to run `git`");
@ -367,7 +367,7 @@ fn install_git_hook_maybe(config: &Config) -> io::Result<()> {
println!();
println!(
"Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` before
If you'd like, x.py can install a git hook for you that will automatically run `test tidy` before
pushing your code to ensure your code is up to par. If you decide later that this behavior is
undesirable, simply delete the `pre-push` file from .git/hooks."
);

View file

@ -1,6 +1,6 @@
#!/usr/bin/env bash
#
# Call `tidy --bless` before git push
# Call `tidy` before git push
# Copy this script to .git/hooks to activate,
# and remove it from .git/hooks to deactivate.
#

View file

@ -0,0 +1,15 @@
trait Modify {
fn modify(&mut self) ;
}
impl<T> Modify for T {
fn modify(&mut self) {}
}
trait Foo {
fn mute(&mut self) {
self.modify(); //~ ERROR cannot borrow `self` as mutable
}
}
fn main() {}

View file

@ -0,0 +1,12 @@
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
--> $DIR/issue-93078.rs:11:9
|
LL | self.modify();
| ^^^^^^^^^^^^^ cannot borrow as mutable
|
= note: as `Self` may be unsized, this call attempts to take `&mut &mut self`
= note: however, `&mut self` expands to `self: &mut Self`, therefore `self` cannot be borrowed mutably
error: aborting due to previous error
For more information about this error, try `rustc --explain E0596`.

View file

@ -0,0 +1,4 @@
static X: i32 = 42;
const Y: i32 = X; //~ ERROR constants cannot refer to statics [E0013]
fn main() {}

View file

@ -0,0 +1,11 @@
error[E0013]: constants cannot refer to statics
--> $DIR/E0013.rs:2:16
|
LL | const Y: i32 = X;
| ^
|
= help: consider extracting the value of the `static` to a `const`, and referring to that
error: aborting due to previous error
For more information about this error, try `rustc --explain E0013`.

View file

@ -0,0 +1,8 @@
fn create_some() -> Option<u8> {
Some(1)
}
const FOO: Option<u8> = create_some();
//~^ ERROR cannot call non-const fn `create_some` in constants [E0015]
fn main() {}

View file

@ -0,0 +1,11 @@
error[E0015]: cannot call non-const fn `create_some` in constants
--> $DIR/E0015.rs:5:25
|
LL | const FOO: Option<u8> = create_some();
| ^^^^^^^^^^^^^
|
= note: calls in constants are limited to constant functions, tuple structs and tuple variants
error: aborting due to previous error
For more information about this error, try `rustc --explain E0015`.

View file

@ -0,0 +1,10 @@
struct S<'a>(&'a str);
fn f(inner: fn(&str, &S)) {
}
#[allow(unreachable_code)]
fn main() {
let inner: fn(_, _) = unimplemented!();
f(inner); //~ ERROR mismatched types
}

View file

@ -0,0 +1,19 @@
error[E0308]: mismatched types
--> $DIR/closure-with-wrong-borrows.rs:9:7
|
LL | f(inner);
| - ^^^^^ one type is more general than the other
| |
| arguments to this function are incorrect
|
= note: expected fn pointer `for<'a, 'b, 'c> fn(&'a str, &'b S<'c>)`
found fn pointer `fn(_, _)`
note: function defined here
--> $DIR/closure-with-wrong-borrows.rs:3:4
|
LL | fn f(inner: fn(&str, &S)) {
| ^ -------------------
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View file

@ -3,14 +3,17 @@ use std::hash::Hash;
use rustdoc_json_types::{
Constant, Crate, DynTrait, Enum, FnDecl, Function, FunctionPointer, GenericArg, GenericArgs,
GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, Module, OpaqueTy, Path,
Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias, Type, TypeBinding,
TypeBindingKind, Typedef, Union, Variant, VariantKind, WherePredicate,
GenericBound, GenericParamDef, Generics, Id, Impl, Import, ItemEnum, ItemSummary, Module,
OpaqueTy, Path, Primitive, ProcMacro, Static, Struct, StructKind, Term, Trait, TraitAlias,
Type, TypeBinding, TypeBindingKind, Typedef, Union, Variant, VariantKind, WherePredicate,
};
use serde_json::Value;
use crate::{item_kind::Kind, json_find, Error, ErrorKind};
// This is a rustc implementation detail that we rely on here
const LOCAL_CRATE_ID: u32 = 0;
/// The Validator walks over the JSON tree, and ensures it is well formed.
/// It is made of several parts.
///
@ -53,12 +56,19 @@ impl<'a> Validator<'a> {
}
pub fn check_crate(&mut self) {
// Graph traverse the index
let root = &self.krate.root;
self.add_mod_id(root);
while let Some(id) = set_remove(&mut self.todo) {
self.seen_ids.insert(id);
self.check_item(id);
}
let root_crate_id = self.krate.index[root].crate_id;
assert_eq!(root_crate_id, LOCAL_CRATE_ID, "LOCAL_CRATE_ID is wrong");
for (id, item_info) in &self.krate.paths {
self.check_item_info(id, item_info);
}
}
fn check_item(&mut self, id: &'a Id) {
@ -364,6 +374,19 @@ impl<'a> Validator<'a> {
fp.generic_params.iter().for_each(|gpd| self.check_generic_param_def(gpd));
}
fn check_item_info(&mut self, id: &Id, item_info: &ItemSummary) {
// FIXME: Their should be a better way to determine if an item is local, rather than relying on `LOCAL_CRATE_ID`,
// which encodes rustc implementation details.
if item_info.crate_id == LOCAL_CRATE_ID && !self.krate.index.contains_key(id) {
self.errs.push(Error {
id: id.clone(),
kind: ErrorKind::Custom(
"Id for local item in `paths` but not in `index`".to_owned(),
),
})
}
}
fn add_id_checked(&mut self, id: &'a Id, valid: fn(Kind) -> bool, expected: &str) {
if let Some(kind) = self.kind_of(id) {
if valid(kind) {

View file

@ -1,6 +1,6 @@
use std::collections::HashMap;
use rustdoc_json_types::{Crate, Item, Visibility};
use rustdoc_json_types::{Crate, Item, ItemKind, ItemSummary, Visibility, FORMAT_VERSION};
use crate::json_find::SelectorPart;
@ -64,3 +64,101 @@ fn errors_on_missing_links() {
}],
);
}
// Test we would catch
// https://github.com/rust-lang/rust/issues/104064#issuecomment-1368589718
#[test]
fn errors_on_local_in_paths_and_not_index() {
let krate = Crate {
root: id("0:0:1572"),
crate_version: None,
includes_private: false,
index: HashMap::from_iter([
(
id("0:0:1572"),
Item {
id: id("0:0:1572"),
crate_id: 0,
name: Some("microcore".to_owned()),
span: None,
visibility: Visibility::Public,
docs: None,
links: HashMap::from_iter([(("prim@i32".to_owned(), id("0:1:1571")))]),
attrs: Vec::new(),
deprecation: None,
inner: ItemEnum::Module(Module {
is_crate: true,
items: vec![id("0:1:717")],
is_stripped: false,
}),
},
),
(
id("0:1:717"),
Item {
id: id("0:1:717"),
crate_id: 0,
name: Some("i32".to_owned()),
span: None,
visibility: Visibility::Public,
docs: None,
links: HashMap::default(),
attrs: Vec::new(),
deprecation: None,
inner: ItemEnum::Primitive(Primitive { name: "i32".to_owned(), impls: vec![] }),
},
),
]),
paths: HashMap::from_iter([(
id("0:1:1571"),
ItemSummary {
crate_id: 0,
path: vec!["microcore".to_owned(), "i32".to_owned()],
kind: ItemKind::Primitive,
},
)]),
external_crates: HashMap::default(),
format_version: rustdoc_json_types::FORMAT_VERSION,
};
check(
&krate,
&[Error {
id: id("0:1:1571"),
kind: ErrorKind::Custom("Id for local item in `paths` but not in `index`".to_owned()),
}],
);
}
#[test]
#[should_panic = "LOCAL_CRATE_ID is wrong"]
fn checks_local_crate_id_is_correct() {
let krate = Crate {
root: id("root"),
crate_version: None,
includes_private: false,
index: HashMap::from_iter([(
id("root"),
Item {
id: id("root"),
crate_id: LOCAL_CRATE_ID.wrapping_add(1),
name: Some("irrelavent".to_owned()),
span: None,
visibility: Visibility::Public,
docs: None,
links: HashMap::default(),
attrs: Vec::new(),
deprecation: None,
inner: ItemEnum::Module(Module {
is_crate: true,
items: vec![],
is_stripped: false,
}),
},
)]),
paths: HashMap::default(),
external_crates: HashMap::default(),
format_version: FORMAT_VERSION,
};
check(&krate, &[]);
}

View file

@ -15,8 +15,6 @@
//!
//! 4. We check that the error code is actually emitted by the compiler.
//! - This is done by searching `compiler/` with a regex.
//!
//! This tidy check was merged and refactored from two others. See #PR_NUM for information about linting changes that occurred during this refactor.
use std::{ffi::OsStr, fs, path::Path};
@ -33,8 +31,8 @@ const IGNORE_DOCTEST_CHECK: &[&str] = &["E0464", "E0570", "E0601", "E0602"];
// Error codes that don't yet have a UI test. This list will eventually be removed.
const IGNORE_UI_TEST_CHECK: &[&str] = &[
"E0313", "E0461", "E0465", "E0476", "E0490", "E0514", "E0523", "E0554", "E0640", "E0717",
"E0729", "E0789",
"E0461", "E0465", "E0476", "E0490", "E0514", "E0523", "E0554", "E0640", "E0717", "E0729",
"E0789",
];
macro_rules! verbose_print {
@ -57,7 +55,7 @@ pub fn check(root_path: &Path, search_paths: &[&Path], verbose: bool, bad: &mut
let no_longer_emitted = check_error_codes_docs(root_path, &error_codes, &mut errors, verbose);
// Stage 3: check list has UI tests
check_error_codes_tests(root_path, &error_codes, &mut errors, verbose);
check_error_codes_tests(root_path, &error_codes, &mut errors, verbose, &no_longer_emitted);
// Stage 4: check list is emitted by compiler
check_error_codes_used(search_paths, &error_codes, &mut errors, &no_longer_emitted, verbose);
@ -174,8 +172,9 @@ fn check_error_codes_docs(
return;
}
let (found_code_example, found_proper_doctest, emit_ignore_warning, emit_no_longer_warning) =
let (found_code_example, found_proper_doctest, emit_ignore_warning, no_longer_emitted) =
check_explanation_has_doctest(&contents, &err_code);
if emit_ignore_warning {
verbose_print!(
verbose,
@ -183,13 +182,11 @@ fn check_error_codes_docs(
`IGNORE_DOCTEST_CHECK` constant instead."
);
}
if emit_no_longer_warning {
if no_longer_emitted {
no_longer_emitted_codes.push(err_code.to_owned());
verbose_print!(
verbose,
"warning: Error code `{err_code}` is no longer emitted and should be removed entirely."
);
}
if !found_code_example {
verbose_print!(
verbose,
@ -226,7 +223,7 @@ fn check_explanation_has_doctest(explanation: &str, err_code: &str) -> (bool, bo
let mut found_proper_doctest = false;
let mut emit_ignore_warning = false;
let mut emit_no_longer_warning = false;
let mut no_longer_emitted = false;
for line in explanation.lines() {
let line = line.trim();
@ -246,13 +243,13 @@ fn check_explanation_has_doctest(explanation: &str, err_code: &str) -> (bool, bo
} else if line
.starts_with("#### Note: this error code is no longer emitted by the compiler")
{
emit_no_longer_warning = true;
no_longer_emitted = true;
found_code_example = true;
found_proper_doctest = true;
}
}
(found_code_example, found_proper_doctest, emit_ignore_warning, emit_no_longer_warning)
(found_code_example, found_proper_doctest, emit_ignore_warning, no_longer_emitted)
}
// Stage 3: Checks that each error code has a UI test in the correct directory
@ -261,6 +258,7 @@ fn check_error_codes_tests(
error_codes: &[String],
errors: &mut Vec<String>,
verbose: bool,
no_longer_emitted: &[String],
) {
let tests_path = root_path.join(Path::new(ERROR_TESTS_PATH));
@ -295,6 +293,11 @@ fn check_error_codes_tests(
}
};
if no_longer_emitted.contains(code) {
// UI tests *can't* contain error codes that are no longer emitted.
continue;
}
let mut found_code = false;
for line in file.lines() {