From 0c1b2731f8aabf994c3fffce16182404081c8f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 7 Feb 2024 20:01:09 +0000 Subject: [PATCH 01/14] Provide more suggestions on invalid equality where bounds ``` error: equality constraints are not yet supported in `where` clauses --> $DIR/equality-bound.rs:50:9 | LL | IntoIterator::Item = A, | ^^^^^^^^^^^^^^^^^^^^^^ not supported | = note: see issue #20041 for more information help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax | LL ~ fn from_iter>(_: T) -> Self LL | where LL ~ | error: equality constraints are not yet supported in `where` clauses --> $DIR/equality-bound.rs:63:9 | LL | T::Item = A, | ^^^^^^^^^^^ not supported | = note: see issue #20041 for more information help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax | LL ~ fn from_iter>(_: T) -> Self LL | where LL ~ | ``` Fix #68982. --- .../rustc_ast_passes/src/ast_validation.rs | 67 ++++++++++++- .../equality-bound.rs | 56 +++++++++++ .../equality-bound.stderr | 95 ++++++++++++++++++- 3 files changed, 212 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 9ea5d1ed5fa..ec54f1032c3 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1593,12 +1593,71 @@ fn deny_equality_constraints( } } } - // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo`. if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind { + // Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo`. + for bounds in generics.params.iter().map(|p| &p.bounds).chain( + generics.where_clause.predicates.iter().filter_map(|pred| match pred { + WherePredicate::BoundPredicate(p) => Some(&p.bounds), + _ => None, + }), + ) { + for bound in bounds { + if let GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound { + if full_path.segments[..full_path.segments.len() - 1] + .iter() + .map(|segment| segment.ident.name) + .zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name)) + .all(|(a, b)| a == b) + { + let potential_assoc = full_path.segments.iter().last().unwrap(); + // println!("asd"); + if let [trait_segment] = &poly.trait_ref.path.segments[..] { + let assoc = pprust::path_to_string(&ast::Path::from_ident( + potential_assoc.ident, + )); + let ty = pprust::ty_to_string(&predicate.rhs_ty); + let (args, span) = match &trait_segment.args { + Some(args) => match args.deref() { + ast::GenericArgs::AngleBracketed(args) => { + let Some(arg) = args.args.last() else { + continue; + }; + (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi()) + } + _ => continue, + }, + None => ( + format!("<{assoc} = {ty}>"), + trait_segment.span().shrink_to_hi(), + ), + }; + err.assoc2 = Some(errors::AssociatedSuggestion2 { + span, + args, + predicate: predicate.span, + trait_segment: trait_segment.ident, + potential_assoc: potential_assoc.ident, + }); + } + } + } + } + } + // Given `A: Foo, A::Bar = RhsTy`, suggest `A: Foo`. if let [potential_param, potential_assoc] = &full_path.segments[..] { - for param in &generics.params { - if param.ident == potential_param.ident { - for bound in ¶m.bounds { + for (ident, bounds) in generics.params.iter().map(|p| (p.ident, &p.bounds)).chain( + generics.where_clause.predicates.iter().filter_map(|pred| match pred { + WherePredicate::BoundPredicate(p) + if let ast::TyKind::Path(None, path) = &p.bounded_ty.kind + && let [segment] = &path.segments[..] => + { + Some((segment.ident, &p.bounds)) + } + _ => None, + }), + ) { + if ident == potential_param.ident { + for bound in bounds { if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) = bound { diff --git a/tests/ui/generic-associated-types/equality-bound.rs b/tests/ui/generic-associated-types/equality-bound.rs index fcc2da8014f..63bb5dd3567 100644 --- a/tests/ui/generic-associated-types/equality-bound.rs +++ b/tests/ui/generic-associated-types/equality-bound.rs @@ -12,4 +12,60 @@ fn sum3(i: J) -> i32 where I::Item = i32 { panic!() } +use std::iter::FromIterator; + +struct X {} + +impl FromIterator for X { + fn from_iter(_: T) -> Self + where + T: IntoIterator, + IntoIterator::Item = A, + //~^ ERROR equality constraints are not yet supported in `where` clauses + //~| ERROR cannot find type `A` in this scope + { + todo!() + } +} + +struct Y {} + +impl FromIterator for Y { + fn from_iter(_: T) -> Self + where + T: IntoIterator, + T::Item = A, + //~^ ERROR equality constraints are not yet supported in `where` clauses + //~| ERROR cannot find type `A` in this scope + { + todo!() + } +} + +struct Z {} + +impl FromIterator for Z { + fn from_iter(_: T) -> Self + where + IntoIterator::Item = A, + //~^ ERROR equality constraints are not yet supported in `where` clauses + //~| ERROR cannot find type `A` in this scope + { + todo!() + } +} + +struct K {} + +impl FromIterator for K { + fn from_iter(_: T) -> Self + where + T::Item = A, + //~^ ERROR equality constraints are not yet supported in `where` clauses + //~| ERROR cannot find type `A` in this scope + { + todo!() + } +} + fn main() {} diff --git a/tests/ui/generic-associated-types/equality-bound.stderr b/tests/ui/generic-associated-types/equality-bound.stderr index b21ff30a27d..8e29d9092c5 100644 --- a/tests/ui/generic-associated-types/equality-bound.stderr +++ b/tests/ui/generic-associated-types/equality-bound.stderr @@ -32,6 +32,96 @@ LL | fn sum3(i: J) -> i32 where I::Item = i32 { | = note: see issue #20041 for more information +error: equality constraints are not yet supported in `where` clauses + --> $DIR/equality-bound.rs:23:9 + | +LL | IntoIterator::Item = A, + | ^^^^^^^^^^^^^^^^^^^^^^ not supported + | + = note: see issue #20041 for more information +help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax + | +LL ~ T: IntoIterator, +LL ~ , + | + +error: equality constraints are not yet supported in `where` clauses + --> $DIR/equality-bound.rs:37:9 + | +LL | T::Item = A, + | ^^^^^^^^^^^ not supported + | + = note: see issue #20041 for more information +help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax + | +LL ~ T: IntoIterator, +LL ~ , + | + +error: equality constraints are not yet supported in `where` clauses + --> $DIR/equality-bound.rs:50:9 + | +LL | IntoIterator::Item = A, + | ^^^^^^^^^^^^^^^^^^^^^^ not supported + | + = note: see issue #20041 for more information +help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax + | +LL ~ fn from_iter>(_: T) -> Self +LL | where +LL ~ , + | + +error: equality constraints are not yet supported in `where` clauses + --> $DIR/equality-bound.rs:63:9 + | +LL | T::Item = A, + | ^^^^^^^^^^^ not supported + | + = note: see issue #20041 for more information +help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax + | +LL ~ fn from_iter>(_: T) -> Self +LL | where +LL ~ , + | + +error[E0412]: cannot find type `A` in this scope + --> $DIR/equality-bound.rs:23:30 + | +LL | IntoIterator::Item = A, + | ^ help: a struct with a similar name exists: `K` +... +LL | struct K {} + | -------- similarly named struct `K` defined here + +error[E0412]: cannot find type `A` in this scope + --> $DIR/equality-bound.rs:37:19 + | +LL | T::Item = A, + | ^ help: a struct with a similar name exists: `K` +... +LL | struct K {} + | -------- similarly named struct `K` defined here + +error[E0412]: cannot find type `A` in this scope + --> $DIR/equality-bound.rs:50:30 + | +LL | IntoIterator::Item = A, + | ^ help: a struct with a similar name exists: `K` +... +LL | struct K {} + | -------- similarly named struct `K` defined here + +error[E0412]: cannot find type `A` in this scope + --> $DIR/equality-bound.rs:63:19 + | +LL | struct K {} + | -------- similarly named struct `K` defined here +... +LL | T::Item = A, + | ^ help: a struct with a similar name exists: `K` + error[E0433]: failed to resolve: use of undeclared type `I` --> $DIR/equality-bound.rs:9:41 | @@ -41,6 +131,7 @@ LL | fn sum3(i: J) -> i32 where I::Item = i32 { | use of undeclared type `I` | help: a type parameter with a similar name exists: `J` -error: aborting due to 4 previous errors +error: aborting due to 12 previous errors -For more information about this error, try `rustc --explain E0433`. +Some errors have detailed explanations: E0412, E0433. +For more information about an error, try `rustc --explain E0412`. From 535c64336d6dcd588dd794d526047a4425e6e402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 8 Feb 2024 00:26:42 +0000 Subject: [PATCH 02/14] Do not leave stray commas after applying suggestion --- .../rustc_ast_passes/src/ast_validation.rs | 117 +++++++++--------- .../equality-bound.rs | 39 +++--- .../equality-bound.stderr | 116 +++++++++++------ 3 files changed, 160 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ec54f1032c3..356b578d518 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1593,6 +1593,58 @@ fn deny_equality_constraints( } } } + + let mut suggest = + |poly: &PolyTraitRef, potential_assoc: &PathSegment, predicate: &WhereEqPredicate| { + if let [trait_segment] = &poly.trait_ref.path.segments[..] { + let assoc = pprust::path_to_string(&ast::Path::from_ident(potential_assoc.ident)); + let ty = pprust::ty_to_string(&predicate.rhs_ty); + let (args, span) = match &trait_segment.args { + Some(args) => match args.deref() { + ast::GenericArgs::AngleBracketed(args) => { + let Some(arg) = args.args.last() else { + return; + }; + (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi()) + } + _ => return, + }, + None => (format!("<{assoc} = {ty}>"), trait_segment.span().shrink_to_hi()), + }; + let removal_span = if generics.where_clause.predicates.len() == 1 { + // We're removing th eonly where bound left, remove the whole thing. + generics.where_clause.span + } else { + let mut span = predicate.span; + let mut prev: Option = None; + let mut preds = generics.where_clause.predicates.iter().peekable(); + // Find the predicate that shouldn't have been in the where bound list. + while let Some(pred) = preds.next() { + if let WherePredicate::EqPredicate(pred) = pred + && pred.span == predicate.span + { + if let Some(next) = preds.peek() { + // This is the first predicate, remove the trailing comma as well. + span = span.with_hi(next.span().lo()); + } else if let Some(prev) = prev { + // Remove the previous comma as well. + span = span.with_lo(prev.hi()); + } + } + prev = Some(pred.span()); + } + span + }; + err.assoc2 = Some(errors::AssociatedSuggestion2 { + span, + args, + predicate: removal_span, + trait_segment: trait_segment.ident, + potential_assoc: potential_assoc.ident, + }); + } + }; + if let TyKind::Path(None, full_path) = &predicate.lhs_ty.kind { // Given `A: Foo, Foo::Bar = RhsTy`, suggest `A: Foo`. for bounds in generics.params.iter().map(|p| &p.bounds).chain( @@ -1608,37 +1660,9 @@ fn deny_equality_constraints( .map(|segment| segment.ident.name) .zip(poly.trait_ref.path.segments.iter().map(|segment| segment.ident.name)) .all(|(a, b)| a == b) + && let Some(potential_assoc) = full_path.segments.iter().last() { - let potential_assoc = full_path.segments.iter().last().unwrap(); - // println!("asd"); - if let [trait_segment] = &poly.trait_ref.path.segments[..] { - let assoc = pprust::path_to_string(&ast::Path::from_ident( - potential_assoc.ident, - )); - let ty = pprust::ty_to_string(&predicate.rhs_ty); - let (args, span) = match &trait_segment.args { - Some(args) => match args.deref() { - ast::GenericArgs::AngleBracketed(args) => { - let Some(arg) = args.args.last() else { - continue; - }; - (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi()) - } - _ => continue, - }, - None => ( - format!("<{assoc} = {ty}>"), - trait_segment.span().shrink_to_hi(), - ), - }; - err.assoc2 = Some(errors::AssociatedSuggestion2 { - span, - args, - predicate: predicate.span, - trait_segment: trait_segment.ident, - potential_assoc: potential_assoc.ident, - }); - } + suggest(poly, potential_assoc, predicate); } } } @@ -1658,37 +1682,8 @@ fn deny_equality_constraints( ) { if ident == potential_param.ident { for bound in bounds { - if let ast::GenericBound::Trait(trait_ref, TraitBoundModifiers::NONE) = - bound - { - if let [trait_segment] = &trait_ref.trait_ref.path.segments[..] { - let assoc = pprust::path_to_string(&ast::Path::from_ident( - potential_assoc.ident, - )); - let ty = pprust::ty_to_string(&predicate.rhs_ty); - let (args, span) = match &trait_segment.args { - Some(args) => match args.deref() { - ast::GenericArgs::AngleBracketed(args) => { - let Some(arg) = args.args.last() else { - continue; - }; - (format!(", {assoc} = {ty}"), arg.span().shrink_to_hi()) - } - _ => continue, - }, - None => ( - format!("<{assoc} = {ty}>"), - trait_segment.span().shrink_to_hi(), - ), - }; - err.assoc2 = Some(errors::AssociatedSuggestion2 { - span, - args, - predicate: predicate.span, - trait_segment: trait_segment.ident, - potential_assoc: potential_assoc.ident, - }); - } + if let ast::GenericBound::Trait(poly, TraitBoundModifiers::NONE) = bound { + suggest(poly, potential_assoc, predicate); } } } diff --git a/tests/ui/generic-associated-types/equality-bound.rs b/tests/ui/generic-associated-types/equality-bound.rs index 63bb5dd3567..be05181f5d0 100644 --- a/tests/ui/generic-associated-types/equality-bound.rs +++ b/tests/ui/generic-associated-types/equality-bound.rs @@ -17,10 +17,7 @@ use std::iter::FromIterator; struct X {} impl FromIterator for X { - fn from_iter(_: T) -> Self - where - T: IntoIterator, - IntoIterator::Item = A, + fn from_iter(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A, //~^ ERROR equality constraints are not yet supported in `where` clauses //~| ERROR cannot find type `A` in this scope { @@ -31,10 +28,7 @@ impl FromIterator for X { struct Y {} impl FromIterator for Y { - fn from_iter(_: T) -> Self - where - T: IntoIterator, - T::Item = A, + fn from_iter(_: T) -> Self where T: IntoIterator, T::Item = A, //~^ ERROR equality constraints are not yet supported in `where` clauses //~| ERROR cannot find type `A` in this scope { @@ -45,9 +39,7 @@ impl FromIterator for Y { struct Z {} impl FromIterator for Z { - fn from_iter(_: T) -> Self - where - IntoIterator::Item = A, + fn from_iter(_: T) -> Self where IntoIterator::Item = A, //~^ ERROR equality constraints are not yet supported in `where` clauses //~| ERROR cannot find type `A` in this scope { @@ -58,9 +50,7 @@ impl FromIterator for Z { struct K {} impl FromIterator for K { - fn from_iter(_: T) -> Self - where - T::Item = A, + fn from_iter(_: T) -> Self where T::Item = A, //~^ ERROR equality constraints are not yet supported in `where` clauses //~| ERROR cannot find type `A` in this scope { @@ -68,4 +58,25 @@ impl FromIterator for K { } } +struct L {} + +impl FromIterator for L { + fn from_iter(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator, + //~^ ERROR equality constraints are not yet supported in `where` clauses + //~| ERROR cannot find type `A` in this scope + { + todo!() + } +} + +struct M {} + +impl FromIterator for M { + fn from_iter(_: T) -> Self where T::Item = A, T: IntoIterator, + //~^ ERROR equality constraints are not yet supported in `where` clauses + //~| ERROR cannot find type `A` in this scope + { + todo!() + } +} fn main() {} diff --git a/tests/ui/generic-associated-types/equality-bound.stderr b/tests/ui/generic-associated-types/equality-bound.stderr index 8e29d9092c5..a054c06caeb 100644 --- a/tests/ui/generic-associated-types/equality-bound.stderr +++ b/tests/ui/generic-associated-types/equality-bound.stderr @@ -8,7 +8,7 @@ LL | fn sum>(i: I) -> i32 where I::Item = i32 { help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax | LL - fn sum>(i: I) -> i32 where I::Item = i32 { -LL + fn sum>(i: I) -> i32 where { +LL + fn sum>(i: I) -> i32 { | error: equality constraints are not yet supported in `where` clauses @@ -21,7 +21,7 @@ LL | fn sum2(i: I) -> i32 where I::Item = i32 { help: if `Iterator::Item` is an associated type you're trying to set, use the associated type binding syntax | LL - fn sum2(i: I) -> i32 where I::Item = i32 { -LL + fn sum2>(i: I) -> i32 where { +LL + fn sum2>(i: I) -> i32 { | error: equality constraints are not yet supported in `where` clauses @@ -33,94 +33,136 @@ LL | fn sum3(i: J) -> i32 where I::Item = i32 { = note: see issue #20041 for more information error: equality constraints are not yet supported in `where` clauses - --> $DIR/equality-bound.rs:23:9 + --> $DIR/equality-bound.rs:20:58 | -LL | IntoIterator::Item = A, - | ^^^^^^^^^^^^^^^^^^^^^^ not supported +LL | fn from_iter(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A, + | ^^^^^^^^^^^^^^^^^^^^^^ not supported | = note: see issue #20041 for more information help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax | -LL ~ T: IntoIterator, -LL ~ , +LL - fn from_iter(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A, +LL + fn from_iter(_: T) -> Self where T: IntoIterator, | error: equality constraints are not yet supported in `where` clauses - --> $DIR/equality-bound.rs:37:9 + --> $DIR/equality-bound.rs:31:58 | -LL | T::Item = A, - | ^^^^^^^^^^^ not supported +LL | fn from_iter(_: T) -> Self where T: IntoIterator, T::Item = A, + | ^^^^^^^^^^^ not supported | = note: see issue #20041 for more information help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax | -LL ~ T: IntoIterator, -LL ~ , +LL - fn from_iter(_: T) -> Self where T: IntoIterator, T::Item = A, +LL + fn from_iter(_: T) -> Self where T: IntoIterator, | error: equality constraints are not yet supported in `where` clauses - --> $DIR/equality-bound.rs:50:9 + --> $DIR/equality-bound.rs:42:55 | -LL | IntoIterator::Item = A, - | ^^^^^^^^^^^^^^^^^^^^^^ not supported +LL | fn from_iter(_: T) -> Self where IntoIterator::Item = A, + | ^^^^^^^^^^^^^^^^^^^^^^ not supported | = note: see issue #20041 for more information help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax | -LL ~ fn from_iter>(_: T) -> Self -LL | where -LL ~ , +LL - fn from_iter(_: T) -> Self where IntoIterator::Item = A, +LL + fn from_iter>(_: T) -> Self | error: equality constraints are not yet supported in `where` clauses - --> $DIR/equality-bound.rs:63:9 + --> $DIR/equality-bound.rs:53:55 | -LL | T::Item = A, - | ^^^^^^^^^^^ not supported +LL | fn from_iter(_: T) -> Self where T::Item = A, + | ^^^^^^^^^^^ not supported | = note: see issue #20041 for more information help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax | -LL ~ fn from_iter>(_: T) -> Self -LL | where -LL ~ , +LL - fn from_iter(_: T) -> Self where T::Item = A, +LL + fn from_iter>(_: T) -> Self + | + +error: equality constraints are not yet supported in `where` clauses + --> $DIR/equality-bound.rs:64:41 + | +LL | fn from_iter(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator, + | ^^^^^^^^^^^^^^^^^^^^^^ not supported + | + = note: see issue #20041 for more information +help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax + | +LL - fn from_iter(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator, +LL + fn from_iter(_: T) -> Self where T: IntoIterator, + | + +error: equality constraints are not yet supported in `where` clauses + --> $DIR/equality-bound.rs:75:41 + | +LL | fn from_iter(_: T) -> Self where T::Item = A, T: IntoIterator, + | ^^^^^^^^^^^ not supported + | + = note: see issue #20041 for more information +help: if `IntoIterator::Item` is an associated type you're trying to set, use the associated type binding syntax + | +LL - fn from_iter(_: T) -> Self where T::Item = A, T: IntoIterator, +LL + fn from_iter(_: T) -> Self where T: IntoIterator, | error[E0412]: cannot find type `A` in this scope - --> $DIR/equality-bound.rs:23:30 + --> $DIR/equality-bound.rs:20:79 | -LL | IntoIterator::Item = A, - | ^ help: a struct with a similar name exists: `K` +LL | fn from_iter(_: T) -> Self where T: IntoIterator, IntoIterator::Item = A, + | ^ help: a struct with a similar name exists: `K` ... LL | struct K {} | -------- similarly named struct `K` defined here error[E0412]: cannot find type `A` in this scope - --> $DIR/equality-bound.rs:37:19 + --> $DIR/equality-bound.rs:31:68 | -LL | T::Item = A, - | ^ help: a struct with a similar name exists: `K` +LL | fn from_iter(_: T) -> Self where T: IntoIterator, T::Item = A, + | ^ help: a struct with a similar name exists: `K` ... LL | struct K {} | -------- similarly named struct `K` defined here error[E0412]: cannot find type `A` in this scope - --> $DIR/equality-bound.rs:50:30 + --> $DIR/equality-bound.rs:42:76 | -LL | IntoIterator::Item = A, - | ^ help: a struct with a similar name exists: `K` +LL | fn from_iter(_: T) -> Self where IntoIterator::Item = A, + | ^ help: a struct with a similar name exists: `K` ... LL | struct K {} | -------- similarly named struct `K` defined here error[E0412]: cannot find type `A` in this scope - --> $DIR/equality-bound.rs:63:19 + --> $DIR/equality-bound.rs:53:65 | LL | struct K {} | -------- similarly named struct `K` defined here ... -LL | T::Item = A, - | ^ help: a struct with a similar name exists: `K` +LL | fn from_iter(_: T) -> Self where T::Item = A, + | ^ help: a struct with a similar name exists: `K` + +error[E0412]: cannot find type `A` in this scope + --> $DIR/equality-bound.rs:64:62 + | +LL | struct K {} + | -------- similarly named struct `K` defined here +... +LL | fn from_iter(_: T) -> Self where IntoIterator::Item = A, T: IntoIterator, + | ^ help: a struct with a similar name exists: `K` + +error[E0412]: cannot find type `A` in this scope + --> $DIR/equality-bound.rs:75:51 + | +LL | struct K {} + | -------- similarly named struct `K` defined here +... +LL | fn from_iter(_: T) -> Self where T::Item = A, T: IntoIterator, + | ^ help: a struct with a similar name exists: `K` error[E0433]: failed to resolve: use of undeclared type `I` --> $DIR/equality-bound.rs:9:41 @@ -131,7 +173,7 @@ LL | fn sum3(i: J) -> i32 where I::Item = i32 { | use of undeclared type `I` | help: a type parameter with a similar name exists: `J` -error: aborting due to 12 previous errors +error: aborting due to 16 previous errors Some errors have detailed explanations: E0412, E0433. For more information about an error, try `rustc --explain E0412`. From 2d73597b93d27b94e1b534d84352f51629418380 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 8 Feb 2024 17:51:32 +0000 Subject: [PATCH 03/14] Bail out of drop elaboration when encountering error types --- .../src/move_paths/builder.rs | 5 ++++- tests/ui/drop/drop_elaboration_with_errors.rs | 20 +++++++++++++++++++ .../drop/drop_elaboration_with_errors.stderr | 14 +++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/ui/drop/drop_elaboration_with_errors.rs create mode 100644 tests/ui/drop/drop_elaboration_with_errors.stderr diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 30dd915521c..8c2690574e5 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -1,7 +1,7 @@ use rustc_index::IndexVec; use rustc_middle::mir::tcx::{PlaceTy, RvalueInitializationState}; use rustc_middle::mir::*; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use smallvec::{smallvec, SmallVec}; use std::mem; @@ -132,6 +132,9 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { let body = self.builder.body; let tcx = self.builder.tcx; let place_ty = place_ref.ty(body, tcx).ty; + if place_ty.references_error() { + return MovePathResult::Error; + } match elem { ProjectionElem::Deref => match place_ty.kind() { ty::Ref(..) | ty::RawPtr(..) => { diff --git a/tests/ui/drop/drop_elaboration_with_errors.rs b/tests/ui/drop/drop_elaboration_with_errors.rs new file mode 100644 index 00000000000..77862762e87 --- /dev/null +++ b/tests/ui/drop/drop_elaboration_with_errors.rs @@ -0,0 +1,20 @@ +// can't use build-fail, because this also fails check-fail, but +// the ICE from #120787 only reproduces on build-fail. +// compile-flags: --emit=mir + +#![feature(type_alias_impl_trait)] + +struct Foo { + field: String, +} + +type Tait = impl Sized; + +fn ice_cold(beverage: Tait) { + let Foo { field } = beverage; + _ = field; +} + +fn main() { + Ok(()) //~ ERROR mismatched types +} diff --git a/tests/ui/drop/drop_elaboration_with_errors.stderr b/tests/ui/drop/drop_elaboration_with_errors.stderr new file mode 100644 index 00000000000..bec229631e1 --- /dev/null +++ b/tests/ui/drop/drop_elaboration_with_errors.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/drop_elaboration_with_errors.rs:19:5 + | +LL | fn main() { + | - expected `()` because of default return type +LL | Ok(()) + | ^^^^^^ expected `()`, found `Result<(), _>` + | + = note: expected unit type `()` + found enum `Result<(), _>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. From 730560b982006c35f811a5de53fe8e1fa422c024 Mon Sep 17 00:00:00 2001 From: Tristan F Date: Mon, 12 Feb 2024 08:20:13 -0500 Subject: [PATCH 04/14] docs: mention round-to-even in precision formatting --- library/alloc/src/fmt.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index fce2585cbf5..acff026b91b 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -278,6 +278,19 @@ //! Hello, ` 123` has 3 right-aligned characters //! ``` //! +//! When truncuating these values, Rust uses round-to-even, which may +//! cause concern when formatting for scientific notation. For example, +//! +//! ``` +//! print!("{0:.1$e}", 12345, 3); +//! ``` +//! +//! Would return: +//! +//! ```text +//! 1.234e4 +//! ``` +//! //! ## Localization //! //! In some programming languages, the behavior of string formatting functions From 718b304d82bae9ba6db0872b851c7c0e5032b4c0 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Mon, 12 Feb 2024 15:23:42 +0100 Subject: [PATCH 05/14] llvm-wrapper: adapt for LLVM API change: Add support for EXPORTAS name types Adapt for llvm/llvm-project@8f23464. --- compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index a2dfebec594..b45706fd1e5 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1801,6 +1801,9 @@ extern "C" LLVMRustResult LLVMRustWriteImportLibrary( std::string{}, // ExtName std::string{}, // SymbolName std::string{}, // AliasTarget +#if LLVM_VERSION_GE(19, 0) + std::string{}, // ExportAs +#endif ordinal, // Ordinal ordinal_present, // Noname false, // Data From 30f66659535c1eb37f98b42b42323089c1a21bb0 Mon Sep 17 00:00:00 2001 From: "Tristan F." Date: Mon, 12 Feb 2024 14:43:19 +0000 Subject: [PATCH 06/14] style: fmt --- library/alloc/src/fmt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index acff026b91b..6899ff4711f 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -284,7 +284,7 @@ //! ``` //! print!("{0:.1$e}", 12345, 3); //! ``` -//! +//! //! Would return: //! //! ```text From 142ab9e88264e6820a7d817b1592eec6380438a7 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Feb 2024 22:22:14 +0200 Subject: [PATCH 07/14] iterator.rs: remove "Basic usage" text Only one example is given (for each method) --- library/core/src/iter/traits/iterator.rs | 40 ------------------------ 1 file changed, 40 deletions(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 83f8fd25b50..20dd95a3a46 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -89,8 +89,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [1, 2, 3]; /// @@ -249,8 +247,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [1, 2, 3]; /// assert_eq!(a.iter().count(), 3); @@ -280,8 +276,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [1, 2, 3]; /// assert_eq!(a.iter().last(), Some(&3)); @@ -324,8 +318,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(iter_advance_by)] /// @@ -432,8 +424,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [0, 1, 2, 3, 4, 5]; /// let mut iter = a.iter().step_by(2); @@ -1342,8 +1332,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [1, 2, 3]; /// @@ -1434,8 +1422,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [1, 2, 3, 4]; /// @@ -1486,8 +1472,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let words = ["alpha", "beta", "gamma"]; /// @@ -1765,8 +1749,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// // an iterator which alternates between Some and None /// struct Alternate { @@ -1911,8 +1893,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let mut words = ["hello", "world", "of", "Rust"].into_iter(); /// @@ -2221,8 +2201,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [1, 2, 3]; /// @@ -3193,8 +3171,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [1, 2, 3]; /// let b: Vec = Vec::new(); @@ -3232,8 +3208,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [1, 2, 3]; /// let b: Vec = Vec::new(); @@ -3420,8 +3394,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [(1, 2), (3, 4), (5, 6)]; /// @@ -3458,8 +3430,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [1, 2, 3]; /// @@ -3538,8 +3508,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [1, 2, 3]; /// @@ -3624,8 +3592,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// let a = [1, 2, 3]; /// let sum: i32 = a.iter().sum(); @@ -3703,8 +3669,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(iter_order_by)] /// @@ -3790,8 +3754,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(iter_order_by)] /// @@ -3863,8 +3825,6 @@ pub trait Iterator { /// /// # Examples /// - /// Basic usage: - /// /// ``` /// #![feature(iter_order_by)] /// From 37d2ea2fa064411de78ec24a178a05dc02517673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 6 Feb 2024 03:30:16 +0000 Subject: [PATCH 08/14] Properly handle `async` blocks and `fn`s in `if` exprs without `else` When encountering a tail expression in the then arm of an `if` expression without an `else` arm, account for `async fn` and `async` blocks to suggest `return`ing the value and pointing at the return type of the `async fn`. We now also account for AFIT when looking for the return type to point at. Fix #115405. --- compiler/rustc_hir_typeck/src/coercion.rs | 39 +++++-- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 37 +++++-- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 5 +- .../src/fn_ctxt/suggestions.rs | 103 +++++++++++++----- compiler/rustc_middle/src/hir/map/mod.rs | 2 +- .../rustc_parse/src/parser/diagnostics.rs | 2 +- .../missing-return-in-async-block.fixed | 22 ++++ .../missing-return-in-async-block.rs | 22 ++++ .../missing-return-in-async-block.stderr | 35 ++++++ .../in-trait/default-body-type-err-2.stderr | 2 + .../ui/loops/dont-suggest-break-thru-item.rs | 2 + .../loops/dont-suggest-break-thru-item.stderr | 40 ++++--- 12 files changed, 250 insertions(+), 61 deletions(-) create mode 100644 tests/ui/async-await/missing-return-in-async-block.fixed create mode 100644 tests/ui/async-await/missing-return-in-async-block.rs create mode 100644 tests/ui/async-await/missing-return-in-async-block.stderr diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 549ad44d7e3..882fa770016 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -92,14 +92,17 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { type CoerceResult<'tcx> = InferResult<'tcx, (Vec>, Ty<'tcx>)>; -struct CollectRetsVisitor<'tcx> { - ret_exprs: Vec<&'tcx hir::Expr<'tcx>>, +pub struct CollectRetsVisitor<'tcx> { + pub ret_exprs: Vec<&'tcx hir::Expr<'tcx>>, } impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> { fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if let hir::ExprKind::Ret(_) = expr.kind { - self.ret_exprs.push(expr); + match expr.kind { + hir::ExprKind::Ret(_) => self.ret_exprs.push(expr), + // `return` in closures does not return from the outer function + hir::ExprKind::Closure(_) => return, + _ => {} } intravisit::walk_expr(self, expr); } @@ -1845,13 +1848,31 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } let parent_id = fcx.tcx.hir().get_parent_item(id); - let parent_item = fcx.tcx.hir_node_by_def_id(parent_id.def_id); + let mut parent_item = fcx.tcx.hir_node_by_def_id(parent_id.def_id); + // When suggesting return, we need to account for closures and async blocks, not just items. + for (_, node) in fcx.tcx.hir().parent_iter(id) { + match node { + hir::Node::Expr(&hir::Expr { + kind: hir::ExprKind::Closure(hir::Closure { .. }), + .. + }) => { + parent_item = node; + break; + } + hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => break, + _ => {} + } + } - if let (Some(expr), Some(_), Some((fn_id, fn_decl, _, _))) = - (expression, blk_id, fcx.get_node_fn_decl(parent_item)) - { + if let (Some(expr), Some(_), Some(fn_decl)) = (expression, blk_id, parent_item.fn_decl()) { fcx.suggest_missing_break_or_return_expr( - &mut err, expr, fn_decl, expected, found, id, fn_id, + &mut err, + expr, + fn_decl, + expected, + found, + id, + parent_id.into(), ); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 165937de247..3847f03a378 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -963,14 +963,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { owner_id, .. }) => 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 Node::Item(&hir::Item { - ident, - kind: hir::ItemKind::Fn(ref sig, ..), - owner_id, - .. - }) = self.tcx.parent_hir_node(hir_id) => - { + Node::Expr(&hir::Expr { + hir_id, + kind: + hir::ExprKind::Closure(hir::Closure { + kind: hir::ClosureKind::Coroutine(..), .. + }), + .. + }) => { + let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) { + Node::Item(&hir::Item { + ident, + kind: hir::ItemKind::Fn(ref sig, ..), + owner_id, + .. + }) => (ident, sig, owner_id), + Node::TraitItem(&hir::TraitItem { + ident, + kind: hir::TraitItemKind::Fn(ref sig, ..), + owner_id, + .. + }) => (ident, sig, owner_id), + Node::ImplItem(&hir::ImplItem { + ident, + kind: hir::ImplItemKind::Fn(ref sig, ..), + owner_id, + .. + }) => (ident, sig, owner_id), + _ => return None, + }; Some(( hir::HirId::make_owner(owner_id.def_id), &sig.decl, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 35b3f27d791..65b8505c090 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1726,7 +1726,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// 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)> { + pub(crate) fn get_parent_fn_decl( + &self, + blk_id: hir::HirId, + ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { let parent = self.tcx.hir_node_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)) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 193c9a4b908..38cc1f5c102 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1,5 +1,6 @@ use super::FnCtxt; +use crate::coercion::CollectRetsVisitor; use crate::errors; use crate::fluent_generated as fluent; use crate::fn_ctxt::rustc_span::BytePos; @@ -16,6 +17,7 @@ use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; +use rustc_hir::intravisit::{Map, Visitor}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node, @@ -827,6 +829,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } hir::FnRetTy::Return(hir_ty) => { if let hir::TyKind::OpaqueDef(item_id, ..) = hir_ty.kind + // FIXME: account for RPITIT. && let hir::Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(op_ty), .. }) = self.tcx.hir_node(item_id.hir_id()) @@ -1038,33 +1041,81 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - if let hir::FnRetTy::Return(ty) = fn_decl.output { - let ty = self.astconv().ast_ty_to_ty(ty); - let bound_vars = self.tcx.late_bound_vars(fn_id); - let ty = self - .tcx - .instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars)); - let ty = match self.tcx.asyncness(fn_id.owner) { - ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| { - span_bug!(fn_decl.output.span(), "failed to get output type of async function") - }), - ty::Asyncness::No => ty, - }; - let ty = self.normalize(expr.span, ty); - if self.can_coerce(found, ty) { - if let Some(owner_node) = self.tcx.hir_node(fn_id).as_owner() - && let Some(span) = expr.span.find_ancestor_inside(*owner_node.span()) - { - err.multipart_suggestion( - "you might have meant to return this value", - vec![ - (span.shrink_to_lo(), "return ".to_string()), - (span.shrink_to_hi(), ";".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } + let in_closure = matches!( + self.tcx + .hir() + .parent_iter(id) + .filter(|(_, node)| { + matches!( + node, + Node::Expr(Expr { kind: ExprKind::Closure(..), .. }) + | Node::Item(_) + | Node::TraitItem(_) + | Node::ImplItem(_) + ) + }) + .next(), + Some((_, Node::Expr(Expr { kind: ExprKind::Closure(..), .. }))) + ); + + let can_return = match fn_decl.output { + hir::FnRetTy::Return(ty) => { + let ty = self.astconv().ast_ty_to_ty(ty); + let bound_vars = self.tcx.late_bound_vars(fn_id); + let ty = self + .tcx + .instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars)); + let ty = match self.tcx.asyncness(fn_id.owner) { + ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| { + span_bug!( + fn_decl.output.span(), + "failed to get output type of async function" + ) + }), + ty::Asyncness::No => ty, + }; + let ty = self.normalize(expr.span, ty); + self.can_coerce(found, ty) } + hir::FnRetTy::DefaultReturn(_) if in_closure => { + let mut rets = vec![]; + if let Some(ret_coercion) = self.ret_coercion.as_ref() { + let ret_ty = ret_coercion.borrow().expected_ty(); + rets.push(ret_ty); + } + let mut visitor = CollectRetsVisitor { ret_exprs: vec![] }; + if let Some(item) = self.tcx.hir().find(id) + && let Node::Expr(expr) = item + { + visitor.visit_expr(expr); + for expr in visitor.ret_exprs { + if let Some(ty) = self.typeck_results.borrow().node_type_opt(expr.hir_id) { + rets.push(ty); + } + } + if let hir::ExprKind::Block(hir::Block { expr: Some(expr), .. }, _) = expr.kind + { + if let Some(ty) = self.typeck_results.borrow().node_type_opt(expr.hir_id) { + rets.push(ty); + } + } + } + rets.into_iter().all(|ty| self.can_coerce(found, ty)) + } + _ => false, + }; + if can_return + && let Some(owner_node) = self.tcx.hir_node(fn_id).as_owner() + && let Some(span) = expr.span.find_ancestor_inside(owner_node.span()) + { + err.multipart_suggestion( + "you might have meant to return this value", + vec![ + (span.shrink_to_lo(), "return ".to_string()), + (span.shrink_to_hi(), ";".to_string()), + ], + Applicability::MaybeIncorrect, + ); } } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 8e1cb6a514f..e7d9dc04886 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -617,7 +617,7 @@ impl<'hir> Map<'hir> { Node::Item(_) | Node::ForeignItem(_) | Node::TraitItem(_) - | Node::Expr(Expr { kind: ExprKind::Closure { .. }, .. }) + | Node::Expr(Expr { kind: ExprKind::Closure(_), .. }) | Node::ImplItem(_) // The input node `id` must be enclosed in the method's body as opposed // to some other place such as its return type (fixes #114918). diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 7a24b819b5f..445d5b2ce79 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -900,7 +900,7 @@ impl<'a> Parser<'a> { // fn foo() -> Foo { // field: value, // } - info!(?maybe_struct_name, ?self.token); + debug!(?maybe_struct_name, ?self.token); let mut snapshot = self.create_snapshot_for_diagnostic(); let path = Path { segments: ThinVec::new(), diff --git a/tests/ui/async-await/missing-return-in-async-block.fixed b/tests/ui/async-await/missing-return-in-async-block.fixed new file mode 100644 index 00000000000..3dbac7945b6 --- /dev/null +++ b/tests/ui/async-await/missing-return-in-async-block.fixed @@ -0,0 +1,22 @@ +// run-rustfix +// edition:2021 +use std::future::Future; +use std::pin::Pin; +pub struct S; +pub fn foo() { + let _ = Box::pin(async move { + if true { + return Ok(S); //~ ERROR mismatched types + } + Err(()) + }); +} +pub fn bar() -> Pin> + 'static>> { + Box::pin(async move { + if true { + return Ok(S); //~ ERROR mismatched types + } + Err(()) + }) +} +fn main() {} diff --git a/tests/ui/async-await/missing-return-in-async-block.rs b/tests/ui/async-await/missing-return-in-async-block.rs new file mode 100644 index 00000000000..7d04e0e0fad --- /dev/null +++ b/tests/ui/async-await/missing-return-in-async-block.rs @@ -0,0 +1,22 @@ +// run-rustfix +// edition:2021 +use std::future::Future; +use std::pin::Pin; +pub struct S; +pub fn foo() { + let _ = Box::pin(async move { + if true { + Ok(S) //~ ERROR mismatched types + } + Err(()) + }); +} +pub fn bar() -> Pin> + 'static>> { + Box::pin(async move { + if true { + Ok(S) //~ ERROR mismatched types + } + Err(()) + }) +} +fn main() {} diff --git a/tests/ui/async-await/missing-return-in-async-block.stderr b/tests/ui/async-await/missing-return-in-async-block.stderr new file mode 100644 index 00000000000..5ea76e5f7bf --- /dev/null +++ b/tests/ui/async-await/missing-return-in-async-block.stderr @@ -0,0 +1,35 @@ +error[E0308]: mismatched types + --> $DIR/missing-return-in-async-block.rs:9:13 + | +LL | / if true { +LL | | Ok(S) + | | ^^^^^ expected `()`, found `Result` +LL | | } + | |_________- expected this to be `()` + | + = note: expected unit type `()` + found enum `Result` +help: you might have meant to return this value + | +LL | return Ok(S); + | ++++++ + + +error[E0308]: mismatched types + --> $DIR/missing-return-in-async-block.rs:17:13 + | +LL | / if true { +LL | | Ok(S) + | | ^^^^^ expected `()`, found `Result` +LL | | } + | |_________- expected this to be `()` + | + = note: expected unit type `()` + found enum `Result` +help: you might have meant to return this value + | +LL | return Ok(S); + | ++++++ + + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr b/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr index 77f6945f064..9fa73d817ca 100644 --- a/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr +++ b/tests/ui/impl-trait/in-trait/default-body-type-err-2.stderr @@ -1,6 +1,8 @@ error[E0308]: mismatched types --> $DIR/default-body-type-err-2.rs:7:9 | +LL | async fn woopsie_async(&self) -> String { + | ------ expected `String` because of return type LL | 42 | ^^- help: try using a conversion method: `.to_string()` | | diff --git a/tests/ui/loops/dont-suggest-break-thru-item.rs b/tests/ui/loops/dont-suggest-break-thru-item.rs index b46ba89e81d..308101115e5 100644 --- a/tests/ui/loops/dont-suggest-break-thru-item.rs +++ b/tests/ui/loops/dont-suggest-break-thru-item.rs @@ -8,6 +8,7 @@ fn closure() { if true { Err(1) //~^ ERROR mismatched types + //~| HELP you might have meant to return this value } Ok(()) @@ -21,6 +22,7 @@ fn async_block() { if true { Err(1) //~^ ERROR mismatched types + //~| HELP you might have meant to return this value } Ok(()) diff --git a/tests/ui/loops/dont-suggest-break-thru-item.stderr b/tests/ui/loops/dont-suggest-break-thru-item.stderr index 4fce4715119..c84a98198f5 100644 --- a/tests/ui/loops/dont-suggest-break-thru-item.stderr +++ b/tests/ui/loops/dont-suggest-break-thru-item.stderr @@ -5,14 +5,37 @@ LL | / if true { LL | | Err(1) | | ^^^^^^ expected `()`, found `Result<_, {integer}>` LL | | +LL | | LL | | } | |_____________- expected this to be `()` | = note: expected unit type `()` found enum `Result<_, {integer}>` +help: you might have meant to return this value + | +LL | return Err(1); + | ++++++ + error[E0308]: mismatched types - --> $DIR/dont-suggest-break-thru-item.rs:22:17 + --> $DIR/dont-suggest-break-thru-item.rs:23:17 + | +LL | / if true { +LL | | Err(1) + | | ^^^^^^ expected `()`, found `Result<_, {integer}>` +LL | | +LL | | +LL | | } + | |_____________- expected this to be `()` + | + = note: expected unit type `()` + found enum `Result<_, {integer}>` +help: you might have meant to return this value + | +LL | return Err(1); + | ++++++ + + +error[E0308]: mismatched types + --> $DIR/dont-suggest-break-thru-item.rs:37:17 | LL | / if true { LL | | Err(1) @@ -25,20 +48,7 @@ LL | | } found enum `Result<_, {integer}>` error[E0308]: mismatched types - --> $DIR/dont-suggest-break-thru-item.rs:35:17 - | -LL | / if true { -LL | | Err(1) - | | ^^^^^^ expected `()`, found `Result<_, {integer}>` -LL | | -LL | | } - | |_____________- expected this to be `()` - | - = note: expected unit type `()` - found enum `Result<_, {integer}>` - -error[E0308]: mismatched types - --> $DIR/dont-suggest-break-thru-item.rs:47:17 + --> $DIR/dont-suggest-break-thru-item.rs:49:17 | LL | / if true { LL | | Err(1) From d07195fe6b5f522438d9d79f4bec3bdc44ce9764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 6 Feb 2024 05:04:58 +0000 Subject: [PATCH 09/14] Remove visitor use --- compiler/rustc_hir_typeck/src/coercion.rs | 4 +- .../src/fn_ctxt/suggestions.rs | 63 +++++++------------ 2 files changed, 23 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 882fa770016..72fdff6025f 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -92,8 +92,8 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { type CoerceResult<'tcx> = InferResult<'tcx, (Vec>, Ty<'tcx>)>; -pub struct CollectRetsVisitor<'tcx> { - pub ret_exprs: Vec<&'tcx hir::Expr<'tcx>>, +struct CollectRetsVisitor<'tcx> { + ret_exprs: Vec<&'tcx hir::Expr<'tcx>>, } impl<'tcx> Visitor<'tcx> for CollectRetsVisitor<'tcx> { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 38cc1f5c102..0e18a96df71 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1,6 +1,5 @@ use super::FnCtxt; -use crate::coercion::CollectRetsVisitor; use crate::errors; use crate::fluent_generated as fluent; use crate::fn_ctxt::rustc_span::BytePos; @@ -17,7 +16,6 @@ use rustc_errors::{Applicability, Diagnostic, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; -use rustc_hir::intravisit::{Map, Visitor}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId, Node, @@ -1041,22 +1039,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - let in_closure = matches!( - self.tcx - .hir() - .parent_iter(id) - .filter(|(_, node)| { - matches!( - node, - Node::Expr(Expr { kind: ExprKind::Closure(..), .. }) - | Node::Item(_) - | Node::TraitItem(_) - | Node::ImplItem(_) - ) - }) - .next(), - Some((_, Node::Expr(Expr { kind: ExprKind::Closure(..), .. }))) - ); + let scope = self + .tcx + .hir() + .parent_iter(id) + .filter(|(_, node)| { + matches!( + node, + Node::Expr(Expr { kind: ExprKind::Closure(..), .. }) + | Node::Item(_) + | Node::TraitItem(_) + | Node::ImplItem(_) + ) + }) + .next(); + let in_closure = + matches!(scope, Some((_, Node::Expr(Expr { kind: ExprKind::Closure(..), .. })))); let can_return = match fn_decl.output { hir::FnRetTy::Return(ty) => { @@ -1078,35 +1076,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.can_coerce(found, ty) } hir::FnRetTy::DefaultReturn(_) if in_closure => { - let mut rets = vec![]; - if let Some(ret_coercion) = self.ret_coercion.as_ref() { - let ret_ty = ret_coercion.borrow().expected_ty(); - rets.push(ret_ty); - } - let mut visitor = CollectRetsVisitor { ret_exprs: vec![] }; - if let Some(item) = self.tcx.hir().find(id) - && let Node::Expr(expr) = item - { - visitor.visit_expr(expr); - for expr in visitor.ret_exprs { - if let Some(ty) = self.typeck_results.borrow().node_type_opt(expr.hir_id) { - rets.push(ty); - } - } - if let hir::ExprKind::Block(hir::Block { expr: Some(expr), .. }, _) = expr.kind - { - if let Some(ty) = self.typeck_results.borrow().node_type_opt(expr.hir_id) { - rets.push(ty); - } - } - } - rets.into_iter().all(|ty| self.can_coerce(found, ty)) + self.ret_coercion.as_ref().map_or(false, |ret| { + let ret_ty = ret.borrow().expected_ty(); + self.can_coerce(found, ret_ty) + }) } _ => false, }; if can_return && let Some(owner_node) = self.tcx.hir_node(fn_id).as_owner() - && let Some(span) = expr.span.find_ancestor_inside(owner_node.span()) + && let Some(span) = expr.span.find_ancestor_inside(*owner_node.span()) { err.multipart_suggestion( "you might have meant to return this value", From c51b9ff8ba0318755db4d0787206e732688fbdc5 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Feb 2024 23:08:00 +0200 Subject: [PATCH 10/14] remove redundant logic Made redundant in 3f697b85f2196ea7d2a5d4fa1f88c39e63871d39 --- compiler/rustc_hir_typeck/src/method/suggest.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 7fc51e36a2b..ff6a52594a1 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1073,12 +1073,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // for instance self.tcx.at(span).type_of(*def_id).instantiate_identity() != rcvr_ty - && self - .tcx - .at(span) - .type_of(*def_id) - .instantiate_identity() - != rcvr_ty } (Mode::Path, false, _) => true, _ => false, From 882396cbd0835491204d574f769f4d16763e8b95 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Mon, 12 Feb 2024 23:22:49 +0200 Subject: [PATCH 11/14] fix comment --- compiler/rustc_hir_typeck/src/method/suggest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 7fc51e36a2b..0231d871ddd 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1092,7 +1092,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inherent_impls_candidate.sort(); inherent_impls_candidate.dedup(); - // number of type to shows at most. + // number of types to show at most let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 }; let type_candidates = inherent_impls_candidate .iter() From 6fe4d66e647d26b707039f6b6520e6f5c77fdf71 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Feb 2024 15:14:58 +0100 Subject: [PATCH 12/14] allow static_mut_ref in some tests that specifically test mutable statics --- .../const_refs_to_static_fail_invalid.rs | 2 +- .../const_refs_to_static_fail_invalid.stderr | 27 ++------- .../ui/consts/issue-17718-const-bad-values.rs | 3 +- .../issue-17718-const-bad-values.stderr | 21 +------ ..._refers_to_static_cross_crate.32bit.stderr | 21 +------ ..._refers_to_static_cross_crate.64bit.stderr | 21 +------ .../const_refers_to_static_cross_crate.rs | 2 +- .../consts/static_mut_containing_mut_ref.rs | 2 +- .../static_mut_containing_mut_ref.stderr | 17 ------ ...ic_mut_containing_mut_ref2.mut_refs.stderr | 17 +----- .../consts/static_mut_containing_mut_ref2.rs | 4 +- ...tatic_mut_containing_mut_ref2.stock.stderr | 17 +----- tests/ui/thread-local/thread-local-static.rs | 4 +- .../thread-local/thread-local-static.stderr | 25 ++------ .../thread-local-static.thir.stderr | 59 ------------------- 15 files changed, 30 insertions(+), 212 deletions(-) delete mode 100644 tests/ui/consts/static_mut_containing_mut_ref.stderr delete mode 100644 tests/ui/thread-local/thread-local-static.thir.stderr diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.rs b/tests/ui/consts/const_refs_to_static_fail_invalid.rs index bf52f884209..665b876c43e 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.rs +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.rs @@ -1,6 +1,7 @@ // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" // normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*ALLOC[0-9]+(\+[a-z0-9]+)?()?─*╼ )+ *│.*" -> "HEX_DUMP" #![feature(const_refs_to_static)] +#![allow(static_mut_ref)] fn invalid() { static S: i8 = 10; @@ -38,7 +39,6 @@ fn mutable() { const C: &i32 = unsafe { &S_MUT }; //~^ERROR: undefined behavior //~| encountered reference to mutable memory - //~| WARN shared reference of mutable static is discouraged // This *must not build*, the constant we are matching against // could change its value! diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr index 35051557b61..082f8532444 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr @@ -1,20 +1,5 @@ -warning: shared reference of mutable static is discouraged - --> $DIR/const_refs_to_static_fail_invalid.rs:38:30 - | -LL | const C: &i32 = unsafe { &S_MUT }; - | ^^^^^^ shared reference of mutable static - | - = note: for more information, see issue #114447 - = note: reference of mutable static is a hard error from 2024 edition - = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior - = note: `#[warn(static_mut_ref)]` on by default -help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer - | -LL | const C: &i32 = unsafe { addr_of!(S_MUT) }; - | ~~~~~~~~~~~~~~~ - error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refs_to_static_fail_invalid.rs:8:5 + --> $DIR/const_refs_to_static_fail_invalid.rs:9:5 | LL | const C: &bool = unsafe { std::mem::transmute(&S) }; | ^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0a, but expected a boolean @@ -25,13 +10,13 @@ LL | const C: &bool = unsafe { std::mem::transmute(&S) }; } error: could not evaluate constant pattern - --> $DIR/const_refs_to_static_fail_invalid.rs:14:9 + --> $DIR/const_refs_to_static_fail_invalid.rs:15:9 | LL | C => {} | ^ error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refs_to_static_fail_invalid.rs:24:5 + --> $DIR/const_refs_to_static_fail_invalid.rs:25:5 | LL | const C: &i8 = unsafe { &S }; | ^^^^^^^^^^^^ constructing invalid value: encountered reference to `extern` static in `const` @@ -42,13 +27,13 @@ LL | const C: &i8 = unsafe { &S }; } error: could not evaluate constant pattern - --> $DIR/const_refs_to_static_fail_invalid.rs:30:9 + --> $DIR/const_refs_to_static_fail_invalid.rs:31:9 | LL | C => {} | ^ error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refs_to_static_fail_invalid.rs:38:5 + --> $DIR/const_refs_to_static_fail_invalid.rs:39:5 | LL | const C: &i32 = unsafe { &S_MUT }; | ^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` @@ -64,6 +49,6 @@ error: could not evaluate constant pattern LL | C => {}, | ^ -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs index 2b593a192ee..0299bfef1b4 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.rs +++ b/tests/ui/consts/issue-17718-const-bad-values.rs @@ -1,9 +1,10 @@ +#![allow(static_mut_ref)] + const C1: &'static mut [usize] = &mut []; //~^ ERROR: mutable references are not allowed static mut S: usize = 3; const C2: &'static mut usize = unsafe { &mut S }; //~^ ERROR: referencing statics in constants -//~| WARN mutable reference of mutable static is discouraged [static_mut_ref] fn main() {} diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr index 92bab1ab53e..57fcb1c7e9a 100644 --- a/tests/ui/consts/issue-17718-const-bad-values.stderr +++ b/tests/ui/consts/issue-17718-const-bad-values.stderr @@ -1,26 +1,11 @@ -warning: mutable reference of mutable static is discouraged - --> $DIR/issue-17718-const-bad-values.rs:5:41 - | -LL | const C2: &'static mut usize = unsafe { &mut S }; - | ^^^^^^ mutable reference of mutable static - | - = note: for more information, see issue #114447 - = note: reference of mutable static is a hard error from 2024 edition - = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior - = note: `#[warn(static_mut_ref)]` on by default -help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer - | -LL | const C2: &'static mut usize = unsafe { addr_of_mut!(S) }; - | ~~~~~~~~~~~~~~~ - error[E0764]: mutable references are not allowed in the final value of constants - --> $DIR/issue-17718-const-bad-values.rs:1:34 + --> $DIR/issue-17718-const-bad-values.rs:3:34 | LL | const C1: &'static mut [usize] = &mut []; | ^^^^^^^ error[E0658]: referencing statics in constants is unstable - --> $DIR/issue-17718-const-bad-values.rs:5:46 + --> $DIR/issue-17718-const-bad-values.rs:7:46 | LL | const C2: &'static mut usize = unsafe { &mut S }; | ^ @@ -31,7 +16,7 @@ LL | const C2: &'static mut usize = unsafe { &mut S }; = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable. = help: to fix this, the value can be extracted to a `const` and then used. -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors Some errors have detailed explanations: E0658, E0764. For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr index e280fe622ec..db7e8b6847a 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr @@ -1,20 +1,5 @@ -warning: shared reference of mutable static is discouraged - --> $DIR/const_refers_to_static_cross_crate.rs:12:14 - | -LL | unsafe { &static_cross_crate::ZERO } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static - | - = note: for more information, see issue #114447 - = note: reference of mutable static is a hard error from 2024 edition - = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior - = note: `#[warn(static_mut_ref)]` on by default -help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer - | -LL | unsafe { addr_of!(static_cross_crate::ZERO) } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static_cross_crate.rs:10:1 + --> $DIR/const_refers_to_static_cross_crate.rs:11:1 | LL | const SLICE_MUT: &[u8; 1] = { | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` @@ -79,7 +64,7 @@ LL | U8_MUT3 => true, warning: skipping const checks | help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -99,6 +84,6 @@ help: skipping check for `const_refs_to_static` feature LL | match static_cross_crate::OPT_ZERO { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors; 2 warnings emitted +error: aborting due to 8 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr index 9bca60485c0..200faf35587 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr @@ -1,20 +1,5 @@ -warning: shared reference of mutable static is discouraged - --> $DIR/const_refers_to_static_cross_crate.rs:12:14 - | -LL | unsafe { &static_cross_crate::ZERO } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ shared reference of mutable static - | - = note: for more information, see issue #114447 - = note: reference of mutable static is a hard error from 2024 edition - = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior - = note: `#[warn(static_mut_ref)]` on by default -help: shared references are dangerous since if there's any kind of mutation of that static while the reference lives, that's UB; use `addr_of!` instead to create a raw pointer - | -LL | unsafe { addr_of!(static_cross_crate::ZERO) } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - error[E0080]: it is undefined behavior to use this value - --> $DIR/const_refers_to_static_cross_crate.rs:10:1 + --> $DIR/const_refers_to_static_cross_crate.rs:11:1 | LL | const SLICE_MUT: &[u8; 1] = { | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered reference to mutable memory in `const` @@ -79,7 +64,7 @@ LL | U8_MUT3 => true, warning: skipping const checks | help: skipping check for `const_refs_to_static` feature - --> $DIR/const_refers_to_static_cross_crate.rs:12:15 + --> $DIR/const_refers_to_static_cross_crate.rs:13:15 | LL | unsafe { &static_cross_crate::ZERO } | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -99,6 +84,6 @@ help: skipping check for `const_refs_to_static` feature LL | match static_cross_crate::OPT_ZERO { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors; 2 warnings emitted +error: aborting due to 8 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs index cdbfb37c7c7..bcd29f8b034 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.rs @@ -2,6 +2,7 @@ // aux-build:static_cross_crate.rs // stderr-per-bitwidth #![feature(exclusive_range_pattern, half_open_range_patterns_in_slices)] +#![allow(static_mut_ref)] extern crate static_cross_crate; @@ -10,7 +11,6 @@ extern crate static_cross_crate; const SLICE_MUT: &[u8; 1] = { //~ ERROR undefined behavior //~| encountered reference to mutable memory unsafe { &static_cross_crate::ZERO } - //~^ WARN shared reference of mutable static is discouraged [static_mut_ref] }; const U8_MUT: &u8 = { //~ ERROR undefined behavior diff --git a/tests/ui/consts/static_mut_containing_mut_ref.rs b/tests/ui/consts/static_mut_containing_mut_ref.rs index 874aa59df0b..495804649b1 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref.rs +++ b/tests/ui/consts/static_mut_containing_mut_ref.rs @@ -1,8 +1,8 @@ // build-pass (FIXME(62277): could be check-pass?) +#![allow(static_mut_ref)] static mut STDERR_BUFFER_SPACE: [u8; 42] = [0u8; 42]; pub static mut STDERR_BUFFER: *mut [u8] = unsafe { &mut STDERR_BUFFER_SPACE }; -//~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref.stderr b/tests/ui/consts/static_mut_containing_mut_ref.stderr deleted file mode 100644 index 56ceba41cf8..00000000000 --- a/tests/ui/consts/static_mut_containing_mut_ref.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: mutable reference of mutable static is discouraged - --> $DIR/static_mut_containing_mut_ref.rs:5:52 - | -LL | pub static mut STDERR_BUFFER: *mut [u8] = unsafe { &mut STDERR_BUFFER_SPACE }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static - | - = note: for more information, see issue #114447 - = note: reference of mutable static is a hard error from 2024 edition - = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior - = note: `#[warn(static_mut_ref)]` on by default -help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer - | -LL | pub static mut STDERR_BUFFER: *mut [u8] = unsafe { addr_of_mut!(STDERR_BUFFER_SPACE) }; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -warning: 1 warning emitted - diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr index bc32ecc2c35..42cb119d2ae 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.mut_refs.stderr @@ -1,24 +1,9 @@ -warning: mutable reference of mutable static is discouraged - --> $DIR/static_mut_containing_mut_ref2.rs:8:6 - | -LL | *(&mut STDERR_BUFFER_SPACE) = 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static - | - = note: for more information, see issue #114447 - = note: reference of mutable static is a hard error from 2024 edition - = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior - = note: `#[warn(static_mut_ref)]` on by default -help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer - | -LL | *addr_of_mut!(STDERR_BUFFER_SPACE) = 42; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - error[E0080]: could not evaluate static initializer --> $DIR/static_mut_containing_mut_ref2.rs:8:5 | LL | *(&mut STDERR_BUFFER_SPACE) = 42; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.rs b/tests/ui/consts/static_mut_containing_mut_ref2.rs index b71f1122cd0..e60a17922fd 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.rs +++ b/tests/ui/consts/static_mut_containing_mut_ref2.rs @@ -1,5 +1,5 @@ // revisions: stock mut_refs - +#![allow(static_mut_ref)] #![cfg_attr(mut_refs, feature(const_mut_refs))] static mut STDERR_BUFFER_SPACE: u8 = 0; @@ -8,8 +8,6 @@ pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; //[mut_refs]~^ ERROR could not evaluate static initializer //[stock]~^^ ERROR mutation through a reference is not allowed in statics - //[mut_refs]~^^^ WARN mutable reference of mutable static is discouraged [static_mut_ref] - //[stock]~^^^^ WARN mutable reference of mutable static is discouraged [static_mut_ref] }; fn main() {} diff --git a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr index aea5b8a33b5..5ff9c0b6e2b 100644 --- a/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr +++ b/tests/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -1,18 +1,3 @@ -warning: mutable reference of mutable static is discouraged - --> $DIR/static_mut_containing_mut_ref2.rs:8:6 - | -LL | *(&mut STDERR_BUFFER_SPACE) = 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ mutable reference of mutable static - | - = note: for more information, see issue #114447 - = note: reference of mutable static is a hard error from 2024 edition - = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior - = note: `#[warn(static_mut_ref)]` on by default -help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer - | -LL | *addr_of_mut!(STDERR_BUFFER_SPACE) = 42; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - error[E0658]: mutation through a reference is not allowed in statics --> $DIR/static_mut_containing_mut_ref2.rs:8:5 | @@ -23,6 +8,6 @@ LL | *(&mut STDERR_BUFFER_SPACE) = 42; = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/thread-local/thread-local-static.rs b/tests/ui/thread-local/thread-local-static.rs index dac9259a6a6..a2c1954881f 100644 --- a/tests/ui/thread-local/thread-local-static.rs +++ b/tests/ui/thread-local/thread-local-static.rs @@ -2,14 +2,14 @@ #![feature(thread_local)] #![feature(const_swap)] +#![allow(static_mut_ref)] #[thread_local] static mut STATIC_VAR_2: [u32; 8] = [4; 8]; const fn g(x: &mut [u32; 8]) { //~^ ERROR mutable references are not allowed std::mem::swap(x, &mut STATIC_VAR_2) - //~^ WARN mutable reference of mutable static is discouraged [static_mut_ref] - //~^^ ERROR thread-local statics cannot be accessed + //~^ ERROR thread-local statics cannot be accessed //~| ERROR mutable references are not allowed //~| ERROR use of mutable static is unsafe } diff --git a/tests/ui/thread-local/thread-local-static.stderr b/tests/ui/thread-local/thread-local-static.stderr index 3dd1e2d4000..a6499fd15ec 100644 --- a/tests/ui/thread-local/thread-local-static.stderr +++ b/tests/ui/thread-local/thread-local-static.stderr @@ -1,20 +1,5 @@ -warning: mutable reference of mutable static is discouraged - --> $DIR/thread-local-static.rs:10:23 - | -LL | std::mem::swap(x, &mut STATIC_VAR_2) - | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static - | - = note: for more information, see issue #114447 - = note: reference of mutable static is a hard error from 2024 edition - = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior - = note: `#[warn(static_mut_ref)]` on by default -help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer - | -LL | std::mem::swap(x, addr_of_mut!(STATIC_VAR_2)) - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ - error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/thread-local-static.rs:10:28 + --> $DIR/thread-local-static.rs:11:28 | LL | std::mem::swap(x, &mut STATIC_VAR_2) | ^^^^^^^^^^^^ use of mutable static @@ -22,7 +7,7 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2) = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0658]: mutable references are not allowed in constant functions - --> $DIR/thread-local-static.rs:8:12 + --> $DIR/thread-local-static.rs:9:12 | LL | const fn g(x: &mut [u32; 8]) { | ^ @@ -32,13 +17,13 @@ LL | const fn g(x: &mut [u32; 8]) { = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0625]: thread-local statics cannot be accessed at compile-time - --> $DIR/thread-local-static.rs:10:28 + --> $DIR/thread-local-static.rs:11:28 | LL | std::mem::swap(x, &mut STATIC_VAR_2) | ^^^^^^^^^^^^ error[E0658]: mutable references are not allowed in constant functions - --> $DIR/thread-local-static.rs:10:23 + --> $DIR/thread-local-static.rs:11:23 | LL | std::mem::swap(x, &mut STATIC_VAR_2) | ^^^^^^^^^^^^^^^^^ @@ -47,7 +32,7 @@ LL | std::mem::swap(x, &mut STATIC_VAR_2) = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0133, E0625, E0658. For more information about an error, try `rustc --explain E0133`. diff --git a/tests/ui/thread-local/thread-local-static.thir.stderr b/tests/ui/thread-local/thread-local-static.thir.stderr deleted file mode 100644 index 2043b268c09..00000000000 --- a/tests/ui/thread-local/thread-local-static.thir.stderr +++ /dev/null @@ -1,59 +0,0 @@ -warning: mutable reference of mutable static is discouraged - --> $DIR/thread-local-static.rs:12:23 - | -LL | std::mem::swap(x, &mut STATIC_VAR_2) - | ^^^^^^^^^^^^^^^^^ mutable reference of mutable static - | - = note: for more information, see issue #114447 - = note: reference of mutable static is a hard error from 2024 edition - = note: mutable statics can be written to by multiple threads: aliasing violations or data races will cause undefined behavior - = note: `#[warn(static_mut_ref)]` on by default -help: mutable references are dangerous since if there's any other pointer or reference used for that static while the reference lives, that's UB; use `addr_of_mut!` instead to create a raw pointer - | -LL | std::mem::swap(x, addr_of_mut!(STATIC_VAR_2)) - | ~~~~~~~~~~~~~~~~~~~~~~~~~~ - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/thread-local-static.rs:10:12 - | -LL | const fn g(x: &mut [u32; 8]) { - | ^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error[E0625]: thread-local statics cannot be accessed at compile-time - --> $DIR/thread-local-static.rs:12:28 - | -LL | std::mem::swap(x, &mut STATIC_VAR_2) - | ^^^^^^^^^^^^ - -error[E0013]: constant functions cannot refer to statics - --> $DIR/thread-local-static.rs:12:28 - | -LL | std::mem::swap(x, &mut STATIC_VAR_2) - | ^^^^^^^^^^^^ - | - = help: consider extracting the value of the `static` to a `const`, and referring to that - -error[E0658]: mutable references are not allowed in constant functions - --> $DIR/thread-local-static.rs:12:23 - | -LL | std::mem::swap(x, &mut STATIC_VAR_2) - | ^^^^^^^^^^^^^^^^^ - | - = note: see issue #57349 for more information - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/thread-local-static.rs:12:23 - | -LL | std::mem::swap(x, &mut STATIC_VAR_2) - | ^^^^^^^^^^^^^^^^^ use of mutable static - | - = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior - -error: aborting due to 5 previous errors; 1 warning emitted - -Some errors have detailed explanations: E0013, E0133, E0625, E0658. -For more information about an error, try `rustc --explain E0013`. From 9d1bd2e067a82d6a2552b3705bbe6f256e9bde0c Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Mon, 12 Feb 2024 19:13:09 -0500 Subject: [PATCH 13/14] PassWrapper: adapt for llvm/llvm-project@93cdd1b5cfa3735c599949b77e24dbfbe570441a Should be no functional change. @rustbot label: +llvm-main --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 3b6bf03686b..a358a40f92b 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -43,6 +43,9 @@ #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" #include "llvm/Support/TimeProfiler.h" +#if LLVM_VERSION_GE(19, 0) +#include "llvm/Support/PGOOptions.h" +#endif #include "llvm/Transforms/Instrumentation/GCOVProfiler.h" #include "llvm/Transforms/Instrumentation/InstrProfiling.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" @@ -749,6 +752,9 @@ LLVMRustOptimize( FS, #endif PGOOptions::IRInstr, PGOOptions::NoCSAction, +#if LLVM_VERSION_GE(19, 0) + PGOOptions::ColdFuncOpt::Default, +#endif DebugInfoForProfiling); } else if (PGOUsePath) { assert(!PGOSampleUsePath); @@ -758,6 +764,9 @@ LLVMRustOptimize( FS, #endif PGOOptions::IRUse, PGOOptions::NoCSAction, +#if LLVM_VERSION_GE(19, 0) + PGOOptions::ColdFuncOpt::Default, +#endif DebugInfoForProfiling); } else if (PGOSampleUsePath) { PGOOpt = PGOOptions(PGOSampleUsePath, "", "", @@ -766,6 +775,9 @@ LLVMRustOptimize( FS, #endif PGOOptions::SampleUse, PGOOptions::NoCSAction, +#if LLVM_VERSION_GE(19, 0) + PGOOptions::ColdFuncOpt::Default, +#endif DebugInfoForProfiling); } else if (DebugInfoForProfiling) { PGOOpt = PGOOptions("", "", "", @@ -774,6 +786,9 @@ LLVMRustOptimize( FS, #endif PGOOptions::NoAction, PGOOptions::NoCSAction, +#if LLVM_VERSION_GE(19, 0) + PGOOptions::ColdFuncOpt::Default, +#endif DebugInfoForProfiling); } From 0f53e720a852cad485daab8d5882ef498d8905bd Mon Sep 17 00:00:00 2001 From: Tristan F <26509014+LeoDog896@users.noreply.github.com> Date: Mon, 12 Feb 2024 20:17:47 -0500 Subject: [PATCH 14/14] docs: use correct link, use secondary example --- library/alloc/src/fmt.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs index 6899ff4711f..b9918752540 100644 --- a/library/alloc/src/fmt.rs +++ b/library/alloc/src/fmt.rs @@ -278,17 +278,20 @@ //! Hello, ` 123` has 3 right-aligned characters //! ``` //! -//! When truncuating these values, Rust uses round-to-even, which may -//! cause concern when formatting for scientific notation. For example, +//! When truncating these values, Rust uses [round half-to-even](https://en.wikipedia.org/wiki/Rounding#Rounding_half_to_even), +//! which is the default rounding mode in IEEE 754. +//! For example, //! //! ``` //! print!("{0:.1$e}", 12345, 3); +//! print!("{0:.1$e}", 12355, 3); //! ``` //! //! Would return: //! //! ```text //! 1.234e4 +//! 1.236e4 //! ``` //! //! ## Localization