Auto merge of #112228 - compiler-errors:rollup-97i0pli, r=compiler-errors

Rollup of 6 pull requests

Successful merges:

 - #109609 (Separate AnonConst from ConstBlock in HIR.)
 - #112166 (bootstrap: Rename profile = user to profile = dist)
 - #112168 (Lower `unchecked_div`/`_rem` to MIR's `BinOp::Div`/`Rem`)
 - #112183 (Normalize anon consts in new solver)
 - #112211 (pass `--lib` to `x doc`)
 - #112223 (Don't ICE in new solver when auto traits have associated types)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-06-02 23:02:42 +00:00
commit 7a0070eaea
63 changed files with 408 additions and 229 deletions

View file

@ -71,9 +71,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
let kind = match &e.kind {
ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
ExprKind::ConstBlock(anon_const) => {
let anon_const = self.lower_anon_const(anon_const);
hir::ExprKind::ConstBlock(anon_const)
ExprKind::ConstBlock(c) => {
let c = self.with_new_scopes(|this| hir::ConstBlock {
def_id: this.local_def_id(c.id),
hir_id: this.lower_node_id(c.id),
body: this.lower_const_body(c.value.span, Some(&c.value)),
});
hir::ExprKind::ConstBlock(c)
}
ExprKind::Repeat(expr, count) => {
let expr = self.lower_expr(expr);

View file

@ -223,6 +223,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
});
}
fn visit_inline_const(&mut self, constant: &'hir ConstBlock) {
self.insert(DUMMY_SP, constant.hir_id, Node::ConstBlock(constant));
self.with_parent(constant.hir_id, |this| {
intravisit::walk_inline_const(this, constant);
});
}
fn visit_expr(&mut self, expr: &'hir Expr<'hir>) {
self.insert(expr.span, expr.hir_id, Node::Expr(expr));

View file

@ -475,9 +475,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
sym::unchecked_add
| sym::unchecked_sub
| sym::unchecked_mul
| sym::unchecked_div
| sym::exact_div
| sym::unchecked_rem
| sym::unchecked_shl
| sym::unchecked_shr => {
intrinsic_args!(fx, args => (x, y); intrinsic);
@ -487,8 +485,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
sym::unchecked_add => BinOp::Add,
sym::unchecked_sub => BinOp::Sub,
sym::unchecked_mul => BinOp::Mul,
sym::unchecked_div | sym::exact_div => BinOp::Div,
sym::unchecked_rem => BinOp::Rem,
sym::exact_div => BinOp::Div,
sym::unchecked_shl => BinOp::Shl,
sym::unchecked_shr => BinOp::Shr,
_ => unreachable!(),

View file

@ -211,8 +211,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
args[1].val.unaligned_volatile_store(bx, dst);
return;
}
| sym::unchecked_div
| sym::unchecked_rem
| sym::unchecked_shl
| sym::unchecked_shr
| sym::unchecked_add
@ -229,20 +227,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.exactudiv(args[0].immediate(), args[1].immediate())
}
}
sym::unchecked_div => {
if signed {
bx.sdiv(args[0].immediate(), args[1].immediate())
} else {
bx.udiv(args[0].immediate(), args[1].immediate())
}
}
sym::unchecked_rem => {
if signed {
bx.srem(args[0].immediate(), args[1].immediate())
} else {
bx.urem(args[0].immediate(), args[1].immediate())
}
}
sym::unchecked_shl => bx.shl(args[0].immediate(), args[1].immediate()),
sym::unchecked_shr => {
if signed {

View file

@ -238,9 +238,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
| sym::unchecked_shr
| sym::unchecked_add
| sym::unchecked_sub
| sym::unchecked_mul
| sym::unchecked_div
| sym::unchecked_rem => {
| sym::unchecked_mul => {
let l = self.read_immediate(&args[0])?;
let r = self.read_immediate(&args[1])?;
let bin_op = match intrinsic_name {
@ -249,8 +247,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::unchecked_add => BinOp::Add,
sym::unchecked_sub => BinOp::Sub,
sym::unchecked_mul => BinOp::Mul,
sym::unchecked_div => BinOp::Div,
sym::unchecked_rem => BinOp::Rem,
_ => bug!(),
};
let (val, overflowed, _ty) = self.overflowing_binary_op(bin_op, &l, &r)?;

View file

@ -1675,6 +1675,14 @@ pub struct AnonConst {
pub body: BodyId,
}
/// An inline constant expression `const { something }`.
#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub struct ConstBlock {
pub hir_id: HirId,
pub def_id: LocalDefId,
pub body: BodyId,
}
/// An expression.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Expr<'hir> {
@ -1922,7 +1930,7 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum ExprKind<'hir> {
/// Allow anonymous constants from an inline `const` block
ConstBlock(AnonConst),
ConstBlock(ConstBlock),
/// An array (e.g., `[a, b, c, d]`).
Array(&'hir [Expr<'hir>]),
/// A function call.
@ -3641,6 +3649,7 @@ pub enum Node<'hir> {
Variant(&'hir Variant<'hir>),
Field(&'hir FieldDef<'hir>),
AnonConst(&'hir AnonConst),
ConstBlock(&'hir ConstBlock),
Expr(&'hir Expr<'hir>),
ExprField(&'hir ExprField<'hir>),
Stmt(&'hir Stmt<'hir>),
@ -3695,6 +3704,7 @@ impl<'hir> Node<'hir> {
Node::TypeBinding(b) => Some(b.ident),
Node::Param(..)
| Node::AnonConst(..)
| Node::ConstBlock(..)
| Node::Expr(..)
| Node::Stmt(..)
| Node::Block(..)
@ -3758,7 +3768,7 @@ impl<'hir> Node<'hir> {
})
| Node::Expr(Expr {
kind:
ExprKind::ConstBlock(AnonConst { body, .. })
ExprKind::ConstBlock(ConstBlock { body, .. })
| ExprKind::Closure(Closure { body, .. })
| ExprKind::Repeat(_, ArrayLen::Body(AnonConst { body, .. })),
..
@ -3878,6 +3888,13 @@ impl<'hir> Node<'hir> {
this
}
/// Expect a [`Node::ConstBlock`] or panic.
#[track_caller]
pub fn expect_inline_const(self) -> &'hir ConstBlock {
let Node::ConstBlock(this) = self else { self.expect_failed("an inline constant") };
this
}
/// Expect a [`Node::Expr`] or panic.
#[track_caller]
pub fn expect_expr(self) -> &'hir Expr<'hir> {

View file

@ -335,6 +335,9 @@ pub trait Visitor<'v>: Sized {
fn visit_anon_const(&mut self, c: &'v AnonConst) {
walk_anon_const(self, c)
}
fn visit_inline_const(&mut self, c: &'v ConstBlock) {
walk_inline_const(self, c)
}
fn visit_expr(&mut self, ex: &'v Expr<'v>) {
walk_expr(self, ex)
}
@ -679,13 +682,18 @@ pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonCo
visitor.visit_nested_body(constant.body);
}
pub fn walk_inline_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v ConstBlock) {
visitor.visit_id(constant.hir_id);
visitor.visit_nested_body(constant.body);
}
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) {
visitor.visit_id(expression.hir_id);
match expression.kind {
ExprKind::Array(subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions);
}
ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
ExprKind::ConstBlock(ref const_block) => visitor.visit_inline_const(const_block),
ExprKind::Repeat(ref element, ref count) => {
visitor.visit_expr(element);
visitor.visit_array_length(count)

View file

@ -392,7 +392,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
// Manually recurse over closures and inline consts, because they are the only
// case of nested bodies that share the parent environment.
hir::ExprKind::Closure(&hir::Closure { body, .. })
| hir::ExprKind::ConstBlock(hir::AnonConst { body, .. }) => {
| hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) => {
let body = visitor.tcx.hir().body(body);
visitor.visit_body(body);
}

View file

@ -50,7 +50,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// We do not allow generic parameters in anon consts if we are inside
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.lazy_normalization() {
} else if tcx.features().generic_const_exprs {
let parent_node = tcx.hir().get_parent(hir_id);
if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
&& constant.hir_id == hir_id
@ -123,9 +123,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
{
Some(parent_def_id.to_def_id())
}
Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
}
// Exclude `GlobalAsm` here which cannot have generics.
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
if asm.operands.iter().any(|(op, _op_sp)| match op {
@ -142,7 +139,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
}
}
}
Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
Node::ConstBlock(_)
| Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => {
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
}
Node::Item(item) => match item.kind {
@ -339,17 +337,14 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
}
// provide junk type parameter defs for const blocks.
if let Node::AnonConst(_) = node {
let parent_node = tcx.hir().get_parent(hir_id);
if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
params.push(ty::GenericParamDef {
index: next_index(),
name: Symbol::intern("<const_ty>"),
def_id: def_id.to_def_id(),
pure_wrt_drop: false,
kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
});
}
if let Node::ConstBlock(_) = node {
params.push(ty::GenericParamDef {
index: next_index(),
name: Symbol::intern("<const_ty>"),
def_id: def_id.to_def_id(),
pure_wrt_drop: false,
kind: ty::GenericParamDefKind::Type { has_default: false, synthetic: false },
});
}
let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();

View file

@ -463,7 +463,7 @@ pub(super) fn explicit_predicates_of<'tcx>(
}
}
} else {
if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
if matches!(def_kind, DefKind::AnonConst) && tcx.features().generic_const_exprs {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let parent_def_id = tcx.hir().get_parent_item(hir_id);

View file

@ -34,12 +34,6 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
return tcx.typeck(def_id).node_type(e.hir_id)
}
Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
if anon_const.hir_id == hir_id =>
{
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
return substs.as_inline_const().ty()
}
Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
| Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
if asm.operands.iter().any(|(op, _op_sp)| match op {
@ -487,6 +481,11 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
Node::AnonConst(_) => anon_const_type_of(tcx, def_id),
Node::ConstBlock(_) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
substs.as_inline_const().ty()
}
Node::GenericParam(param) => match &param.kind {
GenericParamKind::Type { default: Some(ty), .. }
| GenericParamKind::Const { ty, .. } => icx.to_ty(ty),

View file

@ -20,7 +20,8 @@ pub fn provide(providers: &mut Providers) {
fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] {
let id = tcx.hir().local_def_id_to_hir_id(item_def_id);
if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.lazy_normalization()
if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst)
&& tcx.features().generic_const_exprs
{
if tcx.hir().opt_const_param_default_param_def_id(id).is_some() {
// In `generics_of` we set the generics' parent to be our parent's parent which means that

View file

@ -84,6 +84,7 @@ impl<'a> State<'a> {
Node::ImplItem(a) => self.print_impl_item(a),
Node::Variant(a) => self.print_variant(a),
Node::AnonConst(a) => self.print_anon_const(a),
Node::ConstBlock(a) => self.print_inline_const(a),
Node::Expr(a) => self.print_expr(a),
Node::ExprField(a) => self.print_expr_field(&a),
Node::Stmt(a) => self.print_stmt(a),
@ -1095,10 +1096,10 @@ impl<'a> State<'a> {
self.end()
}
fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst) {
fn print_inline_const(&mut self, constant: &hir::ConstBlock) {
self.ibox(INDENT_UNIT);
self.word_space("const");
self.print_anon_const(anon_const);
self.ann.nested(self, Nested::Body(constant.body));
self.end()
}
@ -1370,7 +1371,7 @@ impl<'a> State<'a> {
self.print_expr_vec(exprs);
}
hir::ExprKind::ConstBlock(ref anon_const) => {
self.print_expr_anon_const(anon_const);
self.print_inline_const(anon_const);
}
hir::ExprKind::Repeat(element, ref count) => {
self.print_expr_repeat(element, count);

View file

@ -348,9 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
ExprKind::ConstBlock(ref anon_const) => {
self.check_expr_const_block(anon_const, expected, expr)
}
ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected, expr),
ExprKind::Repeat(element, ref count) => {
self.check_expr_repeat(element, count, expected, expr)
}
@ -1368,20 +1366,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn check_expr_const_block(
&self,
anon_const: &'tcx hir::AnonConst,
block: &'tcx hir::ConstBlock,
expected: Expectation<'tcx>,
_expr: &'tcx hir::Expr<'tcx>,
) -> Ty<'tcx> {
let body = self.tcx.hir().body(anon_const.body);
let body = self.tcx.hir().body(block.body);
// Create a new function context.
let def_id = anon_const.def_id;
let def_id = block.def_id;
let fcx = FnCtxt::new(self, self.param_env.with_const(), def_id);
crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
let ty = fcx.check_expr_with_expectation(&body.value, expected);
fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
fcx.write_ty(anon_const.hir_id, ty);
fcx.write_ty(block.hir_id, ty);
ty
}

View file

@ -270,6 +270,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
| hir::Node::Variant(..)
| hir::Node::Field(..)
| hir::Node::AnonConst(..)
| hir::Node::ConstBlock(..)
| hir::Node::Stmt(..)
| hir::Node::PathSegment(..)
| hir::Node::Ty(..)

View file

@ -227,7 +227,7 @@ impl<'tcx> InferCtxt<'tcx> {
return self.unify_const_variable(vid, a, relation.param_env());
}
(ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
if self.tcx.lazy_normalization() =>
if self.tcx.features().generic_const_exprs || self.tcx.trait_solver_next() =>
{
relation.register_const_equate_obligation(a, b);
return Ok(b);

View file

@ -1191,7 +1191,7 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) ->
fn should_encode_const(def_kind: DefKind) -> bool {
match def_kind {
DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => true,
DefKind::Const | DefKind::AssocConst | DefKind::AnonConst | DefKind::InlineConst => true,
DefKind::Struct
| DefKind::Union
@ -1210,7 +1210,6 @@ fn should_encode_const(def_kind: DefKind) -> bool {
| DefKind::Closure
| DefKind::Generator
| DefKind::ConstParam
| DefKind::InlineConst
| DefKind::AssocTy
| DefKind::TyParam
| DefKind::Trait

View file

@ -44,6 +44,7 @@ pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> {
}
Node::AnonConst(constant) => Some((constant.def_id, constant.body)),
Node::ConstBlock(constant) => Some((constant.def_id, constant.body)),
_ => None,
}
@ -240,15 +241,8 @@ impl<'hir> Map<'hir> {
None => bug!("constructor node without a constructor"),
}
}
Node::AnonConst(_) => {
let inline = match self.find_parent(hir_id) {
Some(Node::Expr(&Expr {
kind: ExprKind::ConstBlock(ref anon_const), ..
})) if anon_const.hir_id == hir_id => true,
_ => false,
};
if inline { DefKind::InlineConst } else { DefKind::AnonConst }
}
Node::AnonConst(_) => DefKind::AnonConst,
Node::ConstBlock(_) => DefKind::InlineConst,
Node::Field(_) => DefKind::Field,
Node::Expr(expr) => match expr.kind {
ExprKind::Closure(Closure { movability: None, .. }) => DefKind::Closure,
@ -1060,6 +1054,7 @@ impl<'hir> Map<'hir> {
Node::Variant(variant) => variant.span,
Node::Field(field) => field.span,
Node::AnonConst(constant) => self.body(constant.body).value.span,
Node::ConstBlock(constant) => self.body(constant.body).value.span,
Node::Expr(expr) => expr.span,
Node::ExprField(field) => field.span,
Node::Stmt(stmt) => stmt.span,
@ -1289,6 +1284,7 @@ fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id))
}
Some(Node::AnonConst(_)) => node_str("const"),
Some(Node::ConstBlock(_)) => node_str("const"),
Some(Node::Expr(_)) => node_str("expr"),
Some(Node::ExprField(_)) => node_str("expr field"),
Some(Node::Stmt(_)) => node_str("stmt"),
@ -1434,6 +1430,11 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> {
intravisit::walk_anon_const(self, c)
}
fn visit_inline_const(&mut self, c: &'hir ConstBlock) {
self.body_owners.push(c.def_id);
intravisit::walk_inline_const(self, c)
}
fn visit_expr(&mut self, ex: &'hir Expr<'hir>) {
if let ExprKind::Closure(closure) = ex.kind {
self.body_owners.push(closure.def_id);

View file

@ -1273,13 +1273,18 @@ pub enum BinOp {
Mul,
/// The `/` operator (division)
///
/// Division by zero is UB, because the compiler should have inserted checks
/// prior to this.
/// For integer types, division by zero is UB, as is `MIN / -1` for signed.
/// The compiler should have inserted checks prior to this.
///
/// Floating-point division by zero is safe, and does not need guards.
Div,
/// The `%` operator (modulus)
///
/// Using zero as the modulus (second operand) is UB, because the compiler
/// should have inserted checks prior to this.
/// For integer types, using zero as the modulus (second operand) is UB,
/// as is `MIN % -1` for signed.
/// The compiler should have inserted checks prior to this.
///
/// Floating-point remainder by zero is safe, and does not need guards.
Rem,
/// The `^` operator (bitwise xor)
BitXor,

View file

@ -1015,15 +1015,6 @@ impl<'tcx> TyCtxt<'tcx> {
self.query_system.on_disk_cache.as_ref().map_or(Ok(0), |c| c.serialize(self, encoder))
}
/// If `true`, we should use lazy normalization for constants, otherwise
/// we still evaluate them eagerly.
#[inline]
pub fn lazy_normalization(self) -> bool {
let features = self.features();
// Note: We only use lazy normalization for generic const expressions.
features.generic_const_exprs
}
#[inline]
pub fn local_crate_exports_generics(self) -> bool {
debug_assert!(self.sess.opts.share_generics());

View file

@ -556,7 +556,7 @@ fn construct_const<'a, 'tcx>(
span,
..
}) => (*span, ty.span),
Node::AnonConst(_) => {
Node::AnonConst(_) | Node::ConstBlock(_) => {
let span = tcx.def_span(def);
(span, span)
}

View file

@ -582,22 +582,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// Converts inline const patterns.
fn lower_inline_const(
&mut self,
anon_const: &'tcx hir::AnonConst,
block: &'tcx hir::ConstBlock,
id: hir::HirId,
span: Span,
) -> PatKind<'tcx> {
let tcx = self.tcx;
let def_id = anon_const.def_id;
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
let body_id = match tcx.hir().get(hir_id) {
hir::Node::AnonConst(ac) => ac.body,
_ => span_bug!(
tcx.def_span(def_id.to_def_id()),
"from_inline_const can only process anonymous constants"
),
};
let def_id = block.def_id;
let body_id = block.body;
let expr = &tcx.hir().body(body_id).value;
let ty = tcx.typeck(def_id).node_type(hir_id);
let ty = tcx.typeck(def_id).node_type(block.hir_id);
// Special case inline consts that are just literals. This is solely
// a performance optimization, as we could also just go through the regular

View file

@ -421,10 +421,8 @@ impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_, 'tcx> {
intravisit::walk_block(self, block);
}
fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
if matches!(self.tcx.def_kind(c.def_id), DefKind::InlineConst) {
self.visit_body(self.tcx.hir().body(c.body))
}
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
self.visit_body(self.tcx.hir().body(c.body))
}
fn visit_fn(

View file

@ -82,30 +82,35 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
drop(args);
terminator.kind = TerminatorKind::Goto { target };
}
sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
if let Some(target) = *target {
let lhs;
let rhs;
{
let mut args = args.drain(..);
lhs = args.next().unwrap();
rhs = args.next().unwrap();
}
let bin_op = match intrinsic_name {
sym::wrapping_add => BinOp::Add,
sym::wrapping_sub => BinOp::Sub,
sym::wrapping_mul => BinOp::Mul,
_ => bug!("unexpected intrinsic"),
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
*destination,
Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))),
))),
});
terminator.kind = TerminatorKind::Goto { target };
sym::wrapping_add
| sym::wrapping_sub
| sym::wrapping_mul
| sym::unchecked_div
| sym::unchecked_rem => {
let target = target.unwrap();
let lhs;
let rhs;
{
let mut args = args.drain(..);
lhs = args.next().unwrap();
rhs = args.next().unwrap();
}
let bin_op = match intrinsic_name {
sym::wrapping_add => BinOp::Add,
sym::wrapping_sub => BinOp::Sub,
sym::wrapping_mul => BinOp::Mul,
sym::unchecked_div => BinOp::Div,
sym::unchecked_rem => BinOp::Rem,
_ => bug!("unexpected intrinsic"),
};
block.statements.push(Statement {
source_info: terminator.source_info,
kind: StatementKind::Assign(Box::new((
*destination,
Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))),
))),
});
terminator.kind = TerminatorKind::Goto { target };
}
sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
if let Some(target) = *target {

View file

@ -199,6 +199,11 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon));
}
fn visit_inline_const(&mut self, block: &'tcx hir::ConstBlock) {
let kind = Some(hir::ConstContext::Const);
self.recurse_into(kind, None, |this| intravisit::walk_inline_const(this, block));
}
fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
let owner = self.tcx.hir().body_owner_def_id(body.id());
let kind = self.tcx.hir().body_const_context(owner);

View file

@ -500,6 +500,17 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
self.in_pat = in_pat;
}
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
// When inline const blocks are used in pattern position, paths
// referenced by it should be considered as used.
let in_pat = mem::replace(&mut self.in_pat, false);
self.live_symbols.insert(c.def_id);
intravisit::walk_inline_const(self, c);
self.in_pat = in_pat;
}
}
fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {

View file

@ -24,7 +24,7 @@ enum Context {
Closure(Span),
AsyncClosure(Span),
LabeledBlock,
AnonConst,
Constant,
}
#[derive(Copy, Clone)]
@ -53,7 +53,11 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
}
fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) {
self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c));
self.with_context(Constant, |v| intravisit::walk_anon_const(v, c));
}
fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) {
self.with_context(Constant, |v| intravisit::walk_inline_const(v, c));
}
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
@ -192,7 +196,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
AsyncClosure(closure_span) => {
self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name });
}
Normal | AnonConst => {
Normal | Constant => {
self.sess.emit_err(OutsideLoop { span, name, is_break: name == "break" });
}
}

View file

@ -322,10 +322,13 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
ty::PredicateKind::Ambiguous => {
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
}
// FIXME: implement these predicates :)
ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => {
// FIXME: implement this predicate :)
ty::PredicateKind::ConstEvaluatable(_) => {
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
ty::PredicateKind::ConstEquate(_, _) => {
bug!("ConstEquate should not be emitted when `-Ztrait-solver=next` is active")
}
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
bug!("TypeWellFormedFromEnv is only used for Chalk")
}
@ -772,4 +775,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
values
}
// Try to evaluate a const, or return `None` if the const is too generic.
// This doesn't mean the const isn't evaluatable, though, and should be treated
// as an ambiguity rather than no-solution.
pub(super) fn try_const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
unevaluated: ty::UnevaluatedConst<'tcx>,
ty: Ty<'tcx>,
) -> Option<ty::Const<'tcx>> {
use rustc_middle::mir::interpret::ErrorHandled;
match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, None) {
Ok(ct) => Some(ct),
Err(ErrorHandled::Reported(e)) => Some(self.tcx().const_error(ty, e.into())),
Err(ErrorHandled::TooGeneric) => None,
}
}
}

View file

@ -118,16 +118,6 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
TypeError::Sorts(expected_found),
)
}
ty::PredicateKind::ConstEquate(a, b) => {
let (a, b) = infcx.instantiate_binder_with_placeholders(
goal.predicate.kind().rebind((a, b)),
);
let expected_found = ExpectedFound::new(true, a, b);
FulfillmentErrorCode::CodeConstEquateError(
expected_found,
TypeError::ConstMismatch(expected_found),
)
}
ty::PredicateKind::Clause(_)
| ty::PredicateKind::WellFormed(_)
| ty::PredicateKind::ObjectSafe(_)
@ -138,7 +128,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
SelectionError::Unimplemented,
)
}
ty::PredicateKind::TypeWellFormedFromEnv(_) => {
ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::TypeWellFormedFromEnv(_) => {
bug!("unexpected goal: {goal:?}")
}
},

View file

@ -22,25 +22,65 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
&mut self,
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
) -> QueryResult<'tcx> {
match goal.predicate.projection_ty.kind(self.tcx()) {
ty::AliasKind::Projection => {
let def_id = goal.predicate.def_id();
match self.tcx().def_kind(def_id) {
DefKind::AssocTy | DefKind::AssocConst => {
// To only compute normalization once for each projection we only
// normalize if the expected term is an unconstrained inference variable.
// assemble normalization candidates if the expected term is an
// unconstrained inference variable.
//
// Why: For better cache hits, since if we have an unconstrained RHS then
// there are only as many cache keys as there are (canonicalized) alias
// types in each normalizes-to goal. This also weakens inference in a
// forwards-compatible way so we don't use the value of the RHS term to
// affect candidate assembly for projections.
//
// E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
// `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
// `U` and equate it with `u32`. This means that we don't need a separate
// projection cache in the solver.
// projection cache in the solver, since we're piggybacking off of regular
// goal caching.
if self.term_is_fully_unconstrained(goal) {
let candidates = self.assemble_and_evaluate_candidates(goal);
self.merge_candidates(candidates)
match self.tcx().associated_item(def_id).container {
ty::AssocItemContainer::TraitContainer => {
let candidates = self.assemble_and_evaluate_candidates(goal);
self.merge_candidates(candidates)
}
ty::AssocItemContainer::ImplContainer => {
bug!("IATs not supported here yet")
}
}
} else {
self.set_normalizes_to_hack_goal(goal);
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
}
ty::AliasKind::Opaque => self.normalize_opaque_type(goal),
ty::AliasKind::Inherent => bug!("IATs not supported here yet"),
DefKind::AnonConst => self.normalize_anon_const(goal),
DefKind::OpaqueTy => self.normalize_opaque_type(goal),
kind => bug!("unknown DefKind {} in projection goal: {goal:#?}", kind.descr(def_id)),
}
}
#[instrument(level = "debug", skip(self), ret)]
fn normalize_anon_const(
&mut self,
goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
) -> QueryResult<'tcx> {
if let Some(normalized_const) = self.try_const_eval_resolve(
goal.param_env,
ty::UnevaluatedConst::new(
goal.predicate.projection_ty.def_id,
goal.predicate.projection_ty.substs,
),
self.tcx()
.type_of(goal.predicate.projection_ty.def_id)
.no_bound_vars()
.expect("const ty should not rely on other generics"),
) {
self.eq(goal.param_env, normalized_const, goal.predicate.term.ct().unwrap())?;
self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else {
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
}
}
}
@ -173,17 +213,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
);
// Finally we construct the actual value of the associated type.
let is_const = matches!(tcx.def_kind(assoc_def.item.def_id), DefKind::AssocConst);
let ty = tcx.type_of(assoc_def.item.def_id);
let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
let identity_substs =
ty::InternalSubsts::identity_for_item(tcx, assoc_def.item.def_id);
let did = assoc_def.item.def_id;
let kind =
ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs));
ty.map_bound(|ty| tcx.mk_const(kind, ty).into())
} else {
ty.map_bound(|ty| ty.into())
let term = match assoc_def.item.kind {
ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()),
ty::AssocKind::Const => bug!("associated const projection is not supported yet"),
ty::AssocKind::Fn => unreachable!("we should never project to a fn"),
};
ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))
@ -193,10 +226,14 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
}
fn consider_auto_trait_candidate(
_ecx: &mut EvalCtxt<'_, 'tcx>,
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
bug!("auto traits do not have associated types: {:?}", goal);
ecx.tcx().sess.delay_span_bug(
ecx.tcx().def_span(goal.predicate.def_id()),
"associated types not allowed on auto traits",
);
Err(NoSolution)
}
fn consider_trait_alias_candidate(

View file

@ -672,7 +672,9 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
#[instrument(skip(self), level = "debug")]
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
let tcx = self.selcx.tcx();
if tcx.lazy_normalization() || !needs_normalization(&constant, self.param_env.reveal()) {
if tcx.features().generic_const_exprs
|| !needs_normalization(&constant, self.param_env.reveal())
{
constant
} else {
let constant = constant.super_fold_with(self);

View file

@ -186,6 +186,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
kind: hir::TraitItemKind::Const(..), ..
})
| hir::Node::AnonConst(_)
| hir::Node::ConstBlock(_)
| hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. })
| hir::Node::ImplItem(hir::ImplItem {
kind:

View file

@ -834,6 +834,7 @@ macro_rules! tool_doc {
cargo.arg("-Zskip-rustdoc-fingerprint");
// Only include compiler crates, no dependencies of those, such as `libc`.
cargo.arg("--no-deps");
cargo.arg("--lib");
$(
cargo.arg("-p").arg($krate);
)+

View file

@ -20,7 +20,7 @@ pub enum Profile {
Codegen,
Library,
Tools,
User,
Dist,
None,
}
@ -42,7 +42,7 @@ impl Profile {
pub fn all() -> impl Iterator<Item = Self> {
use Profile::*;
// N.B. these are ordered by how they are displayed, not alphabetically
[Library, Compiler, Codegen, Tools, User, None].iter().copied()
[Library, Compiler, Codegen, Tools, Dist, None].iter().copied()
}
pub fn purpose(&self) -> String {
@ -52,7 +52,7 @@ impl Profile {
Compiler => "Contribute to the compiler itself",
Codegen => "Contribute to the compiler, and also modify LLVM or codegen",
Tools => "Contribute to tools which depend on the compiler, but do not modify it directly (e.g. rustdoc, clippy, miri)",
User => "Install Rust from source",
Dist => "Install Rust from source",
None => "Do not modify `config.toml`"
}
.to_string()
@ -72,7 +72,7 @@ impl Profile {
Profile::Codegen => "codegen",
Profile::Library => "library",
Profile::Tools => "tools",
Profile::User => "user",
Profile::Dist => "dist",
Profile::None => "none",
}
}
@ -86,7 +86,7 @@ impl FromStr for Profile {
"lib" | "library" => Ok(Profile::Library),
"compiler" => Ok(Profile::Compiler),
"llvm" | "codegen" => Ok(Profile::Codegen),
"maintainer" | "user" => Ok(Profile::User),
"maintainer" | "dist" => Ok(Profile::Dist),
"tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => {
Ok(Profile::Tools)
}
@ -159,7 +159,7 @@ pub fn setup(config: &Config, profile: Profile) {
"test src/tools/rustfmt",
],
Profile::Library => &["check", "build", "test library/std", "doc"],
Profile::User => &["dist", "build"],
Profile::Dist => &["dist", "build"],
};
println!();
@ -169,7 +169,7 @@ pub fn setup(config: &Config, profile: Profile) {
println!("- `x.py {}`", cmd);
}
if profile != Profile::User {
if profile != Profile::Dist {
println!(
"For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
);

View file

@ -7,7 +7,7 @@
bb0: {
- _0 = std::intrinsics::min_align_of::<T>() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:21:5: 21:40
- // + span: $DIR/lower_intrinsics.rs:27:5: 27:40
- // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::min_align_of::<T>}, val: Value(<ZST>) }
+ _0 = AlignOf(T); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:42

View file

@ -11,7 +11,7 @@
StorageLive(_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
- _1 = std::intrinsics::assume(const true) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:106:9: 106:32
- // + span: $DIR/lower_intrinsics.rs:112:9: 112:32
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(bool) {std::intrinsics::assume}, val: Value(<ZST>) }
+ assume(const true); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:38

View file

@ -31,7 +31,7 @@
_3 = &(*_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:42: +1:44
- _2 = discriminant_value::<T>(move _3) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:82:5: 82:41
- // + span: $DIR/lower_intrinsics.rs:88:5: 88:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a T) -> <T as DiscriminantKind>::Discriminant {discriminant_value::<T>}, val: Value(<ZST>) }
+ _2 = discriminant((*_3)); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:45
@ -46,13 +46,13 @@
StorageLive(_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
_19 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:83:42: 83:44
// + span: $DIR/lower_intrinsics.rs:89:42: 89:44
// + literal: Const { ty: &i32, val: Unevaluated(discriminant, [T], Some(promoted[2])) }
_7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
_6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:+2:42: +2:44
- _5 = discriminant_value::<i32>(move _6) -> [return: bb2, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:83:5: 83:41
- // + span: $DIR/lower_intrinsics.rs:89:5: 89:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a i32) -> <i32 as DiscriminantKind>::Discriminant {discriminant_value::<i32>}, val: Value(<ZST>) }
+ _5 = discriminant((*_6)); // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
+ goto -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:45
@ -67,13 +67,13 @@
StorageLive(_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
_18 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:84:42: 84:45
// + span: $DIR/lower_intrinsics.rs:90:42: 90:45
// + literal: Const { ty: &(), val: Unevaluated(discriminant, [T], Some(promoted[1])) }
_11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
_10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:+3:42: +3:45
- _9 = discriminant_value::<()>(move _10) -> [return: bb3, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:84:5: 84:41
- // + span: $DIR/lower_intrinsics.rs:90:5: 90:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a ()) -> <() as DiscriminantKind>::Discriminant {discriminant_value::<()>}, val: Value(<ZST>) }
+ _9 = discriminant((*_10)); // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
+ goto -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:+3:5: +3:46
@ -88,13 +88,13 @@
StorageLive(_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
_17 = const _; // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:85:42: 85:47
// + span: $DIR/lower_intrinsics.rs:91:42: 91:47
// + literal: Const { ty: &E, val: Unevaluated(discriminant, [T], Some(promoted[0])) }
_15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
_14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:+4:42: +4:47
- _13 = discriminant_value::<E>(move _14) -> [return: bb4, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:85:5: 85:41
- // + span: $DIR/lower_intrinsics.rs:91:5: 91:41
- // + literal: Const { ty: for<'a> extern "rust-intrinsic" fn(&'a E) -> <E as DiscriminantKind>::Discriminant {discriminant_value::<E>}, val: Value(<ZST>) }
+ _13 = discriminant((*_14)); // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48
+ goto -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:+4:5: +4:48

View file

@ -49,7 +49,7 @@
StorageDead(_9); // scope 3 at $DIR/lower_intrinsics.rs:+4:90: +4:91
- _3 = copy_nonoverlapping::<i32>(move _4, move _8, const 0_usize) -> [return: bb1, unwind unreachable]; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:99:9: 99:28
- // + span: $DIR/lower_intrinsics.rs:105:9: 105:28
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, *mut i32, usize) {copy_nonoverlapping::<i32>}, val: Value(<ZST>) }
+ copy_nonoverlapping(dst = move _8, src = move _4, count = const 0_usize); // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95
+ goto -> bb1; // scope 3 at $DIR/lower_intrinsics.rs:+4:9: +4:95

View file

@ -11,7 +11,7 @@
_2 = move _1; // scope 0 at $DIR/lower_intrinsics.rs:+1:30: +1:31
- _0 = std::intrinsics::forget::<T>(move _2) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:26:5: 26:29
- // + span: $DIR/lower_intrinsics.rs:32:5: 32:29
- // + literal: Const { ty: extern "rust-intrinsic" fn(T) {std::intrinsics::forget::<T>}, val: Value(<ZST>) }
+ _0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:32

View file

@ -13,7 +13,7 @@
StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+2:9: +2:18
_1 = std::intrinsics::size_of::<T>; // scope 0 at $DIR/lower_intrinsics.rs:+2:21: +2:51
// mir::Constant
// + span: $DIR/lower_intrinsics.rs:37:21: 37:51
// + span: $DIR/lower_intrinsics.rs:43:21: 43:51
// + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(<ZST>) }
StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14
_2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+3:5: +3:14

View file

@ -24,7 +24,7 @@
_4 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+2:55: +2:56
- _3 = option_payload_ptr::<usize>(move _4) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:137:18: 137:54
- // + span: $DIR/lower_intrinsics.rs:143:18: 143:54
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<usize>) -> *const usize {option_payload_ptr::<usize>}, val: Value(<ZST>) }
+ _3 = &raw const (((*_4) as Some).0: usize); // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+2:18: +2:57
@ -37,7 +37,7 @@
_6 = &raw const (*_2); // scope 2 at $DIR/lower_intrinsics.rs:+3:55: +3:56
- _5 = option_payload_ptr::<String>(move _6) -> [return: bb2, unwind unreachable]; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:138:18: 138:54
- // + span: $DIR/lower_intrinsics.rs:144:18: 144:54
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Option<String>) -> *const String {option_payload_ptr::<String>}, val: Value(<ZST>) }
+ _5 = &raw const (((*_6) as Some).0: std::string::String); // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57
+ goto -> bb2; // scope 2 at $DIR/lower_intrinsics.rs:+3:18: +3:57

View file

@ -15,7 +15,7 @@
_4 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:33: +1:34
- _0 = offset::<*const i32, isize>(move _3, move _4) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:144:5: 144:29
- // + span: $DIR/lower_intrinsics.rs:150:5: 150:29
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32, isize) -> *const i32 {offset::<*const i32, isize>}, val: Value(<ZST>) }
+ _0 = Offset(move _3, move _4); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:35

View file

@ -13,7 +13,7 @@
_2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
- _0 = read_via_copy::<i32>(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:119:14: 119:45
- // + span: $DIR/lower_intrinsics.rs:125:14: 125:45
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const i32) -> i32 {read_via_copy::<i32>}, val: Value(<ZST>) }
+ _0 = (*_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48

View file

@ -13,7 +13,7 @@
_2 = &raw const (*_1); // scope 1 at $DIR/lower_intrinsics.rs:+1:46: +1:47
- _0 = read_via_copy::<Never>(move _2) -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:124:14: 124:45
- // + span: $DIR/lower_intrinsics.rs:130:14: 130:45
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*const Never) -> Never {read_via_copy::<Never>}, val: Value(<ZST>) }
+ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:48
}

View file

@ -11,6 +11,12 @@ pub fn wrapping(a: i32, b: i32) {
let _z = core::intrinsics::wrapping_mul(a, b);
}
// EMIT_MIR lower_intrinsics.unchecked.LowerIntrinsics.diff
pub unsafe fn unchecked(a: i32, b: i32) {
let _x = core::intrinsics::unchecked_div(a, b);
let _y = core::intrinsics::unchecked_rem(a, b);
}
// EMIT_MIR lower_intrinsics.size_of.LowerIntrinsics.diff
pub fn size_of<T>() -> usize {
core::intrinsics::size_of::<T>()

View file

@ -7,7 +7,7 @@
bb0: {
- _0 = std::intrinsics::size_of::<T>() -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:16:5: 16:35
- // + span: $DIR/lower_intrinsics.rs:22:5: 22:35
- // + literal: Const { ty: extern "rust-intrinsic" fn() -> usize {std::intrinsics::size_of::<T>}, val: Value(<ZST>) }
+ _0 = SizeOf(T); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:37

View file

@ -13,7 +13,7 @@
_2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
- _0 = transmute::<std::cmp::Ordering, i8>(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:43:14: 43:33
- // + span: $DIR/lower_intrinsics.rs:49:14: 49:33
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(std::cmp::Ordering) -> i8 {transmute::<std::cmp::Ordering, i8>}, val: Value(<ZST>) }
+ _0 = move _2 as i8 (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36

View file

@ -13,7 +13,7 @@
_2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:34: +1:35
- _0 = transmute::<&T, *const T>(move _2) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:53:14: 53:33
- // + span: $DIR/lower_intrinsics.rs:59:14: 59:33
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&T) -> *const T {transmute::<&T, *const T>}, val: Value(<ZST>) }
+ _0 = move _2 as *const T (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:36

View file

@ -12,7 +12,7 @@
StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
- _1 = transmute::<usize, Box<Never>>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:70:25: 70:44
- // + span: $DIR/lower_intrinsics.rs:76:25: 76:44
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> Box<Never> {transmute::<usize, Box<Never>>}, val: Value(<ZST>) }
+ _1 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52

View file

@ -12,7 +12,7 @@
StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
- _1 = transmute::<usize, &mut Never>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:64:25: 64:44
- // + span: $DIR/lower_intrinsics.rs:70:25: 70:44
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &mut Never {transmute::<usize, &mut Never>}, val: Value(<ZST>) }
+ _1 = const 1_usize as &mut Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52

View file

@ -12,7 +12,7 @@
StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10
- _1 = transmute::<usize, &Never>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:58:21: 58:40
- // + span: $DIR/lower_intrinsics.rs:64:21: 64:40
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &Never {transmute::<usize, &Never>}, val: Value(<ZST>) }
+ _1 = const 1_usize as &Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48

View file

@ -13,7 +13,7 @@
_2 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+1:47: +1:48
- _0 = transmute::<(), Never>(move _2) -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:48:14: 48:46
- // + span: $DIR/lower_intrinsics.rs:54:14: 54:46
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Never {transmute::<(), Never>}, val: Value(<ZST>) }
+ _0 = move _2 as Never (Transmute); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49
+ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:49

View file

@ -0,0 +1,60 @@
- // MIR for `unchecked` before LowerIntrinsics
+ // MIR for `unchecked` after LowerIntrinsics
fn unchecked(_1: i32, _2: i32) -> () {
debug a => _1; // in scope 0 at $DIR/lower_intrinsics.rs:+0:25: +0:26
debug b => _2; // in scope 0 at $DIR/lower_intrinsics.rs:+0:33: +0:34
let mut _0: (); // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:41: +0:41
let _3: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:11
let mut _4: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47
let mut _5: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+1:49: +1:50
let mut _7: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+2:46: +2:47
let mut _8: i32; // in scope 0 at $DIR/lower_intrinsics.rs:+2:49: +2:50
scope 1 {
debug _x => _3; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:11
let _6: i32; // in scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:11
scope 2 {
debug _y => _6; // in scope 2 at $DIR/lower_intrinsics.rs:+2:9: +2:11
}
}
bb0: {
StorageLive(_3); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:11
StorageLive(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47
_4 = _1; // scope 0 at $DIR/lower_intrinsics.rs:+1:46: +1:47
StorageLive(_5); // scope 0 at $DIR/lower_intrinsics.rs:+1:49: +1:50
_5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:49: +1:50
- _3 = unchecked_div::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:51
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:16:14: 16:45
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i32, i32) -> i32 {unchecked_div::<i32>}, val: Value(<ZST>) }
+ _3 = Div(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:51
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:51
}
bb1: {
StorageDead(_5); // scope 0 at $DIR/lower_intrinsics.rs:+1:50: +1:51
StorageDead(_4); // scope 0 at $DIR/lower_intrinsics.rs:+1:50: +1:51
StorageLive(_6); // scope 1 at $DIR/lower_intrinsics.rs:+2:9: +2:11
StorageLive(_7); // scope 1 at $DIR/lower_intrinsics.rs:+2:46: +2:47
_7 = _1; // scope 1 at $DIR/lower_intrinsics.rs:+2:46: +2:47
StorageLive(_8); // scope 1 at $DIR/lower_intrinsics.rs:+2:49: +2:50
_8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:49: +2:50
- _6 = unchecked_rem::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:51
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:17:14: 17:45
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i32, i32) -> i32 {unchecked_rem::<i32>}, val: Value(<ZST>) }
+ _6 = Rem(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:51
+ goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:51
}
bb2: {
StorageDead(_8); // scope 1 at $DIR/lower_intrinsics.rs:+2:50: +2:51
StorageDead(_7); // scope 1 at $DIR/lower_intrinsics.rs:+2:50: +2:51
_0 = const (); // scope 0 at $DIR/lower_intrinsics.rs:+0:41: +3:2
StorageDead(_6); // scope 1 at $DIR/lower_intrinsics.rs:+3:1: +3:2
StorageDead(_3); // scope 0 at $DIR/lower_intrinsics.rs:+3:1: +3:2
return; // scope 0 at $DIR/lower_intrinsics.rs:+3:2: +3:2
}
}

View file

@ -13,7 +13,7 @@
StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
- _2 = std::intrinsics::unreachable() -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:31:14: 31:43
- // + span: $DIR/lower_intrinsics.rs:37:14: 37:43
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(<ZST>) }
+ unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45
}

View file

@ -32,7 +32,7 @@
_5 = _2; // scope 0 at $DIR/lower_intrinsics.rs:+1:53: +1:54
- _3 = add_with_overflow::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:112:14: 112:49
- // + span: $DIR/lower_intrinsics.rs:118:14: 118:49
- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {add_with_overflow::<i32>}, val: Value(<ZST>) }
+ _3 = CheckedAdd(move _4, move _5); // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55
+ goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:55
@ -48,7 +48,7 @@
_8 = _2; // scope 1 at $DIR/lower_intrinsics.rs:+2:53: +2:54
- _6 = sub_with_overflow::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:113:14: 113:49
- // + span: $DIR/lower_intrinsics.rs:119:14: 119:49
- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {sub_with_overflow::<i32>}, val: Value(<ZST>) }
+ _6 = CheckedSub(move _7, move _8); // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55
+ goto -> bb2; // scope 1 at $DIR/lower_intrinsics.rs:+2:14: +2:55
@ -64,7 +64,7 @@
_11 = _2; // scope 2 at $DIR/lower_intrinsics.rs:+3:53: +3:54
- _9 = mul_with_overflow::<i32>(move _10, move _11) -> [return: bb3, unwind unreachable]; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:114:14: 114:49
- // + span: $DIR/lower_intrinsics.rs:120:14: 120:49
- // + literal: Const { ty: extern "rust-intrinsic" fn(i32, i32) -> (i32, bool) {mul_with_overflow::<i32>}, val: Value(<ZST>) }
+ _9 = CheckedMul(move _10, move _11); // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55
+ goto -> bb3; // scope 2 at $DIR/lower_intrinsics.rs:+3:14: +3:55

View file

@ -17,7 +17,7 @@
_4 = move _2; // scope 1 at $DIR/lower_intrinsics.rs:+1:50: +1:51
- _0 = write_via_move::<String>(move _3, move _4) -> [return: bb1, unwind unreachable]; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:52
- // mir::Constant
- // + span: $DIR/lower_intrinsics.rs:129:14: 129:46
- // + span: $DIR/lower_intrinsics.rs:135:14: 135:46
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(*mut String, String) {write_via_move::<String>}, val: Value(<ZST>) }
+ (*_3) = move _4; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:52
+ goto -> bb1; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:52

View file

@ -1,5 +1,5 @@
error[E0380]: auto traits cannot have associated items
--> $DIR/issue-23080-2.rs:5:10
--> $DIR/issue-23080-2.rs:8:10
|
LL | unsafe auto trait Trait {
| ----- auto traits cannot have associated items

View file

@ -0,0 +1,11 @@
error[E0380]: auto traits cannot have associated items
--> $DIR/issue-23080-2.rs:8:10
|
LL | unsafe auto trait Trait {
| ----- auto traits cannot have associated items
LL | type Output;
| -----^^^^^^- help: remove these associated items
error: aborting due to previous error
For more information about this error, try `rustc --explain E0380`.

View file

@ -1,3 +1,6 @@
// revisions: current next
//[next] compile-flags: -Ztrait-solver=next
#![feature(auto_traits)]
#![feature(negative_impls)]

View file

@ -0,0 +1,8 @@
// compile-flags: -Ztrait-solver=next
// check-pass
fn has_default<const N: usize>() where [(); N]: Default {}
fn main() {
has_default::<1>();
}

View file

@ -1,35 +1,13 @@
// compile-flags: -Ztrait-solver=next
// check-pass
#[derive(Default)]
struct Foo {
x: i32,
}
impl MyDefault for Foo {
fn my_default() -> Self {
Self {
x: 0,
}
}
}
trait MyDefault {
fn my_default() -> Self;
}
impl MyDefault for [Foo; 0] {
fn my_default() -> Self {
[]
}
}
impl MyDefault for [Foo; 1] {
fn my_default() -> Self {
[Foo::my_default(); 1]
}
}
fn main() {
let mut xs = <[Foo; 1]>::my_default();
let mut xs = <[Foo; 1]>::default();
xs[0].x = 1;
(&mut xs[0]).x = 2;
}

View file

@ -0,0 +1,18 @@
error[E0277]: the trait bound `(): Trait<1>` is not satisfied
--> $DIR/unevaluated-const-impl-trait-ref.rs:20:13
|
LL | needs::<1>();
| ^ the trait `Trait<1>` is not implemented for `()`
|
= help: the following other types implement trait `Trait<N>`:
<() as Trait<0>>
<() as Trait<2>>
note: required by a bound in `needs`
--> $DIR/unevaluated-const-impl-trait-ref.rs:10:38
|
LL | fn needs<const N: usize>() where (): Trait<N> {}
| ^^^^^^^^ required by this bound in `needs`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,22 @@
// compile-flags: -Ztrait-solver=next
// revisions: works fails
//[works] check-pass
trait Trait<const N: usize> {}
impl Trait<{ 1 - 1 }> for () {}
impl Trait<{ 1 + 1 }> for () {}
fn needs<const N: usize>() where (): Trait<N> {}
#[cfg(works)]
fn main() {
needs::<0>();
needs::<2>();
}
#[cfg(fails)]
fn main() {
needs::<1>();
//[fails]~^ ERROR the trait bound `(): Trait<1>` is not satisfied
}