Auto merge of #109284 - matthiaskrgr:rollup-aaublsx, r=matthiaskrgr

Rollup of 9 pull requests

Successful merges:

 - #109102 (Erase escaping late-bound regions when probing for ambiguous associated types)
 - #109200 (Fix index out of bounds in `suggest_trait_fn_ty_for_impl_fn_infer`)
 - #109211 (E0206 - update description )
 - #109222 (Do not ICE for unexpected lifetime with ConstGeneric rib)
 - #109235 (fallback to lstat when stat fails on Windows)
 - #109248 (Pass the right HIR back from `get_fn_decl`)
 - #109251 (Suggest surrounding the macro with `{}` to interpret as a statement)
 - #109256 (Check for llvm-tools before install)
 - #109257 (resolve: Improve debug impls for `NameBinding`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-03-18 03:16:32 +00:00
commit 85123d2504
23 changed files with 252 additions and 65 deletions

View File

@ -1,5 +1,5 @@
The `Copy` trait was implemented on a type which is neither a struct nor an
enum.
The `Copy` trait was implemented on a type which is neither a struct, an
enum, nor a union.
Erroneous code example:
@ -10,6 +10,6 @@ struct Bar;
impl Copy for &'static mut Bar { } // error!
```
You can only implement `Copy` for a struct or an enum.
You can only implement `Copy` for a struct, an enum, or a union.
The previous example will fail because `&'static mut Bar`
is not a struct or enum.
is not a struct, an enum, or a union.

View File

@ -245,12 +245,24 @@ pub(super) fn emit_frag_parse_err(
e.note(
"the macro call doesn't expand to an expression, but it can expand to a statement",
);
e.span_suggestion_verbose(
site_span.shrink_to_hi(),
"add `;` to interpret the expansion as a statement",
";",
Applicability::MaybeIncorrect,
);
if parser.token == token::Semi {
if let Ok(snippet) = parser.sess.source_map().span_to_snippet(site_span) {
e.span_suggestion_verbose(
site_span,
"surround the macro invocation with `{}` to interpret the expansion as a statement",
format!("{{ {}; }}", snippet),
Applicability::MaybeIncorrect,
);
}
} else {
e.span_suggestion_verbose(
site_span.shrink_to_hi(),
"add `;` to interpret the expansion as a statement",
";",
Applicability::MaybeIncorrect,
);
}
}
},
_ => annotate_err_with_kind(&mut e, kind, site_span),

View File

@ -2396,13 +2396,24 @@ fn probe_traits_that_match_assoc_ty(
tcx,
infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id),
);
// I guess we don't need to make a universe unless we need it,
// but also we're on the error path, so it doesn't matter here.
let universe = infcx.create_next_universe();
infcx
.can_eq(
ty::ParamEnv::empty(),
impl_.self_ty(),
// Must fold past escaping bound vars too,
// since we have those at this point in astconv.
tcx.fold_regions(qself_ty, |_, _| tcx.lifetimes.re_erased),
tcx.replace_escaping_bound_vars_uncached(qself_ty, ty::fold::FnMutDelegate {
regions: &mut |_| tcx.lifetimes.re_erased,
types: &mut |bv| tcx.mk_placeholder(ty::PlaceholderType {
universe,
name: bv.kind,
}),
consts: &mut |bv, ty| tcx.mk_const(ty::PlaceholderConst {
universe,
name: bv
}, ty),
})
)
})
&& tcx.impl_polarity(impl_def_id) != ty::ImplPolarity::Negative
@ -3317,10 +3328,13 @@ fn suggest_trait_fn_ty_for_impl_fn_infer(
tcx,
trait_ref.substs.extend_to(tcx, assoc.def_id, |param, _| tcx.mk_param_from_def(param)),
);
let fn_sig = tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), fn_sig);
let ty = if let Some(arg_idx) = arg_idx { fn_sig.input(arg_idx) } else { fn_sig.output() };
Some(tcx.liberate_late_bound_regions(fn_hir_id.expect_owner().to_def_id(), ty))
Some(if let Some(arg_idx) = arg_idx {
*fn_sig.inputs().get(arg_idx)?
} else {
fn_sig.output()
})
}
#[instrument(level = "trace", skip(self, generate_err))]

View File

@ -299,7 +299,7 @@ fn maybe_get_coercion_reason(&self, hir_id: hir::HirId, sp: Span) -> Option<(Spa
{
// check that the `if` expr without `else` is the fn body's expr
if expr.span == sp {
return self.get_fn_decl(hir_id).and_then(|(fn_decl, _)| {
return self.get_fn_decl(hir_id).and_then(|(_, fn_decl, _)| {
let span = fn_decl.output.span();
let snippet = self.tcx.sess.source_map().span_to_snippet(span).ok()?;
Some((span, format!("expected `{snippet}` because of this return type")))

View File

@ -1722,12 +1722,13 @@ fn report_return_mismatched_types<'a>(
fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
}
}
fcx.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
fcx.get_node_fn_decl(parent)
.map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
} else {
fcx.get_fn_decl(parent_id)
};
if let Some((fn_decl, can_suggest)) = fn_decl {
if let Some((fn_id, fn_decl, can_suggest)) = fn_decl {
if blk_id.is_none() {
pointing_at_return_type |= fcx.suggest_missing_return_type(
&mut err,
@ -1735,7 +1736,7 @@ fn report_return_mismatched_types<'a>(
expected,
found,
can_suggest,
fcx.tcx.hir().get_parent_item(id).into(),
fn_id,
);
}
if !pointing_at_return_type {
@ -1746,17 +1747,11 @@ fn report_return_mismatched_types<'a>(
let parent_id = fcx.tcx.hir().get_parent_item(id);
let parent_item = fcx.tcx.hir().get_by_def_id(parent_id.def_id);
if let (Some(expr), Some(_), Some((fn_decl, _, _))) =
if let (Some(expr), Some(_), Some((fn_id, fn_decl, _, _))) =
(expression, blk_id, fcx.get_node_fn_decl(parent_item))
{
fcx.suggest_missing_break_or_return_expr(
&mut err,
expr,
fn_decl,
expected,
found,
id,
parent_id.into(),
&mut err, expr, fn_decl, expected, found, id, fn_id,
);
}
@ -1882,7 +1877,7 @@ fn add_impl_trait_explanation<'a>(
}
fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id)
if let Some((_, fn_decl, _)) = fcx.get_fn_decl(blk_id)
&& let hir::FnRetTy::Return(ty) = fn_decl.output
&& let ty = fcx.astconv().ast_ty_to_ty( ty)
&& let ty::Dynamic(..) = ty.kind()

View File

@ -788,7 +788,7 @@ fn check_expr_return(
self.ret_coercion_span.set(Some(expr.span));
}
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(
self,
&cause,

View File

@ -898,51 +898,74 @@ pub fn resolve_ty_and_res_fully_qualified_call(
)
}
/// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise.
/// Given a function `Node`, return its `HirId` and `FnDecl` if it exists. Given a closure
/// that is the child of a function, return that function's `HirId` and `FnDecl` instead.
/// This may seem confusing at first, but this is used in diagnostics for `async fn`,
/// for example, where most of the type checking actually happens within a nested closure,
/// but we often want access to the parent function's signature.
///
/// Otherwise, return false.
pub(in super::super) fn get_node_fn_decl(
&self,
node: Node<'tcx>,
) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> {
) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
match node {
Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => {
Node::Item(&hir::Item {
ident,
kind: hir::ItemKind::Fn(ref sig, ..),
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((&sig.decl, ident, ident.name != sym::main))
Some((
hir::HirId::make_owner(owner_id.def_id),
&sig.decl,
ident,
ident.name != sym::main,
))
}
Node::TraitItem(&hir::TraitItem {
ident,
kind: hir::TraitItemKind::Fn(ref sig, ..),
owner_id,
..
}) => Some((&sig.decl, ident, true)),
}) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, true)),
Node::ImplItem(&hir::ImplItem {
ident,
kind: hir::ImplItemKind::Fn(ref sig, ..),
owner_id,
..
}) => Some((&sig.decl, ident, false)),
Node::Expr(&hir::Expr {
hir_id,
kind: hir::ExprKind::Closure(..),
..
}) if let Some(Node::Item(&hir::Item {
}) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)),
Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. })
if let Some(Node::Item(&hir::Item {
ident,
kind: hir::ItemKind::Fn(ref sig, ..),
owner_id,
..
})) = self.tcx.hir().find_parent(hir_id) => Some((
hir::HirId::make_owner(owner_id.def_id),
&sig.decl,
ident,
kind: hir::ItemKind::Fn(ref sig, ..),
..
})) = self.tcx.hir().find_parent(hir_id) => {
Some((&sig.decl, ident, ident.name != sym::main))
},
ident.name != sym::main,
)),
_ => None,
}
}
/// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a
/// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
/// suggestion can be made, `None` otherwise.
pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> {
pub fn get_fn_decl(
&self,
blk_id: hir::HirId,
) -> Option<(hir::HirId, &'tcx hir::FnDecl<'tcx>, bool)> {
// 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.
self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
let parent = self.tcx.hir().get(blk_id);
self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main))
self.get_node_fn_decl(parent)
.map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
})
}

View File

@ -1669,7 +1669,7 @@ fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
/// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident))
}
/// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail

View File

@ -64,8 +64,7 @@ pub fn suggest_mismatched_types_on_tail(
let expr = expr.peel_drop_temps();
self.suggest_missing_semicolon(err, expr, expected, false);
let mut pointing_at_return_type = false;
if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
let fn_id = self.tcx.hir().get_return_block(blk_id).unwrap();
if let Some((fn_id, fn_decl, can_suggest)) = self.get_fn_decl(blk_id) {
pointing_at_return_type = self.suggest_missing_return_type(
err,
&fn_decl,

View File

@ -85,20 +85,28 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Single {
ref source,
ref target,
ref source_bindings,
ref target_bindings,
ref type_ns_only,
ref nested,
ref id,
// Ignore the following to avoid an infinite loop while printing.
source_bindings: _,
target_bindings: _,
} => f
.debug_struct("Single")
.field("source", source)
.field("target", target)
// Ignore the nested bindings to avoid an infinite loop while printing.
.field(
"source_bindings",
&source_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))),
)
.field(
"target_bindings",
&target_bindings.clone().map(|b| b.into_inner().map(|_| format_args!(".."))),
)
.field("type_ns_only", type_ns_only)
.field("nested", nested)
.field("id", id)
.finish_non_exhaustive(),
.finish(),
Glob { ref is_prelude, ref max_vis, ref id } => f
.debug_struct("Glob")
.field("is_prelude", is_prelude)

View File

@ -1478,8 +1478,9 @@ fn resolve_lifetime(&mut self, lifetime: &'ast Lifetime, use_ctxt: visit::Lifeti
} else {
LifetimeUseSet::Many
}),
LifetimeRibKind::Generics { .. } => None,
LifetimeRibKind::ConstGeneric | LifetimeRibKind::AnonConst => {
LifetimeRibKind::Generics { .. }
| LifetimeRibKind::ConstGeneric => None,
LifetimeRibKind::AnonConst => {
span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind)
}
})

View File

@ -1236,7 +1236,17 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
}
pub fn stat(path: &Path) -> io::Result<FileAttr> {
metadata(path, ReparsePoint::Follow)
match metadata(path, ReparsePoint::Follow) {
Err(err) if err.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => {
if let Ok(attrs) = lstat(path) {
if !attrs.file_type().is_symlink() {
return Ok(attrs);
}
}
Err(err)
}
result => result,
}
}
pub fn lstat(path: &Path) -> io::Result<FileAttr> {

View File

@ -210,10 +210,13 @@ fn run($sel, $builder: &Builder<'_>) {
}
};
LlvmTools, alias = "llvm-tools", Self::should_build(_config), only_hosts: true, {
let tarball = builder
.ensure(dist::LlvmTools { target: self.target })
.expect("missing llvm-tools");
install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) {
install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
} else {
builder.info(
&format!("skipping llvm-tools stage{} ({}): external LLVM", self.compiler.stage, self.target),
);
}
};
Rustfmt, alias = "rustfmt", Self::should_build(_config), only_hosts: true, {
if let Some(tarball) = builder.ensure(dist::Rustfmt {

View File

@ -25,4 +25,9 @@ fn d<const C: S>() {}
//~^ ERROR missing lifetime specifier
//~| ERROR `S<'_>` is forbidden as the type of a const generic parameter
trait Foo<'a> {}
struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
//~^ ERROR use of non-static lifetime `'a` in const generic
//~| ERROR `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter
fn main() {}

View File

@ -9,6 +9,14 @@ help: consider introducing a named lifetime parameter
LL | fn d<'a, const C: S<'a>>() {}
| +++ ++++
error[E0771]: use of non-static lifetime `'a` in const generic
--> $DIR/unusual-rib-combinations.rs:29:22
|
LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
| ^^
|
= note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
error[E0214]: parenthesized type parameters may only be used with a `Fn` trait
--> $DIR/unusual-rib-combinations.rs:7:16
|
@ -55,7 +63,16 @@ LL | fn d<const C: S>() {}
= note: the only supported types are integers, `bool` and `char`
= help: more complex types are supported with `#![feature(adt_const_params)]`
error: aborting due to 7 previous errors
error: `&dyn for<'a> Foo<'a>` is forbidden as the type of a const generic parameter
--> $DIR/unusual-rib-combinations.rs:29:21
|
LL | struct Bar<const N: &'a (dyn for<'a> Foo<'a>)>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the only supported types are integers, `bool` and `char`
= help: more complex types are supported with `#![feature(adt_const_params)]`
Some errors have detailed explanations: E0106, E0214, E0308.
error: aborting due to 9 previous errors
Some errors have detailed explanations: E0106, E0214, E0308, E0771.
For more information about an error, try `rustc --explain E0106`.

View File

@ -0,0 +1,7 @@
macro_rules! statement {
() => {;}; //~ ERROR expected expression
}
fn main() {
let _ = statement!();
}

View File

@ -0,0 +1,18 @@
error: expected expression, found `;`
--> $DIR/issue-109237.rs:2:12
|
LL | () => {;};
| ^ expected expression
...
LL | let _ = statement!();
| ------------ in this macro invocation
|
= note: the macro call doesn't expand to an expression, but it can expand to a statement
= note: this error originates in the macro `statement` (in Nightly builds, run with -Z macro-backtrace for more info)
help: surround the macro invocation with `{}` to interpret the expansion as a statement
|
LL | let _ = { statement!(); };
| ~~~~~~~~~~~~~~~~~
error: aborting due to previous error

View File

@ -0,0 +1,10 @@
trait Foo {
fn bar();
}
impl Foo for () {
fn bar(s: _) {}
//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
}
fn main() {}

View File

@ -0,0 +1,14 @@
error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
--> $DIR/bad-infer-in-trait-impl.rs:6:15
|
LL | fn bar(s: _) {}
| ^ not allowed in type signatures
|
help: use type parameters instead
|
LL | fn bar<T>(s: T) {}
| +++ ~
error: aborting due to previous error
For more information about this error, try `rustc --explain E0121`.

View File

@ -0,0 +1,11 @@
// edition: 2021
// Make sure we don't ICE when suggesting a return type
// for an async fn that has late-bound vars...
async fn ice(_: &i32) {
true
//~^ ERROR mismatched types
}
fn main() {}

View File

@ -0,0 +1,11 @@
error[E0308]: mismatched types
--> $DIR/suggest-ret-on-async-w-late.rs:7:5
|
LL | async fn ice(_: &i32) {
| - help: try adding a return type: `-> bool`
LL | true
| ^^^^ expected `()`, found `bool`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,11 @@
#![feature(non_lifetime_binders)]
//~^ WARN the feature `non_lifetime_binders` is incomplete
fn f()
where
for<B> B::Item: Send,
//~^ ERROR ambiguous associated type
{
}
fn main() {}

View File

@ -0,0 +1,18 @@
warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
--> $DIR/missing-assoc-item.rs:1:12
|
LL | #![feature(non_lifetime_binders)]
| ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
= note: `#[warn(incomplete_features)]` on by default
error[E0223]: ambiguous associated type
--> $DIR/missing-assoc-item.rs:6:12
|
LL | for<B> B::Item: Send,
| ^^^^^^^ help: use the fully-qualified path: `<B as IntoIterator>::Item`
error: aborting due to previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0223`.