about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-07-14 18:50:26 +0000
committerbors <bors@rust-lang.org>2024-07-14 18:50:26 +0000
commitf8e4ac0760216724f69b1ebc369bf03da56a7520 (patch)
tree0e992830fa43bb7a4d570daac24c3fb7b9d8a9c5
parent09682988f280bd9345e9e855e6f64a111c2a8ece (diff)
parentf19cb0b2945747aaed53413dc57f4f974b2ea9d2 (diff)
downloadrust-f8e4ac0760216724f69b1ebc369bf03da56a7520.tar.gz
rust-f8e4ac0760216724f69b1ebc369bf03da56a7520.zip
Auto merge of #127728 - matthiaskrgr:rollup-ercdbjd, r=matthiaskrgr
Rollup of 5 pull requests

Successful merges:

 - #127273 (Fix `DebugParser`.)
 - #127587 (Report usage of lib features in ast validation)
 - #127592 (doc: Suggest `str::repeat` over `iter::repeat().take().collect()`)
 - #127630 (Remove lang feature for type ascription (since it's a lib feature now))
 - #127711 (Add regression test for a gce + effects ICE)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs6
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs18
-rw-r--r--compiler/rustc_parse/src/parser/tests.rs362
-rw-r--r--compiler/rustc_passes/messages.ftl3
-rw-r--r--compiler/rustc_passes/src/errors.rs8
-rw-r--r--compiler/rustc_passes/src/stability.rs6
-rw-r--r--library/core/src/iter/sources/repeat.rs4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs24
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr64
11 files changed, 406 insertions, 93 deletions
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 9cf3182daea..2178b65727d 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -607,8 +607,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
     // does not check the same for lib features unless there's at least one
     // declared lang feature
     if !sess.opts.unstable_features.is_nightly_build() {
-        let lang_features = &features.declared_lang_features;
-        if lang_features.len() == 0 {
+        if features.declared_features.is_empty() {
             return;
         }
         for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
@@ -624,7 +623,8 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
                 attr.meta_item_list().into_iter().flatten().flat_map(|nested| nested.ident())
             {
                 let name = ident.name;
-                let stable_since = lang_features
+                let stable_since = features
+                    .declared_lang_features
                     .iter()
                     .flat_map(|&(feature, _, since)| if feature == name { since } else { None })
                     .next();
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index a48c0a4450c..f47bfdad131 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -1,5 +1,5 @@
 #![feature(
-    no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types,
+    no_core, lang_items, intrinsics, unboxed_closures, extern_types,
     decl_macro, rustc_attrs, transparent_unions, auto_traits, freeze_impls,
     thread_local
 )]
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 5673101dc24..1db3774222a 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -621,8 +621,6 @@ declare_features! (
     (unstable, try_blocks, "1.29.0", Some(31436)),
     /// Allows `impl Trait` to be used inside type aliases (RFC 2515).
     (unstable, type_alias_impl_trait, "1.38.0", Some(63063)),
-    /// Allows the use of type ascription in expressions.
-    (unstable, type_ascription, "1.6.0", Some(23416)),
     /// Allows creation of instances of a struct by moving fields that have
     /// not changed from prior instances of the same struct (RFC #2528)
     (unstable, type_changing_struct_update, "1.58.0", Some(86555)),
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index b1588357bff..958458eda9a 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1537,14 +1537,16 @@ impl<'a> Parser<'a> {
 
                 // we don't need N spans, but we want at least one, so print all of prev_token
                 dbg_fmt.field("prev_token", &parser.prev_token);
-                // make it easier to peek farther ahead by taking TokenKinds only until EOF
-                let tokens = (0..*lookahead)
-                    .map(|i| parser.look_ahead(i, |tok| tok.kind.clone()))
-                    .scan(parser.prev_token == TokenKind::Eof, |eof, tok| {
-                        let current = eof.then_some(tok.clone()); // include a trailing EOF token
-                        *eof |= &tok == &TokenKind::Eof;
-                        current
-                    });
+                let mut tokens = vec![];
+                for i in 0..*lookahead {
+                    let tok = parser.look_ahead(i, |tok| tok.kind.clone());
+                    let is_eof = tok == TokenKind::Eof;
+                    tokens.push(tok);
+                    if is_eof {
+                        // Don't look ahead past EOF.
+                        break;
+                    }
+                }
                 dbg_fmt.field_with("tokens", |field| field.debug_list().entries(tokens).finish());
                 dbg_fmt.field("approx_token_stream_pos", &parser.num_bump_calls);
 
diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs
index 5b2d119e42b..cf791d332a2 100644
--- a/compiler/rustc_parse/src/parser/tests.rs
+++ b/compiler/rustc_parse/src/parser/tests.rs
@@ -1376,12 +1376,13 @@ fn ttdelim_span() {
     });
 }
 
-// Uses a macro rather than a function so that failure messages mention the
-// correct line in the test function.
-macro_rules! look {
-    ($p:ident, $dist:literal, $kind:expr) => {
-        $p.look_ahead($dist, |tok| assert_eq!($kind, tok.kind));
-    };
+#[track_caller]
+fn look(p: &Parser<'_>, dist: usize, kind: rustc_ast::token::TokenKind) {
+    // Do the `assert_eq` outside the closure so that `track_caller` works.
+    // (`#![feature(closure_track_caller)]` + `#[track_caller]` on the closure
+    // doesn't give the line number in the test below if the assertion fails.)
+    let tok = p.look_ahead(dist, |tok| tok.clone());
+    assert_eq!(kind, tok.kind);
 }
 
 #[test]
@@ -1397,63 +1398,63 @@ fn look_ahead() {
         let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string());
 
         // Current position is the `fn`.
-        look!(p, 0, token::Ident(kw::Fn, raw_no));
-        look!(p, 1, token::Ident(sym_f, raw_no));
-        look!(p, 2, token::OpenDelim(Delimiter::Parenthesis));
-        look!(p, 3, token::Ident(sym_x, raw_no));
-        look!(p, 4, token::Colon);
-        look!(p, 5, token::Ident(sym::u32, raw_no));
-        look!(p, 6, token::CloseDelim(Delimiter::Parenthesis));
-        look!(p, 7, token::OpenDelim(Delimiter::Brace));
-        look!(p, 8, token::Ident(sym_x, raw_no));
-        look!(p, 9, token::CloseDelim(Delimiter::Brace));
-        look!(p, 10, token::Ident(kw::Struct, raw_no));
-        look!(p, 11, token::Ident(sym_S, raw_no));
-        look!(p, 12, token::Semi);
+        look(&p, 0, token::Ident(kw::Fn, raw_no));
+        look(&p, 1, token::Ident(sym_f, raw_no));
+        look(&p, 2, token::OpenDelim(Delimiter::Parenthesis));
+        look(&p, 3, token::Ident(sym_x, raw_no));
+        look(&p, 4, token::Colon);
+        look(&p, 5, token::Ident(sym::u32, raw_no));
+        look(&p, 6, token::CloseDelim(Delimiter::Parenthesis));
+        look(&p, 7, token::OpenDelim(Delimiter::Brace));
+        look(&p, 8, token::Ident(sym_x, raw_no));
+        look(&p, 9, token::CloseDelim(Delimiter::Brace));
+        look(&p, 10, token::Ident(kw::Struct, raw_no));
+        look(&p, 11, token::Ident(sym_S, raw_no));
+        look(&p, 12, token::Semi);
         // Any lookahead past the end of the token stream returns `Eof`.
-        look!(p, 13, token::Eof);
-        look!(p, 14, token::Eof);
-        look!(p, 15, token::Eof);
-        look!(p, 100, token::Eof);
+        look(&p, 13, token::Eof);
+        look(&p, 14, token::Eof);
+        look(&p, 15, token::Eof);
+        look(&p, 100, token::Eof);
 
         // Move forward to the first `x`.
         for _ in 0..3 {
             p.bump();
         }
-        look!(p, 0, token::Ident(sym_x, raw_no));
-        look!(p, 1, token::Colon);
-        look!(p, 2, token::Ident(sym::u32, raw_no));
-        look!(p, 3, token::CloseDelim(Delimiter::Parenthesis));
-        look!(p, 4, token::OpenDelim(Delimiter::Brace));
-        look!(p, 5, token::Ident(sym_x, raw_no));
-        look!(p, 6, token::CloseDelim(Delimiter::Brace));
-        look!(p, 7, token::Ident(kw::Struct, raw_no));
-        look!(p, 8, token::Ident(sym_S, raw_no));
-        look!(p, 9, token::Semi);
-        look!(p, 10, token::Eof);
-        look!(p, 11, token::Eof);
-        look!(p, 100, token::Eof);
+        look(&p, 0, token::Ident(sym_x, raw_no));
+        look(&p, 1, token::Colon);
+        look(&p, 2, token::Ident(sym::u32, raw_no));
+        look(&p, 3, token::CloseDelim(Delimiter::Parenthesis));
+        look(&p, 4, token::OpenDelim(Delimiter::Brace));
+        look(&p, 5, token::Ident(sym_x, raw_no));
+        look(&p, 6, token::CloseDelim(Delimiter::Brace));
+        look(&p, 7, token::Ident(kw::Struct, raw_no));
+        look(&p, 8, token::Ident(sym_S, raw_no));
+        look(&p, 9, token::Semi);
+        look(&p, 10, token::Eof);
+        look(&p, 11, token::Eof);
+        look(&p, 100, token::Eof);
 
         // Move forward to the `;`.
         for _ in 0..9 {
             p.bump();
         }
-        look!(p, 0, token::Semi);
+        look(&p, 0, token::Semi);
         // Any lookahead past the end of the token stream returns `Eof`.
-        look!(p, 1, token::Eof);
-        look!(p, 100, token::Eof);
+        look(&p, 1, token::Eof);
+        look(&p, 100, token::Eof);
 
         // Move one past the `;`, i.e. past the end of the token stream.
         p.bump();
-        look!(p, 0, token::Eof);
-        look!(p, 1, token::Eof);
-        look!(p, 100, token::Eof);
+        look(&p, 0, token::Eof);
+        look(&p, 1, token::Eof);
+        look(&p, 100, token::Eof);
 
         // Bumping after Eof is idempotent.
         p.bump();
-        look!(p, 0, token::Eof);
-        look!(p, 1, token::Eof);
-        look!(p, 100, token::Eof);
+        look(&p, 0, token::Eof);
+        look(&p, 1, token::Eof);
+        look(&p, 100, token::Eof);
     });
 }
 
@@ -1476,24 +1477,261 @@ fn look_ahead_non_outermost_stream() {
         for _ in 0..3 {
             p.bump();
         }
-        look!(p, 0, token::Ident(kw::Fn, raw_no));
-        look!(p, 1, token::Ident(sym_f, raw_no));
-        look!(p, 2, token::OpenDelim(Delimiter::Parenthesis));
-        look!(p, 3, token::Ident(sym_x, raw_no));
-        look!(p, 4, token::Colon);
-        look!(p, 5, token::Ident(sym::u32, raw_no));
-        look!(p, 6, token::CloseDelim(Delimiter::Parenthesis));
-        look!(p, 7, token::OpenDelim(Delimiter::Brace));
-        look!(p, 8, token::Ident(sym_x, raw_no));
-        look!(p, 9, token::CloseDelim(Delimiter::Brace));
-        look!(p, 10, token::Ident(kw::Struct, raw_no));
-        look!(p, 11, token::Ident(sym_S, raw_no));
-        look!(p, 12, token::Semi);
-        look!(p, 13, token::CloseDelim(Delimiter::Brace));
+        look(&p, 0, token::Ident(kw::Fn, raw_no));
+        look(&p, 1, token::Ident(sym_f, raw_no));
+        look(&p, 2, token::OpenDelim(Delimiter::Parenthesis));
+        look(&p, 3, token::Ident(sym_x, raw_no));
+        look(&p, 4, token::Colon);
+        look(&p, 5, token::Ident(sym::u32, raw_no));
+        look(&p, 6, token::CloseDelim(Delimiter::Parenthesis));
+        look(&p, 7, token::OpenDelim(Delimiter::Brace));
+        look(&p, 8, token::Ident(sym_x, raw_no));
+        look(&p, 9, token::CloseDelim(Delimiter::Brace));
+        look(&p, 10, token::Ident(kw::Struct, raw_no));
+        look(&p, 11, token::Ident(sym_S, raw_no));
+        look(&p, 12, token::Semi);
+        look(&p, 13, token::CloseDelim(Delimiter::Brace));
         // Any lookahead past the end of the token stream returns `Eof`.
-        look!(p, 14, token::Eof);
-        look!(p, 15, token::Eof);
-        look!(p, 100, token::Eof);
+        look(&p, 14, token::Eof);
+        look(&p, 15, token::Eof);
+        look(&p, 100, token::Eof);
+    });
+}
+
+// FIXME(nnethercote) All the output is currently wrong.
+#[test]
+fn debug_lookahead() {
+    create_default_session_globals_then(|| {
+        let psess = psess();
+        let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string());
+
+        // Current position is the `fn`.
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(0)),
+            "Parser {
+    prev_token: Token {
+        kind: Question,
+        span: Span {
+            lo: BytePos(
+                0,
+            ),
+            hi: BytePos(
+                0,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [],
+    approx_token_stream_pos: 1,
+    ..
+}"
+        );
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(7)),
+            "Parser {
+    prev_token: Token {
+        kind: Question,
+        span: Span {
+            lo: BytePos(
+                0,
+            ),
+            hi: BytePos(
+                0,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [
+        Ident(
+            \"fn\",
+            No,
+        ),
+        Ident(
+            \"f\",
+            No,
+        ),
+        OpenDelim(
+            Parenthesis,
+        ),
+        Ident(
+            \"x\",
+            No,
+        ),
+        Colon,
+        Ident(
+            \"u32\",
+            No,
+        ),
+        CloseDelim(
+            Parenthesis,
+        ),
+    ],
+    approx_token_stream_pos: 1,
+    ..
+}"
+        );
+        // There are 13 tokens. We request 15, get 14; the last one is `Eof`.
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(15)),
+            "Parser {
+    prev_token: Token {
+        kind: Question,
+        span: Span {
+            lo: BytePos(
+                0,
+            ),
+            hi: BytePos(
+                0,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [
+        Ident(
+            \"fn\",
+            No,
+        ),
+        Ident(
+            \"f\",
+            No,
+        ),
+        OpenDelim(
+            Parenthesis,
+        ),
+        Ident(
+            \"x\",
+            No,
+        ),
+        Colon,
+        Ident(
+            \"u32\",
+            No,
+        ),
+        CloseDelim(
+            Parenthesis,
+        ),
+        OpenDelim(
+            Brace,
+        ),
+        Ident(
+            \"x\",
+            No,
+        ),
+        CloseDelim(
+            Brace,
+        ),
+        Ident(
+            \"struct\",
+            No,
+        ),
+        Ident(
+            \"S\",
+            No,
+        ),
+        Semi,
+        Eof,
+    ],
+    approx_token_stream_pos: 1,
+    ..
+}"
+        );
+
+        // Move forward to the second `x`.
+        for _ in 0..8 {
+            p.bump();
+        }
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(1)),
+            "Parser {
+    prev_token: Token {
+        kind: OpenDelim(
+            Brace,
+        ),
+        span: Span {
+            lo: BytePos(
+                13,
+            ),
+            hi: BytePos(
+                14,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [
+        Ident(
+            \"x\",
+            No,
+        ),
+    ],
+    approx_token_stream_pos: 9,
+    ..
+}"
+        );
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(4)),
+            "Parser {
+    prev_token: Token {
+        kind: OpenDelim(
+            Brace,
+        ),
+        span: Span {
+            lo: BytePos(
+                13,
+            ),
+            hi: BytePos(
+                14,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [
+        Ident(
+            \"x\",
+            No,
+        ),
+        CloseDelim(
+            Brace,
+        ),
+        Ident(
+            \"struct\",
+            No,
+        ),
+        Ident(
+            \"S\",
+            No,
+        ),
+    ],
+    approx_token_stream_pos: 9,
+    ..
+}"
+        );
+
+        // Move two past the final token (the `;`).
+        for _ in 0..6 {
+            p.bump();
+        }
+        assert_eq!(
+            &format!("{:#?}", p.debug_lookahead(3)),
+            "Parser {
+    prev_token: Token {
+        kind: Eof,
+        span: Span {
+            lo: BytePos(
+                27,
+            ),
+            hi: BytePos(
+                28,
+            ),
+            ctxt: #0,
+        },
+    },
+    tokens: [
+        Eof,
+    ],
+    approx_token_stream_pos: 15,
+    ..
+}"
+        );
     });
 }
 
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index d7513fbad63..1d93cbaddd6 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -290,9 +290,6 @@ passes_export_name =
 passes_extern_main =
     the `main` function cannot be declared in an `extern` block
 
-passes_feature_only_on_nightly =
-    `#![feature]` may not be used on the {$release_channel} release channel
-
 passes_feature_previously_declared =
     feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared}
 
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index a026ff3b13b..58d27d5b4bb 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1493,14 +1493,6 @@ pub struct TraitImplConstStable {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_feature_only_on_nightly, code = E0554)]
-pub struct FeatureOnlyOnNightly {
-    #[primary_span]
-    pub span: Span,
-    pub release_channel: &'static str,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_unknown_feature, code = E0635)]
 pub struct UnknownFeature {
     #[primary_span]
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 6bdfaf0c908..2c34f477de5 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -936,12 +936,6 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     let declared_lib_features = &tcx.features().declared_lib_features;
     let mut remaining_lib_features = FxIndexMap::default();
     for (feature, span) in declared_lib_features {
-        if !tcx.sess.opts.unstable_features.is_nightly_build() {
-            tcx.dcx().emit_err(errors::FeatureOnlyOnNightly {
-                span: *span,
-                release_channel: env!("CFG_RELEASE_CHANNEL"),
-            });
-        }
         if remaining_lib_features.contains_key(&feature) {
             // Warn if the user enables a lib feature multiple times.
             tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature });
diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs
index 0168b11c739..243f938bce2 100644
--- a/library/core/src/iter/sources/repeat.rs
+++ b/library/core/src/iter/sources/repeat.rs
@@ -8,11 +8,15 @@ use crate::num::NonZero;
 /// Infinite iterators like `repeat()` are often used with adapters like
 /// [`Iterator::take()`], in order to make them finite.
 ///
+/// Use [`str::repeat()`] instead of this function if you just want to repeat
+/// a char/string `n`th times.
+///
 /// If the element type of the iterator you need does not implement `Clone`,
 /// or if you do not want to keep the repeated element in memory, you can
 /// instead use the [`repeat_with()`] function.
 ///
 /// [`repeat_with()`]: crate::iter::repeat_with
+/// [`str::repeat()`]: ../../std/primitive.str.html#method.repeat
 ///
 /// # Examples
 ///
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs
new file mode 100644
index 00000000000..21e91c731b3
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.rs
@@ -0,0 +1,24 @@
+#![feature(generic_const_exprs)]
+//~^ WARN: the feature `generic_const_exprs` is incomplete
+
+// Regression test for #125770 which would ICE under the old effects desugaring that
+// created a const generic parameter for constness on `Add`.
+
+use std::ops::Add;
+
+pub struct Dimension;
+
+pub struct Quantity<S, const D: Dimension>(S);
+//~^ ERROR: `Dimension` is forbidden as the type of a const generic parameter
+
+impl<const D: Dimension, LHS, RHS> Add<LHS, D> for Quantity<LHS, { Dimension }> {}
+//~^ ERROR: trait takes at most 1 generic argument
+//~| ERROR: `Dimension` is forbidden as the type of a const generic parameter
+
+pub fn add<const U: Dimension>(x: Quantity<f32, U>) -> Quantity<f32, U> {
+    //~^ ERROR: `Dimension` is forbidden as the type of a const generic parameter
+    x + y
+    //~^ ERROR: cannot find value `y` in this scope
+}
+
+fn main() {}
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr
new file mode 100644
index 00000000000..8c814295de4
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/mismatched_generic_args.stderr
@@ -0,0 +1,64 @@
+error[E0425]: cannot find value `y` in this scope
+  --> $DIR/mismatched_generic_args.rs:20:9
+   |
+LL | pub fn add<const U: Dimension>(x: Quantity<f32, U>) -> Quantity<f32, U> {
+   |                  - similarly named const parameter `U` defined here
+LL |
+LL |     x + y
+   |         ^ help: a const parameter with a similar name exists: `U`
+
+warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/mismatched_generic_args.rs:1:12
+   |
+LL | #![feature(generic_const_exprs)]
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: `Dimension` is forbidden as the type of a const generic parameter
+  --> $DIR/mismatched_generic_args.rs:11:33
+   |
+LL | pub struct Quantity<S, const D: Dimension>(S);
+   |                                 ^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
+   |
+LL + #![feature(adt_const_params)]
+   |
+
+error[E0107]: trait takes at most 1 generic argument but 2 generic arguments were supplied
+  --> $DIR/mismatched_generic_args.rs:14:36
+   |
+LL | impl<const D: Dimension, LHS, RHS> Add<LHS, D> for Quantity<LHS, { Dimension }> {}
+   |                                    ^^^ expected at most 1 generic argument
+
+error: `Dimension` is forbidden as the type of a const generic parameter
+  --> $DIR/mismatched_generic_args.rs:14:15
+   |
+LL | impl<const D: Dimension, LHS, RHS> Add<LHS, D> for Quantity<LHS, { Dimension }> {}
+   |               ^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
+   |
+LL + #![feature(adt_const_params)]
+   |
+
+error: `Dimension` is forbidden as the type of a const generic parameter
+  --> $DIR/mismatched_generic_args.rs:18:21
+   |
+LL | pub fn add<const U: Dimension>(x: Quantity<f32, U>) -> Quantity<f32, U> {
+   |                     ^^^^^^^^^
+   |
+   = note: the only supported types are integers, `bool` and `char`
+help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types
+   |
+LL + #![feature(adt_const_params)]
+   |
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0107, E0425.
+For more information about an error, try `rustc --explain E0107`.