Auto merge of #146650 - matthiaskrgr:rollup-rjrklz9, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - rust-lang/rust#146442 (Display ?Sized, const, and lifetime parameters in trait item suggestions across a crate boundary) - rust-lang/rust#146474 (Improve `core::ascii` coverage) - rust-lang/rust#146605 (Bump rustfix 0.8.1 -> 0.8.7) - rust-lang/rust#146611 (bootstrap: emit hint if a config key is used in the wrong section) - rust-lang/rust#146618 (Do not run ui test if options specific to LLVM are used when another codegen backend is used) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
@@ -4817,9 +4817,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustfix"
|
||||
version = "0.8.1"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81864b097046da5df3758fdc6e4822bbb70afa06317e8ca45ea1b51cb8c5e5a4"
|
||||
checksum = "82fa69b198d894d84e23afde8e9ab2af4400b2cba20d6bf2b428a8b01c222c5a"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
||||
@@ -70,6 +70,7 @@ pub mod intrinsic;
|
||||
mod region;
|
||||
pub mod wfcheck;
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::num::NonZero;
|
||||
|
||||
pub use check::{check_abi, check_custom_abi};
|
||||
@@ -86,7 +87,7 @@ use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::print::with_types_for_signature;
|
||||
use rustc_middle::ty::{
|
||||
self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypingMode,
|
||||
self, GenericArgs, GenericArgsRef, OutlivesPredicate, Region, Ty, TyCtxt, TypingMode,
|
||||
};
|
||||
use rustc_middle::{bug, span_bug};
|
||||
use rustc_session::parse::feature_err;
|
||||
@@ -335,6 +336,7 @@ fn bounds_from_generic_predicates<'tcx>(
|
||||
assoc: ty::AssocItem,
|
||||
) -> (String, String) {
|
||||
let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default();
|
||||
let mut regions: FxIndexMap<Region<'tcx>, Vec<Region<'tcx>>> = FxIndexMap::default();
|
||||
let mut projections = vec![];
|
||||
for (predicate, _) in predicates {
|
||||
debug!("predicate {:?}", predicate);
|
||||
@@ -351,20 +353,23 @@ fn bounds_from_generic_predicates<'tcx>(
|
||||
ty::ClauseKind::Projection(projection_pred) => {
|
||||
projections.push(bound_predicate.rebind(projection_pred));
|
||||
}
|
||||
ty::ClauseKind::RegionOutlives(OutlivesPredicate(a, b)) => {
|
||||
regions.entry(a).or_default().push(b);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
let mut where_clauses = vec![];
|
||||
let generics = tcx.generics_of(assoc.def_id);
|
||||
let types_str = generics
|
||||
let params = generics
|
||||
.own_params
|
||||
.iter()
|
||||
.filter(|p| matches!(p.kind, GenericParamDefKind::Type { synthetic: false, .. }))
|
||||
.map(|p| {
|
||||
// we just checked that it's a type, so the unwrap can't fail
|
||||
let ty = tcx.mk_param_from_def(p).as_type().unwrap();
|
||||
if let Some(bounds) = types.get(&ty) {
|
||||
.filter(|p| !p.kind.is_synthetic())
|
||||
.map(|p| match tcx.mk_param_from_def(p).kind() {
|
||||
ty::GenericArgKind::Type(ty) => {
|
||||
let bounds =
|
||||
types.get(&ty).map(Cow::Borrowed).unwrap_or_else(|| Cow::Owned(Vec::new()));
|
||||
let mut bounds_str = vec![];
|
||||
for bound in bounds.iter().copied() {
|
||||
let mut projections_str = vec![];
|
||||
@@ -377,7 +382,11 @@ fn bounds_from_generic_predicates<'tcx>(
|
||||
projections_str.push(format!("{} = {}", name, p.term));
|
||||
}
|
||||
}
|
||||
let bound_def_path = tcx.def_path_str(bound);
|
||||
let bound_def_path = if tcx.is_lang_item(bound, LangItem::MetaSized) {
|
||||
String::from("?Sized")
|
||||
} else {
|
||||
tcx.def_path_str(bound)
|
||||
};
|
||||
if projections_str.is_empty() {
|
||||
where_clauses.push(format!("{}: {}", ty, bound_def_path));
|
||||
} else {
|
||||
@@ -393,8 +402,21 @@ fn bounds_from_generic_predicates<'tcx>(
|
||||
} else {
|
||||
format!("{}: {}", ty, bounds_str.join(" + "))
|
||||
}
|
||||
} else {
|
||||
ty.to_string()
|
||||
}
|
||||
ty::GenericArgKind::Const(ct) => {
|
||||
format!("const {ct}: {}", tcx.type_of(p.def_id).skip_binder())
|
||||
}
|
||||
ty::GenericArgKind::Lifetime(region) => {
|
||||
if let Some(v) = regions.get(®ion)
|
||||
&& !v.is_empty()
|
||||
{
|
||||
format!(
|
||||
"{region}: {}",
|
||||
v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ")
|
||||
)
|
||||
} else {
|
||||
region.to_string()
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -409,7 +431,7 @@ fn bounds_from_generic_predicates<'tcx>(
|
||||
}
|
||||
|
||||
let generics =
|
||||
if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) };
|
||||
if params.is_empty() { "".to_string() } else { format!("<{}>", params.join(", ")) };
|
||||
|
||||
let where_clauses = if where_clauses.is_empty() {
|
||||
"".to_string()
|
||||
|
||||
@@ -505,3 +505,10 @@ fn test_escape_ascii_iter() {
|
||||
let _ = it.advance_back_by(4);
|
||||
assert_eq!(it.to_string(), r#"fastpath\xffremainder"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_invalid_u8() {
|
||||
for c in 128..=255 {
|
||||
assert_eq!(core::ascii::Char::from_u8(c), None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1853,13 +1853,7 @@ fn load_toml_config(
|
||||
} else {
|
||||
toml_path.clone()
|
||||
});
|
||||
(
|
||||
get_toml(&toml_path).unwrap_or_else(|e| {
|
||||
eprintln!("ERROR: Failed to parse '{}': {e}", toml_path.display());
|
||||
exit!(2);
|
||||
}),
|
||||
path,
|
||||
)
|
||||
(get_toml(&toml_path).unwrap_or_else(|e| bad_config(&toml_path, e)), path)
|
||||
} else {
|
||||
(TomlConfig::default(), None)
|
||||
}
|
||||
@@ -1892,10 +1886,8 @@ fn postprocess_toml(
|
||||
.unwrap()
|
||||
.join(include_path);
|
||||
|
||||
let included_toml = get_toml(&include_path).unwrap_or_else(|e| {
|
||||
eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display());
|
||||
exit!(2);
|
||||
});
|
||||
let included_toml =
|
||||
get_toml(&include_path).unwrap_or_else(|e| bad_config(&include_path, e));
|
||||
toml.merge(
|
||||
Some(include_path),
|
||||
&mut Default::default(),
|
||||
@@ -2398,3 +2390,98 @@ pub(crate) fn read_file_by_commit<'a>(
|
||||
git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap()));
|
||||
git.run_capture_stdout(dwn_ctx.exec_ctx).stdout()
|
||||
}
|
||||
|
||||
fn bad_config(toml_path: &Path, e: toml::de::Error) -> ! {
|
||||
eprintln!("ERROR: Failed to parse '{}': {e}", toml_path.display());
|
||||
let e_s = e.to_string();
|
||||
if e_s.contains("unknown field")
|
||||
&& let Some(field_name) = e_s.split("`").nth(1)
|
||||
&& let sections = find_correct_section_for_field(field_name)
|
||||
&& !sections.is_empty()
|
||||
{
|
||||
if sections.len() == 1 {
|
||||
match sections[0] {
|
||||
WouldBeValidFor::TopLevel { is_section } => {
|
||||
if is_section {
|
||||
eprintln!(
|
||||
"hint: section name `{field_name}` used as a key within a section"
|
||||
);
|
||||
} else {
|
||||
eprintln!("hint: try using `{field_name}` as a top level key");
|
||||
}
|
||||
}
|
||||
WouldBeValidFor::Section(section) => {
|
||||
eprintln!("hint: try moving `{field_name}` to the `{section}` section")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
eprintln!(
|
||||
"hint: `{field_name}` would be valid {}",
|
||||
join_oxford_comma(sections.iter(), "or"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
exit!(2);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum WouldBeValidFor {
|
||||
TopLevel { is_section: bool },
|
||||
Section(&'static str),
|
||||
}
|
||||
|
||||
fn join_oxford_comma(
|
||||
mut parts: impl ExactSizeIterator<Item = impl std::fmt::Display>,
|
||||
conj: &str,
|
||||
) -> String {
|
||||
use std::fmt::Write;
|
||||
let mut out = String::new();
|
||||
|
||||
assert!(parts.len() > 1);
|
||||
while let Some(part) = parts.next() {
|
||||
if parts.len() == 0 {
|
||||
write!(&mut out, "{conj} {part}")
|
||||
} else {
|
||||
write!(&mut out, "{part}, ")
|
||||
}
|
||||
.unwrap();
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
impl std::fmt::Display for WouldBeValidFor {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::TopLevel { .. } => write!(f, "at top level"),
|
||||
Self::Section(section_name) => write!(f, "in section `{section_name}`"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn find_correct_section_for_field(field_name: &str) -> Vec<WouldBeValidFor> {
|
||||
let sections = ["build", "install", "llvm", "gcc", "rust", "dist"];
|
||||
sections
|
||||
.iter()
|
||||
.map(Some)
|
||||
.chain([None])
|
||||
.filter_map(|section_name| {
|
||||
let dummy_config_str = if let Some(section_name) = section_name {
|
||||
format!("{section_name}.{field_name} = 0\n")
|
||||
} else {
|
||||
format!("{field_name} = 0\n")
|
||||
};
|
||||
let is_unknown_field = toml::from_str::<toml::Value>(&dummy_config_str)
|
||||
.and_then(TomlConfig::deserialize)
|
||||
.err()
|
||||
.is_some_and(|e| e.to_string().contains("unknown field"));
|
||||
if is_unknown_field {
|
||||
None
|
||||
} else {
|
||||
Some(section_name.copied().map(WouldBeValidFor::Section).unwrap_or_else(|| {
|
||||
WouldBeValidFor::TopLevel { is_section: sections.contains(&field_name) }
|
||||
}))
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -203,6 +203,10 @@ impl CodegenBackend {
|
||||
Self::Llvm => "llvm",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_llvm(self) -> bool {
|
||||
matches!(self, Self::Llvm)
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration for `compiletest` *per invocation*.
|
||||
|
||||
@@ -81,8 +81,8 @@ pub(super) fn handle_needs(
|
||||
},
|
||||
Need {
|
||||
name: "needs-enzyme",
|
||||
condition: config.has_enzyme,
|
||||
ignore_reason: "ignored when LLVM Enzyme is disabled",
|
||||
condition: config.has_enzyme && config.default_codegen_backend.is_llvm(),
|
||||
ignore_reason: "ignored when LLVM Enzyme is disabled or LLVM is not the default codegen backend",
|
||||
},
|
||||
Need {
|
||||
name: "needs-run-enabled",
|
||||
@@ -161,8 +161,8 @@ pub(super) fn handle_needs(
|
||||
},
|
||||
Need {
|
||||
name: "needs-llvm-zstd",
|
||||
condition: cache.llvm_zstd,
|
||||
ignore_reason: "ignored if LLVM wasn't build with zstd for ELF section compression",
|
||||
condition: cache.llvm_zstd && config.default_codegen_backend.is_llvm(),
|
||||
ignore_reason: "ignored if LLVM wasn't build with zstd for ELF section compression or LLVM is not the default codegen backend",
|
||||
},
|
||||
Need {
|
||||
name: "needs-rustc-debug-assertions",
|
||||
@@ -279,7 +279,10 @@ pub(super) fn handle_needs(
|
||||
|
||||
// Handled elsewhere.
|
||||
if name == "needs-llvm-components" {
|
||||
return IgnoreDecision::Continue;
|
||||
if config.default_codegen_backend.is_llvm() {
|
||||
return IgnoreDecision::Continue;
|
||||
}
|
||||
return IgnoreDecision::Ignore { reason: "LLVM specific test".into() };
|
||||
}
|
||||
|
||||
let mut found_valid = false;
|
||||
|
||||
@@ -8,7 +8,7 @@ trait Get {
|
||||
}
|
||||
|
||||
trait Other {
|
||||
fn uhoh<U: Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Sized, Self: Get, Self: Get {}
|
||||
fn uhoh<U: Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Sized, Self: Get {}
|
||||
//~^ ERROR the trait bound `Self: Get` is not satisfied
|
||||
//~| ERROR the trait bound `Self: Get` is not satisfied
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ impl<T> ProjectedMyTrait for T
|
||||
|
||||
fn require_trait<T: MyTrait>(_: T) {}
|
||||
|
||||
fn foo<T : MyTrait + 'static + 'static, U : MyTrait + 'static + 'static>(wrap: Wrapper<'_, Option<T>>, wrap1: Wrapper<'_, Option<U>>) {
|
||||
fn foo<T : MyTrait + 'static, U : MyTrait + 'static>(wrap: Wrapper<'_, Option<T>>, wrap1: Wrapper<'_, Option<U>>) {
|
||||
//~^ HELP consider restricting the type parameter to the `'static` lifetime
|
||||
//~| HELP consider restricting the type parameter to the `'static` lifetime
|
||||
require_trait(wrap);
|
||||
|
||||
@@ -66,7 +66,7 @@ fn asteroids() -> impl FnOnce() -> bool {
|
||||
|
||||
// https://github.com/rust-lang/rust/issues/105179
|
||||
fn r#match() -> i32 {
|
||||
((match () { () => 1 })) + match () { () => 1 } //~ ERROR expected expression, found `+`
|
||||
(match () { () => 1 }) + match () { () => 1 } //~ ERROR expected expression, found `+`
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ fn matches() -> bool {
|
||||
(match () { _ => true }) && match () { _ => true }; //~ ERROR mismatched types
|
||||
//~^ ERROR expected `;`, found keyword `match`
|
||||
(match () { _ => true }) && true; //~ ERROR mismatched types
|
||||
((match () { _ => true })) && true //~ ERROR mismatched types
|
||||
(match () { _ => true }) && true //~ ERROR mismatched types
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
fn main() {}
|
||||
|
||||
@@ -4,9 +4,12 @@ extern crate dep;
|
||||
use dep::*;
|
||||
|
||||
struct Local;
|
||||
|
||||
impl Trait for Local {}
|
||||
//~^ ERROR not all trait items implemented
|
||||
//~| HELP implement the missing item: `fn foo(_: impl Sized) { todo!() }`
|
||||
//~| HELP implement the missing item: `fn bar<T>(_: impl Sized) { todo!() }`
|
||||
//~| HELP implement the missing item: `fn bar<T>(_: impl Sized) where Foo<T>: MetaSized { todo!() }`
|
||||
//~| HELP implement the missing item: `fn baz<const N: usize>() { todo!() }`
|
||||
//~| HELP implement the missing item: `fn quux<'a: 'b, 'b, T>() where T: ?Sized { todo!() }`
|
||||
|
||||
fn main() {}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
error[E0046]: not all trait items implemented, missing: `foo`, `bar`
|
||||
--> $DIR/apitit-unimplemented-method.rs:7:1
|
||||
error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `baz`, `quux`
|
||||
--> $DIR/apitit-unimplemented-method.rs:8:1
|
||||
|
|
||||
LL | impl Trait for Local {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar` in implementation
|
||||
| ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `baz`, `quux` in implementation
|
||||
|
|
||||
= help: implement the missing item: `fn foo(_: impl Sized) { todo!() }`
|
||||
= help: implement the missing item: `fn bar<T>(_: impl Sized) { todo!() }`
|
||||
= help: implement the missing item: `fn bar<T>(_: impl Sized) where Foo<T>: MetaSized { todo!() }`
|
||||
= help: implement the missing item: `fn baz<const N: usize>() { todo!() }`
|
||||
= help: implement the missing item: `fn quux<'a: 'b, 'b, T>() where T: ?Sized { todo!() }`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
#![feature(sized_hierarchy)]
|
||||
|
||||
use std::marker::MetaSized;
|
||||
|
||||
pub struct Foo<T> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
pub trait Trait {
|
||||
fn foo(_: impl Sized);
|
||||
fn bar<T>(_: impl Sized);
|
||||
fn bar<T>(_: impl Sized)
|
||||
where
|
||||
Foo<T>: MetaSized;
|
||||
fn baz<'a, const N: usize>();
|
||||
fn quux<'a: 'b, 'b, T: ?Sized>();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ pub struct Vector2<T: Debug + Copy + Clone> {
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct AABB<K: Debug + std::marker::Copy + std::marker::Copy + std::marker::Copy + std::marker::Copy> {
|
||||
pub struct AABB<K: Debug + std::marker::Copy> {
|
||||
pub loc: Vector2<K>, //~ ERROR the trait bound `K: Copy` is not satisfied
|
||||
//~^ ERROR the trait bound `K: Copy` is not satisfied
|
||||
//~| ERROR the trait bound `K: Copy` is not satisfied
|
||||
|
||||
@@ -8,7 +8,7 @@ pub struct Vector2<T: Debug + Copy + Clone>{
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)] //~ ERROR the trait `Copy` cannot be implemented for this type
|
||||
pub struct AABB<K: Copy + Debug + std::fmt::Debug + std::fmt::Debug + std::fmt::Debug>{
|
||||
pub struct AABB<K: Copy + Debug + std::fmt::Debug>{
|
||||
pub loc: Vector2<K>, //~ ERROR `K` doesn't implement `Debug`
|
||||
//~^ ERROR `K` doesn't implement `Debug`
|
||||
pub size: Vector2<K> //~ ERROR `K` doesn't implement `Debug`
|
||||
|
||||
@@ -10,7 +10,7 @@ struct ConstrainedStruct<X: Copy> {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
trait InsufficientlyConstrainedGeneric<X=()> where Self: Sized, X: std::marker::Copy, X: std::marker::Copy {
|
||||
trait InsufficientlyConstrainedGeneric<X=()> where Self: Sized, X: std::marker::Copy {
|
||||
fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
|
||||
//~^ ERROR the trait bound `X: Copy` is not satisfied
|
||||
ConstrainedStruct { x }
|
||||
@@ -20,7 +20,7 @@ trait InsufficientlyConstrainedGeneric<X=()> where Self: Sized, X: std::marker::
|
||||
|
||||
// Regression test for #120838
|
||||
#[allow(dead_code)]
|
||||
trait InsufficientlyConstrainedGenericWithEmptyWhere<X=()> where Self: Sized, X: std::marker::Copy, X: std::marker::Copy {
|
||||
trait InsufficientlyConstrainedGenericWithEmptyWhere<X=()> where Self: Sized, X: std::marker::Copy {
|
||||
fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
|
||||
//~^ ERROR the trait bound `X: Copy` is not satisfied
|
||||
ConstrainedStruct { x }
|
||||
|
||||
Reference in New Issue
Block a user