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:
commit
e187f8871e
77 changed files with 1682 additions and 343 deletions
14
Cargo.lock
14
Cargo.lock
|
@ -351,7 +351,7 @@ dependencies = [
|
|||
"cargo-test-macro",
|
||||
"cargo-test-support",
|
||||
"cargo-util",
|
||||
"clap 4.1.3",
|
||||
"clap 4.1.4",
|
||||
"crates-io",
|
||||
"curl",
|
||||
"curl-sys",
|
||||
|
@ -655,9 +655,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.1.3"
|
||||
version = "4.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8d93d855ce6a0aa87b8473ef9169482f40abaa2e9e0993024c35c902cbd5920"
|
||||
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"clap_derive 4.1.0",
|
||||
|
@ -675,7 +675,7 @@ version = "4.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
|
||||
dependencies = [
|
||||
"clap 4.1.3",
|
||||
"clap 4.1.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2294,7 +2294,7 @@ name = "jsondoclint"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap 4.1.3",
|
||||
"clap 4.1.4",
|
||||
"fs-err",
|
||||
"rustdoc-json-types",
|
||||
"serde",
|
||||
|
@ -2557,7 +2557,7 @@ dependencies = [
|
|||
"ammonia",
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"clap 4.1.3",
|
||||
"clap 4.1.4",
|
||||
"clap_complete",
|
||||
"elasticlunr-rs",
|
||||
"env_logger 0.10.0",
|
||||
|
@ -3528,7 +3528,7 @@ dependencies = [
|
|||
name = "rustbook"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 4.1.3",
|
||||
"clap 4.1.4",
|
||||
"env_logger 0.7.1",
|
||||
"mdbook",
|
||||
]
|
||||
|
|
|
@ -267,6 +267,9 @@ impl TargetDataLayout {
|
|||
["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?,
|
||||
["f32", ref a @ ..] => dl.f32_align = align(a, "f32")?,
|
||||
["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 @ ..] => {
|
||||
dl.pointer_size = size(s, p)?;
|
||||
dl.pointer_align = align(a, p)?;
|
||||
|
@ -861,7 +864,7 @@ pub enum Primitive {
|
|||
Int(Integer, bool),
|
||||
F32,
|
||||
F64,
|
||||
Pointer,
|
||||
Pointer(AddressSpace),
|
||||
}
|
||||
|
||||
impl Primitive {
|
||||
|
@ -872,7 +875,10 @@ impl Primitive {
|
|||
Int(i, _) => i.size(),
|
||||
F32 => Size::from_bits(32),
|
||||
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),
|
||||
F32 => dl.f32_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
|
||||
|
@ -1188,7 +1180,8 @@ impl FieldsShape {
|
|||
/// An identifier that specifies the address space that some operation
|
||||
/// should operate on. Special address spaces have an effect on code generation,
|
||||
/// 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);
|
||||
|
||||
impl AddressSpace {
|
||||
|
@ -1468,7 +1461,6 @@ pub struct PointeeInfo {
|
|||
pub size: Size,
|
||||
pub align: Align,
|
||||
pub safe: Option<PointerKind>,
|
||||
pub address_space: AddressSpace,
|
||||
}
|
||||
|
||||
/// Used in `might_permit_raw_init` to indicate the kind of initialisation
|
||||
|
|
|
@ -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);
|
||||
visitor.visit_ty(&mutable_type.ty)
|
||||
}
|
||||
TyKind::Tup(tuple_element_types) => {
|
||||
walk_list!(visitor, visit_ty, tuple_element_types);
|
||||
TyKind::Tup(tys) => {
|
||||
walk_list!(visitor, visit_ty, tys);
|
||||
}
|
||||
TyKind::BareFn(function_declaration) => {
|
||||
walk_list!(visitor, visit_generic_param, &function_declaration.generic_params);
|
||||
|
|
|
@ -35,7 +35,8 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type {
|
|||
},
|
||||
Primitive::F32 => types::F32,
|
||||
Primitive::F64 => types::F64,
|
||||
Primitive::Pointer => pointer_ty(tcx),
|
||||
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
|
||||
Primitive::Pointer(_) => pointer_ty(tcx),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -709,7 +709,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
|
|||
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);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -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 offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
|
||||
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)
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -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")
|
||||
as u64;
|
||||
|
||||
let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
|
||||
|
||||
llvals.push(cx.scalar_to_backend(
|
||||
InterpScalar::from_pointer(
|
||||
interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
|
||||
&cx.tcx,
|
||||
),
|
||||
abi::Scalar::Initialized { value: Primitive::Pointer, valid_range: WrappingRange::full(dl.pointer_size) },
|
||||
cx.type_i8p(),
|
||||
abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) },
|
||||
cx.type_i8p_ext(address_space),
|
||||
));
|
||||
next_offset = offset + pointer_size;
|
||||
}
|
||||
|
|
|
@ -253,7 +253,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
Int(i, false) => cx.type_from_unsigned_integer(i),
|
||||
F32 => cx.type_f32(),
|
||||
F64 => cx.type_f64(),
|
||||
Pointer => {
|
||||
Pointer(address_space) => {
|
||||
// If we know the alignment, pick something better than i8.
|
||||
let pointee =
|
||||
if let Some(pointee) = self.pointee_info_at(cx, offset) {
|
||||
|
@ -262,7 +262,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
|
|||
else {
|
||||
cx.type_i8()
|
||||
};
|
||||
cx.type_ptr_to(pointee)
|
||||
cx.type_ptr_to_ext(pointee, address_space)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
/// the equivalent integer type.
|
||||
fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Type {
|
||||
let dl = &cx.tcx.data_layout;
|
||||
match scalar.primitive() {
|
||||
Primitive::Int(Integer::I8, _) => cx.type_i8(),
|
||||
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::F32 => cx.type_f32(),
|
||||
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!(),
|
||||
}
|
||||
}
|
||||
|
@ -868,6 +870,7 @@ fn llvm_fixup_input<'ll, 'tcx>(
|
|||
reg: InlineAsmRegClass,
|
||||
layout: &TyAndLayout<'tcx>,
|
||||
) -> &'ll Value {
|
||||
let dl = &bx.tcx.data_layout;
|
||||
match (reg, layout.abi) {
|
||||
(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
|
||||
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 count = 16 / layout.size.bytes();
|
||||
let vec_ty = bx.cx.type_vector(elem_ty, count);
|
||||
if let Primitive::Pointer = s.primitive() {
|
||||
value = bx.ptrtoint(value, bx.cx.type_isize());
|
||||
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
|
||||
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))
|
||||
}
|
||||
|
@ -958,7 +963,7 @@ fn llvm_fixup_output<'ll, 'tcx>(
|
|||
}
|
||||
(InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) => {
|
||||
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
|
||||
|
|
|
@ -511,7 +511,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
|
|||
bx.range_metadata(load, scalar.valid_range(bx));
|
||||
}
|
||||
}
|
||||
abi::Pointer => {
|
||||
abi::Pointer(_) => {
|
||||
if !scalar.valid_range(bx).contains(0) {
|
||||
bx.nonnull_metadata(load);
|
||||
}
|
||||
|
|
|
@ -236,7 +236,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
Scalar::Int(int) => {
|
||||
let data = int.assert_bits(layout.size(self));
|
||||
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) }
|
||||
} else {
|
||||
self.const_bitcast(llval, llty)
|
||||
|
@ -284,7 +284,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||
1,
|
||||
)
|
||||
};
|
||||
if layout.primitive() != Pointer {
|
||||
if !matches!(layout.primitive(), Pointer(_)) {
|
||||
unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
|
||||
} else {
|
||||
self.const_bitcast(llval, llty)
|
||||
|
|
|
@ -13,7 +13,7 @@ use rustc_codegen_ssa::traits::*;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
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,
|
||||
};
|
||||
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::{bug, span_bug};
|
||||
use rustc_session::config::Lto;
|
||||
use rustc_target::abi::{
|
||||
AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
|
||||
};
|
||||
use rustc_target::abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange};
|
||||
use std::ops::Range;
|
||||
|
||||
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")
|
||||
as u64;
|
||||
|
||||
let address_space = match cx.tcx.global_alloc(alloc_id) {
|
||||
GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
|
||||
GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => {
|
||||
AddressSpace::DATA
|
||||
}
|
||||
};
|
||||
let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
|
||||
|
||||
llvals.push(cx.scalar_to_backend(
|
||||
InterpScalar::from_pointer(
|
||||
|
@ -111,7 +104,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
|
|||
&cx.tcx,
|
||||
),
|
||||
Scalar::Initialized {
|
||||
value: Primitive::Pointer,
|
||||
value: Primitive::Pointer(address_space),
|
||||
valid_range: WrappingRange::full(dl.pointer_size),
|
||||
},
|
||||
cx.type_i8p_ext(address_space),
|
||||
|
|
|
@ -122,7 +122,8 @@ fn tag_base_type<'ll, 'tcx>(
|
|||
Primitive::Int(t, _) => t,
|
||||
Primitive::F32 => Integer::I32,
|
||||
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
|
||||
// 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`.
|
||||
|
|
|
@ -149,7 +149,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
|||
emit_va_arg(self, args[0], ret_ty)
|
||||
}
|
||||
}
|
||||
Primitive::F64 | Primitive::Pointer => {
|
||||
Primitive::F64 | Primitive::Pointer(_) => {
|
||||
emit_va_arg(self, args[0], ret_ty)
|
||||
}
|
||||
// `va_arg` should never be used with the return type f32.
|
||||
|
|
|
@ -7,7 +7,7 @@ use rustc_middle::bug;
|
|||
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::{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::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
@ -312,14 +312,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
|
|||
Int(i, _) => cx.type_from_integer(i),
|
||||
F32 => cx.type_f32(),
|
||||
F64 => cx.type_f64(),
|
||||
Pointer => {
|
||||
Pointer(address_space) => {
|
||||
// If we know the alignment, pick something better than i8.
|
||||
let (pointee, address_space) =
|
||||
if let Some(pointee) = self.pointee_info_at(cx, offset) {
|
||||
(cx.type_pointee_for_align(pointee.align), pointee.address_space)
|
||||
} else {
|
||||
(cx.type_i8(), AddressSpace::DATA)
|
||||
};
|
||||
let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) {
|
||||
cx.type_pointee_for_align(pointee.align)
|
||||
} else {
|
||||
cx.type_i8()
|
||||
};
|
||||
cx.type_ptr_to_ext(pointee, address_space)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1801,8 +1801,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
match (src.layout.abi, dst.layout.abi) {
|
||||
(abi::Abi::Scalar(src_scalar), abi::Abi::Scalar(dst_scalar)) => {
|
||||
// HACK(eddyb) LLVM doesn't like `bitcast`s between pointers and non-pointers.
|
||||
let src_is_ptr = src_scalar.primitive() == abi::Pointer;
|
||||
let dst_is_ptr = dst_scalar.primitive() == abi::Pointer;
|
||||
let src_is_ptr = matches!(src_scalar.primitive(), abi::Pointer(_));
|
||||
let dst_is_ptr = matches!(dst_scalar.primitive(), abi::Pointer(_));
|
||||
if src_is_ptr == dst_is_ptr {
|
||||
assert_eq!(src.layout.size, dst.layout.size);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ use rustc_middle::mir;
|
|||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
|
||||
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};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
|
@ -209,6 +209,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
|
|||
bx: &mut Bx,
|
||||
cast_to: Ty<'tcx>,
|
||||
) -> V {
|
||||
let dl = &bx.tcx().data_layout;
|
||||
let cast_to_layout = bx.cx().layout_of(cast_to);
|
||||
let cast_to_size = cast_to_layout.layout.size();
|
||||
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 } => {
|
||||
// Cast to an integer so we don't have to treat a pointer as a
|
||||
// special case.
|
||||
let (tag, tag_llty) = if tag_scalar.primitive().is_ptr() {
|
||||
let t = bx.type_isize();
|
||||
let tag = bx.ptrtoint(tag_imm, t);
|
||||
(tag, t)
|
||||
} else {
|
||||
(tag_imm, bx.cx().immediate_backend_type(tag_op.layout))
|
||||
let (tag, tag_llty) = match tag_scalar.primitive() {
|
||||
// FIXME(erikdesjardins): handle non-default addrspace ptr sizes
|
||||
Pointer(_) => {
|
||||
let t = bx.type_from_integer(dl.ptr_sized_integer());
|
||||
let tag = bx.ptrtoint(tag_imm, t);
|
||||
(tag, t)
|
||||
}
|
||||
_ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)),
|
||||
};
|
||||
|
||||
let tag_size = tag_scalar.size(bx.cx());
|
||||
|
|
|
@ -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");
|
||||
let scalar = alloc.read_scalar(
|
||||
alloc_range(Size::ZERO, size),
|
||||
/*read_provenance*/ s.is_ptr(),
|
||||
/*read_provenance*/ matches!(s, abi::Pointer(_)),
|
||||
)?;
|
||||
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
|
||||
let a_val = alloc.read_scalar(
|
||||
alloc_range(Size::ZERO, a_size),
|
||||
/*read_provenance*/ a.is_ptr(),
|
||||
/*read_provenance*/ matches!(a, abi::Pointer(_)),
|
||||
)?;
|
||||
let b_val = alloc.read_scalar(
|
||||
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 })
|
||||
}
|
||||
|
|
|
@ -710,3 +710,24 @@ passes_ignored_derived_impls =
|
|||
[one] trait {$trait_list}, but this is
|
||||
*[other] traits {$trait_list}, but these are
|
||||
} 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`
|
||||
|
|
|
@ -62,7 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
|| self.suggest_floating_point_literal(err, expr, expected)
|
||||
|| self.note_result_coercion(err, expr, expected, expr_ty);
|
||||
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<'_>,
|
||||
found: Ty<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
mismatch_span: Span,
|
||||
) -> bool {
|
||||
let map = self.tcx.hir();
|
||||
|
||||
|
@ -270,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
lt_op: |_| self.tcx.lifetimes.re_erased,
|
||||
ct_op: |c| c,
|
||||
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(_)) => {
|
||||
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_span = None;
|
||||
let mut prev_span: Option<Span> = None;
|
||||
|
||||
for binding in expr_finder.uses {
|
||||
// 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.
|
||||
let arg = &args[i];
|
||||
let arg_ty = self.node_ty(arg.hir_id);
|
||||
err.span_label(
|
||||
arg.span,
|
||||
&format!(
|
||||
"this is of type `{arg_ty}`, which causes `{ident}` to be \
|
||||
inferred as `{ty}`",
|
||||
),
|
||||
);
|
||||
if !arg.span.overlaps(mismatch_span) {
|
||||
err.span_label(
|
||||
arg.span,
|
||||
&format!(
|
||||
"this is of type `{arg_ty}`, which causes `{ident}` to be \
|
||||
inferred as `{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()
|
||||
{
|
||||
// We only point at the first place where the found type was inferred.
|
||||
if !segment.ident.span.overlaps(mismatch_span) {
|
||||
err.span_label(
|
||||
segment.ident.span,
|
||||
with_forced_trimmed_paths!(format!(
|
||||
"here the type of `{ident}` is inferred to be `{ty}`",
|
||||
)),
|
||||
);
|
||||
);}
|
||||
break;
|
||||
} else if !param_args.is_empty() {
|
||||
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
|
||||
// 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.
|
||||
err.span_label(
|
||||
span,
|
||||
with_forced_trimmed_paths!(format!(
|
||||
"here the type of `{ident}` is inferred to be `{ty}`",
|
||||
)),
|
||||
);
|
||||
if !span.overlaps(mismatch_span) {
|
||||
err.span_label(
|
||||
span,
|
||||
with_forced_trimmed_paths!(format!(
|
||||
"here the type of `{ident}` is inferred to be `{ty}`",
|
||||
)),
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
prev = ty;
|
||||
|
|
|
@ -808,7 +808,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
kind: TypeVariableOriginKind::MiscVariable,
|
||||
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
|
||||
self.label_fn_like(
|
||||
|
|
|
@ -38,6 +38,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
|
|||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
|
||||
let tcx = self.tcx;
|
||||
let dl = &tcx.data_layout;
|
||||
let span = tcx.hir().span(hir_id);
|
||||
let normalize = |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
|
||||
// `Option<typeof(function)>` to present a clearer error.
|
||||
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")
|
||||
.note(&format!("source type: {from}"))
|
||||
.note(&format!("target type: {to}"))
|
||||
|
|
|
@ -110,7 +110,7 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_macros::HashStable;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_serialize::{Decodable, Encodable};
|
||||
use rustc_target::abi::Endian;
|
||||
use rustc_target::abi::{AddressSpace, Endian, HasDataLayout};
|
||||
|
||||
use crate::mir;
|
||||
use crate::ty::codec::{TyDecoder, TyEncoder};
|
||||
|
@ -438,6 +438,17 @@ impl<'tcx> GlobalAlloc<'tcx> {
|
|||
_ => 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> {
|
||||
|
|
|
@ -128,7 +128,8 @@ impl PrimitiveExt for Primitive {
|
|||
Int(i, signed) => i.to_ty(tcx, signed),
|
||||
F32 => tcx.types.f32,
|
||||
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> {
|
||||
match *self {
|
||||
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"),
|
||||
}
|
||||
}
|
||||
|
@ -812,132 +817,125 @@ where
|
|||
let tcx = cx.tcx();
|
||||
let param_env = cx.param_env();
|
||||
|
||||
let addr_space_of_ty = |ty: Ty<'tcx>| {
|
||||
if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA }
|
||||
};
|
||||
|
||||
let pointee_info = match *this.ty.kind() {
|
||||
ty::RawPtr(mt) if offset.bytes() == 0 => {
|
||||
tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
|
||||
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;
|
||||
}
|
||||
let pointee_info =
|
||||
match *this.ty.kind() {
|
||||
ty::RawPtr(mt) if offset.bytes() == 0 => {
|
||||
tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
|
||||
size: layout.size,
|
||||
align: layout.align.abi,
|
||||
safe: None,
|
||||
})
|
||||
}
|
||||
|
||||
let mut result = None;
|
||||
|
||||
if let Some(variant) = data_variant {
|
||||
let ptr_end = offset + Pointer.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
|
||||
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 }
|
||||
})
|
||||
}
|
||||
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
|
||||
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 {
|
||||
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>`.
|
||||
if let Some(ref mut pointee) = result {
|
||||
if let ty::Adt(def, _) = this.ty.kind() {
|
||||
if def.is_box() && offset.bytes() == 0 {
|
||||
pointee.safe = Some(PointerKind::UniqueOwned);
|
||||
// FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
|
||||
if let Some(ref mut pointee) = result {
|
||||
if let ty::Adt(def, _) = this.ty.kind() {
|
||||
if def.is_box() && offset.bytes() == 0 {
|
||||
pointee.safe = Some(PointerKind::UniqueOwned);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
};
|
||||
result
|
||||
}
|
||||
};
|
||||
|
||||
debug!(
|
||||
"pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
|
||||
|
|
|
@ -147,6 +147,12 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
|||
ExprKind::AddressOf { mutability, arg } => Ok(
|
||||
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),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2372,7 +2372,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
/// Some special error handling for the "top-level" patterns in a match arm,
|
||||
/// `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 first_pat: P<Pat>,
|
||||
expected: Expected,
|
||||
|
@ -2383,26 +2383,41 @@ impl<'a> Parser<'a> {
|
|||
if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
|
||||
|| !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;
|
||||
}
|
||||
// The pattern looks like it might be a path with a `::` -> `:` typo:
|
||||
// `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
|
||||
// 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 `:`".
|
||||
match self.expected_one_of_not_found(&[], &[]) {
|
||||
Err(mut err) => {
|
||||
self.bump(); // Skip the `:`.
|
||||
match self.parse_pat_no_top_alt(expected) {
|
||||
snapshot_pat.bump(); // Skip the `:`.
|
||||
snapshot_type.bump(); // Skip the `:`.
|
||||
match snapshot_pat.parse_pat_no_top_alt(expected) {
|
||||
Err(inner_err) => {
|
||||
// Carry on as if we had not done anything, callers will emit a
|
||||
// reasonable error.
|
||||
inner_err.cancel();
|
||||
err.cancel();
|
||||
self.restore_snapshot(snapshot);
|
||||
}
|
||||
Ok(mut pat) => {
|
||||
// We've parsed the rest of the pattern.
|
||||
|
@ -2466,8 +2481,8 @@ impl<'a> Parser<'a> {
|
|||
_ => {}
|
||||
}
|
||||
if show_sugg {
|
||||
err.span_suggestion(
|
||||
span,
|
||||
err.span_suggestion_verbose(
|
||||
colon_span.until(self.look_ahead(1, |t| t.span)),
|
||||
"maybe write a path separator here",
|
||||
"::",
|
||||
Applicability::MaybeIncorrect,
|
||||
|
@ -2475,13 +2490,24 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
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.
|
||||
self.restore_snapshot(snapshot);
|
||||
}
|
||||
};
|
||||
first_pat
|
||||
|
|
|
@ -116,7 +116,8 @@ impl<'a> Parser<'a> {
|
|||
|
||||
// Check if the user wrote `foo:bar` instead of `foo::bar`.
|
||||
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 {
|
||||
|
|
|
@ -11,6 +11,7 @@ use rustc_ast::{
|
|||
self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
|
||||
MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
|
||||
};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
|
@ -43,17 +44,24 @@ pub(super) enum AllowPlus {
|
|||
No,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
pub(super) enum RecoverQPath {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
pub(super) enum RecoverQuestionMark {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
pub(super) enum RecoverAnonEnum {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
/// Signals whether parsing a type should recover `->`.
|
||||
///
|
||||
/// More specifically, when parsing a function like:
|
||||
|
@ -86,7 +94,7 @@ impl RecoverReturnSign {
|
|||
}
|
||||
|
||||
// Is `...` (`CVarArgs`) legal at this level of type parsing?
|
||||
#[derive(PartialEq)]
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
enum AllowCVariadic {
|
||||
Yes,
|
||||
No,
|
||||
|
@ -111,6 +119,7 @@ impl<'a> Parser<'a> {
|
|||
RecoverReturnSign::Yes,
|
||||
None,
|
||||
RecoverQuestionMark::Yes,
|
||||
RecoverAnonEnum::No,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -125,6 +134,7 @@ impl<'a> Parser<'a> {
|
|||
RecoverReturnSign::Yes,
|
||||
Some(ty_params),
|
||||
RecoverQuestionMark::Yes,
|
||||
RecoverAnonEnum::No,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -139,6 +149,7 @@ impl<'a> Parser<'a> {
|
|||
RecoverReturnSign::Yes,
|
||||
None,
|
||||
RecoverQuestionMark::Yes,
|
||||
RecoverAnonEnum::Yes,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -156,6 +167,7 @@ impl<'a> Parser<'a> {
|
|||
RecoverReturnSign::Yes,
|
||||
None,
|
||||
RecoverQuestionMark::Yes,
|
||||
RecoverAnonEnum::No,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -169,6 +181,7 @@ impl<'a> Parser<'a> {
|
|||
RecoverReturnSign::Yes,
|
||||
None,
|
||||
RecoverQuestionMark::No,
|
||||
RecoverAnonEnum::No,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -180,6 +193,7 @@ impl<'a> Parser<'a> {
|
|||
RecoverReturnSign::Yes,
|
||||
None,
|
||||
RecoverQuestionMark::No,
|
||||
RecoverAnonEnum::No,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -192,6 +206,7 @@ impl<'a> Parser<'a> {
|
|||
RecoverReturnSign::OnlyFatArrow,
|
||||
None,
|
||||
RecoverQuestionMark::Yes,
|
||||
RecoverAnonEnum::No,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -211,6 +226,7 @@ impl<'a> Parser<'a> {
|
|||
recover_return_sign,
|
||||
None,
|
||||
RecoverQuestionMark::Yes,
|
||||
RecoverAnonEnum::Yes,
|
||||
)?;
|
||||
FnRetTy::Ty(ty)
|
||||
} else if recover_return_sign.can_recover(&self.token.kind) {
|
||||
|
@ -232,6 +248,7 @@ impl<'a> Parser<'a> {
|
|||
recover_return_sign,
|
||||
None,
|
||||
RecoverQuestionMark::Yes,
|
||||
RecoverAnonEnum::Yes,
|
||||
)?;
|
||||
FnRetTy::Ty(ty)
|
||||
} else {
|
||||
|
@ -247,6 +264,7 @@ impl<'a> Parser<'a> {
|
|||
recover_return_sign: RecoverReturnSign,
|
||||
ty_generics: Option<&Generics>,
|
||||
recover_question_mark: RecoverQuestionMark,
|
||||
recover_anon_enum: RecoverAnonEnum,
|
||||
) -> PResult<'a, P<Ty>> {
|
||||
let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
|
||||
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);
|
||||
|
||||
// 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)?;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
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) }
|
||||
}
|
||||
|
||||
|
|
|
@ -6,11 +6,12 @@
|
|||
|
||||
use crate::errors::{
|
||||
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_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_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
|
||||
use rustc_hir as hir;
|
||||
|
@ -19,11 +20,12 @@ use rustc_hir::intravisit::{self, Visitor};
|
|||
use rustc_hir::{
|
||||
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::middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_middle::ty::{ParamEnv, TyCtxt};
|
||||
use rustc_session::lint::builtin::{
|
||||
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::{Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use std::cell::Cell;
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
pub(crate) fn target_from_impl_item<'tcx>(
|
||||
|
@ -62,8 +65,29 @@ enum ItemLike<'tcx> {
|
|||
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> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
||||
// Whether or not this visitor should abort after finding errors
|
||||
abort: Cell<bool>,
|
||||
}
|
||||
|
||||
impl CheckAttrVisitor<'_> {
|
||||
|
@ -173,7 +197,7 @@ impl CheckAttrVisitor<'_> {
|
|||
sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod),
|
||||
sym::plugin_registrar => self.check_plugin_registrar(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)
|
||||
}
|
||||
sym::automatically_derived => {
|
||||
|
@ -183,6 +207,16 @@ impl CheckAttrVisitor<'_> {
|
|||
self.check_generic_attr(hir_id, attr, target, Target::Mod)
|
||||
}
|
||||
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 },
|
||||
);
|
||||
}
|
||||
|
||||
/// 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> {
|
||||
|
@ -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) {
|
||||
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);
|
||||
if module_def_id.is_top_level_module() {
|
||||
check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
|
||||
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) {
|
||||
|
|
|
@ -12,6 +12,7 @@ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
|
|||
use rustc_middle::ty::{MainDefinition, Ty};
|
||||
use rustc_span::{Span, Symbol, DUMMY_SP};
|
||||
|
||||
use crate::check_attr::ProcMacroKind;
|
||||
use crate::lang_items::Duplicate;
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -1515,3 +1516,52 @@ pub struct ChangeFieldsToBeOfUnitType {
|
|||
#[suggestion_part(code = "()")]
|
||||
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,
|
||||
}
|
||||
|
|
|
@ -227,20 +227,27 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
|
|||
&& let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
|
||||
&& let Some(items) = self.diagnostic_metadata.current_impl_items
|
||||
&& 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);
|
||||
return true
|
||||
}
|
||||
false
|
||||
})
|
||||
&& let AssocItemKind::Fn(fn_) = &item.kind
|
||||
{
|
||||
debug!(?fn_);
|
||||
let self_sugg = if fn_.sig.decl.has_self() { "self." } else { "Self::" };
|
||||
let self_sugg = match &item.kind {
|
||||
AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => "self.",
|
||||
_ => "Self::",
|
||||
};
|
||||
|
||||
Some((
|
||||
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()
|
||||
))
|
||||
} else {
|
||||
|
|
|
@ -288,6 +288,7 @@ symbols! {
|
|||
Target,
|
||||
ToOwned,
|
||||
ToString,
|
||||
TokenStream,
|
||||
Try,
|
||||
TryCaptureGeneric,
|
||||
TryCapturePrintable,
|
||||
|
|
|
@ -39,7 +39,7 @@ where
|
|||
{
|
||||
match arg_layout.abi {
|
||||
Abi::Scalar(scalar) => match scalar.primitive() {
|
||||
abi::Int(..) | abi::Pointer => {
|
||||
abi::Int(..) | abi::Pointer(_) => {
|
||||
if arg_layout.size.bits() > xlen {
|
||||
return Err(CannotUseFpConv);
|
||||
}
|
||||
|
|
|
@ -346,7 +346,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
// The primitive for this algorithm.
|
||||
Abi::Scalar(scalar) => {
|
||||
let kind = match scalar.primitive() {
|
||||
abi::Int(..) | abi::Pointer => RegKind::Integer,
|
||||
abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
|
||||
abi::F32 | abi::F64 => RegKind::Float,
|
||||
};
|
||||
Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
|
||||
|
|
|
@ -45,7 +45,7 @@ where
|
|||
{
|
||||
match arg_layout.abi {
|
||||
Abi::Scalar(scalar) => match scalar.primitive() {
|
||||
abi::Int(..) | abi::Pointer => {
|
||||
abi::Int(..) | abi::Pointer(_) => {
|
||||
if arg_layout.size.bits() > xlen {
|
||||
return Err(CannotUseFpConv);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ where
|
|||
{
|
||||
let dl = cx.data_layout();
|
||||
|
||||
if !scalar.primitive().is_float() {
|
||||
if !matches!(scalar.primitive(), abi::F32 | abi::F64) {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -83,11 +83,11 @@ where
|
|||
(abi::F32, _) => offset += Reg::f32().size,
|
||||
(_, abi::F64) => offset += Reg::f64().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));
|
||||
}
|
||||
data = arg_scalar(cx, scalar2, offset, data);
|
||||
|
|
|
@ -50,7 +50,7 @@ where
|
|||
Abi::Uninhabited => return Ok(()),
|
||||
|
||||
Abi::Scalar(scalar) => match scalar.primitive() {
|
||||
abi::Int(..) | abi::Pointer => Class::Int,
|
||||
abi::Int(..) | abi::Pointer(_) => Class::Int,
|
||||
abi::F32 | abi::F64 => Class::Sse,
|
||||
},
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
|
|||
C: HasDataLayout,
|
||||
{
|
||||
match self.abi {
|
||||
Abi::Scalar(scalar) => scalar.primitive().is_float(),
|
||||
Abi::Scalar(scalar) => matches!(scalar.primitive(), F32 | F64),
|
||||
Abi::Aggregate { .. } => {
|
||||
if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
|
||||
self.field(cx, 0).is_single_fp_element(cx)
|
||||
|
|
|
@ -138,6 +138,16 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<'tcx> + Copy + Eq {
|
|||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||
goal: Goal<'tcx, Self>,
|
||||
) -> 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> {
|
||||
|
@ -266,6 +276,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
G::consider_builtin_tuple_candidate(self, goal)
|
||||
} else if lang_items.pointee_trait() == Some(trait_def_id) {
|
||||
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 {
|
||||
Err(NoSolution)
|
||||
};
|
||||
|
@ -321,9 +335,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
| ty::Tuple(_)
|
||||
| ty::Param(_)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Infer(_)
|
||||
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||
| 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,
|
||||
};
|
||||
|
||||
|
@ -371,9 +386,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
|||
| ty::Tuple(_)
|
||||
| ty::Param(_)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Infer(_)
|
||||
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||
| 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,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use std::mem;
|
||||
|
||||
use super::{Certainty, InferCtxtEvalExt};
|
||||
use rustc_infer::{
|
||||
infer::InferCtxt,
|
||||
traits::{
|
||||
query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
|
||||
SelectionError, TraitEngine,
|
||||
},
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::{
|
||||
query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
|
||||
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.
|
||||
///
|
||||
|
@ -70,9 +71,55 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
|
|||
Err(NoSolution) => {
|
||||
errors.push(FulfillmentError {
|
||||
obligation: obligation.clone(),
|
||||
code: FulfillmentErrorCode::CodeSelectionError(
|
||||
SelectionError::Unimplemented,
|
||||
),
|
||||
code: match goal.predicate.kind().skip_binder() {
|
||||
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,
|
||||
});
|
||||
continue;
|
||||
|
|
|
@ -277,12 +277,15 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
param_env,
|
||||
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),
|
||||
// FIXME: implement these predicates :)
|
||||
ty::PredicateKind::WellFormed(_)
|
||||
| ty::PredicateKind::ObjectSafe(_)
|
||||
| ty::PredicateKind::ConstEvaluatable(_)
|
||||
| ty::PredicateKind::ConstEquate(_, _) => {
|
||||
ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => {
|
||||
self.make_canonical_response(Certainty::Yes)
|
||||
}
|
||||
ty::PredicateKind::TypeWellFormedFromEnv(..) => {
|
||||
|
@ -362,6 +365,32 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
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> {
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
|
|||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{ProjectionPredicate, TypeSuperVisitable, TypeVisitor};
|
||||
use rustc_middle::ty::{ToPredicate, TypeVisitable};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_span::{sym, DUMMY_SP};
|
||||
use std::iter;
|
||||
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())])
|
||||
}
|
||||
|
||||
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.
|
||||
let sized_predicate = ty::Binder::dummy(tcx.at(DUMMY_SP).mk_trait_ref(
|
||||
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!(
|
||||
"unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
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.
|
||||
|
|
|
@ -192,6 +192,50 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
|||
) -> QueryResult<'tcx> {
|
||||
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> {
|
||||
|
|
|
@ -24,15 +24,16 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
|
|||
| ty::Never
|
||||
| ty::Char => Ok(vec![]),
|
||||
|
||||
ty::Placeholder(..)
|
||||
| ty::Dynamic(..)
|
||||
ty::Dynamic(..)
|
||||
| ty::Param(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Alias(ty::Projection, ..)
|
||||
| ty::Bound(..)
|
||||
| ty::Infer(ty::TyVar(_)) => Err(NoSolution),
|
||||
| ty::Placeholder(..) => 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, _) => {
|
||||
Ok(vec![element_ty])
|
||||
|
@ -99,11 +100,12 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
|
|||
| ty::Foreign(..)
|
||||
| ty::Alias(..)
|
||||
| ty::Param(_)
|
||||
| ty::Infer(ty::TyVar(_)) => Err(NoSolution),
|
||||
| ty::Placeholder(..) => Err(NoSolution),
|
||||
|
||||
ty::Placeholder(..)
|
||||
| ty::Bound(..)
|
||||
| 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::Tuple(tys) => Ok(tys.to_vec()),
|
||||
|
||||
|
@ -148,11 +150,12 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
|
|||
| ty::Adt(_, _)
|
||||
| ty::Alias(_, _)
|
||||
| ty::Param(_)
|
||||
| ty::Infer(ty::TyVar(_)) => Err(NoSolution),
|
||||
| ty::Placeholder(..) => Err(NoSolution),
|
||||
|
||||
ty::Placeholder(..)
|
||||
| ty::Bound(..)
|
||||
| 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::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>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
self_ty: Ty<'tcx>,
|
||||
|
@ -215,9 +219,13 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
|||
| ty::Tuple(_)
|
||||
| ty::Alias(_, _)
|
||||
| ty::Param(_)
|
||||
| ty::Placeholder(_)
|
||||
| ty::Bound(_, _)
|
||||
| ty::Infer(_)
|
||||
| ty::Placeholder(..)
|
||||
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
|
||||
| ty::Error(_) => Err(NoSolution),
|
||||
|
||||
ty::Bound(..)
|
||||
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||
bug!("unexpected type `{self_ty}`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ use rustc_hir as hir;
|
|||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
|
||||
use rustc_span::def_id::{DefId, LocalDefId};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use std::iter;
|
||||
/// Returns the set of obligations needed to make `arg` well-formed.
|
||||
|
@ -75,6 +75,34 @@ pub fn obligations<'tcx>(
|
|||
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
|
||||
/// 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
|
||||
|
|
|
@ -244,7 +244,7 @@ fn adjust_for_rust_scalar<'tcx>(
|
|||
}
|
||||
|
||||
// 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) {
|
||||
attrs.set(ArgAttribute::NonNull);
|
||||
|
@ -479,7 +479,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
|
|||
}
|
||||
|
||||
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();
|
||||
} else {
|
||||
// We want to pass small aggregates as immediates, but using
|
||||
|
|
|
@ -134,7 +134,7 @@ fn layout_of_uncached<'tcx>(
|
|||
ty::FloatTy::F64 => F64,
|
||||
}),
|
||||
ty::FnPtr(_) => {
|
||||
let mut ptr = scalar_unit(Pointer);
|
||||
let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
|
||||
ptr.valid_range_mut().start = 1;
|
||||
tcx.intern_layout(LayoutS::scalar(cx, ptr))
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ fn layout_of_uncached<'tcx>(
|
|||
|
||||
// Potentially-wide pointers.
|
||||
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() {
|
||||
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::Dynamic(..) => {
|
||||
let mut vtable = scalar_unit(Pointer);
|
||||
let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
|
||||
vtable.valid_range_mut().start = 1;
|
||||
vtable
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ fn layout_of_uncached<'tcx>(
|
|||
ty::Dynamic(_, _, ty::DynStar) => {
|
||||
let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false));
|
||||
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;
|
||||
tcx.intern_layout(cx.scalar_pair(data, vtable))
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ pub fn is_available() -> bool {
|
|||
///
|
||||
/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]`
|
||||
/// and `#[proc_macro_derive]` definitions.
|
||||
#[rustc_diagnostic_item = "TokenStream"]
|
||||
#[stable(feature = "proc_macro_lib", since = "1.15.0")]
|
||||
#[derive(Clone)]
|
||||
pub struct TokenStream(Option<bridge::client::TokenStream>);
|
||||
|
|
|
@ -16,12 +16,17 @@ fn main() {
|
|||
let mut build_lock;
|
||||
let _build_lock_guard;
|
||||
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() {
|
||||
Ok(lock) => lock,
|
||||
err => {
|
||||
println!("warning: build directory locked, waiting for lock");
|
||||
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())
|
||||
}
|
||||
};
|
||||
|
@ -98,3 +103,30 @@ fn check_version(config: &Config) -> Option<String> {
|
|||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
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))
|
||||
}
|
||||
|
|
26
tests/mir-opt/building/custom/operators.f.built.after.mir
Normal file
26
tests/mir-opt/building/custom/operators.f.built.after.mir
Normal 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
|
||||
}
|
||||
}
|
28
tests/mir-opt/building/custom/operators.rs
Normal file
28
tests/mir-opt/building/custom/operators.rs
Normal 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()
|
||||
})
|
||||
}
|
17
tests/ui/parser/anon-enums.rs
Normal file
17
tests/ui/parser/anon-enums.rs
Normal 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
|
||||
}
|
||||
}
|
68
tests/ui/parser/anon-enums.stderr
Normal file
68
tests/ui/parser/anon-enums.stderr
Normal 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
|
||||
|
20
tests/ui/parser/fake-anon-enums-in-macros.rs
Normal file
20
tests/ui/parser/fake-anon-enums-in-macros.rs
Normal 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);
|
||||
}
|
|
@ -68,7 +68,6 @@ fn main() {
|
|||
Foo:Bar::Baz => {}
|
||||
//~^ ERROR: expected one of
|
||||
//~| HELP: maybe write a path separator here
|
||||
//~| ERROR: failed to resolve: `Bar` is a variant, not a module
|
||||
}
|
||||
match myfoo {
|
||||
Foo::Bar => {}
|
||||
|
|
|
@ -2,89 +2,118 @@ error: expected one of `@` or `|`, found `:`
|
|||
--> $DIR/issue-87086-colon-path-sep.rs:17:12
|
||||
|
|
||||
LL | Foo:Bar => {}
|
||||
| ^
|
||||
| ^--- specifying the type of a pattern isn't supported
|
||||
| |
|
||||
| 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 `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:23:17
|
||||
|
|
||||
LL | qux::Foo:Bar => {}
|
||||
| ^
|
||||
| ^--- specifying the type of a pattern isn't supported
|
||||
| |
|
||||
| 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 `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:29:12
|
||||
|
|
||||
LL | qux:Foo::Baz => {}
|
||||
| ^
|
||||
| ^-------- specifying the type of a pattern isn't supported
|
||||
| |
|
||||
| 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 `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:35:12
|
||||
|
|
||||
LL | qux: Foo::Baz if true => {}
|
||||
| ^
|
||||
| ^ -------- specifying the type of a pattern isn't supported
|
||||
| |
|
||||
| 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 `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:40:15
|
||||
|
|
||||
LL | if let Foo:Bar = f() {
|
||||
| ^
|
||||
| ^--- specifying the type of a pattern isn't supported
|
||||
| |
|
||||
| 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 `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:48:16
|
||||
|
|
||||
LL | ref qux: Foo::Baz => {}
|
||||
| ^
|
||||
| ^ -------- specifying the type of a pattern isn't supported
|
||||
| |
|
||||
| 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 `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:57:16
|
||||
|
|
||||
LL | mut qux: Foo::Baz => {}
|
||||
| ^
|
||||
| ^ -------- specifying the type of a pattern isn't supported
|
||||
| |
|
||||
| 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 `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:68:12
|
||||
|
|
||||
LL | Foo:Bar::Baz => {}
|
||||
| ^
|
||||
| ^-------- specifying the type of a pattern isn't supported
|
||||
| |
|
||||
| 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 `:`
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:75:12
|
||||
--> $DIR/issue-87086-colon-path-sep.rs:74:12
|
||||
|
|
||||
LL | Foo:Bar => {}
|
||||
| ^
|
||||
| ^--- specifying the type of a pattern isn't supported
|
||||
| |
|
||||
| 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 => {}
|
||||
| ^^^ `Bar` is a variant, not a module
|
||||
help: maybe write a path separator here
|
||||
|
|
||||
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`.
|
||||
|
|
26
tests/ui/proc-macro/allowed-signatures.rs
Normal file
26
tests/ui/proc-macro/allowed-signatures.rs
Normal 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()
|
||||
}
|
31
tests/ui/proc-macro/proc-macro-abi.rs
Normal file
31
tests/ui/proc-macro/proc-macro-abi.rs
Normal 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
|
||||
}
|
20
tests/ui/proc-macro/proc-macro-abi.stderr
Normal file
20
tests/ui/proc-macro/proc-macro-abi.stderr
Normal 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
|
||||
|
32
tests/ui/proc-macro/signature-proc-macro-attribute.rs
Normal file
32
tests/ui/proc-macro/signature-proc-macro-attribute.rs
Normal 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
|
||||
}
|
42
tests/ui/proc-macro/signature-proc-macro-attribute.stderr
Normal file
42
tests/ui/proc-macro/signature-proc-macro-attribute.stderr
Normal 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
|
||||
|
31
tests/ui/proc-macro/signature-proc-macro-derive.rs
Normal file
31
tests/ui/proc-macro/signature-proc-macro-derive.rs
Normal 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
|
||||
}
|
40
tests/ui/proc-macro/signature-proc-macro-derive.stderr
Normal file
40
tests/ui/proc-macro/signature-proc-macro-derive.stderr
Normal 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
|
||||
|
31
tests/ui/proc-macro/signature-proc-macro.rs
Normal file
31
tests/ui/proc-macro/signature-proc-macro.rs
Normal 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
|
||||
}
|
40
tests/ui/proc-macro/signature-proc-macro.stderr
Normal file
40
tests/ui/proc-macro/signature-proc-macro.stderr
Normal 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
|
||||
|
|
@ -8,6 +8,10 @@ extern crate proc_macro;
|
|||
|
||||
#[proc_macro_derive(A)]
|
||||
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 {}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
||||
LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
|
||||
LL | |
|
||||
LL | | loop {}
|
||||
LL | | }
|
||||
| | ^
|
||||
| | |
|
||||
| |_call the function in a closure: `|| unsafe { /* code */ }`
|
||||
| required by a bound introduced by this call
|
||||
LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: proc macro functions may not be `unsafe`
|
||||
--> $DIR/signature.rs:10:1
|
||||
|
|
||||
= help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for fn item `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
|
||||
= 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
|
||||
LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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`.
|
||||
|
|
11
tests/ui/suggestions/assoc-const-without-self.rs
Normal file
11
tests/ui/suggestions/assoc-const-without-self.rs
Normal 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() {}
|
14
tests/ui/suggestions/assoc-const-without-self.stderr
Normal file
14
tests/ui/suggestions/assoc-const-without-self.stderr
Normal 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`.
|
17
tests/ui/traits/new-solver/async.fail.stderr
Normal file
17
tests/ui/traits/new-solver/async.fail.stderr
Normal 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`.
|
19
tests/ui/traits/new-solver/async.rs
Normal file
19
tests/ui/traits/new-solver/async.rs
Normal 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 });
|
||||
}
|
64
tests/ui/traits/new-solver/generator.fail.stderr
Normal file
64
tests/ui/traits/new-solver/generator.fail.stderr
Normal 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`.
|
32
tests/ui/traits/new-solver/generator.rs
Normal file
32
tests/ui/traits/new-solver/generator.rs
Normal 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
|
||||
})
|
||||
}
|
20
tests/ui/typeck/bad-type-in-vec-push.rs
Normal file
20
tests/ui/typeck/bad-type-in-vec-push.rs
Normal 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
|
||||
}
|
29
tests/ui/typeck/bad-type-in-vec-push.stderr
Normal file
29
tests/ui/typeck/bad-type-in-vec-push.stderr
Normal 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`.
|
|
@ -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).)
|
||||
"""
|
||||
|
||||
[mentions."src/doc/style-guide"]
|
||||
cc = ["@rust-lang/style"]
|
||||
|
||||
[assign]
|
||||
warn_non_default_branch = true
|
||||
contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html"
|
||||
|
@ -560,6 +563,12 @@ ast_lowering = [
|
|||
fallback = [
|
||||
"@Mark-Simulacrum"
|
||||
]
|
||||
style-team = [
|
||||
"@calebcartwright",
|
||||
"@compiler-errors",
|
||||
"@joshtriplett",
|
||||
"@yaahc",
|
||||
]
|
||||
|
||||
[assign.owners]
|
||||
"/.github/workflows" = ["infra-ci"]
|
||||
|
@ -604,6 +613,7 @@ fallback = [
|
|||
"/src/doc/rust-by-example" = ["@ehuss"]
|
||||
"/src/doc/rustc-dev-guide" = ["@ehuss"]
|
||||
"/src/doc/rustdoc" = ["rustdoc"]
|
||||
"/src/doc/style-guide" = ["style-team"]
|
||||
"/src/etc" = ["@Mark-Simulacrum"]
|
||||
"/src/librustdoc" = ["rustdoc"]
|
||||
"/src/llvm-project" = ["@cuviper"]
|
||||
|
|
Loading…
Reference in a new issue