diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index af0198705a2fe..a0fe307cffcdb 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -74,7 +74,9 @@ status_check() { check_dispatch $1 beta nomicon src/doc/nomicon check_dispatch $1 beta reference src/doc/reference check_dispatch $1 beta rust-by-example src/doc/rust-by-example - check_dispatch $1 beta edition-guide src/doc/edition-guide + # Temporarily disabled until + # https://github.com/rust-lang/rust/issues/60459 is fixed. + # check_dispatch $1 beta edition-guide src/doc/edition-guide check_dispatch $1 beta rls src/tools/rls check_dispatch $1 beta rustfmt src/tools/rustfmt check_dispatch $1 beta clippy-driver src/tools/clippy diff --git a/src/doc/book b/src/doc/book index db919bc6bb907..29fe982990e43 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit db919bc6bb9071566e9c4f05053672133eaac33e +Subproject commit 29fe982990e43b9367be0ff47abc82fb2123fd03 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index c413d42a207bd..581c6cccfaf99 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit c413d42a207bd082f801ec0137c31b71e4bfed4c +Subproject commit 581c6cccfaf995394ea9dcac362dc8e731c18558 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index de3d55f521e65..9858872bd1b7d 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit de3d55f521e657863df45260ebbca1b10527f662 +Subproject commit 9858872bd1b7dbba5ec27dc30d34eba00acd7ef9 diff --git a/src/doc/nomicon b/src/doc/nomicon index fb29b147be4d9..c656171b749b7 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit fb29b147be4d9a1f8e24aba753a7e1de537abf61 +Subproject commit c656171b749b7307f21371dd0d3278efee5573b8 diff --git a/src/doc/reference b/src/doc/reference index 2a2de9ce09597..862b669c39582 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 2a2de9ce095979978ad7b582daecf94e4070b916 +Subproject commit 862b669c395822bb0938781d74f860e5762ad4fb diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 1ff0f8e018838..811c697b232c6 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 1ff0f8e018838a710ebc0cc1a7bf74ebe73ad9f1 +Subproject commit 811c697b232c611ed754d279ed20643a0c4096f6 diff --git a/src/doc/rustc-guide b/src/doc/rustc-guide index 99e1b1d53656b..3cb727b62b953 160000 --- a/src/doc/rustc-guide +++ b/src/doc/rustc-guide @@ -1 +1 @@ -Subproject commit 99e1b1d53656be08654df399fc200584aebb50e4 +Subproject commit 3cb727b62b953d59b4360d39aa68b6dc8f157655 diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index d1ca05780930a..cd207478f8f6f 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -305,8 +305,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(missing_trait) = missing_trait { if op.node == hir::BinOpKind::Add && - self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, - rhs_ty, &mut err, true, op) { + self.check_str_addition( + lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, true, op) { // This has nothing here because it means we did string // concatenation (e.g., "Hello " += "World!"). This means // we don't want the note in the else clause to be emitted @@ -400,8 +400,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(missing_trait) = missing_trait { if op.node == hir::BinOpKind::Add && - self.check_str_addition(expr, lhs_expr, rhs_expr, lhs_ty, - rhs_ty, &mut err, false, op) { + self.check_str_addition( + lhs_expr, rhs_expr, lhs_ty, rhs_ty, &mut err, false, op) { // This has nothing here because it means we did string // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted @@ -502,9 +502,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { false } + /// Provide actionable suggestions when trying to add two strings with incorrect types, + /// like `&str + &str`, `String + String` and `&str + &String`. + /// + /// If this function returns `true` it means a note was printed, so we don't need + /// to print the normal "implementation of `std::ops::Add` might be missing" note fn check_str_addition( &self, - expr: &'gcx hir::Expr, lhs_expr: &'gcx hir::Expr, rhs_expr: &'gcx hir::Expr, lhs_ty: Ty<'tcx>, @@ -514,45 +518,78 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { op: hir::BinOp, ) -> bool { let source_map = self.tcx.sess.source_map(); + let remove_borrow_msg = "String concatenation appends the string on the right to the \ + string on the left and may require reallocation. This \ + requires ownership of the string on the left"; + let msg = "`to_owned()` can be used to create an owned `String` \ from a string reference. String concatenation \ appends the string on the right to the string \ on the left and may require reallocation. This \ requires ownership of the string on the left"; - // If this function returns true it means a note was printed, so we don't need - // to print the normal "implementation of `std::ops::Add` might be missing" note + + let is_std_string = |ty| &format!("{:?}", ty) == "std::string::String"; + match (&lhs_ty.sty, &rhs_ty.sty) { - (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) - if l_ty.sty == Str && r_ty.sty == Str => { - if !is_assign { - err.span_label(op.span, - "`+` can't be used to concatenate two `&str` strings"); + (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str + if (l_ty.sty == Str || is_std_string(l_ty)) && ( + r_ty.sty == Str || is_std_string(r_ty) || + &format!("{:?}", rhs_ty) == "&&str" + ) => + { + if !is_assign { // Do not supply this message if `&str += &str` + err.span_label( + op.span, + "`+` cannot be used to concatenate two `&str` strings", + ); match source_map.span_to_snippet(lhs_expr.span) { - Ok(lstring) => err.span_suggestion( - lhs_expr.span, - msg, - format!("{}.to_owned()", lstring), - Applicability::MachineApplicable, - ), + Ok(lstring) => { + err.span_suggestion( + lhs_expr.span, + if lstring.starts_with("&") { + remove_borrow_msg + } else { + msg + }, + if lstring.starts_with("&") { + // let a = String::new(); + // let _ = &a + "bar"; + format!("{}", &lstring[1..]) + } else { + format!("{}.to_owned()", lstring) + }, + Applicability::MachineApplicable, + ) + } _ => err.help(msg), }; } true } - (&Ref(_, l_ty, _), &Adt(..)) - if l_ty.sty == Str && &format!("{:?}", rhs_ty) == "std::string::String" => { - err.span_label(expr.span, - "`+` can't be used to concatenate a `&str` with a `String`"); + (&Ref(_, l_ty, _), &Adt(..)) // Handle `&str` & `&String` + `String` + if (l_ty.sty == Str || is_std_string(l_ty)) && is_std_string(rhs_ty) => + { + err.span_label( + op.span, + "`+` cannot be used to concatenate a `&str` with a `String`", + ); match ( source_map.span_to_snippet(lhs_expr.span), source_map.span_to_snippet(rhs_expr.span), is_assign, ) { (Ok(l), Ok(r), false) => { + let to_string = if l.starts_with("&") { + // let a = String::new(); let b = String::new(); + // let _ = &a + b; + format!("{}", &l[1..]) + } else { + format!("{}.to_owned()", l) + }; err.multipart_suggestion( msg, vec![ - (lhs_expr.span, format!("{}.to_owned()", l)), + (lhs_expr.span, to_string), (rhs_expr.span, format!("&{}", r)), ], Applicability::MachineApplicable, diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 7cb830e751a77..62282006a4024 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -201,11 +201,19 @@ pub trait Error: Debug + Display { #[unstable(feature = "error_type_id", reason = "this is memory unsafe to override in user code", issue = "60784")] - fn type_id(&self) -> TypeId where Self: 'static { + fn type_id(&self, _: private::Internal) -> TypeId where Self: 'static { TypeId::of::() } } +mod private { + // This is a hack to prevent `type_id` from being overridden by `Error` + // implementations, since that can enable unsound downcasting. + #[unstable(feature = "error_type_id", issue = "60784")] + #[derive(Debug)] + pub struct Internal; +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + 'a> From for Box { /// Converts a type of [`Error`] into a box of dyn [`Error`]. @@ -575,7 +583,7 @@ impl dyn Error + 'static { let t = TypeId::of::(); // Get TypeId of the type in the trait object - let boxed = self.type_id(); + let boxed = self.type_id(private::Internal); // Compare both TypeIds on equality t == boxed diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b1c3e46adc0ec..3d55267b8e8cf 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3497,8 +3497,7 @@ impl<'a> Parser<'a> { let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs); self.mk_expr(span, binary, ThinVec::new()) } - AssocOp::Assign => - self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), + AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs), ThinVec::new()), AssocOp::ObsoleteInPlace => self.mk_expr(span, ExprKind::ObsoleteInPlace(lhs, rhs), ThinVec::new()), AssocOp::AssignOp(k) => { diff --git a/src/test/ui/issues/issue-47377.stderr b/src/test/ui/issues/issue-47377.stderr index 88466131e3144..7d11a8c802128 100644 --- a/src/test/ui/issues/issue-47377.stderr +++ b/src/test/ui/issues/issue-47377.stderr @@ -4,7 +4,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` LL | let _a = b + ", World!"; | - ^ ---------- &str | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | diff --git a/src/test/ui/issues/issue-47380.stderr b/src/test/ui/issues/issue-47380.stderr index d69101eab4c46..89a154c5109d8 100644 --- a/src/test/ui/issues/issue-47380.stderr +++ b/src/test/ui/issues/issue-47380.stderr @@ -4,7 +4,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` LL | println!("🦀🦀🦀🦀🦀"); let _a = b + ", World!"; | - ^ ---------- &str | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | diff --git a/src/test/ui/span/issue-39018.rs b/src/test/ui/span/issue-39018.rs index 6dbc8d39976ad..a3b1d1d81799f 100644 --- a/src/test/ui/span/issue-39018.rs +++ b/src/test/ui/span/issue-39018.rs @@ -16,3 +16,23 @@ enum World { Hello, Goodbye, } + +fn foo() { + let a = String::new(); + let b = String::new(); + let c = ""; + let d = ""; + let e = &a; + let _ = &a + &b; //~ ERROR binary operation + let _ = &a + b; //~ ERROR binary operation + let _ = a + &b; // ok + let _ = a + b; //~ ERROR mismatched types + let _ = e + b; //~ ERROR binary operation + let _ = e + &b; //~ ERROR binary operation + let _ = e + d; //~ ERROR binary operation + let _ = e + &d; //~ ERROR binary operation + let _ = &c + &d; //~ ERROR binary operation + let _ = &c + d; //~ ERROR binary operation + let _ = c + &d; //~ ERROR binary operation + let _ = c + d; //~ ERROR binary operation +} diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index a5b91f090d2c0..d8fbf841b6157 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -4,7 +4,7 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` LL | let x = "Hello " + "World!"; | -------- ^ -------- &str | | | - | | `+` can't be used to concatenate two `&str` strings + | | `+` cannot be used to concatenate two `&str` strings | &str help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -25,16 +25,152 @@ error[E0369]: binary operation `+` cannot be applied to type `&str` --> $DIR/issue-39018.rs:11:22 | LL | let x = "Hello " + "World!".to_owned(); - | ---------^-------------------- - | | | - | | std::string::String + | -------- ^ ------------------- std::string::String + | | | + | | `+` cannot be used to concatenate a `&str` with a `String` | &str - | `+` can't be used to concatenate a `&str` with a `String` help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let x = "Hello ".to_owned() + &"World!".to_owned(); | ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:26:16 + | +LL | let _ = &a + &b; + | -- ^ -- &std::string::String + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &std::string::String +help: String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = a + &b; + | ^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:27:16 + | +LL | let _ = &a + b; + | -- ^ - std::string::String + | | | + | | `+` cannot be used to concatenate a `&str` with a `String` + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = a + &b; + | ^ ^^ + +error[E0308]: mismatched types + --> $DIR/issue-39018.rs:29:17 + | +LL | let _ = a + b; + | ^ + | | + | expected &str, found struct `std::string::String` + | help: consider borrowing here: `&b` + | + = note: expected type `&str` + found type `std::string::String` + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:30:15 + | +LL | let _ = e + b; + | - ^ - std::string::String + | | | + | | `+` cannot be used to concatenate a `&str` with a `String` + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + &b; + | ^^^^^^^^^^^^ ^^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:31:15 + | +LL | let _ = e + &b; + | - ^ -- &std::string::String + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + &b; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:32:15 + | +LL | let _ = e + d; + | - ^ - &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + d; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&std::string::String` + --> $DIR/issue-39018.rs:33:15 + | +LL | let _ = e + &d; + | - ^ -- &&str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = e.to_owned() + &d; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&&str` + --> $DIR/issue-39018.rs:34:16 + | +LL | let _ = &c + &d; + | -- ^ -- &&str + | | + | &&str + | + = note: an implementation of `std::ops::Add` might be missing for `&&str` + +error[E0369]: binary operation `+` cannot be applied to type `&&str` + --> $DIR/issue-39018.rs:35:16 + | +LL | let _ = &c + d; + | -- ^ - &str + | | + | &&str + | + = note: an implementation of `std::ops::Add` might be missing for `&&str` + +error[E0369]: binary operation `+` cannot be applied to type `&str` + --> $DIR/issue-39018.rs:36:15 + | +LL | let _ = c + &d; + | - ^ -- &&str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = c.to_owned() + &d; + | ^^^^^^^^^^^^ + +error[E0369]: binary operation `+` cannot be applied to type `&str` + --> $DIR/issue-39018.rs:37:15 + | +LL | let _ = c + d; + | - ^ - &str + | | | + | | `+` cannot be used to concatenate two `&str` strings + | &str +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left + | +LL | let _ = c.to_owned() + d; + | ^^^^^^^^^^^^ + +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0369`. +Some errors have detailed explanations: E0308, E0369. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/str/str-concat-on-double-ref.stderr b/src/test/ui/str/str-concat-on-double-ref.stderr index 61ebcfdefc316..3e53cdc4d98ca 100644 --- a/src/test/ui/str/str-concat-on-double-ref.stderr +++ b/src/test/ui/str/str-concat-on-double-ref.stderr @@ -3,10 +3,13 @@ error[E0369]: binary operation `+` cannot be applied to type `&std::string::Stri | LL | let c = a + b; | - ^ - &str - | | + | | | + | | `+` cannot be used to concatenate two `&str` strings | &std::string::String +help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | - = note: an implementation of `std::ops::Add` might be missing for `&std::string::String` +LL | let c = a.to_owned() + b; + | ^^^^^^^^^^^^ error: aborting due to previous error diff --git a/triagebot.toml b/triagebot.toml index 6f60481600c2e..0e703a3ab349d 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -4,3 +4,5 @@ allow-unauthenticated = [ # I-* without I-nominated "I-compilemem", "I-compiletime", "I-crash", "I-hang", "I-ICE", "I-slow", ] + +[assign]