mGCA: Validate const literal against expected type
Co-authored-by: Boxy <rust@boxyuwu.dev>
This commit is contained in:
parent
381e9ef09e
commit
8af02e230a
25 changed files with 407 additions and 136 deletions
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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<u64>);
|
||||
|
||||
|
|
|
|||
|
|
@ -1412,7 +1412,7 @@ rustc_queries! {
|
|||
// FIXME get rid of this with valtrees
|
||||
query lit_to_const(
|
||||
key: LitToConstInput<'tcx>
|
||||
) -> ty::Const<'tcx> {
|
||||
) -> Option<ty::Value<'tcx>> {
|
||||
desc { "converting literal to const" }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -256,6 +256,10 @@ impl Erasable for Option<ty::EarlyBinder<'_, Ty<'_>>> {
|
|||
type Storage = [u8; size_of::<Option<ty::EarlyBinder<'static, Ty<'static>>>>()];
|
||||
}
|
||||
|
||||
impl Erasable for Option<ty::Value<'_>> {
|
||||
type Storage = [u8; size_of::<Option<ty::Value<'static>>>()];
|
||||
}
|
||||
|
||||
impl Erasable for rustc_hir::MaybeOwner<'_> {
|
||||
type Storage = [u8; size_of::<rustc_hir::MaybeOwner<'static>>()];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ty::Value<'tcx>> {
|
||||
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<u8>`.
|
||||
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 })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
struct ConstBytes<const T: &'static [*mut u8; 3]>
|
||||
//~^ ERROR rustc_dump_predicates
|
||||
//~| NOTE Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] }
|
||||
//~| NOTE Binder { value: TraitPredicate(<ConstBytes<{const error}> as std::marker::Sized>, polarity:Positive), bound_vars: [] }
|
||||
//~| NOTE Binder { value: TraitPredicate(<ConstBytes<b"AAA"> as std::marker::Sized>, polarity:Positive), bound_vars: [] }
|
||||
where
|
||||
ConstBytes<b"AAA">: Sized;
|
||||
//~^ ERROR mismatched types
|
||||
|
|
|
|||
|
|
@ -1,12 +1,3 @@
|
|||
error: rustc_dump_predicates
|
||||
--> $DIR/byte-string-u8-validation.rs:8:1
|
||||
|
|
||||
LL | struct ConstBytes<const T: &'static [*mut u8; 3]>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] }
|
||||
= note: Binder { value: TraitPredicate(<ConstBytes<{const error}> 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<b"AAA">: 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<const T: &'static [*mut u8; 3]>
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: Binder { value: ConstArgHasType(T/#0, &'static [*mut u8; 3_usize]), bound_vars: [] }
|
||||
= note: Binder { value: TraitPredicate(<ConstBytes<b"AAA"> 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`.
|
||||
|
|
|
|||
|
|
@ -7,15 +7,6 @@ LL | struct ConstBytes<const T: &'static [*mut u8; 3]>;
|
|||
= 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<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
| ^^^^^^ 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<b"AAA"> = ConstBytes::<b"BBB">;
|
|||
= 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<b"AAA"> = ConstBytes::<b"BBB">;
|
||||
| ^^^^^^ 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.
|
||||
|
|
|
|||
20
tests/ui/const-generics/mgca/generic_const_type_mismatch.rs
Normal file
20
tests/ui/const-generics/mgca/generic_const_type_mismatch.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
//! Regression test for <https://github.com/rust-lang/rust/issues/150983>
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(
|
||||
generic_const_items,
|
||||
generic_const_parameter_types,
|
||||
min_generic_const_args,
|
||||
unsized_const_params
|
||||
)]
|
||||
use std::marker::ConstParamTy_;
|
||||
|
||||
struct Foo<T> {
|
||||
field: T,
|
||||
}
|
||||
|
||||
#[type_const]
|
||||
const WRAP<T : ConstParamTy_> : T = {
|
||||
Foo::<T>{field : 1} //~ ERROR: type annotations needed for the literal
|
||||
};
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
error: type annotations needed for the literal
|
||||
--> $DIR/generic_const_type_mismatch.rs:17:22
|
||||
|
|
||||
LL | Foo::<T>{field : 1}
|
||||
| ^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
26
tests/ui/const-generics/mgca/nonsensical-negated-literal.rs
Normal file
26
tests/ui/const-generics/mgca/nonsensical-negated-literal.rs
Normal file
|
|
@ -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<const F: 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
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
22
tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs
Normal file
22
tests/ui/const-generics/mgca/tuple_expr_type_mismatch.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
//! Regression test for <https://github.com/rust-lang/rust/issues/151625>
|
||||
#![expect(incomplete_features)]
|
||||
#![feature(
|
||||
adt_const_params,
|
||||
min_generic_const_args,
|
||||
unsized_const_params
|
||||
)]
|
||||
fn foo<const X: (bool, i32)>() {}
|
||||
fn bar<const Y: ([u8; 2], i32)>() {}
|
||||
fn qux<const Z: (char, i32)>() {}
|
||||
|
||||
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`
|
||||
}
|
||||
38
tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr
Normal file
38
tests/ui/const-generics/mgca/tuple_expr_type_mismatch.stderr
Normal file
|
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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::<false, 0xFF>();
|
||||
| ^^^^ 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::<false, { unsafe { char_raw.character } }>();
|
||||
|
|
@ -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::<false, 0xFF>();
|
||||
| ^^^^ 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.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,27 @@
|
|||
error[E0308]: mismatched types
|
||||
--> $DIR/invalid-patterns.rs:31:21
|
||||
|
|
||||
LL | get_flag::<false, 0xFF>();
|
||||
| ^^^^ 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::<false, 0xFF>();
|
||||
| ^^^^ 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.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ trait Trait<T> {
|
|||
|
||||
pub struct Foo<T = Box<dyn Trait<DefaultFoo>>>; //~ ERROR cycle detected
|
||||
//~^ ERROR `T` is never used
|
||||
//~| ERROR cycle detected
|
||||
type DefaultFoo = Foo;
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,26 @@ LL | pub struct Foo<T = Box<dyn Trait<DefaultFoo>>>;
|
|||
| ^^^^^^^^^^
|
||||
|
|
||||
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<T = Box<dyn Trait<DefaultFoo>>>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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<T = Box<dyn Trait<DefaultFoo>>>;
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
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<T = Box<dyn Trait<DefaultFoo>>>;
|
|||
= 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`.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ trait Foo<const N: Bar<2>> {
|
|||
//~^ 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<const M: Foo<2>> {}
|
||||
//~^ 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() {}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ LL | trait Foo<const N: dyn Bar<2>> {
|
|||
| +++
|
||||
|
||||
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<const M: Foo<2>> {}
|
||||
| ^^^^^^
|
||||
|
|
@ -32,7 +32,7 @@ LL | trait Foo<const N: Bar<2>> {
|
|||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
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<const M: Foo<2>> {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
@ -44,6 +44,22 @@ LL | trait Foo<const N: Bar<2>> {
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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<const N: Bar<2>> {
|
||||
| ^^^^^^
|
||||
|
|
||||
= 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<const M: Foo<2>> {}
|
||||
| ^^^^^^
|
||||
|
|
||||
= 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`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue