diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 7bf9ea2688f4c..fb308bc35ebc5 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -157,6 +157,7 @@ impl Step for Llvm {
.define("WITH_POLLY", "OFF")
.define("LLVM_ENABLE_TERMINFO", "OFF")
.define("LLVM_ENABLE_LIBEDIT", "OFF")
+ .define("LLVM_ENABLE_BINDINGS", "OFF")
.define("LLVM_ENABLE_Z3_SOLVER", "OFF")
.define("LLVM_PARALLEL_COMPILE_JOBS", builder.jobs().to_string())
.define("LLVM_TARGET_ARCH", target.split('-').next().unwrap())
@@ -169,15 +170,6 @@ impl Step for Llvm {
}
}
- // By default, LLVM will automatically find OCaml and, if it finds it,
- // install the LLVM bindings in LLVM_OCAML_INSTALL_PATH, which defaults
- // to /usr/bin/ocaml.
- // This causes problem for non-root builds of Rust. Side-step the issue
- // by setting LLVM_OCAML_INSTALL_PATH to a relative path, so it installs
- // in the prefix.
- cfg.define("LLVM_OCAML_INSTALL_PATH",
- env::var_os("LLVM_OCAML_INSTALL_PATH").unwrap_or_else(|| "usr/lib/ocaml".into()));
-
let want_lldb = builder.config.lldb_enabled && !self.emscripten;
// This setting makes the LLVM tools link to the dynamic LLVM library,
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 3cda8d927973c..d5564fd798f39 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -10,6 +10,7 @@
- [Warn-by-default lints](lints/listing/warn-by-default.md)
- [Deny-by-default lints](lints/listing/deny-by-default.md)
- [Codegen options](codegen-options/index.md)
+- [JSON Output](json.md)
- [Targets](targets/index.md)
- [Built-in Targets](targets/built-in.md)
- [Custom Targets](targets/custom.md)
diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md
index 5eea9c8687900..b2cc65c11fd2c 100644
--- a/src/doc/rustc/src/command-line-arguments.md
+++ b/src/doc/rustc/src/command-line-arguments.md
@@ -92,6 +92,7 @@ information about editions may be found in the [edition guide].
[edition guide]: ../edition-guide/introduction.html
## `--emit`: specifies the types of output files to generate
+
This flag controls the types of output files generated by the compiler. It
accepts a comma-separated list of values, and may be specified multiple times.
@@ -241,12 +242,13 @@ The "sysroot" is where `rustc` looks for the crates that come with the Rust
distribution; this flag allows that to be overridden.
## `--error-format`: control how errors are produced
+
This flag lets you control the format of messages. Messages are printed to
stderr. The valid options are:
- `human` — Human-readable output. This is the default.
-- `json` — Structured JSON output.
+- `json` — Structured JSON output. See [the JSON chapter] for more detail.
- `short` — Short, one-line messages.
## `--color`: configure coloring of output
@@ -273,6 +275,7 @@ pathname syntax. For example `--remap-path-prefix foo=bar` will match
`foo/lib.rs` but not `./foo/lib.rs`.
## `--json`: configure json messages printed by the compiler
+
When the `--error-format=json` option is passed to rustc then all of the
compiler's diagnostic output will be emitted in the form of JSON blobs. The
@@ -305,9 +308,13 @@ to customize the output:
Note that it is invalid to combine the `--json` argument with the `--color`
argument, and it is required to combine `--json` with `--error-format=json`.
+See [the JSON chapter] for more detail.
+
## `@path`: load command-line flags from a path
If you specify `@path` on the command-line, then it will open `path` and read
command line options from it. These options are one per line; a blank line indicates
an empty option. The file can use Unix or Windows style line endings, and must be
encoded as UTF-8.
+
+[the JSON chapter]: json.md
diff --git a/src/doc/rustc/src/json.md b/src/doc/rustc/src/json.md
new file mode 100644
index 0000000000000..b737849516310
--- /dev/null
+++ b/src/doc/rustc/src/json.md
@@ -0,0 +1,231 @@
+# JSON Output
+
+This chapter documents the JSON structures emitted by `rustc`. JSON may be
+enabled with the [`--error-format=json` flag][option-error-format]. Additional
+options may be specified with the [`--json` flag][option-json] which can
+change which messages are generated, and the format of the messages.
+
+JSON messages are emitted one per line to stderr.
+
+If parsing the output with Rust, the
+[`cargo_metadata`](https://crates.io/crates/cargo_metadata) crate provides
+some support for parsing the messages.
+
+When parsing, care should be taken to be forwards-compatible with future changes
+to the format. Optional values may be `null`. New fields may be added. Enumerated
+fields like "level" or "suggestion_applicability" may add new values.
+
+## Diagnostics
+
+Diagnostic messages provide errors or possible concerns generated during
+compilation. `rustc` provides detailed information about where the diagnostic
+originates, along with hints and suggestions.
+
+Diagnostics are arranged in a parent/child relationship where the parent
+diagnostic value is the core of the diagnostic, and the attached children
+provide additional context, help, and information.
+
+Diagnostics have the following format:
+
+```javascript
+{
+ /* The primary message. */
+ "message": "unused variable: `x`",
+ /* The diagnostic code.
+ Some messages may set this value to null.
+ */
+ "code": {
+ /* A unique string identifying which diagnostic triggered. */
+ "code": "unused_variables",
+ /* An optional string explaining more detail about the diagnostic code. */
+ "explanation": null
+ },
+ /* The severity of the diagnostic.
+ Values may be:
+ - "error": A fatal error that prevents compilation.
+ - "warning": A possible error or concern.
+ - "note": Additional information or context about the diagnostic.
+ - "help": A suggestion on how to resolve the diagnostic.
+ - "failure-note": A note attached to the message for further information.
+ - "error: internal compiler error": Indicates a bug within the compiler.
+ */
+ "level": "warning",
+ /* An array of source code locations to point out specific details about
+ where the diagnostic originates from. This may be empty, for example
+ for some global messages, or child messages attached to a parent.
+
+ Character offsets are offsets of Unicode Scalar Values.
+ */
+ "spans": [
+ {
+ /* The file where the span is located.
+ For spans located within a macro expansion, this will be the
+ name of the expanded macro in the format "".
+ */
+ "file_name": "lib.rs",
+ /* The byte offset where the span starts (0-based, inclusive). */
+ "byte_start": 21,
+ /* The byte offset where the span ends (0-based, exclusive). */
+ "byte_end": 22,
+ /* The first line number of the span (1-based, inclusive). */
+ "line_start": 2,
+ /* The last line number of the span (1-based, inclusive). */
+ "line_end": 2,
+ /* The first character offset of the line_start (1-based, inclusive). */
+ "column_start": 9,
+ /* The last character offset of the line_end (1-based, exclusive). */
+ "column_end": 10,
+ /* Whether or not this is the "primary" span.
+
+ This indicates that this span is the focal point of the
+ diagnostic.
+
+ There are rare cases where multiple spans may be marked as
+ primary. For example, "immutable borrow occurs here" and
+ "mutable borrow ends here" can be two separate primary spans.
+
+ The top (parent) message should always have at least one
+ primary span, unless it has zero spans. Child messages may have
+ zero or more primary spans.
+ */
+ "is_primary": true,
+ /* An array of objects showing the original source code for this
+ span. This shows the entire lines of text where the span is
+ located. A span across multiple lines will have a separate
+ value for each line.
+ */
+ "text": [
+ {
+ /* The entire line of the original source code. */
+ "text": " let x = 123;",
+ /* The first character offset of the line of
+ where the span covers this line (1-based, inclusive). */
+ "highlight_start": 9,
+ /* The last character offset of the line of
+ where the span covers this line (1-based, exclusive). */
+ "highlight_end": 10
+ }
+ ],
+ /* An optional message to display at this span location.
+ This is typically null for primary spans.
+ */
+ "label": null,
+ /* An optional string of a suggested replacement for this span to
+ solve the issue. Tools may try to replace the contents of the
+ span with this text.
+ */
+ "suggested_replacement": null,
+ /* An optional string that indicates the confidence of the
+ "suggested_replacement". Tools may use this value to determine
+ whether or not suggestions should be automatically applied.
+
+ Possible values may be:
+ - "MachineApplicable": The suggestion is definitely what the
+ user intended. This suggestion should be automatically
+ applied.
+ - "MaybeIncorrect": The suggestion may be what the user
+ intended, but it is uncertain. The suggestion should result
+ in valid Rust code if it is applied.
+ - "HasPlaceholders": The suggestion contains placeholders like
+ `(...)`. The suggestion cannot be applied automatically
+ because it will not result in valid Rust code. The user will
+ need to fill in the placeholders.
+ - "Unspecified": The applicability of the suggestion is unknown.
+ */
+ "suggestion_applicability": null,
+ /* An optional object indicating the expansion of a macro within
+ this span.
+
+ If a message occurs within a macro invocation, this object will
+ provide details of where within the macro expansion the message
+ is located.
+ */
+ "expansion": {
+ /* The span of the macro invocation.
+ Uses the same span definition as the "spans" array.
+ */
+ "span": {/*...*/}
+ /* Name of the macro, such as "foo!" or "#[derive(Eq)]". */
+ "macro_decl_name": "some_macro!",
+ /* Optional span where the relevant part of the macro is
+ defined. */
+ "def_site_span": {/*...*/},
+ }
+ }
+ ],
+ /* Array of attached diagnostic messages.
+ This is an array of objects using the same format as the parent
+ message. Children are not nested (children do not themselves
+ contain "children" definitions).
+ */
+ "children": [
+ {
+ "message": "`#[warn(unused_variables)]` on by default",
+ "code": null,
+ "level": "note",
+ "spans": [],
+ "children": [],
+ "rendered": null
+ },
+ {
+ "message": "consider prefixing with an underscore",
+ "code": null,
+ "level": "help",
+ "spans": [
+ {
+ "file_name": "lib.rs",
+ "byte_start": 21,
+ "byte_end": 22,
+ "line_start": 2,
+ "line_end": 2,
+ "column_start": 9,
+ "column_end": 10,
+ "is_primary": true,
+ "text": [
+ {
+ "text": " let x = 123;",
+ "highlight_start": 9,
+ "highlight_end": 10
+ }
+ ],
+ "label": null,
+ "suggested_replacement": "_x",
+ "suggestion_applicability": "MachineApplicable",
+ "expansion": null
+ }
+ ],
+ "children": [],
+ "rendered": null
+ }
+ ],
+ /* Optional string of the rendered version of the diagnostic as displayed
+ by rustc. Note that this may be influenced by the `--json` flag.
+ */
+ "rendered": "warning: unused variable: `x`\n --> lib.rs:2:9\n |\n2 | let x = 123;\n | ^ help: consider prefixing with an underscore: `_x`\n |\n = note: `#[warn(unused_variables)]` on by default\n\n"
+}
+```
+
+## Artifact notifications
+
+Artifact notifications are emitted when the [`--json=artifacts`
+flag][option-json] is used. They indicate that a file artifact has been saved
+to disk. More information about emit kinds may be found in the [`--emit`
+flag][option-emit] documentation.
+
+```javascript
+{
+ /* The filename that was generated. */
+ "artifact": "libfoo.rlib",
+ /* The kind of artifact that was generated. Possible values:
+ - "link": The generated crate as specified by the crate-type.
+ - "dep-info": The `.d` file with dependency information in a Makefile-like syntax.
+ - "metadata": The Rust `.rmeta` file containing metadata about the crate.
+ - "save-analysis": A JSON file emitted by the `-Zsave-analysis` feature.
+ */
+ "emit": "link"
+}
+```
+
+[option-emit]: command-line-arguments.md#option-emit
+[option-error-format]: command-line-arguments.md#option-error-format
+[option-json]: command-line-arguments.md#option-json
diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs
index 1e39b7f822e99..cbfc55233a1e0 100644
--- a/src/liballoc/fmt.rs
+++ b/src/liballoc/fmt.rs
@@ -86,27 +86,74 @@
//! parameters (corresponding to `format_spec` in the syntax above). These
//! parameters affect the string representation of what's being formatted.
//!
+//! ## Width
+//!
+//! ```
+//! // All of these print "Hello x !"
+//! println!("Hello {:5}!", "x");
+//! println!("Hello {:1$}!", "x", 5);
+//! println!("Hello {1:0$}!", 5, "x");
+//! println!("Hello {:width$}!", "x", width = 5);
+//! ```
+//!
+//! This is a parameter for the "minimum width" that the format should take up.
+//! If the value's string does not fill up this many characters, then the
+//! padding specified by fill/alignment will be used to take up the required
+//! space (see below).
+//!
+//! The value for the width can also be provided as a [`usize`] in the list of
+//! parameters by adding a postfix `$`, indicating that the second argument is
+//! a [`usize`] specifying the width.
+//!
+//! Referring to an argument with the dollar syntax does not affect the "next
+//! argument" counter, so it's usually a good idea to refer to arguments by
+//! position, or use named arguments.
+//!
//! ## Fill/Alignment
//!
-//! The fill character is provided normally in conjunction with the
-//! [`width`](#width)
-//! parameter. This indicates that if the value being formatted is smaller than
-//! `width` some extra characters will be printed around it. The extra
-//! characters are specified by `fill`, and the alignment can be one of the
-//! following options:
+//! ```
+//! assert_eq!(format!("Hello {:<5}!", "x"), "Hello x !");
+//! assert_eq!(format!("Hello {:-<5}!", "x"), "Hello x----!");
+//! assert_eq!(format!("Hello {:^5}!", "x"), "Hello x !");
+//! assert_eq!(format!("Hello {:>5}!", "x"), "Hello x!");
+//! ```
//!
-//! * `<` - the argument is left-aligned in `width` columns
-//! * `^` - the argument is center-aligned in `width` columns
-//! * `>` - the argument is right-aligned in `width` columns
+//! The optional fill character and alignment is provided normally in conjunction with the
+//! [`width`](#width) parameter. It must be defined before `width`, right after the `:`.
+//! This indicates that if the value being formatted is smaller than
+//! `width` some extra characters will be printed around it.
+//! Filling comes in the following variants for different alignments:
+//!
+//! * `[fill]<` - the argument is left-aligned in `width` columns
+//! * `[fill]^` - the argument is center-aligned in `width` columns
+//! * `[fill]>` - the argument is right-aligned in `width` columns
+//!
+//! The default [fill/alignment](#fillalignment) for non-numerics is a space and
+//! left-aligned. The
+//! defaults for numeric formatters is also a space but with right-alignment. If
+//! the `0` flag (see below) is specified for numerics, then the implicit fill character is
+//! `0`.
//!
//! Note that alignment may not be implemented by some types. In particular, it
//! is not generally implemented for the `Debug` trait. A good way to ensure
-//! padding is applied is to format your input, then use this resulting string
-//! to pad your output.
+//! padding is applied is to format your input, then pad this resulting string
+//! to obtain your output:
+//!
+//! ```
+//! println!("Hello {:^15}!", format!("{:?}", Some("hi"))); // => "Hello Some("hi") !"
+//! ```
//!
//! ## Sign/`#`/`0`
//!
-//! These can all be interpreted as flags for a particular formatter.
+//! ```
+//! assert_eq!(format!("Hello {:+}!", 5), "Hello +5!");
+//! assert_eq!(format!("{:#x}!", 27), "0x1b!");
+//! assert_eq!(format!("Hello {:05}!", 5), "Hello 00005!");
+//! assert_eq!(format!("Hello {:05}!", -5), "Hello -0005!");
+//! assert_eq!(format!("{:#010x}!", 27), "0x0000001b!");
+//! ```
+//!
+//! These are all flags altering the behavior of the formatter.
//!
//! * `+` - This is intended for numeric types and indicates that the sign
//! should always be printed. Positive signs are never printed by
@@ -121,7 +168,7 @@
//! * `#X` - precedes the argument with a `0x`
//! * `#b` - precedes the argument with a `0b`
//! * `#o` - precedes the argument with a `0o`
-//! * `0` - This is used to indicate for integer formats that the padding should
+//! * `0` - This is used to indicate for integer formats that the padding to `width` should
//! both be done with a `0` character as well as be sign-aware. A format
//! like `{:08}` would yield `00000001` for the integer `1`, while the
//! same format would yield `-0000001` for the integer `-1`. Notice that
@@ -129,36 +176,7 @@
//! Note that padding zeroes are always placed after the sign (if any)
//! and before the digits. When used together with the `#` flag, a similar
//! rule applies: padding zeroes are inserted after the prefix but before
-//! the digits.
-//!
-//! ## Width
-//!
-//! This is a parameter for the "minimum width" that the format should take up.
-//! If the value's string does not fill up this many characters, then the
-//! padding specified by fill/alignment will be used to take up the required
-//! space.
-//!
-//! The default [fill/alignment](#fillalignment) for non-numerics is a space and
-//! left-aligned. The
-//! defaults for numeric formatters is also a space but with right-alignment. If
-//! the `0` flag is specified for numerics, then the implicit fill character is
-//! `0`.
-//!
-//! The value for the width can also be provided as a [`usize`] in the list of
-//! parameters by using the dollar syntax indicating that the second argument is
-//! a [`usize`] specifying the width, for example:
-//!
-//! ```
-//! // All of these print "Hello x !"
-//! println!("Hello {:5}!", "x");
-//! println!("Hello {:1$}!", "x", 5);
-//! println!("Hello {1:0$}!", 5, "x");
-//! println!("Hello {:width$}!", "x", width = 5);
-//! ```
-//!
-//! Referring to an argument with the dollar syntax does not affect the "next
-//! argument" counter, so it's usually a good idea to refer to arguments by
-//! position, or use named arguments.
+//! the digits. The prefix is included in the total width.
//!
//! ## Precision
//!
@@ -235,9 +253,14 @@
//! them with the same character. For example, the `{` character is escaped with
//! `{{` and the `}` character is escaped with `}}`.
//!
+//! ```
+//! assert_eq!(format!("Hello {{}}"), "Hello {}");
+//! assert_eq!(format!("{{ Hello"), "{ Hello");
+//! ```
+//!
//! # Syntax
//!
-//! To summarize, you can find the full grammar of format strings.
+//! To summarize, here you can find the full grammar of format strings.
//! The syntax for the formatting language used is drawn from other languages,
//! so it should not be too alien. Arguments are formatted with Python-like
//! syntax, meaning that arguments are surrounded by `{}` instead of the C-like
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 998c8f8165204..8f4ade377e312 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -1864,7 +1864,7 @@ if `self < 0`, this is equal to round towards +/- infinity.
# Panics
-This function will panic if `rhs` is 0.
+This function will panic if `rhs` is 0 or the division results in overflow.
# Examples
@@ -1903,7 +1903,7 @@ This is done as if by the Euclidean division algorithm -- given
# Panics
-This function will panic if `rhs` is 0.
+This function will panic if `rhs` is 0 or the division results in overflow.
# Examples
@@ -3694,6 +3694,10 @@ Since, for the positive integers, all common
definitions of division are equal, this
is exactly equal to `self / rhs`.
+# Panics
+
+This function will panic if `rhs` is 0.
+
# Examples
Basic usage:
@@ -3719,6 +3723,10 @@ Since, for the positive integers, all common
definitions of division are equal, this
is exactly equal to `self % rhs`.
+# Panics
+
+This function will panic if `rhs` is 0.
+
# Examples
Basic usage:
diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs
index ac99ccd45eafe..d918b9ee67347 100644
--- a/src/librustc/mir/interpret/error.rs
+++ b/src/librustc/mir/interpret/error.rs
@@ -363,6 +363,8 @@ pub enum UndefinedBehaviorInfo {
UbExperimental(String),
/// Unreachable code was executed.
Unreachable,
+ /// An enum discriminant was set to a value which was outside the range of valid values.
+ InvalidDiscriminant(ScalarMaybeUndef),
}
impl fmt::Debug for UndefinedBehaviorInfo {
@@ -373,6 +375,8 @@ impl fmt::Debug for UndefinedBehaviorInfo {
write!(f, "{}", msg),
Unreachable =>
write!(f, "entered unreachable code"),
+ InvalidDiscriminant(val) =>
+ write!(f, "encountered invalid enum discriminant {}", val),
}
}
}
@@ -400,7 +404,6 @@ pub enum UnsupportedOpInfo<'tcx> {
InvalidMemoryAccess,
InvalidFunctionPointer,
InvalidBool,
- InvalidDiscriminant(ScalarMaybeUndef),
PointerOutOfBounds {
ptr: Pointer,
msg: CheckInAllocMsg,
@@ -485,8 +488,6 @@ impl fmt::Debug for UnsupportedOpInfo<'tcx> {
write!(f, "incorrect alloc info: expected size {} and align {}, \
got size {} and align {}",
size.bytes(), align.bytes(), size2.bytes(), align2.bytes()),
- InvalidDiscriminant(val) =>
- write!(f, "encountered invalid enum discriminant {}", val),
InvalidMemoryAccess =>
write!(f, "tried to access memory through an invalid pointer"),
DanglingPointerDeref =>
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 4bdd71f9602ac..4d9be55945e02 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -647,7 +647,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let bits_discr = raw_discr
.not_undef()
.and_then(|raw_discr| self.force_bits(raw_discr, discr_val.layout.size))
- .map_err(|_| err_unsup!(InvalidDiscriminant(raw_discr.erase_tag())))?;
+ .map_err(|_| err_ub!(InvalidDiscriminant(raw_discr.erase_tag())))?;
let real_discr = if discr_val.layout.ty.is_signed() {
// going from layout tag type to typeck discriminant type
// requires first sign extending with the discriminant layout
@@ -677,7 +677,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
_ => bug!("tagged layout for non-adt non-generator"),
}.ok_or_else(
- || err_unsup!(InvalidDiscriminant(raw_discr.erase_tag()))
+ || err_ub!(InvalidDiscriminant(raw_discr.erase_tag()))
)?;
(real_discr, index.0)
},
@@ -689,7 +689,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let variants_start = niche_variants.start().as_u32();
let variants_end = niche_variants.end().as_u32();
let raw_discr = raw_discr.not_undef().map_err(|_| {
- err_unsup!(InvalidDiscriminant(ScalarMaybeUndef::Undef))
+ err_ub!(InvalidDiscriminant(ScalarMaybeUndef::Undef))
})?;
match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) {
Err(ptr) => {
@@ -697,7 +697,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let ptr_valid = niche_start == 0 && variants_start == variants_end &&
!self.memory.ptr_may_be_null(ptr);
if !ptr_valid {
- throw_unsup!(InvalidDiscriminant(raw_discr.erase_tag().into()))
+ throw_ub!(InvalidDiscriminant(raw_discr.erase_tag().into()))
}
(dataful_variant.as_u32() as u128, dataful_variant)
},
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 903eb3c1c44b9..0289c52fd3744 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -1031,9 +1031,13 @@ where
variant_index: VariantIdx,
dest: PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
+ let variant_scalar = Scalar::from_u32(variant_index.as_u32()).into();
+
match dest.layout.variants {
layout::Variants::Single { index } => {
- assert_eq!(index, variant_index);
+ if index != variant_index {
+ throw_ub!(InvalidDiscriminant(variant_scalar));
+ }
}
layout::Variants::Multiple {
discr_kind: layout::DiscriminantKind::Tag,
@@ -1041,7 +1045,9 @@ where
discr_index,
..
} => {
- assert!(dest.layout.ty.variant_range(*self.tcx).unwrap().contains(&variant_index));
+ if !dest.layout.ty.variant_range(*self.tcx).unwrap().contains(&variant_index) {
+ throw_ub!(InvalidDiscriminant(variant_scalar));
+ }
let discr_val =
dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
@@ -1064,9 +1070,9 @@ where
discr_index,
..
} => {
- assert!(
- variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len(),
- );
+ if !variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len() {
+ throw_ub!(InvalidDiscriminant(variant_scalar));
+ }
if variant_index != dataful_variant {
let variants_start = niche_variants.start().as_u32();
let variant_index_relative = variant_index.as_u32()
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index 853fcb1beabf5..3444fb60f333b 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -344,7 +344,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
match self.walk_value(op) {
Ok(()) => Ok(()),
Err(err) => match err.kind {
- err_unsup!(InvalidDiscriminant(val)) =>
+ err_ub!(InvalidDiscriminant(val)) =>
throw_validation_failure!(
val, self.path, "a valid enum discriminant"
),
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 49ac1de8fef64..f0c0e57344388 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -8,7 +8,7 @@ use rustc::hir::def::DefKind;
use rustc::hir::def_id::DefId;
use rustc::mir::{
AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue,
- Local, NullOp, UnOp, StatementKind, Statement, LocalKind,
+ Local, UnOp, StatementKind, Statement, LocalKind,
TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp,
SourceScope, SourceScopeLocalData, LocalDecl, BasicBlock,
};
@@ -118,7 +118,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
struct ConstPropMachine;
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine {
- type MemoryKinds= !;
+ type MemoryKinds = !;
type PointerTag = ();
type ExtraFnVal = !;
@@ -434,32 +434,23 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
) -> Option> {
let span = source_info.span;
- // if this isn't a supported operation, then return None
- match rvalue {
- Rvalue::Repeat(..) |
- Rvalue::Aggregate(..) |
- Rvalue::NullaryOp(NullOp::Box, _) |
- Rvalue::Discriminant(..) => return None,
-
- Rvalue::Use(_) |
- Rvalue::Len(_) |
- Rvalue::Cast(..) |
- Rvalue::NullaryOp(..) |
- Rvalue::CheckedBinaryOp(..) |
- Rvalue::Ref(..) |
- Rvalue::UnaryOp(..) |
- Rvalue::BinaryOp(..) => { }
- }
+ let overflow_check = self.tcx.sess.overflow_checks();
- // perform any special checking for specific Rvalue types
- if let Rvalue::UnaryOp(op, arg) = rvalue {
- trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg);
- let overflow_check = self.tcx.sess.overflow_checks();
+ // Perform any special handling for specific Rvalue types.
+ // Generally, checks here fall into one of two categories:
+ // 1. Additional checking to provide useful lints to the user
+ // - In this case, we will do some validation and then fall through to the
+ // end of the function which evals the assignment.
+ // 2. Working around bugs in other parts of the compiler
+ // - In this case, we'll return `None` from this function to stop evaluation.
+ match rvalue {
+ // Additional checking: if overflow checks are disabled (which is usually the case in
+ // release mode), then we need to do additional checking here to give lints to the user
+ // if an overflow would occur.
+ Rvalue::UnaryOp(UnOp::Neg, arg) if !overflow_check => {
+ trace!("checking UnaryOp(op = Neg, arg = {:?})", arg);
- self.use_ecx(source_info, |this| {
- // We check overflow in debug mode already
- // so should only check in release mode.
- if *op == UnOp::Neg && !overflow_check {
+ self.use_ecx(source_info, |this| {
let ty = arg.ty(&this.local_decls, this.tcx);
if ty.is_integral() {
@@ -471,60 +462,70 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
throw_panic!(OverflowNeg)
}
}
+
+ Ok(())
+ })?;
+ }
+
+ // Additional checking: check for overflows on integer binary operations and report
+ // them to the user as lints.
+ Rvalue::BinaryOp(op, left, right) => {
+ trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right);
+
+ let r = self.use_ecx(source_info, |this| {
+ this.ecx.read_immediate(this.ecx.eval_operand(right, None)?)
+ })?;
+ if *op == BinOp::Shr || *op == BinOp::Shl {
+ let left_bits = place_layout.size.bits();
+ let right_size = r.layout.size;
+ let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size));
+ if r_bits.ok().map_or(false, |b| b >= left_bits as u128) {
+ let source_scope_local_data = match self.source_scope_local_data {
+ ClearCrossCrate::Set(ref data) => data,
+ ClearCrossCrate::Clear => return None,
+ };
+ let dir = if *op == BinOp::Shr {
+ "right"
+ } else {
+ "left"
+ };
+ let hir_id = source_scope_local_data[source_info.scope].lint_root;
+ self.tcx.lint_hir(
+ ::rustc::lint::builtin::EXCEEDING_BITSHIFTS,
+ hir_id,
+ span,
+ &format!("attempt to shift {} with overflow", dir));
+ return None;
+ }
}
- Ok(())
- })?;
- } else if let Rvalue::BinaryOp(op, left, right) = rvalue {
- trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right);
-
- let r = self.use_ecx(source_info, |this| {
- this.ecx.read_immediate(this.ecx.eval_operand(right, None)?)
- })?;
- if *op == BinOp::Shr || *op == BinOp::Shl {
- let left_bits = place_layout.size.bits();
- let right_size = r.layout.size;
- let r_bits = r.to_scalar().and_then(|r| r.to_bits(right_size));
- if r_bits.ok().map_or(false, |b| b >= left_bits as u128) {
- let source_scope_local_data = match self.source_scope_local_data {
- ClearCrossCrate::Set(ref data) => data,
- ClearCrossCrate::Clear => return None,
- };
- let dir = if *op == BinOp::Shr {
- "right"
- } else {
- "left"
- };
- let hir_id = source_scope_local_data[source_info.scope].lint_root;
- self.tcx.lint_hir(
- ::rustc::lint::builtin::EXCEEDING_BITSHIFTS,
- hir_id,
- span,
- &format!("attempt to shift {} with overflow", dir));
- return None;
+ // If overflow checking is enabled (like in debug mode by default),
+ // then we'll already catch overflow when we evaluate the `Assert` statement
+ // in MIR. However, if overflow checking is disabled, then there won't be any
+ // `Assert` statement and so we have to do additional checking here.
+ if !overflow_check {
+ self.use_ecx(source_info, |this| {
+ let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?;
+ let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?;
+
+ if overflow {
+ let err = err_panic!(Overflow(*op)).into();
+ return Err(err);
+ }
+
+ Ok(())
+ })?;
}
}
- self.use_ecx(source_info, |this| {
- let l = this.ecx.read_immediate(this.ecx.eval_operand(left, None)?)?;
- let (_, overflow, _ty) = this.ecx.overflowing_binary_op(*op, l, r)?;
-
- // We check overflow in debug mode already
- // so should only check in release mode.
- if !this.tcx.sess.overflow_checks() && overflow {
- let err = err_panic!(Overflow(*op)).into();
- return Err(err);
- }
- Ok(())
- })?;
- } else if let Rvalue::Ref(_, _, place) = rvalue {
- trace!("checking Ref({:?})", place);
+ // Work around: avoid ICE in miri.
// FIXME(wesleywiser) we don't currently handle the case where we try to make a ref
- // from a function argument that hasn't been assigned to in this function.
- if let Place {
- base: PlaceBase::Local(local),
- projection: box []
- } = place {
+ // from a function argument that hasn't been assigned to in this function. The main
+ // issue is if an arg is a fat-pointer, miri `expects()` to be able to read the value
+ // of that pointer to get size info. However, since this is `ConstProp`, that argument
+ // doesn't actually have a backing value and so this causes an ICE.
+ Rvalue::Ref(_, _, Place { base: PlaceBase::Local(local), projection: box [] }) => {
+ trace!("checking Ref({:?})", place);
let alive =
if let LocalValue::Live(_) = self.ecx.frame().locals[*local].value {
true
@@ -535,6 +536,15 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
return None;
}
}
+
+ // Work around: avoid extra unnecessary locals.
+ // FIXME(wesleywiser): const eval will turn this into a `const Scalar()` that
+ // `SimplifyLocals` doesn't know it can remove.
+ Rvalue::Aggregate(_, operands) if operands.len() == 0 => {
+ return None;
+ }
+
+ _ => { }
}
self.use_ecx(source_info, |this| {
diff --git a/src/librustc_resolve/error_codes.rs b/src/librustc_resolve/error_codes.rs
index ab3d95dd8edfe..d47722500ef37 100644
--- a/src/librustc_resolve/error_codes.rs
+++ b/src/librustc_resolve/error_codes.rs
@@ -26,7 +26,7 @@ struct Foo {
}
```
-Please also verify that this wasn't because of a name-clash and rename the type
+Please also verify \hat this wasn't because of a name-clash and rename the type
parameter if so.
"##,
@@ -1735,6 +1735,33 @@ match eco {
```
"##,
+E0577: r##"
+Something other than a module was found in visibility scope.
+
+Erroneous code example:
+
+```compile_fail,E0577,edition2018
+pub struct Sea;
+
+pub (in crate::Sea) struct Shark; // error!
+
+fn main() {}
+```
+
+`Sea` is not a module, therefore it is invalid to use it in a visibility path.
+To fix this error we need to ensure `Sea` is a module.
+
+Please note that the visibility scope can only be applied on ancestors!
+
+```edition2018
+pub mod Sea {
+ pub (in crate::Sea) struct Shark; // ok!
+}
+
+fn main() {}
+```
+"##,
+
E0603: r##"
A private item was used outside its scope.
@@ -1864,6 +1891,5 @@ struct Foo> {
// E0470, removed
E0575,
E0576,
- E0577,
E0578,
}
diff --git a/src/test/compile-fail/consts/const-err3.rs b/src/test/compile-fail/consts/const-err3.rs
index fc10824f0c03c..add4eef13c784 100644
--- a/src/test/compile-fail/consts/const-err3.rs
+++ b/src/test/compile-fail/consts/const-err3.rs
@@ -14,6 +14,7 @@ fn main() {
//~^ ERROR const_err
let _e = [5u8][1];
//~^ ERROR const_err
+ //~| ERROR this expression will panic at runtime
black_box(b);
black_box(c);
black_box(d);
diff --git a/src/test/mir-opt/const_prop/aggregate.rs b/src/test/mir-opt/const_prop/aggregate.rs
new file mode 100644
index 0000000000000..0937d37be6b6e
--- /dev/null
+++ b/src/test/mir-opt/const_prop/aggregate.rs
@@ -0,0 +1,25 @@
+// compile-flags: -O
+
+fn main() {
+ let x = (0, 1, 2).1 + 0;
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+// ...
+// _3 = (const 0i32, const 1i32, const 2i32);
+// _2 = (_3.1: i32);
+// _1 = Add(move _2, const 0i32);
+// ...
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+// ...
+// _3 = (const 0i32, const 1i32, const 2i32);
+// _2 = const 1i32;
+// _1 = Add(move _2, const 0i32);
+// ...
+// }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/boxes.rs b/src/test/mir-opt/const_prop/boxes.rs
new file mode 100644
index 0000000000000..52a7f7ee79503
--- /dev/null
+++ b/src/test/mir-opt/const_prop/boxes.rs
@@ -0,0 +1,53 @@
+// compile-flags: -O
+
+#![feature(box_syntax)]
+
+// Note: this test verifies that we, in fact, do not const prop `box`
+
+fn main() {
+ let x = *(box 42) + 0;
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+// ...
+// _4 = Box(i32);
+// (*_4) = const 42i32;
+// _3 = move _4;
+// ...
+// _2 = (*_3);
+// _1 = Add(move _2, const 0i32);
+// ...
+// drop(_3) -> [return: bb2, unwind: bb1];
+// }
+// bb1 (cleanup): {
+// resume;
+// }
+// bb2: {
+// ...
+// _0 = ();
+// ...
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+// ...
+// _4 = Box(i32);
+// (*_4) = const 42i32;
+// _3 = move _4;
+// ...
+// _2 = (*_3);
+// _1 = Add(move _2, const 0i32);
+// ...
+// drop(_3) -> [return: bb2, unwind: bb1];
+// }
+// bb1 (cleanup): {
+// resume;
+// }
+// bb2: {
+// ...
+// _0 = ();
+// ...
+// }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/discriminant.rs b/src/test/mir-opt/const_prop/discriminant.rs
new file mode 100644
index 0000000000000..07bbd9202b940
--- /dev/null
+++ b/src/test/mir-opt/const_prop/discriminant.rs
@@ -0,0 +1,53 @@
+// compile-flags: -O
+
+fn main() {
+ let x = (if let Some(true) = Some(true) { 42 } else { 10 }) + 0;
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+// ...
+// _3 = std::option::Option::::Some(const true,);
+// _4 = discriminant(_3);
+// switchInt(move _4) -> [1isize: bb3, otherwise: bb2];
+// }
+// bb1: {
+// _2 = const 42i32;
+// goto -> bb4;
+// }
+// bb2: {
+// _2 = const 10i32;
+// goto -> bb4;
+// }
+// bb3: {
+// switchInt(((_3 as Some).0: bool)) -> [false: bb2, otherwise: bb1];
+// }
+// bb4: {
+// _1 = Add(move _2, const 0i32);
+// ...
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+// ...
+// _3 = const Scalar(0x01) : std::option::Option;
+// _4 = const 1isize;
+// switchInt(const 1isize) -> [1isize: bb3, otherwise: bb2];
+// }
+// bb1: {
+// _2 = const 42i32;
+// goto -> bb4;
+// }
+// bb2: {
+// _2 = const 10i32;
+// goto -> bb4;
+// }
+// bb3: {
+// switchInt(const true) -> [false: bb2, otherwise: bb1];
+// }
+// bb4: {
+// _1 = Add(move _2, const 0i32);
+// ...
+// }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/mir-opt/const_prop/repeat.rs b/src/test/mir-opt/const_prop/repeat.rs
new file mode 100644
index 0000000000000..fb091ad2a3d53
--- /dev/null
+++ b/src/test/mir-opt/const_prop/repeat.rs
@@ -0,0 +1,37 @@
+// compile-flags: -O
+
+fn main() {
+ let x: u32 = [42; 8][2] + 0;
+}
+
+// END RUST SOURCE
+// START rustc.main.ConstProp.before.mir
+// bb0: {
+// ...
+// _3 = [const 42u32; 8];
+// ...
+// _4 = const 2usize;
+// _5 = const 8usize;
+// _6 = Lt(_4, _5);
+// assert(move _6, "index out of bounds: the len is move _5 but the index is _4") -> bb1;
+// }
+// bb1: {
+// _2 = _3[_4];
+// _1 = Add(move _2, const 0u32);
+// ...
+// return;
+// }
+// END rustc.main.ConstProp.before.mir
+// START rustc.main.ConstProp.after.mir
+// bb0: {
+// ...
+// _6 = const true;
+// assert(const true, "index out of bounds: the len is move _5 but the index is _4") -> bb1;
+// }
+// bb1: {
+// _2 = const 42u32;
+// _1 = Add(move _2, const 0u32);
+// ...
+// return;
+// }
+// END rustc.main.ConstProp.after.mir
diff --git a/src/test/run-fail/overflowing-rsh-5.rs b/src/test/run-fail/overflowing-rsh-5.rs
index 793f495240d57..58dfc5710ae4e 100644
--- a/src/test/run-fail/overflowing-rsh-5.rs
+++ b/src/test/run-fail/overflowing-rsh-5.rs
@@ -2,6 +2,7 @@
// compile-flags: -C debug-assertions
#![warn(exceeding_bitshifts)]
+#![warn(const_err)]
fn main() {
let _n = 1i64 >> [64][0];
diff --git a/src/test/run-fail/overflowing-rsh-6.rs b/src/test/run-fail/overflowing-rsh-6.rs
index d6b2f8dc9f9af..c2fec5e4860af 100644
--- a/src/test/run-fail/overflowing-rsh-6.rs
+++ b/src/test/run-fail/overflowing-rsh-6.rs
@@ -2,6 +2,7 @@
// compile-flags: -C debug-assertions
#![warn(exceeding_bitshifts)]
+#![warn(const_err)]
#![feature(const_indexing)]
fn main() {
diff --git a/src/test/ui/coherence/impl-foreign-for-foreign.rs b/src/test/ui/coherence/impl-foreign-for-foreign.rs
new file mode 100644
index 0000000000000..de0b66a35eb01
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-foreign.rs
@@ -0,0 +1,17 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+
+impl Remote for i32 {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign-for-foreign.stderr b/src/test/ui/coherence/impl-foreign-for-foreign.stderr
new file mode 100644
index 0000000000000..b03a75a77c346
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-foreign.stderr
@@ -0,0 +1,12 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl-foreign-for-foreign.rs:12:1
+ |
+LL | impl Remote for i32 {
+ | ^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs
new file mode 100644
index 0000000000000..5146263d99114
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].rs
@@ -0,0 +1,25 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+
+impl Remote1> for i32 {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+impl Remote1> for f64 {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+impl Remote1> for f32 {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr
new file mode 100644
index 0000000000000..bfaec790b20a6
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr
@@ -0,0 +1,30 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl-foreign-for-foreign[foreign].rs:12:1
+ |
+LL | impl Remote1> for i32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl-foreign-for-foreign[foreign].rs:16:1
+ |
+LL | impl Remote1> for f64 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl-foreign-for-foreign[foreign].rs:20:1
+ |
+LL | impl Remote1> for f32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[local].rs b/src/test/ui/coherence/impl-foreign-for-foreign[local].rs
new file mode 100644
index 0000000000000..050769dcf4ce8
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-foreign[local].rs
@@ -0,0 +1,16 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local(Rc);
+
+impl Remote1> for i32 {}
+impl Remote1> for f32 {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs
new file mode 100644
index 0000000000000..03b11edf98b41
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].rs
@@ -0,0 +1,21 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+
+impl Remote for Box {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+impl Remote for Box> {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr
new file mode 100644
index 0000000000000..2ce4921cf938f
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr
@@ -0,0 +1,21 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl-foreign-for-fundamental[foreign].rs:12:1
+ |
+LL | impl Remote for Box {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl-foreign-for-fundamental[foreign].rs:16:1
+ |
+LL | impl Remote for Box> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs b/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs
new file mode 100644
index 0000000000000..ae03ce6a440dc
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-fundamental[local].rs
@@ -0,0 +1,17 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1(Rc);
+
+impl Remote for Box {}
+impl Remote for Box> {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign-for-local.rs b/src/test/ui/coherence/impl-foreign-for-local.rs
new file mode 100644
index 0000000000000..c9dddeba18dc5
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign-for-local.rs
@@ -0,0 +1,15 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+
+impl Remote for Local {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs
new file mode 100644
index 0000000000000..06efb6c2ad75e
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.rs
@@ -0,0 +1,26 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1(Rc);
+
+impl Remote1> for i32 {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+impl Remote1>> for f64 {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+impl Remote1>> for f32 {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr
new file mode 100644
index 0000000000000..bf2361a1718af
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr
@@ -0,0 +1,30 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:13:1
+ |
+LL | impl Remote1> for i32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:17:1
+ |
+LL | impl Remote1>> for f64 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl-foreign[fundemental[foreign]]-for-foreign.rs:21:1
+ |
+LL | impl Remote1>> for f32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs b/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs
new file mode 100644
index 0000000000000..d47e0a36a5659
--- /dev/null
+++ b/src/test/ui/coherence/impl-foreign[fundemental[local]]-for-foreign.rs
@@ -0,0 +1,18 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1(Rc);
+
+impl Remote1> for i32 {}
+impl Remote1>> for f64 {}
+impl Remote1>> for f32 {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl[t]-foreign-for-(local, t).rs b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).rs
new file mode 100644
index 0000000000000..850b6f85d0ed7
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).rs
@@ -0,0 +1,17 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+
+impl Remote for (Local, T) {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl[t]-foreign-for-(local, t).stderr b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).stderr
new file mode 100644
index 0000000000000..ff0b9d6d0da9a
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign-for-(local, t).stderr
@@ -0,0 +1,12 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl[t]-foreign-for-(local, t).rs:12:1
+ |
+LL | impl Remote for (Local, T) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs
new file mode 100644
index 0000000000000..db7a2ae8076a3
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].rs
@@ -0,0 +1,23 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+use std::sync::Arc;
+
+struct Local;
+
+impl Remote for Rc {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+
+impl Remote for Arc {
+ //~^ ERROR only traits defined in the current crate
+ // | can be implemented for arbitrary types [E0117]
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr
new file mode 100644
index 0000000000000..d7ffcaf76f9a2
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr
@@ -0,0 +1,21 @@
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl[t]-foreign-for-foreign[t].rs:13:1
+ |
+LL | impl Remote for Rc {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
+ --> $DIR/impl[t]-foreign-for-foreign[t].rs:18:1
+ |
+LL | impl Remote for Arc {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ impl doesn't use types inside crate
+ |
+ = note: the impl does not reference only types defined in this crate
+ = note: define and implement a trait or new type instead
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0117`.
diff --git a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs
new file mode 100644
index 0000000000000..4cc19e1a526ca
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].rs
@@ -0,0 +1,17 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+
+impl Remote for Box {
+ //~^ ERROR type parameter `T` must be used as the type parameter for
+ // | some local type (e.g., `MyStruct`)
+}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr
new file mode 100644
index 0000000000000..20ce11ef9759e
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign-for-fundamental[t].stderr
@@ -0,0 +1,11 @@
+error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct`)
+ --> $DIR/impl[t]-foreign-for-fundamental[t].rs:12:1
+ |
+LL | impl Remote for Box {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` must be used as the type parameter for some local type
+ |
+ = note: only traits defined in the current crate can be implemented for a type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0210`.
diff --git a/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs
new file mode 100644
index 0000000000000..914680f191ac9
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign[fundemental[local]]-for-foreign[t].rs
@@ -0,0 +1,17 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1(Rc);
+
+impl Remote1> for Rc {}
+impl Remote1>> for Rc {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs
new file mode 100644
index 0000000000000..1e84ff40c6227
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-foreign[t].rs
@@ -0,0 +1,17 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1(Rc);
+
+impl Remote1 for Rc {}
+impl Remote1> for Rc {}
+
+fn main() {}
diff --git a/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs
new file mode 100644
index 0000000000000..ea6aa101d209c
--- /dev/null
+++ b/src/test/ui/coherence/impl[t]-foreign[local]-for-fundamental[foreign[t]].rs
@@ -0,0 +1,19 @@
+#![feature(re_rebalance_coherence)]
+
+// compile-flags:--crate-name=test
+// aux-build:coherence_lib.rs
+// check-pass
+
+extern crate coherence_lib as lib;
+use lib::*;
+use std::rc::Rc;
+
+struct Local;
+struct Local1(Rc);
+
+impl Remote1 for Box> {}
+impl Remote1> for Box> {}
+impl Remote1> for Box> {}
+impl Remote1>> for Box> {}
+
+fn main() {}
diff --git a/src/test/ui/consts/const-err2.rs b/src/test/ui/consts/const-err2.rs
index ecbcc2a4b496f..e5ee90fc9f11f 100644
--- a/src/test/ui/consts/const-err2.rs
+++ b/src/test/ui/consts/const-err2.rs
@@ -23,6 +23,7 @@ fn main() {
//~^ ERROR const_err
let _e = [5u8][1];
//~^ ERROR index out of bounds
+ //~| ERROR this expression will panic at runtime
black_box(a);
black_box(b);
black_box(c);
diff --git a/src/test/ui/consts/const-err2.stderr b/src/test/ui/consts/const-err2.stderr
index 1d84d44dc27b3..0a09a7213dabc 100644
--- a/src/test/ui/consts/const-err2.stderr
+++ b/src/test/ui/consts/const-err2.stderr
@@ -34,5 +34,11 @@ error: index out of bounds: the len is 1 but the index is 1
LL | let _e = [5u8][1];
| ^^^^^^^^
-error: aborting due to 5 previous errors
+error: this expression will panic at runtime
+ --> $DIR/const-err2.rs:24:14
+ |
+LL | let _e = [5u8][1];
+ | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+
+error: aborting due to 6 previous errors
diff --git a/src/test/ui/consts/const-err3.rs b/src/test/ui/consts/const-err3.rs
index a9cf04cda7a5a..89373f99f75c2 100644
--- a/src/test/ui/consts/const-err3.rs
+++ b/src/test/ui/consts/const-err3.rs
@@ -23,6 +23,7 @@ fn main() {
//~^ ERROR const_err
let _e = [5u8][1];
//~^ ERROR const_err
+ //~| ERROR this expression will panic at runtime
black_box(a);
black_box(b);
black_box(c);
diff --git a/src/test/ui/consts/const-err3.stderr b/src/test/ui/consts/const-err3.stderr
index 0602707be7040..42de247c8f7e0 100644
--- a/src/test/ui/consts/const-err3.stderr
+++ b/src/test/ui/consts/const-err3.stderr
@@ -34,5 +34,11 @@ error: index out of bounds: the len is 1 but the index is 1
LL | let _e = [5u8][1];
| ^^^^^^^^
-error: aborting due to 5 previous errors
+error: this expression will panic at runtime
+ --> $DIR/const-err3.rs:24:14
+ |
+LL | let _e = [5u8][1];
+ | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+
+error: aborting due to 6 previous errors
diff --git a/src/test/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs b/src/test/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs
new file mode 100644
index 0000000000000..0a5ca97e2d971
--- /dev/null
+++ b/src/test/ui/consts/const-eval/write-to-uninhabited-enum-variant.rs
@@ -0,0 +1,29 @@
+// run-pass
+// ignore-wasm
+
+#![allow(dead_code)]
+
+enum Empty { }
+enum Test1 {
+ A(u8),
+ B(Empty),
+}
+enum Test2 {
+ A(u8),
+ B(Empty),
+ C,
+}
+
+fn bar() -> Option {
+ std::process::exit(0)
+}
+
+fn main() {
+ if let Some(x) = bar() {
+ Test1::B(x);
+ }
+
+ if let Some(x) = bar() {
+ Test2::B(x);
+ }
+}
diff --git a/src/test/ui/consts/const-prop-ice.rs b/src/test/ui/consts/const-prop-ice.rs
index 13309f978b672..48c4b7da942e4 100644
--- a/src/test/ui/consts/const-prop-ice.rs
+++ b/src/test/ui/consts/const-prop-ice.rs
@@ -1,3 +1,4 @@
fn main() {
[0; 3][3u64 as usize]; //~ ERROR the len is 3 but the index is 3
+ //~| ERROR this expression will panic at runtime
}
diff --git a/src/test/ui/consts/const-prop-ice.stderr b/src/test/ui/consts/const-prop-ice.stderr
index 4b3880198bf2d..8ecc6f4bc6b12 100644
--- a/src/test/ui/consts/const-prop-ice.stderr
+++ b/src/test/ui/consts/const-prop-ice.stderr
@@ -6,5 +6,11 @@ LL | [0; 3][3u64 as usize];
|
= note: `#[deny(const_err)]` on by default
-error: aborting due to previous error
+error: this expression will panic at runtime
+ --> $DIR/const-prop-ice.rs:2:5
+ |
+LL | [0; 3][3u64 as usize];
+ | ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 3
+
+error: aborting due to 2 previous errors
diff --git a/src/test/ui/issues/issue-54348.rs b/src/test/ui/issues/issue-54348.rs
index 68d838054776e..e7221e2cbb1e1 100644
--- a/src/test/ui/issues/issue-54348.rs
+++ b/src/test/ui/issues/issue-54348.rs
@@ -1,5 +1,7 @@
fn main() {
[1][0u64 as usize];
[1][1.5 as usize]; //~ ERROR index out of bounds
+ //~| ERROR this expression will panic at runtime
[1][1u64 as usize]; //~ ERROR index out of bounds
+ //~| ERROR this expression will panic at runtime
}
diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr
index fa77bd6fd7797..79320ef4f31c7 100644
--- a/src/test/ui/issues/issue-54348.stderr
+++ b/src/test/ui/issues/issue-54348.stderr
@@ -6,11 +6,23 @@ LL | [1][1.5 as usize];
|
= note: `#[deny(const_err)]` on by default
+error: this expression will panic at runtime
+ --> $DIR/issue-54348.rs:3:5
+ |
+LL | [1][1.5 as usize];
+ | ^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+
error: index out of bounds: the len is 1 but the index is 1
- --> $DIR/issue-54348.rs:4:5
+ --> $DIR/issue-54348.rs:5:5
|
LL | [1][1u64 as usize];
| ^^^^^^^^^^^^^^^^^^
-error: aborting due to 2 previous errors
+error: this expression will panic at runtime
+ --> $DIR/issue-54348.rs:5:5
+ |
+LL | [1][1u64 as usize];
+ | ^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1
+
+error: aborting due to 4 previous errors
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts2.rs b/src/test/ui/lint/lint-exceeding-bitshifts2.rs
index 69b627355b801..2c213daddd752 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts2.rs
+++ b/src/test/ui/lint/lint-exceeding-bitshifts2.rs
@@ -8,7 +8,7 @@ fn main() {
let n = 1u8 << (4+3);
let n = 1u8 << (4+4); //~ ERROR: attempt to shift left with overflow
let n = 1i64 >> [63][0];
- let n = 1i64 >> [64][0]; // should be linting, needs to wait for const propagation
+ let n = 1i64 >> [64][0]; //~ ERROR: attempt to shift right with overflow
#[cfg(target_pointer_width = "32")]
const BITS: usize = 32;
diff --git a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr b/src/test/ui/lint/lint-exceeding-bitshifts2.stderr
index cb96982a78930..d9c76d233d03e 100644
--- a/src/test/ui/lint/lint-exceeding-bitshifts2.stderr
+++ b/src/test/ui/lint/lint-exceeding-bitshifts2.stderr
@@ -10,6 +10,12 @@ note: lint level defined here
LL | #![deny(exceeding_bitshifts, const_err)]
| ^^^^^^^^^^^^^^^^^^^
+error: attempt to shift right with overflow
+ --> $DIR/lint-exceeding-bitshifts2.rs:11:15
+ |
+LL | let n = 1i64 >> [64][0];
+ | ^^^^^^^^^^^^^^^
+
error: attempt to shift left with overflow
--> $DIR/lint-exceeding-bitshifts2.rs:17:15
|
@@ -22,5 +28,5 @@ error: attempt to shift left with overflow
LL | let n = 1_usize << BITS;
| ^^^^^^^^^^^^^^^
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
diff --git a/src/test/ui/resolve/resolve-bad-visibility.stderr b/src/test/ui/resolve/resolve-bad-visibility.stderr
index d2fb7c7a9e69d..be59edffe7f59 100644
--- a/src/test/ui/resolve/resolve-bad-visibility.stderr
+++ b/src/test/ui/resolve/resolve-bad-visibility.stderr
@@ -30,4 +30,5 @@ LL | pub(in too_soon) struct H;
error: aborting due to 5 previous errors
-For more information about this error, try `rustc --explain E0433`.
+Some errors have detailed explanations: E0433, E0577.
+For more information about an error, try `rustc --explain E0433`.
diff --git a/src/test/ui/span/visibility-ty-params.stderr b/src/test/ui/span/visibility-ty-params.stderr
index c2f0711b0c866..d3fa1d7732e72 100644
--- a/src/test/ui/span/visibility-ty-params.stderr
+++ b/src/test/ui/span/visibility-ty-params.stderr
@@ -18,3 +18,4 @@ LL | m!{ m<> }
error: aborting due to 3 previous errors
+For more information about this error, try `rustc --explain E0577`.
diff --git a/triagebot.toml b/triagebot.toml
index d87c5b64c21c2..f0e3a99037b02 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -8,3 +8,14 @@ allow-unauthenticated = [
]
[assign]
+
+[ping.icebreakers-llvm]
+message = """\
+Hey LLVM ICE-breakers! This bug has been identified as a good
+"LLVM ICE-breaking candidate". In case it's useful, here are some
+[instructions] for tackling these sorts of bugs. Maybe take a look?
+Thanks! <3
+
+[instructions]: https://rust-lang.github.io/rustc-guide/ice-breaker/llvm.html
+"""
+label = "ICEBreaker-LLVM"