Auto merge of #107314 - matthiaskrgr:rollup-j40lnlj, r=matthiaskrgr

Rollup of 11 pull requests

Successful merges:

 - #106407 (Improve proc macro attribute diagnostics)
 - #106960 (Teach parser to understand fake anonymous enum syntax)
 - #107085 (Custom MIR: Support binary and unary operations)
 - #107086 (Print PID holding bootstrap build lock on Linux)
 - #107175 (Fix escaping inference var ICE in `point_at_expr_source_of_inferred_type`)
 - #107204 (suggest qualifying bare associated constants)
 - #107248 (abi: add AddressSpace field to Primitive::Pointer )
 - #107272 (Implement ObjectSafe and WF in the new solver)
 - #107285 (Implement `Generator` and `Future` in the new solver)
 - #107286 (ICE in new solver if we see an inference variable)
 - #107313 (Add Style Team Triagebot config)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2023-01-26 06:23:14 +00:00
commit e187f8871e
77 changed files with 1682 additions and 343 deletions

View file

@ -351,7 +351,7 @@ dependencies = [
"cargo-test-macro", "cargo-test-macro",
"cargo-test-support", "cargo-test-support",
"cargo-util", "cargo-util",
"clap 4.1.3", "clap 4.1.4",
"crates-io", "crates-io",
"curl", "curl",
"curl-sys", "curl-sys",
@ -655,9 +655,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.1.3" version = "4.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8d93d855ce6a0aa87b8473ef9169482f40abaa2e9e0993024c35c902cbd5920" checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"clap_derive 4.1.0", "clap_derive 4.1.0",
@ -675,7 +675,7 @@ version = "4.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b" checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
dependencies = [ dependencies = [
"clap 4.1.3", "clap 4.1.4",
] ]
[[package]] [[package]]
@ -2294,7 +2294,7 @@ name = "jsondoclint"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap 4.1.3", "clap 4.1.4",
"fs-err", "fs-err",
"rustdoc-json-types", "rustdoc-json-types",
"serde", "serde",
@ -2557,7 +2557,7 @@ dependencies = [
"ammonia", "ammonia",
"anyhow", "anyhow",
"chrono", "chrono",
"clap 4.1.3", "clap 4.1.4",
"clap_complete", "clap_complete",
"elasticlunr-rs", "elasticlunr-rs",
"env_logger 0.10.0", "env_logger 0.10.0",
@ -3528,7 +3528,7 @@ dependencies = [
name = "rustbook" name = "rustbook"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap 4.1.3", "clap 4.1.4",
"env_logger 0.7.1", "env_logger 0.7.1",
"mdbook", "mdbook",
] ]

View file

@ -267,6 +267,9 @@ impl TargetDataLayout {
["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?, ["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?,
["f32", ref a @ ..] => dl.f32_align = align(a, "f32")?, ["f32", ref a @ ..] => dl.f32_align = align(a, "f32")?,
["f64", ref a @ ..] => dl.f64_align = align(a, "f64")?, ["f64", ref a @ ..] => dl.f64_align = align(a, "f64")?,
// FIXME(erikdesjardins): we should be parsing nonzero address spaces
// this will require replacing TargetDataLayout::{pointer_size,pointer_align}
// with e.g. `fn pointer_size_in(AddressSpace)`
[p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => { [p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => {
dl.pointer_size = size(s, p)?; dl.pointer_size = size(s, p)?;
dl.pointer_align = align(a, p)?; dl.pointer_align = align(a, p)?;
@ -861,7 +864,7 @@ pub enum Primitive {
Int(Integer, bool), Int(Integer, bool),
F32, F32,
F64, F64,
Pointer, Pointer(AddressSpace),
} }
impl Primitive { impl Primitive {
@ -872,7 +875,10 @@ impl Primitive {
Int(i, _) => i.size(), Int(i, _) => i.size(),
F32 => Size::from_bits(32), F32 => Size::from_bits(32),
F64 => Size::from_bits(64), F64 => Size::from_bits(64),
Pointer => dl.pointer_size, // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
// different address spaces can have different sizes
// (but TargetDataLayout doesn't currently parse that part of the DL string)
Pointer(_) => dl.pointer_size,
} }
} }
@ -883,26 +889,12 @@ impl Primitive {
Int(i, _) => i.align(dl), Int(i, _) => i.align(dl),
F32 => dl.f32_align, F32 => dl.f32_align,
F64 => dl.f64_align, F64 => dl.f64_align,
Pointer => dl.pointer_align, // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
// different address spaces can have different alignments
// (but TargetDataLayout doesn't currently parse that part of the DL string)
Pointer(_) => dl.pointer_align,
} }
} }
// FIXME(eddyb) remove, it's trivial thanks to `matches!`.
#[inline]
pub fn is_float(self) -> bool {
matches!(self, F32 | F64)
}
// FIXME(eddyb) remove, it's completely unused.
#[inline]
pub fn is_int(self) -> bool {
matches!(self, Int(..))
}
#[inline]
pub fn is_ptr(self) -> bool {
matches!(self, Pointer)
}
} }
/// Inclusive wrap-around range of valid values, that is, if /// Inclusive wrap-around range of valid values, that is, if
@ -1188,7 +1180,8 @@ impl FieldsShape {
/// An identifier that specifies the address space that some operation /// An identifier that specifies the address space that some operation
/// should operate on. Special address spaces have an effect on code generation, /// should operate on. Special address spaces have an effect on code generation,
/// depending on the target and the address spaces it implements. /// depending on the target and the address spaces it implements.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
pub struct AddressSpace(pub u32); pub struct AddressSpace(pub u32);
impl AddressSpace { impl AddressSpace {
@ -1468,7 +1461,6 @@ pub struct PointeeInfo {
pub size: Size, pub size: Size,
pub align: Align, pub align: Align,
pub safe: Option<PointerKind>, pub safe: Option<PointerKind>,
pub address_space: AddressSpace,
} }
/// Used in `might_permit_raw_init` to indicate the kind of initialisation /// Used in `might_permit_raw_init` to indicate the kind of initialisation

View file

@ -400,8 +400,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref); walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref);
visitor.visit_ty(&mutable_type.ty) visitor.visit_ty(&mutable_type.ty)
} }
TyKind::Tup(tuple_element_types) => { TyKind::Tup(tys) => {
walk_list!(visitor, visit_ty, tuple_element_types); walk_list!(visitor, visit_ty, tys);
} }
TyKind::BareFn(function_declaration) => { TyKind::BareFn(function_declaration) => {
walk_list!(visitor, visit_generic_param, &function_declaration.generic_params); walk_list!(visitor, visit_generic_param, &function_declaration.generic_params);

View file

@ -35,7 +35,8 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type {
}, },
Primitive::F32 => types::F32, Primitive::F32 => types::F32,
Primitive::F64 => types::F64, Primitive::F64 => types::F64,
Primitive::Pointer => pointer_ty(tcx), // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => pointer_ty(tcx),
} }
} }

View file

@ -709,7 +709,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
bx.range_metadata(load, vr); bx.range_metadata(load, vr);
} }
} }
abi::Pointer if vr.start < vr.end && !vr.contains(0) => { abi::Pointer(_) if vr.start < vr.end && !vr.contains(0) => {
bx.nonnull_metadata(load); bx.nonnull_metadata(load);
} }
_ => {} _ => {}

View file

@ -211,7 +211,7 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
let base_addr = self.const_bitcast(base_addr, self.usize_type); let base_addr = self.const_bitcast(base_addr, self.usize_type);
let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64); let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
let ptr = self.const_bitcast(base_addr + offset, ptr_type); let ptr = self.const_bitcast(base_addr + offset, ptr_type);
if layout.primitive() != Pointer { if !matches!(layout.primitive(), Pointer(_)) {
self.const_bitcast(ptr.dereference(None).to_rvalue(), ty) self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
} }
else { else {

View file

@ -322,13 +322,16 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
) )
.expect("const_alloc_to_llvm: could not read relocation pointer") .expect("const_alloc_to_llvm: could not read relocation pointer")
as u64; as u64;
let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
llvals.push(cx.scalar_to_backend( llvals.push(cx.scalar_to_backend(
InterpScalar::from_pointer( InterpScalar::from_pointer(
interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)), interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
&cx.tcx, &cx.tcx,
), ),
abi::Scalar::Initialized { value: Primitive::Pointer, valid_range: WrappingRange::full(dl.pointer_size) }, abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) },
cx.type_i8p(), cx.type_i8p_ext(address_space),
)); ));
next_offset = offset + pointer_size; next_offset = offset + pointer_size;
} }

View file

@ -253,7 +253,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
Int(i, false) => cx.type_from_unsigned_integer(i), Int(i, false) => cx.type_from_unsigned_integer(i),
F32 => cx.type_f32(), F32 => cx.type_f32(),
F64 => cx.type_f64(), F64 => cx.type_f64(),
Pointer => { Pointer(address_space) => {
// If we know the alignment, pick something better than i8. // If we know the alignment, pick something better than i8.
let pointee = let pointee =
if let Some(pointee) = self.pointee_info_at(cx, offset) { if let Some(pointee) = self.pointee_info_at(cx, offset) {
@ -262,7 +262,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
else { else {
cx.type_i8() cx.type_i8()
}; };
cx.type_ptr_to(pointee) cx.type_ptr_to_ext(pointee, address_space)
} }
} }
} }

View file

@ -849,6 +849,7 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
/// Helper function to get the LLVM type for a Scalar. Pointers are returned as /// Helper function to get the LLVM type for a Scalar. Pointers are returned as
/// the equivalent integer type. /// the equivalent integer type.
fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Type { fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Type {
let dl = &cx.tcx.data_layout;
match scalar.primitive() { match scalar.primitive() {
Primitive::Int(Integer::I8, _) => cx.type_i8(), Primitive::Int(Integer::I8, _) => cx.type_i8(),
Primitive::Int(Integer::I16, _) => cx.type_i16(), Primitive::Int(Integer::I16, _) => cx.type_i16(),
@ -856,7 +857,8 @@ fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Ty
Primitive::Int(Integer::I64, _) => cx.type_i64(), Primitive::Int(Integer::I64, _) => cx.type_i64(),
Primitive::F32 => cx.type_f32(), Primitive::F32 => cx.type_f32(),
Primitive::F64 => cx.type_f64(), Primitive::F64 => cx.type_f64(),
Primitive::Pointer => cx.type_isize(), // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => cx.type_from_integer(dl.ptr_sized_integer()),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -868,6 +870,7 @@ fn llvm_fixup_input<'ll, 'tcx>(
reg: InlineAsmRegClass, reg: InlineAsmRegClass,
layout: &TyAndLayout<'tcx>, layout: &TyAndLayout<'tcx>,
) -> &'ll Value { ) -> &'ll Value {
let dl = &bx.tcx.data_layout;
match (reg, layout.abi) { match (reg, layout.abi) {
(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => { (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
if let Primitive::Int(Integer::I8, _) = s.primitive() { if let Primitive::Int(Integer::I8, _) = s.primitive() {
@ -881,8 +884,10 @@ fn llvm_fixup_input<'ll, 'tcx>(
let elem_ty = llvm_asm_scalar_type(bx.cx, s); let elem_ty = llvm_asm_scalar_type(bx.cx, s);
let count = 16 / layout.size.bytes(); let count = 16 / layout.size.bytes();
let vec_ty = bx.cx.type_vector(elem_ty, count); let vec_ty = bx.cx.type_vector(elem_ty, count);
if let Primitive::Pointer = s.primitive() { // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
value = bx.ptrtoint(value, bx.cx.type_isize()); if let Primitive::Pointer(_) = s.primitive() {
let t = bx.type_from_integer(dl.ptr_sized_integer());
value = bx.ptrtoint(value, t);
} }
bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0)) bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0))
} }
@ -958,7 +963,7 @@ fn llvm_fixup_output<'ll, 'tcx>(
} }
(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) => { (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) => {
value = bx.extract_element(value, bx.const_i32(0)); value = bx.extract_element(value, bx.const_i32(0));
if let Primitive::Pointer = s.primitive() { if let Primitive::Pointer(_) = s.primitive() {
value = bx.inttoptr(value, layout.llvm_type(bx.cx)); value = bx.inttoptr(value, layout.llvm_type(bx.cx));
} }
value value

View file

@ -511,7 +511,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
bx.range_metadata(load, scalar.valid_range(bx)); bx.range_metadata(load, scalar.valid_range(bx));
} }
} }
abi::Pointer => { abi::Pointer(_) => {
if !scalar.valid_range(bx).contains(0) { if !scalar.valid_range(bx).contains(0) {
bx.nonnull_metadata(load); bx.nonnull_metadata(load);
} }

View file

@ -236,7 +236,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
Scalar::Int(int) => { Scalar::Int(int) => {
let data = int.assert_bits(layout.size(self)); let data = int.assert_bits(layout.size(self));
let llval = self.const_uint_big(self.type_ix(bitsize), data); let llval = self.const_uint_big(self.type_ix(bitsize), data);
if layout.primitive() == Pointer { if matches!(layout.primitive(), Pointer(_)) {
unsafe { llvm::LLVMConstIntToPtr(llval, llty) } unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
} else { } else {
self.const_bitcast(llval, llty) self.const_bitcast(llval, llty)
@ -284,7 +284,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
1, 1,
) )
}; };
if layout.primitive() != Pointer { if !matches!(layout.primitive(), Pointer(_)) {
unsafe { llvm::LLVMConstPtrToInt(llval, llty) } unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
} else { } else {
self.const_bitcast(llval, llty) self.const_bitcast(llval, llty)

View file

@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::interpret::{ use rustc_middle::mir::interpret::{
read_target_uint, Allocation, ConstAllocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer, read_target_uint, Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer,
Scalar as InterpScalar, Scalar as InterpScalar,
}; };
use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::MonoItem;
@ -21,9 +21,7 @@ use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_session::config::Lto; use rustc_session::config::Lto;
use rustc_target::abi::{ use rustc_target::abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange};
AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
};
use std::ops::Range; use std::ops::Range;
pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value { pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value {
@ -98,12 +96,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
.expect("const_alloc_to_llvm: could not read relocation pointer") .expect("const_alloc_to_llvm: could not read relocation pointer")
as u64; as u64;
let address_space = match cx.tcx.global_alloc(alloc_id) { let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => {
AddressSpace::DATA
}
};
llvals.push(cx.scalar_to_backend( llvals.push(cx.scalar_to_backend(
InterpScalar::from_pointer( InterpScalar::from_pointer(
@ -111,7 +104,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
&cx.tcx, &cx.tcx,
), ),
Scalar::Initialized { Scalar::Initialized {
value: Primitive::Pointer, value: Primitive::Pointer(address_space),
valid_range: WrappingRange::full(dl.pointer_size), valid_range: WrappingRange::full(dl.pointer_size),
}, },
cx.type_i8p_ext(address_space), cx.type_i8p_ext(address_space),

View file

@ -122,7 +122,8 @@ fn tag_base_type<'ll, 'tcx>(
Primitive::Int(t, _) => t, Primitive::Int(t, _) => t,
Primitive::F32 => Integer::I32, Primitive::F32 => Integer::I32,
Primitive::F64 => Integer::I64, Primitive::F64 => Integer::I64,
Primitive::Pointer => { // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Primitive::Pointer(_) => {
// If the niche is the NULL value of a reference, then `discr_enum_ty` will be // If the niche is the NULL value of a reference, then `discr_enum_ty` will be
// a RawPtr. CodeView doesn't know what to do with enums whose base type is a // a RawPtr. CodeView doesn't know what to do with enums whose base type is a
// pointer so we fix this up to just be `usize`. // pointer so we fix this up to just be `usize`.

View file

@ -149,7 +149,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
emit_va_arg(self, args[0], ret_ty) emit_va_arg(self, args[0], ret_ty)
} }
} }
Primitive::F64 | Primitive::Pointer => { Primitive::F64 | Primitive::Pointer(_) => {
emit_va_arg(self, args[0], ret_ty) emit_va_arg(self, args[0], ret_ty)
} }
// `va_arg` should never be used with the return type f32. // `va_arg` should never be used with the return type f32.

View file

@ -7,7 +7,7 @@ use rustc_middle::bug;
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Ty, TypeVisitable}; use rustc_middle::ty::{self, Ty, TypeVisitable};
use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; use rustc_target::abi::{Abi, Align, FieldsShape};
use rustc_target::abi::{Int, Pointer, F32, F64}; use rustc_target::abi::{Int, Pointer, F32, F64};
use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants}; use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants};
use smallvec::{smallvec, SmallVec}; use smallvec::{smallvec, SmallVec};
@ -312,14 +312,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
Int(i, _) => cx.type_from_integer(i), Int(i, _) => cx.type_from_integer(i),
F32 => cx.type_f32(), F32 => cx.type_f32(),
F64 => cx.type_f64(), F64 => cx.type_f64(),
Pointer => { Pointer(address_space) => {
// If we know the alignment, pick something better than i8. // If we know the alignment, pick something better than i8.
let (pointee, address_space) = let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) {
if let Some(pointee) = self.pointee_info_at(cx, offset) { cx.type_pointee_for_align(pointee.align)
(cx.type_pointee_for_align(pointee.align), pointee.address_space) } else {
} else { cx.type_i8()
(cx.type_i8(), AddressSpace::DATA) };
};
cx.type_ptr_to_ext(pointee, address_space) cx.type_ptr_to_ext(pointee, address_space)
} }
} }

View file

@ -1801,8 +1801,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
match (src.layout.abi, dst.layout.abi) { match (src.layout.abi, dst.layout.abi) {
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => { (abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers. // HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
let src_is_ptr = src_scalar.primitive() == abi::Pointer; let src_is_ptr = matches!(src_scalar.primitive(), abi::Pointer(_));
let dst_is_ptr = dst_scalar.primitive() == abi::Pointer; let dst_is_ptr = matches!(dst_scalar.primitive(), abi::Pointer(_));
if src_is_ptr == dst_is_ptr { if src_is_ptr == dst_is_ptr {
assert_eq!(src.layout.size, dst.layout.size); assert_eq!(src.layout.size, dst.layout.size);

View file

@ -9,7 +9,7 @@ use rustc_middle::mir;
use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding}; use rustc_target::abi::{Abi, Align, FieldsShape, Int, Pointer, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants}; use rustc_target::abi::{VariantIdx, Variants};
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -209,6 +209,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
bx: &mut Bx, bx: &mut Bx,
cast_to: Ty<'tcx>, cast_to: Ty<'tcx>,
) -> V { ) -> V {
let dl = &bx.tcx().data_layout;
let cast_to_layout = bx.cx().layout_of(cast_to); let cast_to_layout = bx.cx().layout_of(cast_to);
let cast_to_size = cast_to_layout.layout.size(); let cast_to_size = cast_to_layout.layout.size();
let cast_to = bx.cx().immediate_backend_type(cast_to_layout); let cast_to = bx.cx().immediate_backend_type(cast_to_layout);
@ -250,12 +251,14 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
// Cast to an integer so we don't have to treat a pointer as a // Cast to an integer so we don't have to treat a pointer as a
// special case. // special case.
let (tag, tag_llty) = if tag_scalar.primitive().is_ptr() { let (tag, tag_llty) = match tag_scalar.primitive() {
let t = bx.type_isize(); // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
let tag = bx.ptrtoint(tag_imm, t); Pointer(_) => {
(tag, t) let t = bx.type_from_integer(dl.ptr_sized_integer());
} else { let tag = bx.ptrtoint(tag_imm, t);
(tag_imm, bx.cx().immediate_backend_type(tag_op.layout)) (tag, t)
}
_ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)),
}; };
let tag_size = tag_scalar.size(bx.cx()); let tag_size = tag_scalar.size(bx.cx());

View file

@ -319,7 +319,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size");
let scalar = alloc.read_scalar( let scalar = alloc.read_scalar(
alloc_range(Size::ZERO, size), alloc_range(Size::ZERO, size),
/*read_provenance*/ s.is_ptr(), /*read_provenance*/ matches!(s, abi::Pointer(_)),
)?; )?;
Some(ImmTy { imm: scalar.into(), layout: mplace.layout }) Some(ImmTy { imm: scalar.into(), layout: mplace.layout })
} }
@ -335,11 +335,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields
let a_val = alloc.read_scalar( let a_val = alloc.read_scalar(
alloc_range(Size::ZERO, a_size), alloc_range(Size::ZERO, a_size),
/*read_provenance*/ a.is_ptr(), /*read_provenance*/ matches!(a, abi::Pointer(_)),
)?; )?;
let b_val = alloc.read_scalar( let b_val = alloc.read_scalar(
alloc_range(b_offset, b_size), alloc_range(b_offset, b_size),
/*read_provenance*/ b.is_ptr(), /*read_provenance*/ matches!(b, abi::Pointer(_)),
)?; )?;
Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout }) Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout })
} }

View file

@ -710,3 +710,24 @@ passes_ignored_derived_impls =
[one] trait {$trait_list}, but this is [one] trait {$trait_list}, but this is
*[other] traits {$trait_list}, but these are *[other] traits {$trait_list}, but these are
} intentionally ignored during dead code analysis } intentionally ignored during dead code analysis
passes_proc_macro_typeerror = mismatched {$kind} signature
.label = found {$found}, expected type `proc_macro::TokenStream`
.note = {$kind}s must have a signature of `{$expected_signature}`
passes_proc_macro_diff_arg_count = mismatched {$kind} signature
.label = found unexpected {$count ->
[one] argument
*[other] arguments
}
.note = {$kind}s must have a signature of `{$expected_signature}`
passes_proc_macro_missing_args = mismatched {$kind} signature
.label = {$kind} must have {$expected_input_count ->
[one] one argument
*[other] two arguments
} of type `proc_macro::TokenStream`
passes_proc_macro_invalid_abi = proc macro functions may not be `extern "{$abi}"`
passes_proc_macro_unsafe = proc macro functions may not be `unsafe`

View file

@ -62,7 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| self.suggest_floating_point_literal(err, expr, expected) || self.suggest_floating_point_literal(err, expr, expected)
|| self.note_result_coercion(err, expr, expected, expr_ty); || self.note_result_coercion(err, expr, expected, expr_ty);
if !suggested { if !suggested {
self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected); self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected, expr.span);
} }
} }
@ -222,6 +222,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr: &hir::Expr<'_>, expr: &hir::Expr<'_>,
found: Ty<'tcx>, found: Ty<'tcx>,
expected: Ty<'tcx>, expected: Ty<'tcx>,
mismatch_span: Span,
) -> bool { ) -> bool {
let map = self.tcx.hir(); let map = self.tcx.hir();
@ -270,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lt_op: |_| self.tcx.lifetimes.re_erased, lt_op: |_| self.tcx.lifetimes.re_erased,
ct_op: |c| c, ct_op: |c| c,
ty_op: |t| match *t.kind() { ty_op: |t| match *t.kind() {
ty::Infer(ty::TyVar(vid)) => self.tcx.mk_ty_infer(ty::TyVar(self.root_var(vid))), ty::Infer(ty::TyVar(_)) => self.tcx.mk_ty_var(ty::TyVid::from_u32(0)),
ty::Infer(ty::IntVar(_)) => { ty::Infer(ty::IntVar(_)) => {
self.tcx.mk_ty_infer(ty::IntVar(ty::IntVid { index: 0 })) self.tcx.mk_ty_infer(ty::IntVar(ty::IntVid { index: 0 }))
} }
@ -281,7 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}, },
}; };
let mut prev = eraser.fold_ty(ty); let mut prev = eraser.fold_ty(ty);
let mut prev_span = None; let mut prev_span: Option<Span> = None;
for binding in expr_finder.uses { for binding in expr_finder.uses {
// In every expression where the binding is referenced, we will look at that // In every expression where the binding is referenced, we will look at that
@ -333,13 +334,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// inferred in this method call. // inferred in this method call.
let arg = &args[i]; let arg = &args[i];
let arg_ty = self.node_ty(arg.hir_id); let arg_ty = self.node_ty(arg.hir_id);
err.span_label( if !arg.span.overlaps(mismatch_span) {
arg.span, err.span_label(
&format!( arg.span,
"this is of type `{arg_ty}`, which causes `{ident}` to be \ &format!(
inferred as `{ty}`", "this is of type `{arg_ty}`, which causes `{ident}` to be \
), inferred as `{ty}`",
); ),
);
}
param_args.insert(param_ty, (arg, arg_ty)); param_args.insert(param_ty, (arg, arg_ty));
} }
} }
@ -382,12 +385,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& self.can_eq(self.param_env, ty, found).is_ok() && self.can_eq(self.param_env, ty, found).is_ok()
{ {
// We only point at the first place where the found type was inferred. // We only point at the first place where the found type was inferred.
if !segment.ident.span.overlaps(mismatch_span) {
err.span_label( err.span_label(
segment.ident.span, segment.ident.span,
with_forced_trimmed_paths!(format!( with_forced_trimmed_paths!(format!(
"here the type of `{ident}` is inferred to be `{ty}`", "here the type of `{ident}` is inferred to be `{ty}`",
)), )),
); );}
break; break;
} else if !param_args.is_empty() { } else if !param_args.is_empty() {
break; break;
@ -406,12 +410,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We use the *previous* span because if the type is known *here* it means // We use the *previous* span because if the type is known *here* it means
// it was *evaluated earlier*. We don't do this for method calls because we // it was *evaluated earlier*. We don't do this for method calls because we
// evaluate the method's self type eagerly, but not in any other case. // evaluate the method's self type eagerly, but not in any other case.
err.span_label( if !span.overlaps(mismatch_span) {
span, err.span_label(
with_forced_trimmed_paths!(format!( span,
"here the type of `{ident}` is inferred to be `{ty}`", with_forced_trimmed_paths!(format!(
)), "here the type of `{ident}` is inferred to be `{ty}`",
); )),
);
}
break; break;
} }
prev = ty; prev = ty;

View file

@ -808,7 +808,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind: TypeVariableOriginKind::MiscVariable, kind: TypeVariableOriginKind::MiscVariable,
span: full_call_span, span: full_call_span,
}); });
self.point_at_expr_source_of_inferred_type(&mut err, rcvr, expected, callee_ty); self.point_at_expr_source_of_inferred_type(
&mut err,
rcvr,
expected,
callee_ty,
provided_arg_span,
);
} }
// Call out where the function is defined // Call out where the function is defined
self.label_fn_like( self.label_fn_like(

View file

@ -38,6 +38,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) { pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
let tcx = self.tcx; let tcx = self.tcx;
let dl = &tcx.data_layout;
let span = tcx.hir().span(hir_id); let span = tcx.hir().span(hir_id);
let normalize = |ty| { let normalize = |ty| {
let ty = self.resolve_vars_if_possible(ty); let ty = self.resolve_vars_if_possible(ty);
@ -69,7 +70,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Special-case transmuting from `typeof(function)` and // Special-case transmuting from `typeof(function)` and
// `Option<typeof(function)>` to present a clearer error. // `Option<typeof(function)>` to present a clearer error.
let from = unpack_option_like(tcx, from); let from = unpack_option_like(tcx, from);
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) { if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) {
struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type") struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
.note(&format!("source type: {from}")) .note(&format!("source type: {from}"))
.note(&format!("target type: {to}")) .note(&format!("target type: {to}"))

View file

@ -110,7 +110,7 @@ use rustc_hir::def_id::DefId;
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_serialize::{Decodable, Encodable}; use rustc_serialize::{Decodable, Encodable};
use rustc_target::abi::Endian; use rustc_target::abi::{AddressSpace, Endian, HasDataLayout};
use crate::mir; use crate::mir;
use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::codec::{TyDecoder, TyEncoder};
@ -438,6 +438,17 @@ impl<'tcx> GlobalAlloc<'tcx> {
_ => bug!("expected vtable, got {:?}", self), _ => bug!("expected vtable, got {:?}", self),
} }
} }
/// The address space that this `GlobalAlloc` should be placed in.
#[inline]
pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace {
match self {
GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => {
AddressSpace::DATA
}
}
}
} }
pub(crate) struct AllocMap<'tcx> { pub(crate) struct AllocMap<'tcx> {

View file

@ -128,7 +128,8 @@ impl PrimitiveExt for Primitive {
Int(i, signed) => i.to_ty(tcx, signed), Int(i, signed) => i.to_ty(tcx, signed),
F32 => tcx.types.f32, F32 => tcx.types.f32,
F64 => tcx.types.f64, F64 => tcx.types.f64,
Pointer => tcx.mk_mut_ptr(tcx.mk_unit()), // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Pointer(_) => tcx.mk_mut_ptr(tcx.mk_unit()),
} }
} }
@ -138,7 +139,11 @@ impl PrimitiveExt for Primitive {
fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match *self { match *self {
Int(i, signed) => i.to_ty(tcx, signed), Int(i, signed) => i.to_ty(tcx, signed),
Pointer => tcx.types.usize, // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
Pointer(_) => {
let signed = false;
tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed)
}
F32 | F64 => bug!("floats do not have an int type"), F32 | F64 => bug!("floats do not have an int type"),
} }
} }
@ -812,132 +817,125 @@ where
let tcx = cx.tcx(); let tcx = cx.tcx();
let param_env = cx.param_env(); let param_env = cx.param_env();
let addr_space_of_ty = |ty: Ty<'tcx>| { let pointee_info =
if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA } match *this.ty.kind() {
}; ty::RawPtr(mt) if offset.bytes() == 0 => {
tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
let pointee_info = match *this.ty.kind() { size: layout.size,
ty::RawPtr(mt) if offset.bytes() == 0 => { align: layout.align.abi,
tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo { safe: None,
size: layout.size, })
align: layout.align.abi,
safe: None,
address_space: addr_space_of_ty(mt.ty),
})
}
ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo {
size: layout.size,
align: layout.align.abi,
safe: None,
address_space: cx.data_layout().instruction_address_space,
})
}
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
let address_space = addr_space_of_ty(ty);
let kind = if tcx.sess.opts.optimize == OptLevel::No {
// Use conservative pointer kind if not optimizing. This saves us the
// Freeze/Unpin queries, and can save time in the codegen backend (noalias
// attributes in LLVM have compile-time cost even in unoptimized builds).
PointerKind::SharedMutable
} else {
match mt {
hir::Mutability::Not => {
if ty.is_freeze(tcx, cx.param_env()) {
PointerKind::Frozen
} else {
PointerKind::SharedMutable
}
}
hir::Mutability::Mut => {
// References to self-referential structures should not be considered
// noalias, as another pointer to the structure can be obtained, that
// is not based-on the original reference. We consider all !Unpin
// types to be potentially self-referential here.
if ty.is_unpin(tcx, cx.param_env()) {
PointerKind::UniqueBorrowed
} else {
PointerKind::UniqueBorrowedPinned
}
}
}
};
tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
size: layout.size,
align: layout.align.abi,
safe: Some(kind),
address_space,
})
}
_ => {
let mut data_variant = match this.variants {
// Within the discriminant field, only the niche itself is
// always initialized, so we only check for a pointer at its
// offset.
//
// If the niche is a pointer, it's either valid (according
// to its type), or null (which the niche field's scalar
// validity range encodes). This allows using
// `dereferenceable_or_null` for e.g., `Option<&T>`, and
// this will continue to work as long as we don't start
// using more niches than just null (e.g., the first page of
// the address space, or unaligned pointers).
Variants::Multiple {
tag_encoding: TagEncoding::Niche { untagged_variant, .. },
tag_field,
..
} if this.fields.offset(tag_field) == offset => {
Some(this.for_variant(cx, untagged_variant))
}
_ => Some(this),
};
if let Some(variant) = data_variant {
// We're not interested in any unions.
if let FieldsShape::Union(_) = variant.fields {
data_variant = None;
}
} }
ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
let mut result = None; tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| {
PointeeInfo { size: layout.size, align: layout.align.abi, safe: None }
if let Some(variant) = data_variant { })
let ptr_end = offset + Pointer.size(cx); }
for i in 0..variant.fields.count() { ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
let field_start = variant.fields.offset(i); let kind = if tcx.sess.opts.optimize == OptLevel::No {
if field_start <= offset { // Use conservative pointer kind if not optimizing. This saves us the
let field = variant.field(cx, i); // Freeze/Unpin queries, and can save time in the codegen backend (noalias
result = field.to_result().ok().and_then(|field| { // attributes in LLVM have compile-time cost even in unoptimized builds).
if ptr_end <= field_start + field.size { PointerKind::SharedMutable
// We found the right field, look inside it. } else {
let field_info = match mt {
field.pointee_info_at(cx, offset - field_start); hir::Mutability::Not => {
field_info if ty.is_freeze(tcx, cx.param_env()) {
PointerKind::Frozen
} else { } else {
None PointerKind::SharedMutable
}
}
hir::Mutability::Mut => {
// References to self-referential structures should not be considered
// noalias, as another pointer to the structure can be obtained, that
// is not based-on the original reference. We consider all !Unpin
// types to be potentially self-referential here.
if ty.is_unpin(tcx, cx.param_env()) {
PointerKind::UniqueBorrowed
} else {
PointerKind::UniqueBorrowedPinned
}
}
}
};
tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
size: layout.size,
align: layout.align.abi,
safe: Some(kind),
})
}
_ => {
let mut data_variant = match this.variants {
// Within the discriminant field, only the niche itself is
// always initialized, so we only check for a pointer at its
// offset.
//
// If the niche is a pointer, it's either valid (according
// to its type), or null (which the niche field's scalar
// validity range encodes). This allows using
// `dereferenceable_or_null` for e.g., `Option<&T>`, and
// this will continue to work as long as we don't start
// using more niches than just null (e.g., the first page of
// the address space, or unaligned pointers).
Variants::Multiple {
tag_encoding: TagEncoding::Niche { untagged_variant, .. },
tag_field,
..
} if this.fields.offset(tag_field) == offset => {
Some(this.for_variant(cx, untagged_variant))
}
_ => Some(this),
};
if let Some(variant) = data_variant {
// We're not interested in any unions.
if let FieldsShape::Union(_) = variant.fields {
data_variant = None;
}
}
let mut result = None;
if let Some(variant) = data_variant {
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
// (requires passing in the expected address space from the caller)
let ptr_end = offset + Pointer(AddressSpace::DATA).size(cx);
for i in 0..variant.fields.count() {
let field_start = variant.fields.offset(i);
if field_start <= offset {
let field = variant.field(cx, i);
result = field.to_result().ok().and_then(|field| {
if ptr_end <= field_start + field.size {
// We found the right field, look inside it.
let field_info =
field.pointee_info_at(cx, offset - field_start);
field_info
} else {
None
}
});
if result.is_some() {
break;
} }
});
if result.is_some() {
break;
} }
} }
} }
}
// FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`. // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
if let Some(ref mut pointee) = result { if let Some(ref mut pointee) = result {
if let ty::Adt(def, _) = this.ty.kind() { if let ty::Adt(def, _) = this.ty.kind() {
if def.is_box() && offset.bytes() == 0 { if def.is_box() && offset.bytes() == 0 {
pointee.safe = Some(PointerKind::UniqueOwned); pointee.safe = Some(PointerKind::UniqueOwned);
}
} }
} }
}
result result
} }
}; };
debug!( debug!(
"pointee_info_at (offset={:?}, type kind: {:?}) => {:?}", "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",

View file

@ -147,6 +147,12 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
ExprKind::AddressOf { mutability, arg } => Ok( ExprKind::AddressOf { mutability, arg } => Ok(
Rvalue::AddressOf(*mutability, self.parse_place(*arg)?) Rvalue::AddressOf(*mutability, self.parse_place(*arg)?)
), ),
ExprKind::Binary { op, lhs, rhs } => Ok(
Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)))
),
ExprKind::Unary { op, arg } => Ok(
Rvalue::UnaryOp(*op, self.parse_operand(*arg)?)
),
_ => self.parse_operand(expr_id).map(Rvalue::Use), _ => self.parse_operand(expr_id).map(Rvalue::Use),
) )
} }

View file

@ -2372,7 +2372,7 @@ impl<'a> Parser<'a> {
/// Some special error handling for the "top-level" patterns in a match arm, /// Some special error handling for the "top-level" patterns in a match arm,
/// `for` loop, `let`, &c. (in contrast to subpatterns within such). /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
pub(crate) fn maybe_recover_colon_colon_in_pat_typo( pub(crate) fn maybe_recover_colon_colon_in_pat_typo_or_anon_enum(
&mut self, &mut self,
mut first_pat: P<Pat>, mut first_pat: P<Pat>,
expected: Expected, expected: Expected,
@ -2383,26 +2383,41 @@ impl<'a> Parser<'a> {
if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
|| !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
{ {
let mut snapshot_type = self.create_snapshot_for_diagnostic();
snapshot_type.bump(); // `:`
match snapshot_type.parse_ty() {
Err(inner_err) => {
inner_err.cancel();
}
Ok(ty) => {
let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else {
return first_pat;
};
err.span_label(ty.span, "specifying the type of a pattern isn't supported");
self.restore_snapshot(snapshot_type);
let span = first_pat.span.to(ty.span);
first_pat = self.mk_pat(span, PatKind::Wild);
err.emit();
}
}
return first_pat; return first_pat;
} }
// The pattern looks like it might be a path with a `::` -> `:` typo: // The pattern looks like it might be a path with a `::` -> `:` typo:
// `match foo { bar:baz => {} }` // `match foo { bar:baz => {} }`
let span = self.token.span; let colon_span = self.token.span;
// We only emit "unexpected `:`" error here if we can successfully parse the // We only emit "unexpected `:`" error here if we can successfully parse the
// whole pattern correctly in that case. // whole pattern correctly in that case.
let snapshot = self.create_snapshot_for_diagnostic(); let mut snapshot_pat = self.create_snapshot_for_diagnostic();
let mut snapshot_type = self.create_snapshot_for_diagnostic();
// Create error for "unexpected `:`". // Create error for "unexpected `:`".
match self.expected_one_of_not_found(&[], &[]) { match self.expected_one_of_not_found(&[], &[]) {
Err(mut err) => { Err(mut err) => {
self.bump(); // Skip the `:`. snapshot_pat.bump(); // Skip the `:`.
match self.parse_pat_no_top_alt(expected) { snapshot_type.bump(); // Skip the `:`.
match snapshot_pat.parse_pat_no_top_alt(expected) {
Err(inner_err) => { Err(inner_err) => {
// Carry on as if we had not done anything, callers will emit a
// reasonable error.
inner_err.cancel(); inner_err.cancel();
err.cancel();
self.restore_snapshot(snapshot);
} }
Ok(mut pat) => { Ok(mut pat) => {
// We've parsed the rest of the pattern. // We've parsed the rest of the pattern.
@ -2466,8 +2481,8 @@ impl<'a> Parser<'a> {
_ => {} _ => {}
} }
if show_sugg { if show_sugg {
err.span_suggestion( err.span_suggestion_verbose(
span, colon_span.until(self.look_ahead(1, |t| t.span)),
"maybe write a path separator here", "maybe write a path separator here",
"::", "::",
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,
@ -2475,13 +2490,24 @@ impl<'a> Parser<'a> {
} else { } else {
first_pat = self.mk_pat(new_span, PatKind::Wild); first_pat = self.mk_pat(new_span, PatKind::Wild);
} }
err.emit(); self.restore_snapshot(snapshot_pat);
} }
} }
match snapshot_type.parse_ty() {
Err(inner_err) => {
inner_err.cancel();
}
Ok(ty) => {
err.span_label(ty.span, "specifying the type of a pattern isn't supported");
self.restore_snapshot(snapshot_type);
let new_span = first_pat.span.to(ty.span);
first_pat = self.mk_pat(new_span, PatKind::Wild);
}
}
err.emit();
} }
_ => { _ => {
// Carry on as if we had not done anything. This should be unreachable. // Carry on as if we had not done anything. This should be unreachable.
self.restore_snapshot(snapshot);
} }
}; };
first_pat first_pat

View file

@ -116,7 +116,8 @@ impl<'a> Parser<'a> {
// Check if the user wrote `foo:bar` instead of `foo::bar`. // Check if the user wrote `foo:bar` instead of `foo::bar`.
if ra == RecoverColon::Yes { if ra == RecoverColon::Yes {
first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected); first_pat =
self.maybe_recover_colon_colon_in_pat_typo_or_anon_enum(first_pat, expected);
} }
if let Some(leading_vert_span) = leading_vert_span { if let Some(leading_vert_span) = leading_vert_span {

View file

@ -11,6 +11,7 @@ use rustc_ast::{
self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
}; };
use rustc_ast_pretty::pprust;
use rustc_errors::{pluralize, struct_span_err, Applicability, PResult}; use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::symbol::{kw, sym, Ident};
@ -43,17 +44,24 @@ pub(super) enum AllowPlus {
No, No,
} }
#[derive(PartialEq)] #[derive(PartialEq, Clone, Copy)]
pub(super) enum RecoverQPath { pub(super) enum RecoverQPath {
Yes, Yes,
No, No,
} }
#[derive(PartialEq, Clone, Copy)]
pub(super) enum RecoverQuestionMark { pub(super) enum RecoverQuestionMark {
Yes, Yes,
No, No,
} }
#[derive(PartialEq, Clone, Copy)]
pub(super) enum RecoverAnonEnum {
Yes,
No,
}
/// Signals whether parsing a type should recover `->`. /// Signals whether parsing a type should recover `->`.
/// ///
/// More specifically, when parsing a function like: /// More specifically, when parsing a function like:
@ -86,7 +94,7 @@ impl RecoverReturnSign {
} }
// Is `...` (`CVarArgs`) legal at this level of type parsing? // Is `...` (`CVarArgs`) legal at this level of type parsing?
#[derive(PartialEq)] #[derive(PartialEq, Clone, Copy)]
enum AllowCVariadic { enum AllowCVariadic {
Yes, Yes,
No, No,
@ -111,6 +119,7 @@ impl<'a> Parser<'a> {
RecoverReturnSign::Yes, RecoverReturnSign::Yes,
None, None,
RecoverQuestionMark::Yes, RecoverQuestionMark::Yes,
RecoverAnonEnum::No,
) )
} }
@ -125,6 +134,7 @@ impl<'a> Parser<'a> {
RecoverReturnSign::Yes, RecoverReturnSign::Yes,
Some(ty_params), Some(ty_params),
RecoverQuestionMark::Yes, RecoverQuestionMark::Yes,
RecoverAnonEnum::No,
) )
} }
@ -139,6 +149,7 @@ impl<'a> Parser<'a> {
RecoverReturnSign::Yes, RecoverReturnSign::Yes,
None, None,
RecoverQuestionMark::Yes, RecoverQuestionMark::Yes,
RecoverAnonEnum::Yes,
) )
} }
@ -156,6 +167,7 @@ impl<'a> Parser<'a> {
RecoverReturnSign::Yes, RecoverReturnSign::Yes,
None, None,
RecoverQuestionMark::Yes, RecoverQuestionMark::Yes,
RecoverAnonEnum::No,
) )
} }
@ -169,6 +181,7 @@ impl<'a> Parser<'a> {
RecoverReturnSign::Yes, RecoverReturnSign::Yes,
None, None,
RecoverQuestionMark::No, RecoverQuestionMark::No,
RecoverAnonEnum::No,
) )
} }
@ -180,6 +193,7 @@ impl<'a> Parser<'a> {
RecoverReturnSign::Yes, RecoverReturnSign::Yes,
None, None,
RecoverQuestionMark::No, RecoverQuestionMark::No,
RecoverAnonEnum::No,
) )
} }
@ -192,6 +206,7 @@ impl<'a> Parser<'a> {
RecoverReturnSign::OnlyFatArrow, RecoverReturnSign::OnlyFatArrow,
None, None,
RecoverQuestionMark::Yes, RecoverQuestionMark::Yes,
RecoverAnonEnum::No,
) )
} }
@ -211,6 +226,7 @@ impl<'a> Parser<'a> {
recover_return_sign, recover_return_sign,
None, None,
RecoverQuestionMark::Yes, RecoverQuestionMark::Yes,
RecoverAnonEnum::Yes,
)?; )?;
FnRetTy::Ty(ty) FnRetTy::Ty(ty)
} else if recover_return_sign.can_recover(&self.token.kind) { } else if recover_return_sign.can_recover(&self.token.kind) {
@ -232,6 +248,7 @@ impl<'a> Parser<'a> {
recover_return_sign, recover_return_sign,
None, None,
RecoverQuestionMark::Yes, RecoverQuestionMark::Yes,
RecoverAnonEnum::Yes,
)?; )?;
FnRetTy::Ty(ty) FnRetTy::Ty(ty)
} else { } else {
@ -247,6 +264,7 @@ impl<'a> Parser<'a> {
recover_return_sign: RecoverReturnSign, recover_return_sign: RecoverReturnSign,
ty_generics: Option<&Generics>, ty_generics: Option<&Generics>,
recover_question_mark: RecoverQuestionMark, recover_question_mark: RecoverQuestionMark,
recover_anon_enum: RecoverAnonEnum,
) -> PResult<'a, P<Ty>> { ) -> PResult<'a, P<Ty>> {
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes; let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery); maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
@ -325,14 +343,55 @@ impl<'a> Parser<'a> {
let mut ty = self.mk_ty(span, kind); let mut ty = self.mk_ty(span, kind);
// Try to recover from use of `+` with incorrect priority. // Try to recover from use of `+` with incorrect priority.
if matches!(allow_plus, AllowPlus::Yes) { if allow_plus == AllowPlus::Yes {
self.maybe_recover_from_bad_type_plus(&ty)?; self.maybe_recover_from_bad_type_plus(&ty)?;
} else { } else {
self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty); self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty);
} }
if let RecoverQuestionMark::Yes = recover_question_mark { if RecoverQuestionMark::Yes == recover_question_mark {
ty = self.maybe_recover_from_question_mark(ty); ty = self.maybe_recover_from_question_mark(ty);
} }
if recover_anon_enum == RecoverAnonEnum::Yes
&& self.check_noexpect(&token::BinOp(token::Or))
&& self.look_ahead(1, |t| t.can_begin_type())
{
let mut pipes = vec![self.token.span];
let mut types = vec![ty];
loop {
if !self.eat(&token::BinOp(token::Or)) {
break;
}
pipes.push(self.prev_token.span);
types.push(self.parse_ty_common(
allow_plus,
allow_c_variadic,
recover_qpath,
recover_return_sign,
ty_generics,
recover_question_mark,
RecoverAnonEnum::No,
)?);
}
let mut err = self.struct_span_err(pipes, "anonymous enums are not supported");
for ty in &types {
err.span_label(ty.span, "");
}
err.help(&format!(
"create a named `enum` and use it here instead:\nenum Name {{\n{}\n}}",
types
.iter()
.enumerate()
.map(|(i, t)| format!(
" Variant{}({}),",
i + 1, // Lets not confuse people with zero-indexing :)
pprust::to_string(|s| s.print_type(&t)),
))
.collect::<Vec<_>>()
.join("\n"),
));
err.emit();
return Ok(self.mk_ty(lo.to(self.prev_token.span), TyKind::Err));
}
if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) } if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
} }

View file

@ -6,11 +6,12 @@
use crate::errors::{ use crate::errors::{
self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr, self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr,
OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint, OnlyHasEffectOn, ProcMacroDiffArguments, ProcMacroInvalidAbi, ProcMacroMissingArguments,
ProcMacroTypeError, ProcMacroUnsafe, TransparentIncompatible, UnrecognizedReprHint,
}; };
use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{fluent, Applicability, MultiSpan}; use rustc_errors::{fluent, Applicability, IntoDiagnosticArg, MultiSpan};
use rustc_expand::base::resolve_path; use rustc_expand::base::resolve_path;
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir; use rustc_hir as hir;
@ -19,11 +20,12 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{ use rustc_hir::{
self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID, self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
}; };
use rustc_hir::{MethodKind, Target}; use rustc_hir::{MethodKind, Target, Unsafety};
use rustc_middle::hir::nested_filter; use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault; use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{ParamEnv, TyCtxt};
use rustc_session::lint::builtin::{ use rustc_session::lint::builtin::{
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES, CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES,
}; };
@ -31,6 +33,7 @@ use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use std::cell::Cell;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
pub(crate) fn target_from_impl_item<'tcx>( pub(crate) fn target_from_impl_item<'tcx>(
@ -62,8 +65,29 @@ enum ItemLike<'tcx> {
ForeignItem, ForeignItem,
} }
#[derive(Copy, Clone)]
pub(crate) enum ProcMacroKind {
FunctionLike,
Derive,
Attribute,
}
impl IntoDiagnosticArg for ProcMacroKind {
fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
match self {
ProcMacroKind::Attribute => "attribute proc macro",
ProcMacroKind::Derive => "derive proc macro",
ProcMacroKind::FunctionLike => "function-like proc macro",
}
.into_diagnostic_arg()
}
}
struct CheckAttrVisitor<'tcx> { struct CheckAttrVisitor<'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
// Whether or not this visitor should abort after finding errors
abort: Cell<bool>,
} }
impl CheckAttrVisitor<'_> { impl CheckAttrVisitor<'_> {
@ -173,7 +197,7 @@ impl CheckAttrVisitor<'_> {
sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod), sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod),
sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target), sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
sym::macro_export => self.check_macro_export(hir_id, attr, target), sym::macro_export => self.check_macro_export(hir_id, attr, target),
sym::ignore | sym::should_panic | sym::proc_macro_derive => { sym::ignore | sym::should_panic => {
self.check_generic_attr(hir_id, attr, target, Target::Fn) self.check_generic_attr(hir_id, attr, target, Target::Fn)
} }
sym::automatically_derived => { sym::automatically_derived => {
@ -183,6 +207,16 @@ impl CheckAttrVisitor<'_> {
self.check_generic_attr(hir_id, attr, target, Target::Mod) self.check_generic_attr(hir_id, attr, target, Target::Mod)
} }
sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id), sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id),
sym::proc_macro => {
self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
}
sym::proc_macro_attribute => {
self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
}
sym::proc_macro_derive => {
self.check_generic_attr(hir_id, attr, target, Target::Fn);
self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
}
_ => {} _ => {}
} }
@ -2063,6 +2097,103 @@ impl CheckAttrVisitor<'_> {
errors::Unused { attr_span: attr.span, note }, errors::Unused { attr_span: attr.span, note },
); );
} }
/// A best effort attempt to create an error for a mismatching proc macro signature.
///
/// If this best effort goes wrong, it will just emit a worse error later (see #102923)
fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
let expected_input_count = match kind {
ProcMacroKind::Attribute => 2,
ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1,
};
let expected_signature = match kind {
ProcMacroKind::Attribute => "fn(TokenStream, TokenStream) -> TokenStream",
ProcMacroKind::Derive | ProcMacroKind::FunctionLike => "fn(TokenStream) -> TokenStream",
};
let tcx = self.tcx;
if target == Target::Fn {
let Some(tokenstream) = tcx.get_diagnostic_item(sym::TokenStream) else {return};
let tokenstream = tcx.type_of(tokenstream);
let id = hir_id.expect_owner();
let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id).unwrap();
let sig = tcx.liberate_late_bound_regions(id.to_def_id(), tcx.fn_sig(id));
let sig = tcx.normalize_erasing_regions(ParamEnv::empty(), sig);
// We don't currently require that the function signature is equal to
// `fn(TokenStream) -> TokenStream`, but instead monomorphizes to
// `fn(TokenStream) -> TokenStream` after some substitution of generic arguments.
//
// Properly checking this means pulling in additional `rustc` crates, so we don't.
let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer };
if sig.abi != Abi::Rust {
tcx.sess.emit_err(ProcMacroInvalidAbi { span: hir_sig.span, abi: sig.abi.name() });
self.abort.set(true);
}
if sig.unsafety == Unsafety::Unsafe {
tcx.sess.emit_err(ProcMacroUnsafe { span: hir_sig.span });
self.abort.set(true);
}
let output = sig.output();
// Typecheck the output
if !drcx.types_may_unify(output, tokenstream) {
tcx.sess.emit_err(ProcMacroTypeError {
span: hir_sig.decl.output.span(),
found: output,
kind,
expected_signature,
});
self.abort.set(true);
}
if sig.inputs().len() < expected_input_count {
tcx.sess.emit_err(ProcMacroMissingArguments {
expected_input_count,
span: hir_sig.span,
kind,
expected_signature,
});
self.abort.set(true);
}
// Check that the inputs are correct, if there are enough.
if sig.inputs().len() >= expected_input_count {
for (arg, input) in
sig.inputs().iter().zip(hir_sig.decl.inputs).take(expected_input_count)
{
if !drcx.types_may_unify(*arg, tokenstream) {
tcx.sess.emit_err(ProcMacroTypeError {
span: input.span,
found: *arg,
kind,
expected_signature,
});
self.abort.set(true);
}
}
}
// Check that there are not too many arguments
let body_id = tcx.hir().body_owned_by(id.def_id);
let excess = tcx.hir().body(body_id).params.get(expected_input_count..);
if let Some(excess @ [begin @ end] | excess @ [begin, .., end]) = excess {
tcx.sess.emit_err(ProcMacroDiffArguments {
span: begin.span.to(end.span),
count: excess.len(),
kind,
expected_signature,
});
self.abort.set(true);
}
}
}
} }
impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
@ -2225,12 +2356,15 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
} }
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
let check_attr_visitor = &mut CheckAttrVisitor { tcx }; let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) };
tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor); tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor);
if module_def_id.is_top_level_module() { if module_def_id.is_top_level_module() {
check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None); check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs()); check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
} }
if check_attr_visitor.abort.get() {
tcx.sess.abort_if_errors()
}
} }
pub(crate) fn provide(providers: &mut Providers) { pub(crate) fn provide(providers: &mut Providers) {

View file

@ -12,6 +12,7 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{MainDefinition, Ty}; use rustc_middle::ty::{MainDefinition, Ty};
use rustc_span::{Span, Symbol, DUMMY_SP}; use rustc_span::{Span, Symbol, DUMMY_SP};
use crate::check_attr::ProcMacroKind;
use crate::lang_items::Duplicate; use crate::lang_items::Duplicate;
#[derive(Diagnostic)] #[derive(Diagnostic)]
@ -1515,3 +1516,52 @@ pub struct ChangeFieldsToBeOfUnitType {
#[suggestion_part(code = "()")] #[suggestion_part(code = "()")]
pub spans: Vec<Span>, pub spans: Vec<Span>,
} }
#[derive(Diagnostic)]
#[diag(passes_proc_macro_typeerror)]
#[note]
pub(crate) struct ProcMacroTypeError<'tcx> {
#[primary_span]
#[label]
pub span: Span,
pub found: Ty<'tcx>,
pub kind: ProcMacroKind,
pub expected_signature: &'static str,
}
#[derive(Diagnostic)]
#[diag(passes_proc_macro_diff_arg_count)]
pub(crate) struct ProcMacroDiffArguments {
#[primary_span]
#[label]
pub span: Span,
pub count: usize,
pub kind: ProcMacroKind,
pub expected_signature: &'static str,
}
#[derive(Diagnostic)]
#[diag(passes_proc_macro_missing_args)]
pub(crate) struct ProcMacroMissingArguments {
#[primary_span]
#[label]
pub span: Span,
pub expected_input_count: usize,
pub kind: ProcMacroKind,
pub expected_signature: &'static str,
}
#[derive(Diagnostic)]
#[diag(passes_proc_macro_invalid_abi)]
pub(crate) struct ProcMacroInvalidAbi {
#[primary_span]
pub span: Span,
pub abi: &'static str,
}
#[derive(Diagnostic)]
#[diag(passes_proc_macro_unsafe)]
pub(crate) struct ProcMacroUnsafe {
#[primary_span]
pub span: Span,
}

View file

@ -227,20 +227,27 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
&& let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt() && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
&& let Some(items) = self.diagnostic_metadata.current_impl_items && let Some(items) = self.diagnostic_metadata.current_impl_items
&& let Some(item) = items.iter().find(|i| { && let Some(item) = items.iter().find(|i| {
if let AssocItemKind::Fn(_) = &i.kind && i.ident.name == item_str.name if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind
&& i.ident.name == item_str.name
{ {
debug!(?item_str.name); debug!(?item_str.name);
return true return true
} }
false false
}) })
&& let AssocItemKind::Fn(fn_) = &item.kind
{ {
debug!(?fn_); let self_sugg = match &item.kind {
let self_sugg = if fn_.sig.decl.has_self() { "self." } else { "Self::" }; AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => "self.",
_ => "Self::",
};
Some(( Some((
item_span.shrink_to_lo(), item_span.shrink_to_lo(),
"consider using the associated function", match &item.kind {
AssocItemKind::Fn(..) => "consider using the associated function",
AssocItemKind::Const(..) => "consider using the associated constant",
_ => unreachable!("item kind was filtered above"),
},
self_sugg.to_string() self_sugg.to_string()
)) ))
} else { } else {

View file

@ -288,6 +288,7 @@ symbols! {
Target, Target,
ToOwned, ToOwned,
ToString, ToString,
TokenStream,
Try, Try,
TryCaptureGeneric, TryCaptureGeneric,
TryCapturePrintable, TryCapturePrintable,

View file

@ -39,7 +39,7 @@ where
{ {
match arg_layout.abi { match arg_layout.abi {
Abi::Scalar(scalar) => match scalar.primitive() { Abi::Scalar(scalar) => match scalar.primitive() {
abi::Int(..) | abi::Pointer => { abi::Int(..) | abi::Pointer(_) => {
if arg_layout.size.bits() > xlen { if arg_layout.size.bits() > xlen {
return Err(CannotUseFpConv); return Err(CannotUseFpConv);
} }

View file

@ -346,7 +346,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
// The primitive for this algorithm. // The primitive for this algorithm.
Abi::Scalar(scalar) => { Abi::Scalar(scalar) => {
let kind = match scalar.primitive() { let kind = match scalar.primitive() {
abi::Int(..) | abi::Pointer => RegKind::Integer, abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
abi::F32 | abi::F64 => RegKind::Float, abi::F32 | abi::F64 => RegKind::Float,
}; };
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))

View file

@ -45,7 +45,7 @@ where
{ {
match arg_layout.abi { match arg_layout.abi {
Abi::Scalar(scalar) => match scalar.primitive() { Abi::Scalar(scalar) => match scalar.primitive() {
abi::Int(..) | abi::Pointer => { abi::Int(..) | abi::Pointer(_) => {
if arg_layout.size.bits() > xlen { if arg_layout.size.bits() > xlen {
return Err(CannotUseFpConv); return Err(CannotUseFpConv);
} }

View file

@ -20,7 +20,7 @@ where
{ {
let dl = cx.data_layout(); let dl = cx.data_layout();
if !scalar.primitive().is_float() { if !matches!(scalar.primitive(), abi::F32 | abi::F64) {
return data; return data;
} }
@ -83,11 +83,11 @@ where
(abi::F32, _) => offset += Reg::f32().size, (abi::F32, _) => offset += Reg::f32().size,
(_, abi::F64) => offset += Reg::f64().size, (_, abi::F64) => offset += Reg::f64().size,
(abi::Int(i, _signed), _) => offset += i.size(), (abi::Int(i, _signed), _) => offset += i.size(),
(abi::Pointer, _) => offset += Reg::i64().size, (abi::Pointer(_), _) => offset += Reg::i64().size,
_ => {} _ => {}
} }
if (offset.bytes() % 4) != 0 && scalar2.primitive().is_float() { if (offset.bytes() % 4) != 0 && matches!(scalar2.primitive(), abi::F32 | abi::F64) {
offset += Size::from_bytes(4 - (offset.bytes() % 4)); offset += Size::from_bytes(4 - (offset.bytes() % 4));
} }
data = arg_scalar(cx, scalar2, offset, data); data = arg_scalar(cx, scalar2, offset, data);

View file

@ -50,7 +50,7 @@ where
Abi::Uninhabited => return Ok(()), Abi::Uninhabited => return Ok(()),
Abi::Scalar(scalar) => match scalar.primitive() { Abi::Scalar(scalar) => match scalar.primitive() {
abi::Int(..) | abi::Pointer => Class::Int, abi::Int(..) | abi::Pointer(_) => Class::Int,
abi::F32 | abi::F64 => Class::Sse, abi::F32 | abi::F64 => Class::Sse,
}, },

View file

@ -129,7 +129,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
C: HasDataLayout, C: HasDataLayout,
{ {
match self.abi { match self.abi {
Abi::Scalar(scalar) => scalar.primitive().is_float(), Abi::Scalar(scalar) => matches!(scalar.primitive(), F32 | F64),
Abi::Aggregate { .. } => { Abi::Aggregate { .. } => {
if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
self.field(cx, 0).is_single_fp_element(cx) self.field(cx, 0).is_single_fp_element(cx)

View file

@ -138,6 +138,16 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
ecx: &mut EvalCtxt<'_, 'tcx>, ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>, goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>; ) -> QueryResult<'tcx>;
fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
fn consider_builtin_generator_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
} }
impl<'tcx> EvalCtxt<'_, 'tcx> { impl<'tcx> EvalCtxt<'_, 'tcx> {
@ -266,6 +276,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
G::consider_builtin_tuple_candidate(self, goal) G::consider_builtin_tuple_candidate(self, goal)
} else if lang_items.pointee_trait() == Some(trait_def_id) { } else if lang_items.pointee_trait() == Some(trait_def_id) {
G::consider_builtin_pointee_candidate(self, goal) G::consider_builtin_pointee_candidate(self, goal)
} else if lang_items.future_trait() == Some(trait_def_id) {
G::consider_builtin_future_candidate(self, goal)
} else if lang_items.gen_trait() == Some(trait_def_id) {
G::consider_builtin_generator_candidate(self, goal)
} else { } else {
Err(NoSolution) Err(NoSolution)
}; };
@ -321,9 +335,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::Tuple(_) | ty::Tuple(_)
| ty::Param(_) | ty::Param(_)
| ty::Placeholder(..) | ty::Placeholder(..)
| ty::Infer(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Error(_) => return, | ty::Error(_) => return,
ty::Bound(..) => bug!("unexpected bound type: {goal:?}"), ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
ty::Alias(_, alias_ty) => alias_ty, ty::Alias(_, alias_ty) => alias_ty,
}; };
@ -371,9 +386,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::Tuple(_) | ty::Tuple(_)
| ty::Param(_) | ty::Param(_)
| ty::Placeholder(..) | ty::Placeholder(..)
| ty::Infer(_) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Error(_) => return, | ty::Error(_) => return,
ty::Bound(..) => bug!("unexpected bound type: {goal:?}"), ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
ty::Dynamic(bounds, ..) => bounds, ty::Dynamic(bounds, ..) => bounds,
}; };

View file

@ -1,13 +1,14 @@
use std::mem; use std::mem;
use super::{Certainty, InferCtxtEvalExt}; use rustc_infer::infer::InferCtxt;
use rustc_infer::{ use rustc_infer::traits::{
infer::InferCtxt, query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
traits::{ PredicateObligation, SelectionError, TraitEngine,
query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
SelectionError, TraitEngine,
},
}; };
use rustc_middle::ty;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use super::{Certainty, InferCtxtEvalExt};
/// A trait engine using the new trait solver. /// A trait engine using the new trait solver.
/// ///
@ -70,9 +71,55 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
Err(NoSolution) => { Err(NoSolution) => {
errors.push(FulfillmentError { errors.push(FulfillmentError {
obligation: obligation.clone(), obligation: obligation.clone(),
code: FulfillmentErrorCode::CodeSelectionError( code: match goal.predicate.kind().skip_binder() {
SelectionError::Unimplemented, ty::PredicateKind::Clause(ty::Clause::Projection(_)) => {
), FulfillmentErrorCode::CodeProjectionError(
// FIXME: This could be a `Sorts` if the term is a type
MismatchedProjectionTypes { err: TypeError::Mismatch },
)
}
ty::PredicateKind::Subtype(pred) => {
let (a, b) = infcx.replace_bound_vars_with_placeholders(
goal.predicate.kind().rebind((pred.a, pred.b)),
);
let expected_found = ExpectedFound::new(true, a, b);
FulfillmentErrorCode::CodeSubtypeError(
expected_found,
TypeError::Sorts(expected_found),
)
}
ty::PredicateKind::Coerce(pred) => {
let (a, b) = infcx.replace_bound_vars_with_placeholders(
goal.predicate.kind().rebind((pred.a, pred.b)),
);
let expected_found = ExpectedFound::new(false, a, b);
FulfillmentErrorCode::CodeSubtypeError(
expected_found,
TypeError::Sorts(expected_found),
)
}
ty::PredicateKind::ConstEquate(a, b) => {
let (a, b) = infcx.replace_bound_vars_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(_)
| ty::PredicateKind::ClosureKind(_, _, _)
| ty::PredicateKind::ConstEvaluatable(_)
| ty::PredicateKind::TypeWellFormedFromEnv(_)
| ty::PredicateKind::Ambiguous => {
FulfillmentErrorCode::CodeSelectionError(
SelectionError::Unimplemented,
)
}
},
root_obligation: obligation, root_obligation: obligation,
}); });
continue; continue;

View file

@ -277,12 +277,15 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
param_env, param_env,
predicate: (def_id, substs, kind), predicate: (def_id, substs, kind),
}), }),
ty::PredicateKind::ObjectSafe(trait_def_id) => {
self.compute_object_safe_goal(trait_def_id)
}
ty::PredicateKind::WellFormed(arg) => {
self.compute_well_formed_goal(Goal { param_env, predicate: arg })
}
ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS), ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS),
// FIXME: implement these predicates :) // FIXME: implement these predicates :)
ty::PredicateKind::WellFormed(_) ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => {
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::ConstEvaluatable(_)
| ty::PredicateKind::ConstEquate(_, _) => {
self.make_canonical_response(Certainty::Yes) self.make_canonical_response(Certainty::Yes)
} }
ty::PredicateKind::TypeWellFormedFromEnv(..) => { ty::PredicateKind::TypeWellFormedFromEnv(..) => {
@ -362,6 +365,32 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
Err(NoSolution) Err(NoSolution)
} }
} }
fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> {
if self.tcx().is_object_safe(trait_def_id) {
self.make_canonical_response(Certainty::Yes)
} else {
Err(NoSolution)
}
}
fn compute_well_formed_goal(
&mut self,
goal: Goal<'tcx, ty::GenericArg<'tcx>>,
) -> QueryResult<'tcx> {
self.infcx.probe(|_| {
match crate::traits::wf::unnormalized_obligations(
self.infcx,
goal.param_env,
goal.predicate,
) {
Some(obligations) => self.evaluate_all_and_make_canonical_response(
obligations.into_iter().map(|o| o.into()).collect(),
),
None => self.make_canonical_response(Certainty::AMBIGUOUS),
}
})
}
} }
impl<'tcx> EvalCtxt<'_, 'tcx> { impl<'tcx> EvalCtxt<'_, 'tcx> {

View file

@ -16,7 +16,7 @@ use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ProjectionPredicate, TypeSuperVisitable, TypeVisitor}; use rustc_middle::ty::{ProjectionPredicate, TypeSuperVisitable, TypeVisitor};
use rustc_middle::ty::{ToPredicate, TypeVisitable}; use rustc_middle::ty::{ToPredicate, TypeVisitable};
use rustc_span::DUMMY_SP; use rustc_span::{sym, DUMMY_SP};
use std::iter; use std::iter;
use std::ops::ControlFlow; use std::ops::ControlFlow;
@ -427,7 +427,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
.subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())]) .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
} }
ty::Infer(ty::TyVar(..)) | ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
// FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints. // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
let sized_predicate = ty::Binder::dummy(tcx.at(DUMMY_SP).mk_trait_ref( let sized_predicate = ty::Binder::dummy(tcx.at(DUMMY_SP).mk_trait_ref(
LangItem::Sized, LangItem::Sized,
@ -470,7 +470,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
} }
}, },
ty::Infer(ty::FreshTy(..) | ty::FreshIntTy(..) | ty::FreshFloatTy(..)) ty::Infer(
ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
)
| ty::Bound(..) => bug!( | ty::Bound(..) => bug!(
"unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`", "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
goal.predicate.self_ty() goal.predicate.self_ty()
@ -482,6 +484,73 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
ecx.evaluate_all_and_make_canonical_response(nested_goals) ecx.evaluate_all_and_make_canonical_response(nested_goals)
}) })
} }
fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
let self_ty = goal.predicate.self_ty();
let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
return Err(NoSolution);
};
// Generators are not futures unless they come from `async` desugaring
let tcx = ecx.tcx();
if !tcx.generator_is_async(def_id) {
return Err(NoSolution);
}
let term = substs.as_generator().return_ty().into();
Self::consider_assumption(
ecx,
goal,
ty::Binder::dummy(ty::ProjectionPredicate {
projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]),
term,
})
.to_predicate(tcx),
)
}
fn consider_builtin_generator_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
let self_ty = goal.predicate.self_ty();
let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
return Err(NoSolution);
};
// `async`-desugared generators do not implement the generator trait
let tcx = ecx.tcx();
if tcx.generator_is_async(def_id) {
return Err(NoSolution);
}
let generator = substs.as_generator();
let name = tcx.associated_item(goal.predicate.def_id()).name;
let term = if name == sym::Return {
generator.return_ty().into()
} else if name == sym::Yield {
generator.yield_ty().into()
} else {
bug!("unexpected associated item `<{self_ty} as Generator>::{name}`")
};
Self::consider_assumption(
ecx,
goal,
ty::Binder::dummy(ty::ProjectionPredicate {
projection_ty: ecx
.tcx()
.mk_alias_ty(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
term,
})
.to_predicate(tcx),
)
}
} }
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.

View file

@ -192,6 +192,50 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
) -> QueryResult<'tcx> { ) -> QueryResult<'tcx> {
ecx.make_canonical_response(Certainty::Yes) ecx.make_canonical_response(Certainty::Yes)
} }
fn consider_builtin_future_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else {
return Err(NoSolution);
};
// Generators are not futures unless they come from `async` desugaring
let tcx = ecx.tcx();
if !tcx.generator_is_async(def_id) {
return Err(NoSolution);
}
// Async generator unconditionally implement `Future`
ecx.make_canonical_response(Certainty::Yes)
}
fn consider_builtin_generator_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
let self_ty = goal.predicate.self_ty();
let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
return Err(NoSolution);
};
// `async`-desugared generators do not implement the generator trait
let tcx = ecx.tcx();
if tcx.generator_is_async(def_id) {
return Err(NoSolution);
}
let generator = substs.as_generator();
Self::consider_assumption(
ecx,
goal,
ty::Binder::dummy(
tcx.mk_trait_ref(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
)
.to_predicate(tcx),
)
}
} }
impl<'tcx> EvalCtxt<'_, 'tcx> { impl<'tcx> EvalCtxt<'_, 'tcx> {

View file

@ -24,15 +24,16 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
| ty::Never | ty::Never
| ty::Char => Ok(vec![]), | ty::Char => Ok(vec![]),
ty::Placeholder(..) ty::Dynamic(..)
| ty::Dynamic(..)
| ty::Param(..) | ty::Param(..)
| ty::Foreign(..) | ty::Foreign(..)
| ty::Alias(ty::Projection, ..) | ty::Alias(ty::Projection, ..)
| ty::Bound(..) | ty::Placeholder(..) => Err(NoSolution),
| ty::Infer(ty::TyVar(_)) => Err(NoSolution),
ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), ty::Bound(..)
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("unexpected type `{ty}`")
}
ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
Ok(vec![element_ty]) Ok(vec![element_ty])
@ -99,11 +100,12 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
| ty::Foreign(..) | ty::Foreign(..)
| ty::Alias(..) | ty::Alias(..)
| ty::Param(_) | ty::Param(_)
| ty::Infer(ty::TyVar(_)) => Err(NoSolution), | ty::Placeholder(..) => Err(NoSolution),
ty::Placeholder(..) ty::Bound(..)
| ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), bug!("unexpected type `{ty}`")
}
ty::Tuple(tys) => Ok(tys.to_vec()), ty::Tuple(tys) => Ok(tys.to_vec()),
@ -148,11 +150,12 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
| ty::Adt(_, _) | ty::Adt(_, _)
| ty::Alias(_, _) | ty::Alias(_, _)
| ty::Param(_) | ty::Param(_)
| ty::Infer(ty::TyVar(_)) => Err(NoSolution), | ty::Placeholder(..) => Err(NoSolution),
ty::Placeholder(..) ty::Bound(..)
| ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(), bug!("unexpected type `{ty}`")
}
ty::Tuple(tys) => Ok(tys.to_vec()), ty::Tuple(tys) => Ok(tys.to_vec()),
@ -173,6 +176,7 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
} }
} }
// Returns a binder of the tupled inputs types and output type from a builtin callable type.
pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>( pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
@ -215,9 +219,13 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
| ty::Tuple(_) | ty::Tuple(_)
| ty::Alias(_, _) | ty::Alias(_, _)
| ty::Param(_) | ty::Param(_)
| ty::Placeholder(_) | ty::Placeholder(..)
| ty::Bound(_, _) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Infer(_)
| ty::Error(_) => Err(NoSolution), | ty::Error(_) => Err(NoSolution),
ty::Bound(..)
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("unexpected type `{self_ty}`")
}
} }
} }

View file

@ -4,8 +4,8 @@ use rustc_hir as hir;
use rustc_hir::lang_items::LangItem; use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_span::Span; use rustc_span::{Span, DUMMY_SP};
use std::iter; use std::iter;
/// Returns the set of obligations needed to make `arg` well-formed. /// Returns the set of obligations needed to make `arg` well-formed.
@ -75,6 +75,34 @@ pub fn obligations<'tcx>(
Some(result) Some(result)
} }
/// Compute the predicates that are required for a type to be well-formed.
///
/// This is only intended to be used in the new solver, since it does not
/// take into account recursion depth or proper error-reporting spans.
pub fn unnormalized_obligations<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
arg: GenericArg<'tcx>,
) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
if let ty::GenericArgKind::Lifetime(..) = arg.unpack() {
return Some(vec![]);
}
debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
let mut wf = WfPredicates {
tcx: infcx.tcx,
param_env,
body_id: CRATE_DEF_ID,
span: DUMMY_SP,
out: vec![],
recursion_depth: 0,
item: None,
};
wf.compute(arg);
Some(wf.out)
}
/// Returns the obligations that make this trait reference /// Returns the obligations that make this trait reference
/// well-formed. For example, if there is a trait `Set` defined like /// well-formed. For example, if there is a trait `Set` defined like
/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF /// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF

View file

@ -244,7 +244,7 @@ fn adjust_for_rust_scalar<'tcx>(
} }
// Only pointer types handled below. // Only pointer types handled below.
let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return }; let Scalar::Initialized { value: Pointer(_), valid_range} = scalar else { return };
if !valid_range.contains(0) { if !valid_range.contains(0) {
attrs.set(ArgAttribute::NonNull); attrs.set(ArgAttribute::NonNull);
@ -479,7 +479,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
} }
let size = arg.layout.size; let size = arg.layout.size;
if arg.layout.is_unsized() || size > Pointer.size(cx) { if arg.layout.is_unsized() || size > Pointer(AddressSpace::DATA).size(cx) {
arg.make_indirect(); arg.make_indirect();
} else { } else {
// We want to pass small aggregates as immediates, but using // We want to pass small aggregates as immediates, but using

View file

@ -134,7 +134,7 @@ fn layout_of_uncached<'tcx>(
ty::FloatTy::F64 => F64, ty::FloatTy::F64 => F64,
}), }),
ty::FnPtr(_) => { ty::FnPtr(_) => {
let mut ptr = scalar_unit(Pointer); let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
ptr.valid_range_mut().start = 1; ptr.valid_range_mut().start = 1;
tcx.intern_layout(LayoutS::scalar(cx, ptr)) tcx.intern_layout(LayoutS::scalar(cx, ptr))
} }
@ -144,7 +144,7 @@ fn layout_of_uncached<'tcx>(
// Potentially-wide pointers. // Potentially-wide pointers.
ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
let mut data_ptr = scalar_unit(Pointer); let mut data_ptr = scalar_unit(Pointer(AddressSpace::DATA));
if !ty.is_unsafe_ptr() { if !ty.is_unsafe_ptr() {
data_ptr.valid_range_mut().start = 1; data_ptr.valid_range_mut().start = 1;
} }
@ -178,7 +178,7 @@ fn layout_of_uncached<'tcx>(
} }
ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)), ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
ty::Dynamic(..) => { ty::Dynamic(..) => {
let mut vtable = scalar_unit(Pointer); let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
vtable.valid_range_mut().start = 1; vtable.valid_range_mut().start = 1;
vtable vtable
} }
@ -195,7 +195,7 @@ fn layout_of_uncached<'tcx>(
ty::Dynamic(_, _, ty::DynStar) => { ty::Dynamic(_, _, ty::DynStar) => {
let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false)); let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false));
data.valid_range_mut().start = 0; data.valid_range_mut().start = 0;
let mut vtable = scalar_unit(Pointer); let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
vtable.valid_range_mut().start = 1; vtable.valid_range_mut().start = 1;
tcx.intern_layout(cx.scalar_pair(data, vtable)) tcx.intern_layout(cx.scalar_pair(data, vtable))
} }

View file

@ -74,6 +74,7 @@ pub fn is_available() -> bool {
/// ///
/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` /// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]`
/// and `#[proc_macro_derive]` definitions. /// and `#[proc_macro_derive]` definitions.
#[rustc_diagnostic_item = "TokenStream"]
#[stable(feature = "proc_macro_lib", since = "1.15.0")] #[stable(feature = "proc_macro_lib", since = "1.15.0")]
#[derive(Clone)] #[derive(Clone)]
pub struct TokenStream(Option<bridge::client::TokenStream>); pub struct TokenStream(Option<bridge::client::TokenStream>);

View file

@ -16,12 +16,17 @@ fn main() {
let mut build_lock; let mut build_lock;
let _build_lock_guard; let _build_lock_guard;
if cfg!(any(unix, windows)) { if cfg!(any(unix, windows)) {
build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(config.out.join("lock")))); let path = config.out.join("lock");
build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(&path)));
_build_lock_guard = match build_lock.try_write() { _build_lock_guard = match build_lock.try_write() {
Ok(lock) => lock, Ok(lock) => lock,
err => { err => {
println!("warning: build directory locked, waiting for lock");
drop(err); drop(err);
if let Some(pid) = get_lock_owner(&path) {
println!("warning: build directory locked by process {pid}, waiting for lock");
} else {
println!("warning: build directory locked, waiting for lock");
}
t!(build_lock.write()) t!(build_lock.write())
} }
}; };
@ -98,3 +103,30 @@ fn check_version(config: &Config) -> Option<String> {
Some(msg) Some(msg)
} }
/// Get the PID of the process which took the write lock by
/// parsing `/proc/locks`.
#[cfg(target_os = "linux")]
fn get_lock_owner(f: &std::path::Path) -> Option<u64> {
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::os::unix::fs::MetadataExt;
let lock_inode = std::fs::metadata(f).ok()?.ino();
let lockfile = File::open("/proc/locks").ok()?;
BufReader::new(lockfile).lines().find_map(|line| {
// pid--vvvvvv vvvvvvv--- inode
// 21: FLOCK ADVISORY WRITE 359238 08:02:3719774 0 EOF
let line = line.ok()?;
let parts = line.split_whitespace().collect::<Vec<_>>();
let (pid, inode) = (parts[4].parse::<u64>().ok()?, &parts[5]);
let inode = inode.rsplit_once(':')?.1.parse::<u64>().ok()?;
if inode == lock_inode { Some(pid) } else { None }
})
}
#[cfg(not(target_os = "linux"))]
fn get_lock_owner(_: &std::path::Path) -> Option<u64> {
// FIXME: Implement on other OS's
None
}

View file

@ -109,3 +109,28 @@ pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () {
// as long as it doesn't cause a verifier error by using `bitcast`. // as long as it doesn't cause a verifier error by using `bitcast`.
transmute(x) transmute(x)
} }
pub enum Either<T, U> { A(T), B(U) }
// Previously, we would codegen this as passing/returning a scalar pair of `{ i8, ptr }`,
// with the `ptr` field representing both `&i32` and `fn()` depending on the variant.
// This is incorrect, because `fn()` should be `ptr addrspace(1)`, not `ptr`.
// CHECK: define{{.+}}void @should_not_combine_addrspace({{.+\*|ptr}}{{.+}}sret{{.+}}%0, {{.+\*|ptr}}{{.+}}%x)
#[no_mangle]
#[inline(never)]
pub fn should_not_combine_addrspace(x: Either<&i32, fn()>) -> Either<&i32, fn()> {
x
}
// The incorrectness described above would result in us producing (after optimizations)
// a `ptrtoint`/`inttoptr` roundtrip to convert from `ptr` to `ptr addrspace(1)`.
// CHECK-LABEL: @call_with_fn_ptr
#[no_mangle]
pub fn call_with_fn_ptr<'a>(f: fn()) -> Either<&'a i32, fn()> {
// CHECK-NOT: ptrtoint
// CHECK-NOT: inttoptr
// CHECK: call addrspace(1) void @should_not_combine_addrspace
should_not_combine_addrspace(Either::B(f))
}

View file

@ -0,0 +1,26 @@
// MIR for `f` after built
fn f(_1: i32, _2: bool) -> i32 {
let mut _0: i32; // return place in scope 0 at $DIR/operators.rs:+0:30: +0:33
bb0: {
_1 = Neg(_1); // scope 0 at $DIR/operators.rs:+2:9: +2:15
_2 = Not(_2); // scope 0 at $DIR/operators.rs:+3:9: +3:15
_1 = Add(_1, _1); // scope 0 at $DIR/operators.rs:+4:9: +4:18
_1 = Sub(_1, _1); // scope 0 at $DIR/operators.rs:+5:9: +5:18
_1 = Mul(_1, _1); // scope 0 at $DIR/operators.rs:+6:9: +6:18
_1 = Div(_1, _1); // scope 0 at $DIR/operators.rs:+7:9: +7:18
_1 = Rem(_1, _1); // scope 0 at $DIR/operators.rs:+8:9: +8:18
_1 = BitXor(_1, _1); // scope 0 at $DIR/operators.rs:+9:9: +9:18
_1 = BitAnd(_1, _1); // scope 0 at $DIR/operators.rs:+10:9: +10:18
_1 = Shl(_1, _1); // scope 0 at $DIR/operators.rs:+11:9: +11:19
_1 = Shr(_1, _1); // scope 0 at $DIR/operators.rs:+12:9: +12:19
_2 = Eq(_1, _1); // scope 0 at $DIR/operators.rs:+13:9: +13:19
_2 = Lt(_1, _1); // scope 0 at $DIR/operators.rs:+14:9: +14:18
_2 = Le(_1, _1); // scope 0 at $DIR/operators.rs:+15:9: +15:19
_2 = Ge(_1, _1); // scope 0 at $DIR/operators.rs:+16:9: +16:19
_2 = Gt(_1, _1); // scope 0 at $DIR/operators.rs:+17:9: +17:18
_0 = _1; // scope 0 at $DIR/operators.rs:+18:9: +18:16
return; // scope 0 at $DIR/operators.rs:+19:9: +19:17
}
}

View file

@ -0,0 +1,28 @@
// compile-flags: --crate-type=lib
#![feature(custom_mir, core_intrinsics, inline_const)]
use std::intrinsics::mir::*;
// EMIT_MIR operators.f.built.after.mir
#[custom_mir(dialect = "built")]
pub fn f(a: i32, b: bool) -> i32 {
mir!({
a = -a;
b = !b;
a = a + a;
a = a - a;
a = a * a;
a = a / a;
a = a % a;
a = a ^ a;
a = a & a;
a = a << a;
a = a >> a;
b = a == a;
b = a < a;
b = a <= a;
b = a >= a;
b = a > a;
RET = a;
Return()
})
}

View file

@ -0,0 +1,17 @@
fn foo(x: bool | i32) -> i32 | f64 {
//~^ ERROR anonymous enums are not supported
//~| ERROR anonymous enums are not supported
match x {
x: i32 => x, //~ ERROR expected
true => 42.,
false => 0.333,
}
}
fn main() {
match foo(true) {
42: i32 => (), //~ ERROR expected
_: f64 => (), //~ ERROR expected
x: i32 => (), //~ ERROR expected
}
}

View file

@ -0,0 +1,68 @@
error: anonymous enums are not supported
--> $DIR/anon-enums.rs:1:16
|
LL | fn foo(x: bool | i32) -> i32 | f64 {
| ---- ^ ---
|
= help: create a named `enum` and use it here instead:
enum Name {
Variant1(bool),
Variant2(i32),
}
error: anonymous enums are not supported
--> $DIR/anon-enums.rs:1:30
|
LL | fn foo(x: bool | i32) -> i32 | f64 {
| --- ^ ---
|
= help: create a named `enum` and use it here instead:
enum Name {
Variant1(i32),
Variant2(f64),
}
error: expected one of `@` or `|`, found `:`
--> $DIR/anon-enums.rs:5:10
|
LL | x: i32 => x,
| ^ --- specifying the type of a pattern isn't supported
| |
| expected one of `@` or `|`
|
help: maybe write a path separator here
|
LL | x::i32 => x,
| ~~
error: expected one of `...`, `..=`, `..`, or `|`, found `:`
--> $DIR/anon-enums.rs:13:11
|
LL | 42: i32 => (),
| ^ --- specifying the type of a pattern isn't supported
| |
| expected one of `...`, `..=`, `..`, or `|`
error: expected `|`, found `:`
--> $DIR/anon-enums.rs:14:10
|
LL | _: f64 => (),
| ^ --- specifying the type of a pattern isn't supported
| |
| expected `|`
error: expected one of `@` or `|`, found `:`
--> $DIR/anon-enums.rs:15:10
|
LL | x: i32 => (),
| ^ --- specifying the type of a pattern isn't supported
| |
| expected one of `@` or `|`
|
help: maybe write a path separator here
|
LL | x::i32 => (),
| ~~
error: aborting due to 6 previous errors

View file

@ -0,0 +1,20 @@
// build-pass
macro_rules! check_ty {
($Z:ty) => { compile_error!("triggered"); };
($X:ty | $Y:ty) => { $X };
}
macro_rules! check {
($Z:ty) => { compile_error!("triggered"); };
($X:ty | $Y:ty) => { };
}
check! { i32 | u8 }
fn foo(x: check_ty! { i32 | u8 }) -> check_ty! { i32 | u8 } {
x
}
fn main() {
let x: check_ty! { i32 | u8 } = 42;
let _: check_ty! { i32 | u8 } = foo(x);
}

View file

@ -68,7 +68,6 @@ fn main() {
Foo:Bar::Baz => {} Foo:Bar::Baz => {}
//~^ ERROR: expected one of //~^ ERROR: expected one of
//~| HELP: maybe write a path separator here //~| HELP: maybe write a path separator here
//~| ERROR: failed to resolve: `Bar` is a variant, not a module
} }
match myfoo { match myfoo {
Foo::Bar => {} Foo::Bar => {}

View file

@ -2,89 +2,118 @@ error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:17:12 --> $DIR/issue-87086-colon-path-sep.rs:17:12
| |
LL | Foo:Bar => {} LL | Foo:Bar => {}
| ^ | ^--- specifying the type of a pattern isn't supported
| | | |
| expected one of `@` or `|` | expected one of `@` or `|`
| help: maybe write a path separator here: `::` |
help: maybe write a path separator here
|
LL | Foo::Bar => {}
| ~~
error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:` error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:23:17 --> $DIR/issue-87086-colon-path-sep.rs:23:17
| |
LL | qux::Foo:Bar => {} LL | qux::Foo:Bar => {}
| ^ | ^--- specifying the type of a pattern isn't supported
| | | |
| expected one of 8 possible tokens | expected one of 8 possible tokens
| help: maybe write a path separator here: `::` |
help: maybe write a path separator here
|
LL | qux::Foo::Bar => {}
| ~~
error: expected one of `@` or `|`, found `:` error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:29:12 --> $DIR/issue-87086-colon-path-sep.rs:29:12
| |
LL | qux:Foo::Baz => {} LL | qux:Foo::Baz => {}
| ^ | ^-------- specifying the type of a pattern isn't supported
| | | |
| expected one of `@` or `|` | expected one of `@` or `|`
| help: maybe write a path separator here: `::` |
help: maybe write a path separator here
|
LL | qux::Foo::Baz => {}
| ~~
error: expected one of `@` or `|`, found `:` error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:35:12 --> $DIR/issue-87086-colon-path-sep.rs:35:12
| |
LL | qux: Foo::Baz if true => {} LL | qux: Foo::Baz if true => {}
| ^ | ^ -------- specifying the type of a pattern isn't supported
| | | |
| expected one of `@` or `|` | expected one of `@` or `|`
| help: maybe write a path separator here: `::` |
help: maybe write a path separator here
|
LL | qux::Foo::Baz if true => {}
| ~~
error: expected one of `@` or `|`, found `:` error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:40:15 --> $DIR/issue-87086-colon-path-sep.rs:40:15
| |
LL | if let Foo:Bar = f() { LL | if let Foo:Bar = f() {
| ^ | ^--- specifying the type of a pattern isn't supported
| | | |
| expected one of `@` or `|` | expected one of `@` or `|`
| help: maybe write a path separator here: `::` |
help: maybe write a path separator here
|
LL | if let Foo::Bar = f() {
| ~~
error: expected one of `@` or `|`, found `:` error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:48:16 --> $DIR/issue-87086-colon-path-sep.rs:48:16
| |
LL | ref qux: Foo::Baz => {} LL | ref qux: Foo::Baz => {}
| ^ | ^ -------- specifying the type of a pattern isn't supported
| | | |
| expected one of `@` or `|` | expected one of `@` or `|`
| help: maybe write a path separator here: `::` |
help: maybe write a path separator here
|
LL | ref qux::Foo::Baz => {}
| ~~
error: expected one of `@` or `|`, found `:` error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:57:16 --> $DIR/issue-87086-colon-path-sep.rs:57:16
| |
LL | mut qux: Foo::Baz => {} LL | mut qux: Foo::Baz => {}
| ^ | ^ -------- specifying the type of a pattern isn't supported
| | | |
| expected one of `@` or `|` | expected one of `@` or `|`
| help: maybe write a path separator here: `::` |
help: maybe write a path separator here
|
LL | mut qux::Foo::Baz => {}
| ~~
error: expected one of `@` or `|`, found `:` error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:68:12 --> $DIR/issue-87086-colon-path-sep.rs:68:12
| |
LL | Foo:Bar::Baz => {} LL | Foo:Bar::Baz => {}
| ^ | ^-------- specifying the type of a pattern isn't supported
| | | |
| expected one of `@` or `|` | expected one of `@` or `|`
| help: maybe write a path separator here: `::` |
help: maybe write a path separator here
|
LL | Foo::Bar::Baz => {}
| ~~
error: expected one of `@` or `|`, found `:` error: expected one of `@` or `|`, found `:`
--> $DIR/issue-87086-colon-path-sep.rs:75:12 --> $DIR/issue-87086-colon-path-sep.rs:74:12
| |
LL | Foo:Bar => {} LL | Foo:Bar => {}
| ^ | ^--- specifying the type of a pattern isn't supported
| | | |
| expected one of `@` or `|` | expected one of `@` or `|`
| help: maybe write a path separator here: `::`
error[E0433]: failed to resolve: `Bar` is a variant, not a module
--> $DIR/issue-87086-colon-path-sep.rs:68:13
| |
LL | Foo:Bar::Baz => {} help: maybe write a path separator here
| ^^^ `Bar` is a variant, not a module |
LL | Foo::Bar => {}
| ~~
error: aborting due to 10 previous errors error: aborting due to 9 previous errors
For more information about this error, try `rustc --explain E0433`.

View file

@ -0,0 +1,26 @@
// check-pass
// force-host
// no-prefer-dynamic
#![crate_type = "proc-macro"]
#![allow(private_in_public)]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro]
pub fn foo<T>(t: T) -> TokenStream {
TokenStream::new()
}
trait Project {
type Assoc;
}
impl Project for () {
type Assoc = TokenStream;
}
#[proc_macro]
pub fn uwu(_input: <() as Project>::Assoc) -> <() as Project>::Assoc {
TokenStream::new()
}

View file

@ -0,0 +1,31 @@
// force-host
// no-prefer-dynamic
#![crate_type = "proc-macro"]
#![allow(warnings)]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro]
pub extern "C" fn abi(a: TokenStream) -> TokenStream {
//~^ ERROR proc macro functions may not be `extern "C"`
a
}
#[proc_macro]
pub extern "system" fn abi2(a: TokenStream) -> TokenStream {
//~^ ERROR proc macro functions may not be `extern "system"`
a
}
#[proc_macro]
pub extern fn abi3(a: TokenStream) -> TokenStream {
//~^ ERROR proc macro functions may not be `extern "C"`
a
}
#[proc_macro]
pub extern "Rust" fn abi4(a: TokenStream) -> TokenStream {
a
}

View file

@ -0,0 +1,20 @@
error: proc macro functions may not be `extern "C"`
--> $DIR/proc-macro-abi.rs:11:1
|
LL | pub extern "C" fn abi(a: TokenStream) -> TokenStream {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: proc macro functions may not be `extern "system"`
--> $DIR/proc-macro-abi.rs:17:1
|
LL | pub extern "system" fn abi2(a: TokenStream) -> TokenStream {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: proc macro functions may not be `extern "C"`
--> $DIR/proc-macro-abi.rs:23:1
|
LL | pub extern fn abi3(a: TokenStream) -> TokenStream {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors

View file

@ -0,0 +1,32 @@
// force-host
// no-prefer-dynamic
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_attribute]
pub fn bad_input(input: String) -> TokenStream {
//~^ ERROR mismatched attribute proc macro signature
::proc_macro::TokenStream::new()
}
#[proc_macro_attribute]
pub fn bad_output(input: TokenStream) -> String {
//~^ ERROR mismatched attribute proc macro signature
//~| ERROR mismatched attribute proc macro signature
String::from("blah")
}
#[proc_macro_attribute]
pub fn bad_everything(input: String) -> String {
//~^ ERROR mismatched attribute proc macro signature
//~| ERROR mismatched attribute proc macro signature
input
}
#[proc_macro_attribute]
pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
//~^ ERROR mismatched attribute proc macro signature
}

View file

@ -0,0 +1,42 @@
error: mismatched attribute proc macro signature
--> $DIR/signature-proc-macro-attribute.rs:10:1
|
LL | pub fn bad_input(input: String) -> TokenStream {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
error: mismatched attribute proc macro signature
--> $DIR/signature-proc-macro-attribute.rs:16:42
|
LL | pub fn bad_output(input: TokenStream) -> String {
| ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
|
= note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream`
error: mismatched attribute proc macro signature
--> $DIR/signature-proc-macro-attribute.rs:16:1
|
LL | pub fn bad_output(input: TokenStream) -> String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
error: mismatched attribute proc macro signature
--> $DIR/signature-proc-macro-attribute.rs:23:41
|
LL | pub fn bad_everything(input: String) -> String {
| ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
|
= note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream`
error: mismatched attribute proc macro signature
--> $DIR/signature-proc-macro-attribute.rs:23:1
|
LL | pub fn bad_everything(input: String) -> String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
error: mismatched attribute proc macro signature
--> $DIR/signature-proc-macro-attribute.rs:30:49
|
LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
| ^^^^^^^^^ found unexpected argument
error: aborting due to 6 previous errors

View file

@ -0,0 +1,31 @@
// force-host
// no-prefer-dynamic
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro_derive(Blah)]
pub fn bad_input(input: String) -> TokenStream {
//~^ ERROR mismatched derive proc macro signature
TokenStream::new()
}
#[proc_macro_derive(Bleh)]
pub fn bad_output(input: TokenStream) -> String {
//~^ ERROR mismatched derive proc macro signature
String::from("blah")
}
#[proc_macro_derive(Bluh)]
pub fn bad_everything(input: String) -> String {
//~^ ERROR mismatched derive proc macro signature
//~| ERROR mismatched derive proc macro signature
input
}
#[proc_macro_derive(Blih)]
pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
//~^ ERROR mismatched derive proc macro signature
}

View file

@ -0,0 +1,40 @@
error: mismatched derive proc macro signature
--> $DIR/signature-proc-macro-derive.rs:10:25
|
LL | pub fn bad_input(input: String) -> TokenStream {
| ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
|
= note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
error: mismatched derive proc macro signature
--> $DIR/signature-proc-macro-derive.rs:16:42
|
LL | pub fn bad_output(input: TokenStream) -> String {
| ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
|
= note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
error: mismatched derive proc macro signature
--> $DIR/signature-proc-macro-derive.rs:22:41
|
LL | pub fn bad_everything(input: String) -> String {
| ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
|
= note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
error: mismatched derive proc macro signature
--> $DIR/signature-proc-macro-derive.rs:22:30
|
LL | pub fn bad_everything(input: String) -> String {
| ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
|
= note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
error: mismatched derive proc macro signature
--> $DIR/signature-proc-macro-derive.rs:29:33
|
LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments
error: aborting due to 5 previous errors

View file

@ -0,0 +1,31 @@
// force-host
// no-prefer-dynamic
#![crate_type = "proc-macro"]
extern crate proc_macro;
use proc_macro::TokenStream;
#[proc_macro]
pub fn bad_input(input: String) -> TokenStream {
//~^ ERROR mismatched function-like proc macro signature
::proc_macro::TokenStream::new()
}
#[proc_macro]
pub fn bad_output(input: TokenStream) -> String {
//~^ ERROR mismatched function-like proc macro signature
String::from("blah")
}
#[proc_macro]
pub fn bad_everything(input: String) -> String {
//~^ ERROR mismatched function-like proc macro signature
//~| ERROR mismatched function-like proc macro signature
input
}
#[proc_macro]
pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
//~^ ERROR mismatched function-like proc macro signature
}

View file

@ -0,0 +1,40 @@
error: mismatched function-like proc macro signature
--> $DIR/signature-proc-macro.rs:10:25
|
LL | pub fn bad_input(input: String) -> TokenStream {
| ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
|
= note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
error: mismatched function-like proc macro signature
--> $DIR/signature-proc-macro.rs:16:42
|
LL | pub fn bad_output(input: TokenStream) -> String {
| ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
|
= note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
error: mismatched function-like proc macro signature
--> $DIR/signature-proc-macro.rs:22:41
|
LL | pub fn bad_everything(input: String) -> String {
| ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
|
= note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
error: mismatched function-like proc macro signature
--> $DIR/signature-proc-macro.rs:22:30
|
LL | pub fn bad_everything(input: String) -> String {
| ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
|
= note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
error: mismatched function-like proc macro signature
--> $DIR/signature-proc-macro.rs:29:33
|
LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
| ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments
error: aborting due to 5 previous errors

View file

@ -8,6 +8,10 @@ extern crate proc_macro;
#[proc_macro_derive(A)] #[proc_macro_derive(A)]
pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
//~^ ERROR: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn //~^ ERROR: mismatched derive proc macro signature
//~| mismatched derive proc macro signature
//~| mismatched derive proc macro signature
//~| proc macro functions may not be `extern
//~| proc macro functions may not be `unsafe
loop {} loop {}
} }

View file

@ -1,20 +1,36 @@
error[E0277]: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn(i32, u32) -> u32 {foo}` error: proc macro functions may not be `extern "C"`
--> $DIR/signature.rs:10:1 --> $DIR/signature.rs:10:1
| |
LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 { LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
LL | | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | | loop {}
LL | | } error: proc macro functions may not be `unsafe`
| | ^ --> $DIR/signature.rs:10:1
| | |
| |_call the function in a closure: `|| unsafe { /* code */ }`
| required by a bound introduced by this call
| |
= help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for fn item `unsafe extern "C" fn(i32, u32) -> u32 {foo}` LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
= note: unsafe function cannot be called generically without an unsafe block | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: required by a bound in `ProcMacro::custom_derive`
--> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL
error: aborting due to previous error error: mismatched derive proc macro signature
--> $DIR/signature.rs:10:49
|
LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
| ^^^ found u32, expected type `proc_macro::TokenStream`
|
= note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
error: mismatched derive proc macro signature
--> $DIR/signature.rs:10:33
|
LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
| ^^^ found i32, expected type `proc_macro::TokenStream`
|
= note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
error: mismatched derive proc macro signature
--> $DIR/signature.rs:10:38
|
LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
| ^^^^^^ found unexpected argument
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,11 @@
struct Foo;
impl Foo {
const A_CONST: usize = 1;
fn foo() -> usize {
A_CONST //~ ERROR cannot find value `A_CONST` in this scope
}
}
fn main() {}

View file

@ -0,0 +1,14 @@
error[E0425]: cannot find value `A_CONST` in this scope
--> $DIR/assoc-const-without-self.rs:7:9
|
LL | A_CONST
| ^^^^^^^ not found in this scope
|
help: consider using the associated constant
|
LL | Self::A_CONST
| ++++++
error: aborting due to previous error
For more information about this error, try `rustc --explain E0425`.

View file

@ -0,0 +1,17 @@
error[E0271]: expected `[async block@$DIR/async.rs:12:17: 12:25]` to be a future that resolves to `i32`, but it resolves to `()`
--> $DIR/async.rs:12:17
|
LL | needs_async(async {});
| ----------- ^^^^^^^^ expected `i32`, found `()`
| |
| required by a bound introduced by this call
|
note: required by a bound in `needs_async`
--> $DIR/async.rs:8:31
|
LL | fn needs_async(_: impl Future<Output = i32>) {}
| ^^^^^^^^^^^^ required by this bound in `needs_async`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0271`.

View file

@ -0,0 +1,19 @@
// compile-flags: -Ztrait-solver=next
// edition: 2021
// revisions: pass fail
//[pass] check-pass
use std::future::Future;
fn needs_async(_: impl Future<Output = i32>) {}
#[cfg(fail)]
fn main() {
needs_async(async {});
//[fail]~^ ERROR to be a future that resolves to `i32`, but it resolves to `()`
}
#[cfg(pass)]
fn main() {
needs_async(async { 1i32 });
}

View file

@ -0,0 +1,64 @@
error[E0277]: the trait bound `[generator@$DIR/generator.rs:18:21: 18:23]: Generator<A>` is not satisfied
--> $DIR/generator.rs:18:21
|
LL | needs_generator(|| {
| _____---------------_^
| | |
| | required by a bound introduced by this call
LL | |
LL | |
LL | |
LL | | yield ();
LL | | });
| |_____^ the trait `Generator<A>` is not implemented for `[generator@$DIR/generator.rs:18:21: 18:23]`
|
note: required by a bound in `needs_generator`
--> $DIR/generator.rs:14:28
|
LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `needs_generator`
error[E0271]: type mismatch resolving `<[generator@$DIR/generator.rs:18:21: 18:23] as Generator<A>>::Yield == B`
--> $DIR/generator.rs:18:21
|
LL | needs_generator(|| {
| _____---------------_^
| | |
| | required by a bound introduced by this call
LL | |
LL | |
LL | |
LL | | yield ();
LL | | });
| |_____^ types differ
|
note: required by a bound in `needs_generator`
--> $DIR/generator.rs:14:41
|
LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
| ^^^^^^^^^ required by this bound in `needs_generator`
error[E0271]: type mismatch resolving `<[generator@$DIR/generator.rs:18:21: 18:23] as Generator<A>>::Return == C`
--> $DIR/generator.rs:18:21
|
LL | needs_generator(|| {
| _____---------------_^
| | |
| | required by a bound introduced by this call
LL | |
LL | |
LL | |
LL | | yield ();
LL | | });
| |_____^ types differ
|
note: required by a bound in `needs_generator`
--> $DIR/generator.rs:14:52
|
LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
| ^^^^^^^^^^ required by this bound in `needs_generator`
error: aborting due to 3 previous errors
Some errors have detailed explanations: E0271, E0277.
For more information about an error, try `rustc --explain E0271`.

View file

@ -0,0 +1,32 @@
// compile-flags: -Ztrait-solver=next
// edition: 2021
// revisions: pass fail
//[pass] check-pass
#![feature(generator_trait, generators)]
use std::ops::Generator;
struct A;
struct B;
struct C;
fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
#[cfg(fail)]
fn main() {
needs_generator(|| {
//[fail]~^ ERROR Generator<A>` is not satisfied
//[fail]~| ERROR as Generator<A>>::Yield == B`
//[fail]~| ERROR as Generator<A>>::Return == C`
yield ();
});
}
#[cfg(pass)]
fn main() {
needs_generator(|_: A| {
let _: A = yield B;
C
})
}

View file

@ -0,0 +1,20 @@
// The error message here still is pretty confusing.
fn main() {
let mut result = vec![1];
// The type of `result` is constrained to be `Vec<{integer}>` here.
// But the logic we use to find what expression constrains a type
// is not sophisticated enough to know this.
let mut vector = Vec::new();
vector.sort();
result.push(vector);
//~^ ERROR mismatched types
// So it thinks that the type of `result` is constrained here.
}
fn example2() {
let mut x = vec![1];
x.push("");
//~^ ERROR mismatched types
}

View file

@ -0,0 +1,29 @@
error[E0308]: mismatched types
--> $DIR/bad-type-in-vec-push.rs:11:17
|
LL | vector.sort();
| ------ here the type of `vector` is inferred to be `Vec<_>`
LL | result.push(vector);
| ---- ^^^^^^ expected integer, found struct `Vec`
| |
| arguments to this method are incorrect
|
= note: expected type `{integer}`
found struct `Vec<_>`
note: associated function defined here
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
error[E0308]: mismatched types
--> $DIR/bad-type-in-vec-push.rs:18:12
|
LL | x.push("");
| ---- ^^ expected integer, found `&str`
| |
| arguments to this method are incorrect
|
note: associated function defined here
--> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0308`.

View file

@ -456,6 +456,9 @@ These commits modify **compiler targets**.
(See the [Target Tier Policy](https://doc.rust-lang.org/nightly/rustc/target-tier-policy.html).) (See the [Target Tier Policy](https://doc.rust-lang.org/nightly/rustc/target-tier-policy.html).)
""" """
[mentions."src/doc/style-guide"]
cc = ["@rust-lang/style"]
[assign] [assign]
warn_non_default_branch = true warn_non_default_branch = true
contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html" contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html"
@ -560,6 +563,12 @@ ast_lowering = [
fallback = [ fallback = [
"@Mark-Simulacrum" "@Mark-Simulacrum"
] ]
style-team = [
"@calebcartwright",
"@compiler-errors",
"@joshtriplett",
"@yaahc",
]
[assign.owners] [assign.owners]
"/.github/workflows" = ["infra-ci"] "/.github/workflows" = ["infra-ci"]
@ -604,6 +613,7 @@ fallback = [
"/src/doc/rust-by-example" = ["@ehuss"] "/src/doc/rust-by-example" = ["@ehuss"]
"/src/doc/rustc-dev-guide" = ["@ehuss"] "/src/doc/rustc-dev-guide" = ["@ehuss"]
"/src/doc/rustdoc" = ["rustdoc"] "/src/doc/rustdoc" = ["rustdoc"]
"/src/doc/style-guide" = ["style-team"]
"/src/etc" = ["@Mark-Simulacrum"] "/src/etc" = ["@Mark-Simulacrum"]
"/src/librustdoc" = ["rustdoc"] "/src/librustdoc" = ["rustdoc"]
"/src/llvm-project" = ["@cuviper"] "/src/llvm-project" = ["@cuviper"]