From 8af02e230aac276d7eaa538729abca8618f02225 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Tue, 3 Feb 2026 01:08:44 +0900 Subject: [PATCH] mGCA: Validate const literal against expected type Co-authored-by: Boxy --- .../src/hir_ty_lowering/mod.rs | 27 ++++-- .../rustc_middle/src/mir/interpret/mod.rs | 38 ++++++++ compiler/rustc_middle/src/queries.rs | 2 +- compiler/rustc_middle/src/query/erase.rs | 4 + compiler/rustc_mir_build/src/thir/constant.rs | 89 ++++++++++++------- .../rustc_mir_build/src/thir/pattern/mod.rs | 17 +++- compiler/rustc_ty_utils/src/consts.rs | 5 +- .../byte-string-u8-validation.rs | 2 +- .../byte-string-u8-validation.stderr | 18 ++-- .../mismatch-raw-ptr-in-adt.stderr | 18 ++-- .../mgca/generic_const_type_mismatch.rs | 20 +++++ .../mgca/generic_const_type_mismatch.stderr | 8 ++ .../mgca/nonsensical-negated-literal.rs | 26 ++++++ .../mgca/nonsensical-negated-literal.stderr | 38 ++++++++ .../mgca/tuple_expr_type_mismatch.rs | 22 +++++ .../mgca/tuple_expr_type_mismatch.stderr | 38 ++++++++ .../mgca/type_const-mismatched-types.rs | 1 - .../mgca/type_const-mismatched-types.stderr | 10 +-- .../invalid-patterns.32bit.stderr | 52 +++++------ .../invalid-patterns.64bit.stderr | 48 +++++----- tests/ui/issues/issue-34373.rs | 1 + tests/ui/issues/issue-34373.stderr | 23 ++++- tests/ui/repeat-expr/repeat_count.stderr | 12 +-- ...ce-hir-wf-check-anon-const-issue-122989.rs | 2 + ...ir-wf-check-anon-const-issue-122989.stderr | 22 ++++- 25 files changed, 407 insertions(+), 136 deletions(-) create mode 100644 tests/ui/const-generics/mgca/generic_const_type_mismatch.rs create mode 100644 tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr create mode 100644 tests/ui/const-generics/mgca/nonsensical-negated-literal.rs create mode 100644 tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr create mode 100644 tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs create mode 100644 tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index f58461e5d0e1..e22aa990c3e7 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -35,7 +35,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::DynCompatibilityViolation; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; -use rustc_middle::mir::interpret::LitToConstInput; +use rustc_middle::mir::interpret::{LitToConstInput, const_lit_matches_ty}; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, @@ -2803,8 +2803,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, ) -> Const<'tcx> { let tcx = self.tcx(); + if let LitKind::Err(guar) = *kind { + return ty::Const::new_error(tcx, guar); + } let input = LitToConstInput { lit: *kind, ty, neg }; - tcx.at(span).lit_to_const(input) + match tcx.at(span).lit_to_const(input) { + Some(value) => ty::Const::new_value(tcx, value.valtree, value.ty), + None => { + let e = tcx.dcx().span_err(span, "type annotations needed for the literal"); + ty::Const::new_error(tcx, e) + } + } } #[instrument(skip(self), level = "debug")] @@ -2833,11 +2842,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { _ => None, }; - lit_input - // Allow the `ty` to be an alias type, though we cannot handle it here, we just go through - // the more expensive anon const code path. - .filter(|l| !l.ty.has_aliases()) - .map(|l| tcx.at(expr.span).lit_to_const(l)) + lit_input.and_then(|l| { + if const_lit_matches_ty(tcx, &l.lit, l.ty, l.neg) { + tcx.at(expr.span) + .lit_to_const(l) + .map(|value| ty::Const::new_value(tcx, value.valtree, value.ty)) + } else { + None + } + }) } fn require_type_const_attribute( diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 9762e0f21da9..f31610cd5e14 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -84,6 +84,44 @@ pub struct LitToConstInput<'tcx> { pub neg: bool, } +pub fn const_lit_matches_ty<'tcx>( + tcx: TyCtxt<'tcx>, + kind: &LitKind, + ty: Ty<'tcx>, + neg: bool, +) -> bool { + match (*kind, ty.kind()) { + (LitKind::Str(..), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => true, + (LitKind::Str(..), ty::Str) if tcx.features().deref_patterns() => true, + (LitKind::ByteStr(..), ty::Ref(_, inner_ty, _)) + if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind() + && matches!(ty.kind(), ty::Uint(ty::UintTy::U8)) => + { + true + } + (LitKind::ByteStr(..), ty::Slice(inner_ty) | ty::Array(inner_ty, _)) + if tcx.features().deref_patterns() + && matches!(inner_ty.kind(), ty::Uint(ty::UintTy::U8)) => + { + true + } + (LitKind::Byte(..), ty::Uint(ty::UintTy::U8)) => true, + (LitKind::CStr(..), ty::Ref(_, inner_ty, _)) + if matches!(inner_ty.kind(), ty::Adt(def, _) + if tcx.is_lang_item(def.did(), rustc_hir::LangItem::CStr)) => + { + true + } + (LitKind::Int(..), ty::Uint(_)) if !neg => true, + (LitKind::Int(..), ty::Int(_)) => true, + (LitKind::Bool(..), ty::Bool) => true, + (LitKind::Float(..), ty::Float(_)) => true, + (LitKind::Char(..), ty::Char) => true, + (LitKind::Err(..), _) => true, + _ => false, + } +} + #[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct AllocId(pub NonZero); diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 771c300989f2..60a03cc66d72 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -1412,7 +1412,7 @@ rustc_queries! { // FIXME get rid of this with valtrees query lit_to_const( key: LitToConstInput<'tcx> - ) -> ty::Const<'tcx> { + ) -> Option> { desc { "converting literal to const" } } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 99b1f6d8c251..fe0368525e27 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -256,6 +256,10 @@ impl Erasable for Option>> { type Storage = [u8; size_of::>>>()]; } +impl Erasable for Option> { + type Storage = [u8; size_of::>>()]; +} + impl Erasable for rustc_hir::MaybeOwner<'_> { type Storage = [u8; size_of::>()]; } diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 96248499044a..6b93cf8ec8f4 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -3,7 +3,7 @@ use rustc_ast::{self as ast, UintTy}; use rustc_hir::LangItem; use rustc_middle::bug; use rustc_middle::mir::interpret::LitToConstInput; -use rustc_middle::ty::{self, ScalarInt, TyCtxt, TypeVisitableExt as _}; +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt as _}; use tracing::trace; use crate::builder::parse_float_into_scalar; @@ -11,11 +11,11 @@ use crate::builder::parse_float_into_scalar; pub(crate) fn lit_to_const<'tcx>( tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>, -) -> ty::Const<'tcx> { - let LitToConstInput { lit, ty, neg } = lit_input; +) -> Option> { + let LitToConstInput { lit, ty: expected_ty, neg } = lit_input; - if let Err(guar) = ty.error_reported() { - return ty::Const::new_error(tcx, guar); + if expected_ty.error_reported().is_err() { + return None; } let trunc = |n, width: ty::UintTy| { @@ -32,22 +32,17 @@ pub(crate) fn lit_to_const<'tcx>( .unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)) }; - let valtree = match (lit, ty.kind()) { - (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { + let (valtree, valtree_ty) = match (lit, expected_ty.kind()) { + (ast::LitKind::Str(s, _), _) => { let str_bytes = s.as_str().as_bytes(); - ty::ValTree::from_raw_bytes(tcx, str_bytes) - } - (ast::LitKind::Str(s, _), ty::Str) if tcx.features().deref_patterns() => { - // String literal patterns may have type `str` if `deref_patterns` is enabled, in order - // to allow `deref!("..."): String`. - let str_bytes = s.as_str().as_bytes(); - ty::ValTree::from_raw_bytes(tcx, str_bytes) + let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, tcx.types.str_); + (ty::ValTree::from_raw_bytes(tcx, str_bytes), valtree_ty) } (ast::LitKind::ByteStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if let ty::Slice(ty) | ty::Array(ty, _) = inner_ty.kind() && let ty::Uint(UintTy::U8) = ty.kind() => { - ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) + (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty) } (ast::LitKind::ByteStr(byte_sym, _), ty::Slice(inner_ty) | ty::Array(inner_ty, _)) if tcx.features().deref_patterns() @@ -55,40 +50,66 @@ pub(crate) fn lit_to_const<'tcx>( { // Byte string literal patterns may have type `[u8]` or `[u8; N]` if `deref_patterns` is // enabled, in order to allow, e.g., `deref!(b"..."): Vec`. - ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()) + (ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()), expected_ty) } - (ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => { - ty::ValTree::from_scalar_int(tcx, n.into()) + (ast::LitKind::ByteStr(byte_sym, _), _) => { + let valtree = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()); + let valtree_ty = Ty::new_array(tcx, tcx.types.u8, byte_sym.as_byte_str().len() as u64); + (valtree, valtree_ty) } - (ast::LitKind::CStr(byte_sym, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::CStr)) => + (ast::LitKind::Byte(n), _) => (ty::ValTree::from_scalar_int(tcx, n.into()), tcx.types.u8), + (ast::LitKind::CStr(byte_sym, _), _) + if let Some(cstr_def_id) = tcx.lang_items().get(LangItem::CStr) => { // A CStr is a newtype around a byte slice, so we create the inner slice here. // We need a branch for each "level" of the data structure. + let cstr_ty = tcx.type_of(cstr_def_id).skip_binder(); let bytes = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()); - ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, bytes, *inner_ty)]) + let valtree = + ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, bytes, cstr_ty)]); + let valtree_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, cstr_ty); + (valtree, valtree_ty) } - (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => { + (ast::LitKind::Int(n, ast::LitIntType::Unsigned(ui)), _) if !neg => { + let scalar_int = trunc(n.get(), ui); + (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, ui)) + } + (ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)), _) if neg => return None, + (ast::LitKind::Int(n, ast::LitIntType::Signed(i)), _) => { + let scalar_int = + trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned()); + (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, i)) + } + (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Uint(ui)) if !neg => { let scalar_int = trunc(n.get(), *ui); - ty::ValTree::from_scalar_int(tcx, scalar_int) + (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_uint(tcx, *ui)) } - (ast::LitKind::Int(n, _), ty::Int(i)) => { + (ast::LitKind::Int(n, ast::LitIntType::Unsuffixed), ty::Int(i)) => { // Unsigned "negation" has the same bitwise effect as signed negation, // which gets the result we want without additional casts. let scalar_int = trunc(if neg { u128::wrapping_neg(n.get()) } else { n.get() }, i.to_unsigned()); - ty::ValTree::from_scalar_int(tcx, scalar_int) + (ty::ValTree::from_scalar_int(tcx, scalar_int), Ty::new_int(tcx, *i)) } - (ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int(tcx, b.into()), - (ast::LitKind::Float(n, _), ty::Float(fty)) => { - let bits = parse_float_into_scalar(n, *fty, neg).unwrap_or_else(|| { - tcx.dcx().bug(format!("couldn't parse float literal: {:?}", lit_input.lit)) - }); - ty::ValTree::from_scalar_int(tcx, bits) + (ast::LitKind::Bool(b), _) => (ty::ValTree::from_scalar_int(tcx, b.into()), tcx.types.bool), + (ast::LitKind::Float(n, ast::LitFloatType::Suffixed(fty)), _) => { + let fty = match fty { + ast::FloatTy::F16 => ty::FloatTy::F16, + ast::FloatTy::F32 => ty::FloatTy::F32, + ast::FloatTy::F64 => ty::FloatTy::F64, + ast::FloatTy::F128 => ty::FloatTy::F128, + }; + let bits = parse_float_into_scalar(n, fty, neg)?; + (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, fty)) } - (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int(tcx, c.into()), - (ast::LitKind::Err(guar), _) => return ty::Const::new_error(tcx, guar), - _ => return ty::Const::new_misc_error(tcx), + (ast::LitKind::Float(n, ast::LitFloatType::Unsuffixed), ty::Float(fty)) => { + let bits = parse_float_into_scalar(n, *fty, neg)?; + (ty::ValTree::from_scalar_int(tcx, bits), Ty::new_float(tcx, *fty)) + } + (ast::LitKind::Char(c), _) => (ty::ValTree::from_scalar_int(tcx, c.into()), tcx.types.char), + (ast::LitKind::Err(_), _) => return None, + _ => return None, }; - ty::Const::new_value(tcx, valtree, ty) + Some(ty::Value { ty: valtree_ty, valtree }) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3641561567bc..a231f1fda4b4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -8,13 +8,14 @@ use std::cmp::Ordering; use std::sync::Arc; use rustc_abi::{FieldIdx, Integer}; +use rustc_ast::LitKind; use rustc_data_structures::assert_matches; use rustc_errors::codes::*; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::{self as hir, RangeEnd}; use rustc_index::Idx; -use rustc_middle::mir::interpret::LitToConstInput; +use rustc_middle::mir::interpret::{LitToConstInput, const_lit_matches_ty}; use rustc_middle::thir::{ Ascription, DerefPatBorrowMode, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, }; @@ -197,8 +198,6 @@ impl<'tcx> PatCtxt<'tcx> { expr: Option<&'tcx hir::PatExpr<'tcx>>, ty: Ty<'tcx>, ) -> Result<(), ErrorGuaranteed> { - use rustc_ast::ast::LitKind; - let Some(expr) = expr else { return Ok(()); }; @@ -696,7 +695,17 @@ impl<'tcx> PatCtxt<'tcx> { let pat_ty = self.typeck_results.node_type(pat.hir_id); let lit_input = LitToConstInput { lit: lit.node, ty: pat_ty, neg: *negated }; - let constant = self.tcx.at(expr.span).lit_to_const(lit_input); + let constant = const_lit_matches_ty(self.tcx, &lit.node, pat_ty, *negated) + .then(|| self.tcx.at(expr.span).lit_to_const(lit_input)) + .flatten() + .map(|v| ty::Const::new_value(self.tcx, v.valtree, pat_ty)) + .unwrap_or_else(|| { + ty::Const::new_error_with_message( + self.tcx, + expr.span, + "literal does not match expected type", + ) + }); self.const_to_pat(constant, pat_ty, expr.hir_id, lit.span) } } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index f6d08bd458bd..5029b33e5b6c 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -59,7 +59,10 @@ fn recurse_build<'tcx>( } &ExprKind::Literal { lit, neg } => { let sp = node.span; - tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: node.ty, neg }) + match tcx.at(sp).lit_to_const(LitToConstInput { lit: lit.node, ty: node.ty, neg }) { + Some(value) => ty::Const::new_value(tcx, value.valtree, value.ty), + None => ty::Const::new_misc_error(tcx), + } } &ExprKind::NonHirLiteral { lit, user_ty: _ } => { let val = ty::ValTree::from_scalar_int(tcx, lit); diff --git a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs index 703e63ae047f..063a38c8aa01 100644 --- a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs +++ b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.rs @@ -8,7 +8,7 @@ struct ConstBytes //~^ ERROR rustc_dump_predicates //~| NOTE Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] } -//~| NOTE Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } +//~| NOTE Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } where ConstBytes: Sized; //~^ ERROR mismatched types diff --git a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr index f5f8a420a703..d4b8ac7f021d 100644 --- a/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr +++ b/tests/ui/const-generics/adt_const_params/byte-string-u8-validation.stderr @@ -1,12 +1,3 @@ -error: rustc_dump_predicates - --> $DIR/byte-string-u8-validation.rs:8:1 - | -LL | struct ConstBytes - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] } - = note: Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } - error[E0308]: mismatched types --> $DIR/byte-string-u8-validation.rs:13:16 | @@ -16,6 +7,15 @@ LL | ConstBytes: Sized; = note: expected reference `&'static [*mut u8; 3]` found reference `&'static [u8; 3]` +error: rustc_dump_predicates + --> $DIR/byte-string-u8-validation.rs:8:1 + | +LL | struct ConstBytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] } + = note: Binder { value: TraitPredicate( as std::marker::Sized>, polarity:Positive), bound_vars: [] } + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr index 717e680ee536..d7eec45bae0f 100644 --- a/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr +++ b/tests/ui/const-generics/adt_const_params/mismatch-raw-ptr-in-adt.stderr @@ -7,15 +7,6 @@ LL | struct ConstBytes; = note: `*mut u8` must implement `ConstParamTy_`, but it does not = note: `[*mut u8; 3]` must implement `ConstParamTy_`, but it does not -error[E0308]: mismatched types - --> $DIR/mismatch-raw-ptr-in-adt.rs:9:46 - | -LL | let _: ConstBytes = ConstBytes::; - | ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]` - | - = note: expected reference `&'static [*mut u8; 3]` - found reference `&'static [u8; 3]` - error[E0308]: mismatched types --> $DIR/mismatch-raw-ptr-in-adt.rs:9:23 | @@ -25,6 +16,15 @@ LL | let _: ConstBytes = ConstBytes::; = note: expected reference `&'static [*mut u8; 3]` found reference `&'static [u8; 3]` +error[E0308]: mismatched types + --> $DIR/mismatch-raw-ptr-in-adt.rs:9:46 + | +LL | let _: ConstBytes = ConstBytes::; + | ^^^^^^ expected `&[*mut u8; 3]`, found `&[u8; 3]` + | + = note: expected reference `&'static [*mut u8; 3]` + found reference `&'static [u8; 3]` + error: aborting due to 3 previous errors Some errors have detailed explanations: E0308, E0741. diff --git a/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs b/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs new file mode 100644 index 000000000000..ffde84522a26 --- /dev/null +++ b/tests/ui/const-generics/mgca/generic_const_type_mismatch.rs @@ -0,0 +1,20 @@ +//! Regression test for +#![expect(incomplete_features)] +#![feature( + generic_const_items, + generic_const_parameter_types, + min_generic_const_args, + unsized_const_params +)] +use std::marker::ConstParamTy_; + +struct Foo { + field: T, +} + +#[type_const] +const WRAP : T = { + Foo::{field : 1} //~ ERROR: type annotations needed for the literal +}; + +fn main() {} diff --git a/tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr b/tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr new file mode 100644 index 000000000000..10e37b327eec --- /dev/null +++ b/tests/ui/const-generics/mgca/generic_const_type_mismatch.stderr @@ -0,0 +1,8 @@ +error: type annotations needed for the literal + --> $DIR/generic_const_type_mismatch.rs:17:22 + | +LL | Foo::{field : 1} + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/nonsensical-negated-literal.rs b/tests/ui/const-generics/mgca/nonsensical-negated-literal.rs new file mode 100644 index 000000000000..cd68a2c0d430 --- /dev/null +++ b/tests/ui/const-generics/mgca/nonsensical-negated-literal.rs @@ -0,0 +1,26 @@ +#![feature(adt_const_params, min_generic_const_args)] +#![expect(incomplete_features)] + +use std::marker::ConstParamTy; + +#[derive(Eq, PartialEq, ConstParamTy)] +struct Foo { + field: isize +} + +fn foo() {} + +fn main() { + foo::<{ Foo { field: -1_usize } }>(); + //~^ ERROR: type annotations needed for the literal + foo::<{ Foo { field: { -1_usize } } }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block + foo::<{ Foo { field: -true } }>(); + //~^ ERROR: the constant `true` is not of type `isize` + foo::<{ Foo { field: { -true } } }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block + foo::<{ Foo { field: -"<3" } }>(); + //~^ ERROR: the constant `"<3"` is not of type `isize` + foo::<{ Foo { field: { -"<3" } } }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block +} diff --git a/tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr b/tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr new file mode 100644 index 000000000000..43ed4b71e33e --- /dev/null +++ b/tests/ui/const-generics/mgca/nonsensical-negated-literal.stderr @@ -0,0 +1,38 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/nonsensical-negated-literal.rs:16:26 + | +LL | foo::<{ Foo { field: { -1_usize } } }>(); + | ^^^^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/nonsensical-negated-literal.rs:20:26 + | +LL | foo::<{ Foo { field: { -true } } }>(); + | ^^^^^^^^^ + +error: complex const arguments must be placed inside of a `const` block + --> $DIR/nonsensical-negated-literal.rs:24:26 + | +LL | foo::<{ Foo { field: { -"<3" } } }>(); + | ^^^^^^^^^ + +error: type annotations needed for the literal + --> $DIR/nonsensical-negated-literal.rs:14:26 + | +LL | foo::<{ Foo { field: -1_usize } }>(); + | ^^^^^^^^ + +error: the constant `true` is not of type `isize` + --> $DIR/nonsensical-negated-literal.rs:18:13 + | +LL | foo::<{ Foo { field: -true } }>(); + | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `bool` + +error: the constant `"<3"` is not of type `isize` + --> $DIR/nonsensical-negated-literal.rs:22:13 + | +LL | foo::<{ Foo { field: -"<3" } }>(); + | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `&'static str` + +error: aborting due to 6 previous errors + diff --git a/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs new file mode 100644 index 000000000000..373cce1d6220 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs @@ -0,0 +1,22 @@ +//! Regression test for +#![expect(incomplete_features)] +#![feature( + adt_const_params, + min_generic_const_args, + unsized_const_params +)] +fn foo() {} +fn bar() {} +fn qux() {} + +fn main() { + foo::<{ (1, true) }>(); + //~^ ERROR: type annotations needed for the literal + //~| ERROR: mismatched types: expected `i32`, found `bool` + bar::<{ (1_u32, [1, 2]) }>(); + //~^ ERROR: expected `i32`, found const array + //~| ERROR: mismatched types: expected `[u8; 2]`, found `u32` + qux::<{ (1i32, 'a') }>(); + //~^ ERROR: mismatched types: expected `char`, found `i32` + //~| ERROR: mismatched types: expected `i32`, found `char` +} diff --git a/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr new file mode 100644 index 000000000000..13e2789ccb67 --- /dev/null +++ b/tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr @@ -0,0 +1,38 @@ +error: type annotations needed for the literal + --> $DIR/tuple_expr_type_mismatch.rs:13:14 + | +LL | foo::<{ (1, true) }>(); + | ^ + +error: mismatched types: expected `i32`, found `bool` + --> $DIR/tuple_expr_type_mismatch.rs:13:17 + | +LL | foo::<{ (1, true) }>(); + | ^^^^ + +error: mismatched types: expected `[u8; 2]`, found `u32` + --> $DIR/tuple_expr_type_mismatch.rs:16:14 + | +LL | bar::<{ (1_u32, [1, 2]) }>(); + | ^^^^^ + +error: expected `i32`, found const array + --> $DIR/tuple_expr_type_mismatch.rs:16:21 + | +LL | bar::<{ (1_u32, [1, 2]) }>(); + | ^^^^^^ + +error: mismatched types: expected `char`, found `i32` + --> $DIR/tuple_expr_type_mismatch.rs:19:14 + | +LL | qux::<{ (1i32, 'a') }>(); + | ^^^^ + +error: mismatched types: expected `i32`, found `char` + --> $DIR/tuple_expr_type_mismatch.rs:19:20 + | +LL | qux::<{ (1i32, 'a') }>(); + | ^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/const-generics/mgca/type_const-mismatched-types.rs b/tests/ui/const-generics/mgca/type_const-mismatched-types.rs index 460c5d7b2199..deac97383b04 100644 --- a/tests/ui/const-generics/mgca/type_const-mismatched-types.rs +++ b/tests/ui/const-generics/mgca/type_const-mismatched-types.rs @@ -5,7 +5,6 @@ type const FREE: u32 = 5_usize; //~^ ERROR mismatched types type const FREE2: isize = FREE; -//~^ ERROR the constant `5` is not of type `isize` trait Tr { type const N: usize; diff --git a/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr b/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr index 152dd9ec0cca..1c04ac508569 100644 --- a/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr +++ b/tests/ui/const-generics/mgca/type_const-mismatched-types.stderr @@ -1,9 +1,3 @@ -error: the constant `5` is not of type `isize` - --> $DIR/type_const-mismatched-types.rs:7:1 - | -LL | type const FREE2: isize = FREE; - | ^^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `u32` - error[E0308]: mismatched types --> $DIR/type_const-mismatched-types.rs:4:24 | @@ -17,11 +11,11 @@ LL + type const FREE: u32 = 5_u32; | error[E0308]: mismatched types - --> $DIR/type_const-mismatched-types.rs:15:27 + --> $DIR/type_const-mismatched-types.rs:18:22 | LL | type const N: usize = false; | ^^^^^ expected `usize`, found `bool` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr index cc6a813b747d..b85856db9287 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.32bit.stderr @@ -1,4 +1,28 @@ -error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:31:21 + | +LL | get_flag::(); + | ^^^^ expected `char`, found `u8` + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:33:14 + | +LL | get_flag::<7, 'c'>(); + | ^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:35:14 + | +LL | get_flag::<42, 0x5ad>(); + | ^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:35:18 + | +LL | get_flag::<42, 0x5ad>(); + | ^^^^^ expected `char`, found `u8` + +error[E0080]: reading memory at ALLOC6[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 | LL | get_flag::(); @@ -30,7 +54,7 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character 42 │ B } -error[E0080]: reading memory at ALLOC1[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory +error[E0080]: reading memory at ALLOC12[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:44:58 | LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character } }>(); @@ -40,30 +64,6 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character ff __ __ __ │ .░░░ } -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:31:21 - | -LL | get_flag::(); - | ^^^^ expected `char`, found `u8` - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:33:14 - | -LL | get_flag::<7, 'c'>(); - | ^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:35:14 - | -LL | get_flag::<42, 0x5ad>(); - | ^^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:35:18 - | -LL | get_flag::<42, 0x5ad>(); - | ^^^^^ expected `char`, found `u8` - error: aborting due to 8 previous errors Some errors have detailed explanations: E0080, E0308. diff --git a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr index cc6a813b747d..df7c2a0a8629 100644 --- a/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr +++ b/tests/ui/const-generics/min_const_generics/invalid-patterns.64bit.stderr @@ -1,3 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:31:21 + | +LL | get_flag::(); + | ^^^^ expected `char`, found `u8` + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:33:14 + | +LL | get_flag::<7, 'c'>(); + | ^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:35:14 + | +LL | get_flag::<42, 0x5ad>(); + | ^^ expected `bool`, found integer + +error[E0308]: mismatched types + --> $DIR/invalid-patterns.rs:35:18 + | +LL | get_flag::<42, 0x5ad>(); + | ^^^^^ expected `char`, found `u8` + error[E0080]: reading memory at ALLOC0[0x0..0x4], but memory is uninitialized at [0x1..0x4], and this operation requires initialized memory --> $DIR/invalid-patterns.rs:40:32 | @@ -40,30 +64,6 @@ LL | get_flag::<{ unsafe { bool_raw.boolean } }, { unsafe { char_raw.character ff __ __ __ │ .░░░ } -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:31:21 - | -LL | get_flag::(); - | ^^^^ expected `char`, found `u8` - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:33:14 - | -LL | get_flag::<7, 'c'>(); - | ^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:35:14 - | -LL | get_flag::<42, 0x5ad>(); - | ^^ expected `bool`, found integer - -error[E0308]: mismatched types - --> $DIR/invalid-patterns.rs:35:18 - | -LL | get_flag::<42, 0x5ad>(); - | ^^^^^ expected `char`, found `u8` - error: aborting due to 8 previous errors Some errors have detailed explanations: E0080, E0308. diff --git a/tests/ui/issues/issue-34373.rs b/tests/ui/issues/issue-34373.rs index 5b05811a4eb3..019cab42c643 100644 --- a/tests/ui/issues/issue-34373.rs +++ b/tests/ui/issues/issue-34373.rs @@ -6,6 +6,7 @@ trait Trait { pub struct Foo>>; //~ ERROR cycle detected //~^ ERROR `T` is never used +//~| ERROR cycle detected type DefaultFoo = Foo; fn main() { diff --git a/tests/ui/issues/issue-34373.stderr b/tests/ui/issues/issue-34373.stderr index 03d771931341..49365a701cee 100644 --- a/tests/ui/issues/issue-34373.stderr +++ b/tests/ui/issues/issue-34373.stderr @@ -5,7 +5,26 @@ LL | pub struct Foo>>; | ^^^^^^^^^^ | note: ...which requires expanding type alias `DefaultFoo`... - --> $DIR/issue-34373.rs:9:19 + --> $DIR/issue-34373.rs:10:1 + | +LL | type DefaultFoo = Foo; + | ^^^^^^^^^^^^^^^ + = note: ...which again requires computing type of `Foo::T`, completing the cycle +note: cycle used when checking that `Foo` is well-formed + --> $DIR/issue-34373.rs:7:1 + | +LL | pub struct Foo>>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information + +error[E0391]: cycle detected when computing type of `Foo::T` + --> $DIR/issue-34373.rs:7:34 + | +LL | pub struct Foo>>; + | ^^^^^^^^^^ + | +note: ...which requires expanding type alias `DefaultFoo`... + --> $DIR/issue-34373.rs:10:19 | LL | type DefaultFoo = Foo; | ^^^ @@ -26,7 +45,7 @@ LL | pub struct Foo>>; = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0391, E0392. For more information about an error, try `rustc --explain E0391`. diff --git a/tests/ui/repeat-expr/repeat_count.stderr b/tests/ui/repeat-expr/repeat_count.stderr index cf94ad41ee36..8d8702e981e6 100644 --- a/tests/ui/repeat-expr/repeat_count.stderr +++ b/tests/ui/repeat-expr/repeat_count.stderr @@ -16,12 +16,6 @@ error[E0308]: mismatched types LL | let b = [0; ()]; | ^^ expected `usize`, found `()` -error[E0308]: mismatched types - --> $DIR/repeat_count.rs:33:17 - | -LL | let g = [0; G { g: () }]; - | ^^^^^^^^^^^ expected `usize`, found `G` - error[E0308]: mismatched types --> $DIR/repeat_count.rs:12:17 | @@ -68,6 +62,12 @@ LL - let f = [0; 4u8]; LL + let f = [0; 4usize]; | +error[E0308]: mismatched types + --> $DIR/repeat_count.rs:33:17 + | +LL | let g = [0; G { g: () }]; + | ^^^^^^^^^^^ expected `usize`, found `G` + error: aborting due to 9 previous errors Some errors have detailed explanations: E0308, E0435. diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs index f2b9f037ea5f..13d7a800c51f 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.rs @@ -4,11 +4,13 @@ trait Foo> { //~^ WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //~| ERROR cycle detected when computing type of `Foo::N` + //~| ERROR `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter fn func() {} } trait Bar> {} //~^ WARN trait objects without an explicit `dyn` are deprecated //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! +//~| ERROR `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter fn main() {} diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr index 4024f57af4ff..f9a855d3b93b 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122989.stderr @@ -13,7 +13,7 @@ LL | trait Foo> { | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:20 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 | LL | trait Bar> {} | ^^^^^^ @@ -32,7 +32,7 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^ | note: ...which requires computing type of `Bar::M`... - --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:10:11 + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:11 | LL | trait Bar> {} | ^^^^^^^^^^^^^^^ @@ -44,6 +44,22 @@ LL | trait Foo> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 1 previous error; 2 warnings emitted +error: `(dyn Bar<2> + 'static)` is forbidden as the type of a const generic parameter + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:3:20 + | +LL | trait Foo> { + | ^^^^^^ + | + = note: the only supported types are integers, `bool`, and `char` + +error: `(dyn Foo<2> + 'static)` is forbidden as the type of a const generic parameter + --> $DIR/ice-hir-wf-check-anon-const-issue-122989.rs:11:20 + | +LL | trait Bar> {} + | ^^^^^^ + | + = note: the only supported types are integers, `bool`, and `char` + +error: aborting due to 3 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0391`.