Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b820c76

Browse files
committedJul 6, 2019
Auto merge of #62428 - Centril:rollup-2udow5e, r=Centril
Rollup of 7 pull requests Successful merges: - #62151 (Update linked OpenSSL version) - #62245 (Miri engine: support extra function (pointer) values) - #62257 (forward read_c_str method from Memory to Alloc) - #62264 (Fix perf regression from Miri Machine trait changes) - #62296 (request at least ptr-size alignment from posix_memalign) - #62329 (Remove support for 1-token lookahead from the lexer) - #62377 (Add test for ICE #62375) Failed merges: r? @ghost
2 parents 481068a + 46edb51 commit b820c76

File tree

25 files changed

+511
-385
lines changed

25 files changed

+511
-385
lines changed
 

‎Cargo.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1835,7 +1835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
18351835

18361836
[[package]]
18371837
name = "openssl-src"
1838-
version = "111.1.0+1.1.1a"
1838+
version = "111.3.0+1.1.1c"
18391839
source = "registry+https://github.com/rust-lang/crates.io-index"
18401840
dependencies = [
18411841
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1848,7 +1848,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
18481848
dependencies = [
18491849
"cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)",
18501850
"libc 0.2.54 (registry+https://github.com/rust-lang/crates.io-index)",
1851-
"openssl-src 111.1.0+1.1.1a (registry+https://github.com/rust-lang/crates.io-index)",
1851+
"openssl-src 111.3.0+1.1.1c (registry+https://github.com/rust-lang/crates.io-index)",
18521852
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
18531853
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
18541854
"vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -4384,7 +4384,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
43844384
"checksum opener 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "998c59e83d9474c01127a96e023b7a04bb061dd286bf8bb939d31dc8d31a7448"
43854385
"checksum openssl 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "ec7bd7ca4cce6dbdc77e7c1230682740d307d1218a87fb0349a571272be749f9"
43864386
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
4387-
"checksum openssl-src 111.1.0+1.1.1a (registry+https://github.com/rust-lang/crates.io-index)" = "26bb632127731bf4ac49bf86a5dde12d2ca0918c2234fc39d79d4da2ccbc6da7"
4387+
"checksum openssl-src 111.3.0+1.1.1c (registry+https://github.com/rust-lang/crates.io-index)" = "53ed5f31d294bdf5f7a4ba0a206c2754b0f60e9a63b7e3076babc5317873c797"
43884388
"checksum openssl-sys 0.9.43 (registry+https://github.com/rust-lang/crates.io-index)" = "33c86834957dd5b915623e94f2f4ab2c70dd8f6b70679824155d5ae21dbd495d"
43894389
"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
43904390
"checksum ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024"

‎src/liballoc/tests/heap.rs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::alloc::{Global, Alloc, Layout, System};
22

3-
/// Issue #45955.
3+
/// Issue #45955 and #62251.
44
#[test]
55
fn alloc_system_overaligned_request() {
66
check_overalign_requests(System)
@@ -12,21 +12,23 @@ fn std_heap_overaligned_request() {
1212
}
1313

1414
fn check_overalign_requests<T: Alloc>(mut allocator: T) {
15-
let size = 8;
16-
let align = 16; // greater than size
17-
let iterations = 100;
18-
unsafe {
19-
let pointers: Vec<_> = (0..iterations).map(|_| {
20-
allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap()
21-
}).collect();
22-
for &ptr in &pointers {
23-
assert_eq!((ptr.as_ptr() as usize) % align, 0,
24-
"Got a pointer less aligned than requested")
25-
}
15+
for &align in &[4, 8, 16, 32] { // less than and bigger than `MIN_ALIGN`
16+
for &size in &[align/2, align-1] { // size less than alignment
17+
let iterations = 128;
18+
unsafe {
19+
let pointers: Vec<_> = (0..iterations).map(|_| {
20+
allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap()
21+
}).collect();
22+
for &ptr in &pointers {
23+
assert_eq!((ptr.as_ptr() as usize) % align, 0,
24+
"Got a pointer less aligned than requested")
25+
}
2626

27-
// Clean up
28-
for &ptr in &pointers {
29-
allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap())
27+
// Clean up
28+
for &ptr in &pointers {
29+
allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap())
30+
}
31+
}
3032
}
3133
}
3234
}

‎src/librustc_mir/const_eval.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc::hir::def::DefKind;
1111
use rustc::hir::def_id::DefId;
1212
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled, ScalarMaybeUndef};
1313
use rustc::mir;
14-
use rustc::ty::{self, TyCtxt, query::TyCtxtAt};
14+
use rustc::ty::{self, TyCtxt};
1515
use rustc::ty::layout::{self, LayoutOf, VariantIdx};
1616
use rustc::ty::subst::Subst;
1717
use rustc::traits::Reveal;
@@ -23,7 +23,7 @@ use crate::interpret::{self,
2323
PlaceTy, MPlaceTy, OpTy, ImmTy, Immediate, Scalar,
2424
RawConst, ConstValue,
2525
InterpResult, InterpErrorInfo, InterpError, GlobalId, InterpCx, StackPopCleanup,
26-
Allocation, AllocId, MemoryKind, Memory,
26+
Allocation, AllocId, MemoryKind,
2727
snapshot, RefTracking, intern_const_alloc_recursive,
2828
};
2929

@@ -316,6 +316,7 @@ impl interpret::MayLeak for ! {
316316
impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, 'tcx> {
317317
type MemoryKinds = !;
318318
type PointerTag = ();
319+
type ExtraFnVal = !;
319320

320321
type FrameExtra = ();
321322
type MemoryExtra = ();
@@ -370,6 +371,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
370371
}))
371372
}
372373

374+
fn call_extra_fn(
375+
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
376+
fn_val: !,
377+
_args: &[OpTy<'tcx>],
378+
_dest: Option<PlaceTy<'tcx>>,
379+
_ret: Option<mir::BasicBlock>,
380+
) -> InterpResult<'tcx> {
381+
match fn_val {}
382+
}
383+
373384
fn call_intrinsic(
374385
ecx: &mut InterpCx<'mir, 'tcx, Self>,
375386
instance: ty::Instance<'tcx>,
@@ -398,27 +409,27 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
398409
}
399410

400411
fn find_foreign_static(
412+
_tcx: TyCtxt<'tcx>,
401413
_def_id: DefId,
402-
_tcx: TyCtxtAt<'tcx>,
403414
) -> InterpResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
404415
err!(ReadForeignStatic)
405416
}
406417

407418
#[inline(always)]
408419
fn tag_allocation<'b>(
420+
_memory_extra: &(),
409421
_id: AllocId,
410422
alloc: Cow<'b, Allocation>,
411423
_kind: Option<MemoryKind<!>>,
412-
_memory: &Memory<'mir, 'tcx, Self>,
413424
) -> (Cow<'b, Allocation<Self::PointerTag>>, Self::PointerTag) {
414425
// We do not use a tag so we can just cheaply forward the allocation
415426
(alloc, ())
416427
}
417428

418429
#[inline(always)]
419430
fn tag_static_base_pointer(
431+
_memory_extra: &(),
420432
_id: AllocId,
421-
_memory: &Memory<'mir, 'tcx, Self>,
422433
) -> Self::PointerTag {
423434
()
424435
}

‎src/librustc_mir/interpret/cast.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rustc::mir::interpret::{
1111
};
1212
use rustc::mir::CastKind;
1313

14-
use super::{InterpCx, Machine, PlaceTy, OpTy, Immediate};
14+
use super::{InterpCx, Machine, PlaceTy, OpTy, Immediate, FnVal};
1515

1616
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
1717
fn type_is_fat_ptr(&self, ty: Ty<'tcx>) -> bool {
@@ -86,7 +86,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
8686
def_id,
8787
substs,
8888
).ok_or_else(|| InterpError::TooGeneric.into());
89-
let fn_ptr = self.memory.create_fn_alloc(instance?);
89+
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance?));
9090
self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
9191
}
9292
_ => bug!("reify fn pointer on {:?}", src.layout.ty),
@@ -115,7 +115,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
115115
substs,
116116
ty::ClosureKind::FnOnce,
117117
);
118-
let fn_ptr = self.memory.create_fn_alloc(instance);
118+
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
119119
let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
120120
self.write_immediate(val, dest)?;
121121
}

‎src/librustc_mir/interpret/eval_context.rs

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,23 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
222222
&mut self.memory
223223
}
224224

225+
#[inline(always)]
226+
pub fn force_ptr(
227+
&self,
228+
scalar: Scalar<M::PointerTag>,
229+
) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
230+
self.memory.force_ptr(scalar)
231+
}
232+
233+
#[inline(always)]
234+
pub fn force_bits(
235+
&self,
236+
scalar: Scalar<M::PointerTag>,
237+
size: Size
238+
) -> InterpResult<'tcx, u128> {
239+
self.memory.force_bits(scalar, size)
240+
}
241+
225242
#[inline(always)]
226243
pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer<M::PointerTag> {
227244
self.memory.tag_static_base_pointer(ptr)
@@ -253,6 +270,27 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
253270
self.frame().body
254271
}
255272

273+
#[inline(always)]
274+
pub fn sign_extend(&self, value: u128, ty: TyLayout<'_>) -> u128 {
275+
assert!(ty.abi.is_signed());
276+
sign_extend(value, ty.size)
277+
}
278+
279+
#[inline(always)]
280+
pub fn truncate(&self, value: u128, ty: TyLayout<'_>) -> u128 {
281+
truncate(value, ty.size)
282+
}
283+
284+
#[inline]
285+
pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
286+
ty.is_sized(self.tcx, self.param_env)
287+
}
288+
289+
#[inline]
290+
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
291+
ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP)
292+
}
293+
256294
pub(super) fn subst_and_normalize_erasing_regions<T: TypeFoldable<'tcx>>(
257295
&self,
258296
substs: T,
@@ -288,14 +326,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
288326
).ok_or_else(|| InterpError::TooGeneric.into())
289327
}
290328

291-
pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
292-
ty.is_sized(self.tcx, self.param_env)
293-
}
294-
295-
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
296-
ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP)
297-
}
298-
299329
pub fn load_mir(
300330
&self,
301331
instance: ty::InstanceDef<'tcx>,
@@ -766,32 +796,4 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
766796
trace!("generate stacktrace: {:#?}, {:?}", frames, explicit_span);
767797
frames
768798
}
769-
770-
#[inline(always)]
771-
pub fn sign_extend(&self, value: u128, ty: TyLayout<'_>) -> u128 {
772-
assert!(ty.abi.is_signed());
773-
sign_extend(value, ty.size)
774-
}
775-
776-
#[inline(always)]
777-
pub fn truncate(&self, value: u128, ty: TyLayout<'_>) -> u128 {
778-
truncate(value, ty.size)
779-
}
780-
781-
#[inline(always)]
782-
pub fn force_ptr(
783-
&self,
784-
scalar: Scalar<M::PointerTag>,
785-
) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
786-
self.memory.force_ptr(scalar)
787-
}
788-
789-
#[inline(always)]
790-
pub fn force_bits(
791-
&self,
792-
scalar: Scalar<M::PointerTag>,
793-
size: Size
794-
) -> InterpResult<'tcx, u128> {
795-
self.memory.force_bits(scalar, size)
796-
}
797799
}

‎src/librustc_mir/interpret/machine.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ use std::hash::Hash;
77

88
use rustc::hir::def_id::DefId;
99
use rustc::mir;
10-
use rustc::ty::{self, query::TyCtxtAt};
10+
use rustc::ty::{self, TyCtxt};
1111

1212
use super::{
13-
Allocation, AllocId, InterpResult, Scalar, AllocationExtra,
14-
InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory
13+
Allocation, AllocId, InterpResult, InterpError, Scalar, AllocationExtra,
14+
InterpCx, PlaceTy, OpTy, ImmTy, MemoryKind, Pointer, Memory,
1515
};
1616

1717
/// Whether this kind of memory is allowed to leak
@@ -67,6 +67,11 @@ pub trait Machine<'mir, 'tcx>: Sized {
6767
/// The `default()` is used for pointers to consts, statics, vtables and functions.
6868
type PointerTag: ::std::fmt::Debug + Copy + Eq + Hash + 'static;
6969

70+
/// Machines can define extra (non-instance) things that represent values of function pointers.
71+
/// For example, Miri uses this to return a fucntion pointer from `dlsym`
72+
/// that can later be called to execute the right thing.
73+
type ExtraFnVal: ::std::fmt::Debug + Copy;
74+
7075
/// Extra data stored in every call frame.
7176
type FrameExtra;
7277

@@ -119,6 +124,16 @@ pub trait Machine<'mir, 'tcx>: Sized {
119124
ret: Option<mir::BasicBlock>,
120125
) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>;
121126

127+
/// Execute `fn_val`. it is the hook's responsibility to advance the instruction
128+
/// pointer as appropriate.
129+
fn call_extra_fn(
130+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
131+
fn_val: Self::ExtraFnVal,
132+
args: &[OpTy<'tcx, Self::PointerTag>],
133+
dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
134+
ret: Option<mir::BasicBlock>,
135+
) -> InterpResult<'tcx>;
136+
122137
/// Directly process an intrinsic without pushing a stack frame.
123138
/// If this returns successfully, the engine will take care of jumping to the next block.
124139
fn call_intrinsic(
@@ -136,8 +151,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
136151
///
137152
/// This allocation will then be fed to `tag_allocation` to initialize the "extra" state.
138153
fn find_foreign_static(
154+
tcx: TyCtxt<'tcx>,
139155
def_id: DefId,
140-
tcx: TyCtxtAt<'tcx>,
141156
) -> InterpResult<'tcx, Cow<'tcx, Allocation>>;
142157

143158
/// Called for all binary operations on integer(-like) types when one operand is a pointer
@@ -174,10 +189,10 @@ pub trait Machine<'mir, 'tcx>: Sized {
174189
/// For static allocations, the tag returned must be the same as the one returned by
175190
/// `tag_static_base_pointer`.
176191
fn tag_allocation<'b>(
192+
memory_extra: &Self::MemoryExtra,
177193
id: AllocId,
178194
alloc: Cow<'b, Allocation>,
179195
kind: Option<MemoryKind<Self::MemoryKinds>>,
180-
memory: &Memory<'mir, 'tcx, Self>,
181196
) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag);
182197

183198
/// Return the "base" tag for the given static allocation: the one that is used for direct
@@ -186,8 +201,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
186201
/// Be aware that requesting the `Allocation` for that `id` will lead to cycles
187202
/// for cyclic statics!
188203
fn tag_static_base_pointer(
204+
memory_extra: &Self::MemoryExtra,
189205
id: AllocId,
190-
memory: &Memory<'mir, 'tcx, Self>,
191206
) -> Self::PointerTag;
192207

193208
/// Executes a retagging operation
@@ -209,20 +224,22 @@ pub trait Machine<'mir, 'tcx>: Sized {
209224
extra: Self::FrameExtra,
210225
) -> InterpResult<'tcx>;
211226

227+
#[inline(always)]
212228
fn int_to_ptr(
213-
int: u64,
214229
_mem: &Memory<'mir, 'tcx, Self>,
230+
int: u64,
215231
) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
216-
if int == 0 {
217-
err!(InvalidNullPointerUsage)
232+
Err((if int == 0 {
233+
InterpError::InvalidNullPointerUsage
218234
} else {
219-
err!(ReadBytesAsPointer)
220-
}
235+
InterpError::ReadBytesAsPointer
236+
}).into())
221237
}
222238

239+
#[inline(always)]
223240
fn ptr_to_int(
224-
_ptr: Pointer<Self::PointerTag>,
225241
_mem: &Memory<'mir, 'tcx, Self>,
242+
_ptr: Pointer<Self::PointerTag>,
226243
) -> InterpResult<'tcx, u64> {
227244
err!(ReadPointerAsBytes)
228245
}

‎src/librustc_mir/interpret/memory.rs

Lines changed: 105 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,26 @@ pub enum AllocCheck {
5454
MaybeDead,
5555
}
5656

57+
/// The value of a function pointer.
58+
#[derive(Debug, Copy, Clone)]
59+
pub enum FnVal<'tcx, Other> {
60+
Instance(Instance<'tcx>),
61+
Other(Other),
62+
}
63+
64+
impl<'tcx, Other> FnVal<'tcx, Other> {
65+
pub fn as_instance(self) -> InterpResult<'tcx, Instance<'tcx>> {
66+
match self {
67+
FnVal::Instance(instance) =>
68+
Ok(instance),
69+
FnVal::Other(_) =>
70+
err!(MachineError(
71+
format!("Expected instance function pointer, got 'other' pointer")
72+
)),
73+
}
74+
}
75+
}
76+
5777
// `Memory` has to depend on the `Machine` because some of its operations
5878
// (e.g., `get`) call a `Machine` hook.
5979
pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
@@ -69,16 +89,20 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
6989
// FIXME: this should not be public, but interning currently needs access to it
7090
pub(super) alloc_map: M::MemoryMap,
7191

92+
/// Map for "extra" function pointers.
93+
extra_fn_ptr_map: FxHashMap<AllocId, M::ExtraFnVal>,
94+
7295
/// To be able to compare pointers with NULL, and to check alignment for accesses
7396
/// to ZSTs (where pointers may dangle), we keep track of the size even for allocations
7497
/// that do not exist any more.
98+
// FIXME: this should not be public, but interning currently needs access to it
7599
pub(super) dead_alloc_map: FxHashMap<AllocId, (Size, Align)>,
76100

77101
/// Extra data added by the machine.
78102
pub extra: M::MemoryExtra,
79103

80104
/// Lets us implement `HasDataLayout`, which is awfully convenient.
81-
pub(super) tcx: TyCtxtAt<'tcx>,
105+
pub tcx: TyCtxtAt<'tcx>,
82106
}
83107

84108
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M> {
@@ -98,6 +122,7 @@ where
98122
fn clone(&self) -> Self {
99123
Memory {
100124
alloc_map: self.alloc_map.clone(),
125+
extra_fn_ptr_map: self.extra_fn_ptr_map.clone(),
101126
dead_alloc_map: self.dead_alloc_map.clone(),
102127
extra: (),
103128
tcx: self.tcx,
@@ -109,6 +134,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
109134
pub fn new(tcx: TyCtxtAt<'tcx>, extra: M::MemoryExtra) -> Self {
110135
Memory {
111136
alloc_map: M::MemoryMap::default(),
137+
extra_fn_ptr_map: FxHashMap::default(),
112138
dead_alloc_map: FxHashMap::default(),
113139
extra,
114140
tcx,
@@ -117,11 +143,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
117143

118144
#[inline]
119145
pub fn tag_static_base_pointer(&self, ptr: Pointer) -> Pointer<M::PointerTag> {
120-
ptr.with_tag(M::tag_static_base_pointer(ptr.alloc_id, &self))
146+
ptr.with_tag(M::tag_static_base_pointer(&self.extra, ptr.alloc_id))
121147
}
122148

123-
pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer<M::PointerTag> {
124-
let id = self.tcx.alloc_map.lock().create_fn_alloc(instance);
149+
pub fn create_fn_alloc(
150+
&mut self,
151+
fn_val: FnVal<'tcx, M::ExtraFnVal>,
152+
) -> Pointer<M::PointerTag>
153+
{
154+
let id = match fn_val {
155+
FnVal::Instance(instance) => self.tcx.alloc_map.lock().create_fn_alloc(instance),
156+
FnVal::Other(extra) => {
157+
// FIXME(RalfJung): Should we have a cache here?
158+
let id = self.tcx.alloc_map.lock().reserve();
159+
let old = self.extra_fn_ptr_map.insert(id, extra);
160+
assert!(old.is_none());
161+
id
162+
}
163+
};
125164
self.tag_static_base_pointer(Pointer::from(id))
126165
}
127166

@@ -150,7 +189,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
150189
kind: MemoryKind<M::MemoryKinds>,
151190
) -> Pointer<M::PointerTag> {
152191
let id = self.tcx.alloc_map.lock().reserve();
153-
let (alloc, tag) = M::tag_allocation(id, Cow::Owned(alloc), Some(kind), &self);
192+
let (alloc, tag) = M::tag_allocation(&self.extra, id, Cow::Owned(alloc), Some(kind));
154193
self.alloc_map.insert(id, (kind, alloc.into_owned()));
155194
Pointer::from(id).with_tag(tag)
156195
}
@@ -368,9 +407,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
368407
/// contains a reference to memory that was created during its evaluation (i.e., not to
369408
/// another static), those inner references only exist in "resolved" form.
370409
fn get_static_alloc(
371-
id: AllocId,
410+
memory_extra: &M::MemoryExtra,
372411
tcx: TyCtxtAt<'tcx>,
373-
memory: &Memory<'mir, 'tcx, M>,
412+
id: AllocId,
374413
) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> {
375414
let alloc = tcx.alloc_map.lock().get(id);
376415
let alloc = match alloc {
@@ -384,7 +423,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
384423
// We got a "lazy" static that has not been computed yet.
385424
if tcx.is_foreign_item(def_id) {
386425
trace!("static_alloc: foreign item {:?}", def_id);
387-
M::find_foreign_static(def_id, tcx)?
426+
M::find_foreign_static(tcx.tcx, def_id)?
388427
} else {
389428
trace!("static_alloc: Need to compute {:?}", def_id);
390429
let instance = Instance::mono(tcx.tcx, def_id);
@@ -414,10 +453,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
414453
// We got tcx memory. Let the machine figure out whether and how to
415454
// turn that into memory with the right pointer tag.
416455
Ok(M::tag_allocation(
456+
memory_extra,
417457
id, // always use the ID we got as input, not the "hidden" one.
418458
alloc,
419459
M::STATIC_KIND.map(MemoryKind::Machine),
420-
memory
421460
).0)
422461
}
423462

@@ -430,7 +469,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
430469
// `get_static_alloc` that we can actually use directly without inserting anything anywhere.
431470
// So the error type is `InterpResult<'tcx, &Allocation<M::PointerTag>>`.
432471
let a = self.alloc_map.get_or(id, || {
433-
let alloc = Self::get_static_alloc(id, self.tcx, &self).map_err(Err)?;
472+
let alloc = Self::get_static_alloc(&self.extra, self.tcx, id).map_err(Err)?;
434473
match alloc {
435474
Cow::Borrowed(alloc) => {
436475
// We got a ref, cheaply return that as an "error" so that the
@@ -459,11 +498,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
459498
id: AllocId,
460499
) -> InterpResult<'tcx, &mut Allocation<M::PointerTag, M::AllocExtra>> {
461500
let tcx = self.tcx;
462-
let alloc = Self::get_static_alloc(id, tcx, &self);
501+
let memory_extra = &self.extra;
463502
let a = self.alloc_map.get_mut_or(id, || {
464503
// Need to make a copy, even if `get_static_alloc` is able
465504
// to give us a cheap reference.
466-
let alloc = alloc?;
505+
let alloc = Self::get_static_alloc(memory_extra, tcx, id)?;
467506
if alloc.mutability == Mutability::Immutable {
468507
return err!(ModifiedConstantMemory);
469508
}
@@ -495,56 +534,65 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
495534
id: AllocId,
496535
liveness: AllocCheck,
497536
) -> InterpResult<'static, (Size, Align)> {
537+
// Regular allocations.
498538
if let Ok(alloc) = self.get(id) {
499539
return Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align));
500540
}
501-
// can't do this in the match argument, we may get cycle errors since the lock would get
502-
// dropped after the match.
541+
// Function pointers.
542+
if let Ok(_) = self.get_fn_alloc(id) {
543+
return if let AllocCheck::Dereferencable = liveness {
544+
// The caller requested no function pointers.
545+
err!(DerefFunctionPointer)
546+
} else {
547+
Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
548+
};
549+
}
550+
// Foreign statics.
551+
// Can't do this in the match argument, we may get cycle errors since the lock would
552+
// be held throughout the match.
503553
let alloc = self.tcx.alloc_map.lock().get(id);
504-
// Could also be a fn ptr or extern static
505554
match alloc {
506-
Some(GlobalAlloc::Function(..)) => {
507-
if let AllocCheck::Dereferencable = liveness {
508-
// The caller requested no function pointers.
509-
err!(DerefFunctionPointer)
510-
} else {
511-
Ok((Size::ZERO, Align::from_bytes(1).unwrap()))
512-
}
513-
}
514-
// `self.get` would also work, but can cause cycles if a static refers to itself
515555
Some(GlobalAlloc::Static(did)) => {
516-
// The only way `get` couldn't have worked here is if this is an extern static
517556
assert!(self.tcx.is_foreign_item(did));
518557
// Use size and align of the type
519558
let ty = self.tcx.type_of(did);
520559
let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
521-
Ok((layout.size, layout.align.abi))
560+
return Ok((layout.size, layout.align.abi));
522561
}
523-
_ => {
524-
if let Ok(alloc) = self.get(id) {
525-
Ok((Size::from_bytes(alloc.bytes.len() as u64), alloc.align))
526-
}
527-
else if let AllocCheck::MaybeDead = liveness {
528-
// Deallocated pointers are allowed, we should be able to find
529-
// them in the map.
530-
Ok(*self.dead_alloc_map.get(&id)
531-
.expect("deallocated pointers should all be recorded in `dead_alloc_map`"))
532-
} else {
533-
err!(DanglingPointerDeref)
534-
}
535-
},
562+
_ => {}
563+
}
564+
// The rest must be dead.
565+
if let AllocCheck::MaybeDead = liveness {
566+
// Deallocated pointers are allowed, we should be able to find
567+
// them in the map.
568+
Ok(*self.dead_alloc_map.get(&id)
569+
.expect("deallocated pointers should all be recorded in `dead_alloc_map`"))
570+
} else {
571+
err!(DanglingPointerDeref)
536572
}
537573
}
538574

539-
pub fn get_fn(&self, ptr: Pointer<M::PointerTag>) -> InterpResult<'tcx, Instance<'tcx>> {
575+
fn get_fn_alloc(&self, id: AllocId) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
576+
trace!("reading fn ptr: {}", id);
577+
if let Some(extra) = self.extra_fn_ptr_map.get(&id) {
578+
Ok(FnVal::Other(*extra))
579+
} else {
580+
match self.tcx.alloc_map.lock().get(id) {
581+
Some(GlobalAlloc::Function(instance)) => Ok(FnVal::Instance(instance)),
582+
_ => Err(InterpError::ExecuteMemory.into()),
583+
}
584+
}
585+
}
586+
587+
pub fn get_fn(
588+
&self,
589+
ptr: Scalar<M::PointerTag>,
590+
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
591+
let ptr = self.force_ptr(ptr)?; // We definitely need a pointer value.
540592
if ptr.offset.bytes() != 0 {
541593
return err!(InvalidFunctionPointer);
542594
}
543-
trace!("reading fn ptr: {}", ptr.alloc_id);
544-
match self.tcx.alloc_map.lock().get(ptr.alloc_id) {
545-
Some(GlobalAlloc::Function(instance)) => Ok(instance),
546-
_ => Err(InterpError::ExecuteMemory.into()),
547-
}
595+
self.get_fn_alloc(ptr.alloc_id)
548596
}
549597

550598
pub fn mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {
@@ -680,6 +728,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
680728

681729
/// Reading and writing.
682730
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
731+
/// Reads the given number of bytes from memory. Returns them as a slice.
732+
///
683733
/// Performs appropriate bounds checks.
684734
pub fn read_bytes(
685735
&self,
@@ -693,6 +743,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
693743
self.get(ptr.alloc_id)?.get_bytes(self, ptr, size)
694744
}
695745

746+
/// Reads a 0-terminated sequence of bytes from memory. Returns them as a slice.
747+
///
748+
/// Performs appropriate bounds checks.
749+
pub fn read_c_str(&self, ptr: Scalar<M::PointerTag>) -> InterpResult<'tcx, &[u8]> {
750+
let ptr = self.force_ptr(ptr)?; // We need to read at least 1 byte, so we *need* a ptr.
751+
self.get(ptr.alloc_id)?.read_c_str(self, ptr)
752+
}
753+
696754
/// Performs appropriate bounds checks.
697755
pub fn copy(
698756
&mut self,
@@ -890,7 +948,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
890948
) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
891949
match scalar {
892950
Scalar::Ptr(ptr) => Ok(ptr),
893-
_ => M::int_to_ptr(scalar.to_usize(self)?, self)
951+
_ => M::int_to_ptr(&self, scalar.to_usize(self)?)
894952
}
895953
}
896954

@@ -901,7 +959,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
901959
) -> InterpResult<'tcx, u128> {
902960
match scalar.to_bits_or_ptr(size, self) {
903961
Ok(bits) => Ok(bits),
904-
Err(ptr) => Ok(M::ptr_to_int(ptr, self)? as u128)
962+
Err(ptr) => Ok(M::ptr_to_int(&self, ptr)? as u128)
905963
}
906964
}
907965
}

‎src/librustc_mir/interpret/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub use self::eval_context::{
2424

2525
pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy};
2626

27-
pub use self::memory::{Memory, MemoryKind, AllocCheck};
27+
pub use self::memory::{Memory, MemoryKind, AllocCheck, FnVal};
2828

2929
pub use self::machine::{Machine, AllocMap, MayLeak};
3030

‎src/librustc_mir/interpret/terminator.rs

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use rustc::ty::layout::{self, TyLayout, LayoutOf};
66
use syntax::source_map::Span;
77
use rustc_target::spec::abi::Abi;
88

9-
use rustc::mir::interpret::{InterpResult, PointerArithmetic, InterpError, Scalar};
109
use super::{
11-
InterpCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup
10+
InterpResult, PointerArithmetic, InterpError, Scalar,
11+
InterpCx, Machine, Immediate, OpTy, ImmTy, PlaceTy, MPlaceTy, StackPopCleanup, FnVal,
1212
};
1313

1414
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
@@ -76,16 +76,16 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
7676
};
7777

7878
let func = self.eval_operand(func, None)?;
79-
let (fn_def, abi) = match func.layout.ty.sty {
79+
let (fn_val, abi) = match func.layout.ty.sty {
8080
ty::FnPtr(sig) => {
8181
let caller_abi = sig.abi();
82-
let fn_ptr = self.force_ptr(self.read_scalar(func)?.not_undef()?)?;
83-
let instance = self.memory.get_fn(fn_ptr)?;
84-
(instance, caller_abi)
82+
let fn_ptr = self.read_scalar(func)?.not_undef()?;
83+
let fn_val = self.memory.get_fn(fn_ptr)?;
84+
(fn_val, caller_abi)
8585
}
8686
ty::FnDef(def_id, substs) => {
8787
let sig = func.layout.ty.fn_sig(*self.tcx);
88-
(self.resolve(def_id, substs)?, sig.abi())
88+
(FnVal::Instance(self.resolve(def_id, substs)?), sig.abi())
8989
},
9090
_ => {
9191
let msg = format!("can't handle callee of type {:?}", func.layout.ty);
@@ -94,7 +94,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
9494
};
9595
let args = self.eval_operands(args)?;
9696
self.eval_fn_call(
97-
fn_def,
97+
fn_val,
9898
terminator.source_info.span,
9999
abi,
100100
&args[..],
@@ -228,14 +228,21 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
228228
/// Call this function -- pushing the stack frame and initializing the arguments.
229229
fn eval_fn_call(
230230
&mut self,
231-
instance: ty::Instance<'tcx>,
231+
fn_val: FnVal<'tcx, M::ExtraFnVal>,
232232
span: Span,
233233
caller_abi: Abi,
234234
args: &[OpTy<'tcx, M::PointerTag>],
235235
dest: Option<PlaceTy<'tcx, M::PointerTag>>,
236236
ret: Option<mir::BasicBlock>,
237237
) -> InterpResult<'tcx> {
238-
trace!("eval_fn_call: {:#?}", instance);
238+
trace!("eval_fn_call: {:#?}", fn_val);
239+
240+
let instance = match fn_val {
241+
FnVal::Instance(instance) => instance,
242+
FnVal::Other(extra) => {
243+
return M::call_extra_fn(self, extra, args, dest, ret);
244+
}
245+
};
239246

240247
match instance.def {
241248
ty::InstanceDef::Intrinsic(..) => {
@@ -431,8 +438,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
431438
self.tcx.data_layout.pointer_align.abi,
432439
)?.expect("cannot be a ZST");
433440
let fn_ptr = self.memory.get(vtable_slot.alloc_id)?
434-
.read_ptr_sized(self, vtable_slot)?.to_ptr()?;
435-
let instance = self.memory.get_fn(fn_ptr)?;
441+
.read_ptr_sized(self, vtable_slot)?.not_undef()?;
442+
let drop_fn = self.memory.get_fn(fn_ptr)?;
436443

437444
// `*mut receiver_place.layout.ty` is almost the layout that we
438445
// want for args[0]: We have to project to field 0 because we want
@@ -447,7 +454,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
447454
});
448455
trace!("Patched self operand to {:#?}", args[0]);
449456
// recurse with concrete function
450-
self.eval_fn_call(instance, span, caller_abi, &args, dest, ret)
457+
self.eval_fn_call(drop_fn, span, caller_abi, &args, dest, ret)
451458
}
452459
}
453460
}
@@ -482,7 +489,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
482489
let dest = MPlaceTy::dangling(self.layout_of(ty)?, self);
483490

484491
self.eval_fn_call(
485-
instance,
492+
FnVal::Instance(instance),
486493
span,
487494
Abi::Rust,
488495
&[arg.into()],

‎src/librustc_mir/interpret/traits.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use rustc::ty::{self, Ty, Instance};
22
use rustc::ty::layout::{Size, Align, LayoutOf};
33
use rustc::mir::interpret::{Scalar, Pointer, InterpResult, PointerArithmetic};
44

5-
use super::{InterpCx, InterpError, Machine, MemoryKind};
5+
use super::{InterpCx, InterpError, Machine, MemoryKind, FnVal};
66

77
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
88
/// Creates a dynamic vtable for the given type and vtable origin. This is used only for
@@ -56,7 +56,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
5656
let tcx = &*self.tcx;
5757

5858
let drop = Instance::resolve_drop_in_place(*tcx, ty);
59-
let drop = self.memory.create_fn_alloc(drop);
59+
let drop = self.memory.create_fn_alloc(FnVal::Instance(drop));
6060

6161
// no need to do any alignment checks on the memory accesses below, because we know the
6262
// allocation is correctly aligned as we created it above. Also we're only offsetting by
@@ -84,7 +84,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
8484
def_id,
8585
substs,
8686
).ok_or_else(|| InterpError::TooGeneric)?;
87-
let fn_ptr = self.memory.create_fn_alloc(instance);
87+
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
8888
let method_ptr = vtable.offset(ptr_size * (3 + i as u64), self)?;
8989
self.memory
9090
.get_mut(method_ptr.alloc_id)?
@@ -112,8 +112,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
112112
let drop_fn = self.memory
113113
.get(vtable.alloc_id)?
114114
.read_ptr_sized(self, vtable)?
115-
.to_ptr()?;
116-
let drop_instance = self.memory.get_fn(drop_fn)?;
115+
.not_undef()?;
116+
// We *need* an instance here, no other kind of function value, to be able
117+
// to determine the type.
118+
let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?;
117119
trace!("Found drop fn: {:?}", drop_instance);
118120
let fn_sig = drop_instance.ty(*self.tcx).fn_sig(*self.tcx);
119121
let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);

‎src/librustc_mir/interpret/validity.rs

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@ use rustc::hir;
66
use rustc::ty::layout::{self, TyLayout, LayoutOf, VariantIdx};
77
use rustc::ty;
88
use rustc_data_structures::fx::FxHashSet;
9-
use rustc::mir::interpret::{
10-
GlobalAlloc, InterpResult, InterpError,
11-
};
129

1310
use std::hash::Hash;
1411

1512
use super::{
13+
GlobalAlloc, InterpResult, InterpError,
1614
OpTy, Machine, InterpCx, ValueVisitor, MPlaceTy,
1715
};
1816

@@ -153,15 +151,16 @@ fn wrapping_range_format(r: &RangeInclusive<u128>, max_hi: u128) -> String {
153151
debug_assert!(hi <= max_hi);
154152
if lo > hi {
155153
format!("less or equal to {}, or greater or equal to {}", hi, lo)
154+
} else if lo == hi {
155+
format!("equal to {}", lo)
156+
} else if lo == 0 {
157+
debug_assert!(hi < max_hi, "should not be printing if the range covers everything");
158+
format!("less or equal to {}", hi)
159+
} else if hi == max_hi {
160+
debug_assert!(lo > 0, "should not be printing if the range covers everything");
161+
format!("greater or equal to {}", lo)
156162
} else {
157-
if lo == 0 {
158-
debug_assert!(hi < max_hi, "should not be printing if the range covers everything");
159-
format!("less or equal to {}", hi)
160-
} else if hi == max_hi {
161-
format!("greater or equal to {}", lo)
162-
} else {
163-
format!("in the range {:?}", r)
164-
}
163+
format!("in the range {:?}", r)
165164
}
166165
}
167166

@@ -457,10 +456,10 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
457456
}
458457
ty::FnPtr(_sig) => {
459458
let value = value.to_scalar_or_undef();
460-
let ptr = try_validation!(value.to_ptr(),
461-
value, self.path, "a pointer");
462-
let _fn = try_validation!(self.ecx.memory.get_fn(ptr),
463-
value, self.path, "a function pointer");
459+
let _fn = try_validation!(
460+
value.not_undef().and_then(|ptr| self.ecx.memory.get_fn(ptr)),
461+
value, self.path, "a function pointer"
462+
);
464463
// FIXME: Check if the signature matches
465464
}
466465
// This should be all the primitive types
@@ -504,20 +503,18 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
504503
if lo == 1 && hi == max_hi {
505504
// Only NULL is the niche. So make sure the ptr is NOT NULL.
506505
if self.ecx.memory.ptr_may_be_null(ptr) {
507-
// These conditions are just here to improve the diagnostics so we can
508-
// differentiate between null pointers and dangling pointers
509-
if self.ref_tracking_for_consts.is_some() &&
510-
self.ecx.memory.get(ptr.alloc_id).is_err() &&
511-
self.ecx.memory.get_fn(ptr).is_err() {
512-
return validation_failure!(
513-
"encountered dangling pointer", self.path
514-
);
515-
}
516-
return validation_failure!("a potentially NULL pointer", self.path);
506+
return validation_failure!(
507+
"a potentially NULL pointer",
508+
self.path,
509+
format!(
510+
"something that cannot possibly fail to be {}",
511+
wrapping_range_format(&layout.valid_range, max_hi)
512+
)
513+
);
517514
}
518515
return Ok(());
519516
} else {
520-
// Conservatively, we reject, because the pointer *could* have this
517+
// Conservatively, we reject, because the pointer *could* have a bad
521518
// value.
522519
return validation_failure!(
523520
"a pointer",

‎src/librustc_save_analysis/span_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ impl<'a> SpanUtils<'a> {
5353
pub fn sub_span_of_token(&self, span: Span, tok: TokenKind) -> Option<Span> {
5454
let mut toks = self.retokenise_span(span);
5555
loop {
56-
let next = toks.real_token();
56+
let next = toks.next_token();
5757
if next == token::Eof {
5858
return None;
5959
}

‎src/librustdoc/html/highlight.rs

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,17 @@ pub fn render_with_highlighting(
3838
FileName::Custom(String::from("rustdoc-highlighting")),
3939
src.to_owned(),
4040
);
41-
let highlight_result =
42-
lexer::StringReader::new_or_buffered_errs(&sess, fm, None).and_then(|lexer| {
43-
let mut classifier = Classifier::new(lexer, sess.source_map());
44-
45-
let mut highlighted_source = vec![];
46-
if classifier.write_source(&mut highlighted_source).is_err() {
47-
Err(classifier.lexer.buffer_fatal_errors())
48-
} else {
49-
Ok(String::from_utf8_lossy(&highlighted_source).into_owned())
50-
}
51-
});
41+
let highlight_result = {
42+
let lexer = lexer::StringReader::new(&sess, fm, None);
43+
let mut classifier = Classifier::new(lexer, sess.source_map());
44+
45+
let mut highlighted_source = vec![];
46+
if classifier.write_source(&mut highlighted_source).is_err() {
47+
Err(classifier.lexer.buffer_fatal_errors())
48+
} else {
49+
Ok(String::from_utf8_lossy(&highlighted_source).into_owned())
50+
}
51+
};
5252

5353
match highlight_result {
5454
Ok(highlighted_source) => {
@@ -79,6 +79,7 @@ pub fn render_with_highlighting(
7979
/// each span of text in sequence.
8080
struct Classifier<'a> {
8181
lexer: lexer::StringReader<'a>,
82+
peek_token: Option<Token>,
8283
source_map: &'a SourceMap,
8384

8485
// State of the classifier.
@@ -178,6 +179,7 @@ impl<'a> Classifier<'a> {
178179
fn new(lexer: lexer::StringReader<'a>, source_map: &'a SourceMap) -> Classifier<'a> {
179180
Classifier {
180181
lexer,
182+
peek_token: None,
181183
source_map,
182184
in_attribute: false,
183185
in_macro: false,
@@ -187,10 +189,19 @@ impl<'a> Classifier<'a> {
187189

188190
/// Gets the next token out of the lexer.
189191
fn try_next_token(&mut self) -> Result<Token, HighlightError> {
190-
match self.lexer.try_next_token() {
191-
Ok(token) => Ok(token),
192-
Err(_) => Err(HighlightError::LexError),
192+
if let Some(token) = self.peek_token.take() {
193+
return Ok(token);
194+
}
195+
self.lexer.try_next_token().map_err(|()| HighlightError::LexError)
196+
}
197+
198+
fn peek(&mut self) -> Result<&Token, HighlightError> {
199+
if self.peek_token.is_none() {
200+
self.peek_token = Some(
201+
self.lexer.try_next_token().map_err(|()| HighlightError::LexError)?
202+
);
193203
}
204+
Ok(self.peek_token.as_ref().unwrap())
194205
}
195206

196207
/// Exhausts the `lexer` writing the output into `out`.
@@ -234,7 +245,7 @@ impl<'a> Classifier<'a> {
234245
// reference or dereference operator or a reference or pointer type, instead of the
235246
// bit-and or multiplication operator.
236247
token::BinOp(token::And) | token::BinOp(token::Star)
237-
if self.lexer.peek() != &token::Whitespace => Class::RefKeyWord,
248+
if self.peek()? != &token::Whitespace => Class::RefKeyWord,
238249

239250
// Consider this as part of a macro invocation if there was a
240251
// leading identifier.
@@ -257,7 +268,7 @@ impl<'a> Classifier<'a> {
257268
token::Question => Class::QuestionMark,
258269

259270
token::Dollar => {
260-
if self.lexer.peek().is_ident() {
271+
if self.peek()?.is_ident() {
261272
self.in_macro_nonterminal = true;
262273
Class::MacroNonTerminal
263274
} else {
@@ -280,9 +291,9 @@ impl<'a> Classifier<'a> {
280291
// as an attribute.
281292

282293
// Case 1: #![inner_attribute]
283-
if self.lexer.peek() == &token::Not {
294+
if self.peek()? == &token::Not {
284295
self.try_next_token()?; // NOTE: consumes `!` token!
285-
if self.lexer.peek() == &token::OpenDelim(token::Bracket) {
296+
if self.peek()? == &token::OpenDelim(token::Bracket) {
286297
self.in_attribute = true;
287298
out.enter_span(Class::Attribute)?;
288299
}
@@ -292,7 +303,7 @@ impl<'a> Classifier<'a> {
292303
}
293304

294305
// Case 2: #[outer_attribute]
295-
if self.lexer.peek() == &token::OpenDelim(token::Bracket) {
306+
if self.peek()? == &token::OpenDelim(token::Bracket) {
296307
self.in_attribute = true;
297308
out.enter_span(Class::Attribute)?;
298309
}
@@ -341,7 +352,7 @@ impl<'a> Classifier<'a> {
341352
if self.in_macro_nonterminal {
342353
self.in_macro_nonterminal = false;
343354
Class::MacroNonTerminal
344-
} else if self.lexer.peek() == &token::Not {
355+
} else if self.peek()? == &token::Not {
345356
self.in_macro = true;
346357
Class::Macro
347358
} else {

‎src/librustdoc/passes/check_code_block_syntax.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
3232
dox[code_block.code].to_owned(),
3333
);
3434

35-
let errors = Lexer::new_or_buffered_errs(&sess, source_file, None).and_then(|mut lexer| {
35+
let errors = {
36+
let mut lexer = Lexer::new(&sess, source_file, None);
3637
while let Ok(token::Token { kind, .. }) = lexer.try_next_token() {
3738
if kind == token::Eof {
3839
break;
@@ -46,7 +47,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> {
4647
} else {
4748
Ok(())
4849
}
49-
});
50+
};
5051

5152
if let Err(errors) = errors {
5253
let mut diag = if let Some(sp) =

‎src/libstd/sys/unix/alloc.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ use crate::alloc::{GlobalAlloc, Layout, System};
66
unsafe impl GlobalAlloc for System {
77
#[inline]
88
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
9+
// jemalloc provides alignment less than MIN_ALIGN for small allocations.
10+
// So only rely on MIN_ALIGN if size >= align.
11+
// Also see <https://github.com/rust-lang/rust/issues/45955> and
12+
// <https://github.com/rust-lang/rust/issues/62251#issuecomment-507580914>.
913
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
1014
libc::malloc(layout.size()) as *mut u8
1115
} else {
@@ -21,6 +25,7 @@ unsafe impl GlobalAlloc for System {
2125

2226
#[inline]
2327
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
28+
// See the comment above in `alloc` for why this check looks the way it does.
2429
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
2530
libc::calloc(layout.size(), 1) as *mut u8
2631
} else {
@@ -80,7 +85,10 @@ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
8085
#[inline]
8186
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
8287
let mut out = ptr::null_mut();
83-
let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
88+
// posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
89+
// Since these are all powers of 2, we can just use max.
90+
let align = layout.align().max(crate::mem::size_of::<usize>());
91+
let ret = libc::posix_memalign(&mut out, align, layout.size());
8492
if ret != 0 {
8593
ptr::null_mut()
8694
} else {

‎src/libsyntax/parse/lexer/comments.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ fn read_block_comment(rdr: &mut StringReader<'_>,
268268
while level > 0 {
269269
debug!("=== block comment level {}", level);
270270
if rdr.is_eof() {
271-
rdr.fatal("unterminated block comment").raise();
271+
rdr.fatal_span_(rdr.pos, rdr.pos, "unterminated block comment").raise();
272272
}
273273
if rdr.ch_is('\n') {
274274
trim_whitespace_prefix_and_push_line(&mut lines, curr_line, col);
@@ -346,7 +346,7 @@ pub fn gather_comments(sess: &ParseSess, path: FileName, srdr: &mut dyn Read) ->
346346
srdr.read_to_string(&mut src).unwrap();
347347
let cm = SourceMap::new(sess.source_map().path_mapping().clone());
348348
let source_file = cm.new_source_file(path, src);
349-
let mut rdr = lexer::StringReader::new_raw(sess, source_file, None);
349+
let mut rdr = lexer::StringReader::new(sess, source_file, None);
350350

351351
let mut comments: Vec<Comment> = Vec::new();
352352
let mut code_to_the_left = false; // Only code

‎src/libsyntax/parse/lexer/mod.rs

Lines changed: 74 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@ pub struct StringReader<'a> {
3838
crate source_file: Lrc<syntax_pos::SourceFile>,
3939
/// Stop reading src at this index.
4040
crate end_src_index: usize,
41-
// cached:
42-
peek_token: Token,
43-
peek_span_src_raw: Span,
4441
fatal_errs: Vec<DiagnosticBuilder<'a>>,
4542
// cache a direct reference to the source text, so that we don't have to
4643
// retrieve it via `self.source_file.src.as_ref().unwrap()` all the time.
@@ -49,15 +46,59 @@ pub struct StringReader<'a> {
4946
}
5047

5148
impl<'a> StringReader<'a> {
52-
fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span {
53-
self.mk_sp_and_raw(lo, hi).0
49+
pub fn new(sess: &'a ParseSess,
50+
source_file: Lrc<syntax_pos::SourceFile>,
51+
override_span: Option<Span>) -> Self {
52+
let mut sr = StringReader::new_internal(sess, source_file, override_span);
53+
sr.bump();
54+
sr
55+
}
56+
57+
pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self {
58+
let begin = sess.source_map().lookup_byte_offset(span.lo());
59+
let end = sess.source_map().lookup_byte_offset(span.hi());
60+
61+
// Make the range zero-length if the span is invalid.
62+
if span.lo() > span.hi() || begin.sf.start_pos != end.sf.start_pos {
63+
span = span.shrink_to_lo();
64+
}
65+
66+
let mut sr = StringReader::new_internal(sess, begin.sf, None);
67+
68+
// Seek the lexer to the right byte range.
69+
sr.next_pos = span.lo();
70+
sr.end_src_index = sr.src_index(span.hi());
71+
72+
sr.bump();
73+
74+
sr
5475
}
5576

56-
fn mk_sp_and_raw(&self, lo: BytePos, hi: BytePos) -> (Span, Span) {
57-
let raw = Span::new(lo, hi, NO_EXPANSION);
58-
let real = self.override_span.unwrap_or(raw);
77+
fn new_internal(sess: &'a ParseSess, source_file: Lrc<syntax_pos::SourceFile>,
78+
override_span: Option<Span>) -> Self
79+
{
80+
if source_file.src.is_none() {
81+
sess.span_diagnostic.bug(&format!("Cannot lex source_file without source: {}",
82+
source_file.name));
83+
}
84+
85+
let src = (*source_file.src.as_ref().unwrap()).clone();
86+
87+
StringReader {
88+
sess,
89+
next_pos: source_file.start_pos,
90+
pos: source_file.start_pos,
91+
ch: Some('\n'),
92+
source_file,
93+
end_src_index: src.len(),
94+
src,
95+
fatal_errs: Vec::new(),
96+
override_span,
97+
}
98+
}
5999

60-
(real, raw)
100+
fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span {
101+
self.override_span.unwrap_or_else(|| Span::new(lo, hi, NO_EXPANSION))
61102
}
62103

63104
fn unwrap_or_abort(&mut self, res: Result<Token, ()>) -> Token {
@@ -70,35 +111,32 @@ impl<'a> StringReader<'a> {
70111
}
71112
}
72113

73-
fn next_token(&mut self) -> Token where Self: Sized {
74-
let res = self.try_next_token();
75-
self.unwrap_or_abort(res)
76-
}
77-
78-
/// Returns the next token. EFFECT: advances the string_reader.
114+
/// Returns the next token, including trivia like whitespace or comments.
115+
///
116+
/// `Err(())` means that some errors were encountered, which can be
117+
/// retrieved using `buffer_fatal_errors`.
79118
pub fn try_next_token(&mut self) -> Result<Token, ()> {
80119
assert!(self.fatal_errs.is_empty());
81-
let ret_val = self.peek_token.take();
82-
self.advance_token()?;
83-
Ok(ret_val)
84-
}
85-
86-
fn try_real_token(&mut self) -> Result<Token, ()> {
87-
let mut t = self.try_next_token()?;
88-
loop {
89-
match t.kind {
90-
token::Whitespace | token::Comment | token::Shebang(_) => {
91-
t = self.try_next_token()?;
92-
}
93-
_ => break,
120+
match self.scan_whitespace_or_comment() {
121+
Some(comment) => Ok(comment),
122+
None => {
123+
let (kind, start_pos, end_pos) = if self.is_eof() {
124+
(token::Eof, self.source_file.end_pos, self.source_file.end_pos)
125+
} else {
126+
let start_pos = self.pos;
127+
(self.next_token_inner()?, start_pos, self.pos)
128+
};
129+
let span = self.mk_sp(start_pos, end_pos);
130+
Ok(Token::new(kind, span))
94131
}
95132
}
96-
97-
Ok(t)
98133
}
99134

100-
pub fn real_token(&mut self) -> Token {
101-
let res = self.try_real_token();
135+
/// Returns the next token, including trivia like whitespace or comments.
136+
///
137+
/// Aborts in case of an error.
138+
pub fn next_token(&mut self) -> Token {
139+
let res = self.try_next_token();
102140
self.unwrap_or_abort(res)
103141
}
104142

@@ -120,10 +158,6 @@ impl<'a> StringReader<'a> {
120158
FatalError.raise();
121159
}
122160

123-
fn fatal(&self, m: &str) -> FatalError {
124-
self.fatal_span(self.peek_token.span, m)
125-
}
126-
127161
crate fn emit_fatal_errors(&mut self) {
128162
for err in &mut self.fatal_errs {
129163
err.emit();
@@ -142,81 +176,6 @@ impl<'a> StringReader<'a> {
142176
buffer
143177
}
144178

145-
pub fn peek(&self) -> &Token {
146-
&self.peek_token
147-
}
148-
149-
/// For comments.rs, which hackily pokes into next_pos and ch
150-
fn new_raw(sess: &'a ParseSess,
151-
source_file: Lrc<syntax_pos::SourceFile>,
152-
override_span: Option<Span>) -> Self {
153-
let mut sr = StringReader::new_raw_internal(sess, source_file, override_span);
154-
sr.bump();
155-
156-
sr
157-
}
158-
159-
fn new_raw_internal(sess: &'a ParseSess, source_file: Lrc<syntax_pos::SourceFile>,
160-
override_span: Option<Span>) -> Self
161-
{
162-
if source_file.src.is_none() {
163-
sess.span_diagnostic.bug(&format!("Cannot lex source_file without source: {}",
164-
source_file.name));
165-
}
166-
167-
let src = (*source_file.src.as_ref().unwrap()).clone();
168-
169-
StringReader {
170-
sess,
171-
next_pos: source_file.start_pos,
172-
pos: source_file.start_pos,
173-
ch: Some('\n'),
174-
source_file,
175-
end_src_index: src.len(),
176-
peek_token: Token::dummy(),
177-
peek_span_src_raw: syntax_pos::DUMMY_SP,
178-
src,
179-
fatal_errs: Vec::new(),
180-
override_span,
181-
}
182-
}
183-
184-
pub fn new_or_buffered_errs(sess: &'a ParseSess,
185-
source_file: Lrc<syntax_pos::SourceFile>,
186-
override_span: Option<Span>) -> Result<Self, Vec<Diagnostic>> {
187-
let mut sr = StringReader::new_raw(sess, source_file, override_span);
188-
if sr.advance_token().is_err() {
189-
Err(sr.buffer_fatal_errors())
190-
} else {
191-
Ok(sr)
192-
}
193-
}
194-
195-
pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self {
196-
let begin = sess.source_map().lookup_byte_offset(span.lo());
197-
let end = sess.source_map().lookup_byte_offset(span.hi());
198-
199-
// Make the range zero-length if the span is invalid.
200-
if span.lo() > span.hi() || begin.sf.start_pos != end.sf.start_pos {
201-
span = span.shrink_to_lo();
202-
}
203-
204-
let mut sr = StringReader::new_raw_internal(sess, begin.sf, None);
205-
206-
// Seek the lexer to the right byte range.
207-
sr.next_pos = span.lo();
208-
sr.end_src_index = sr.src_index(span.hi());
209-
210-
sr.bump();
211-
212-
if sr.advance_token().is_err() {
213-
sr.emit_fatal_errors();
214-
FatalError.raise();
215-
}
216-
217-
sr
218-
}
219-
220179
#[inline]
221180
fn ch_is(&self, c: char) -> bool {
222181
self.ch == Some(c)
@@ -269,30 +228,6 @@ impl<'a> StringReader<'a> {
269228
self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), &m[..])
270229
}
271230

272-
/// Advance peek_token to refer to the next token, and
273-
/// possibly update the interner.
274-
fn advance_token(&mut self) -> Result<(), ()> {
275-
match self.scan_whitespace_or_comment() {
276-
Some(comment) => {
277-
self.peek_span_src_raw = comment.span;
278-
self.peek_token = comment;
279-
}
280-
None => {
281-
let (kind, start_pos, end_pos) = if self.is_eof() {
282-
(token::Eof, self.source_file.end_pos, self.source_file.end_pos)
283-
} else {
284-
let start_pos = self.pos;
285-
(self.next_token_inner()?, start_pos, self.pos)
286-
};
287-
let (real, raw) = self.mk_sp_and_raw(start_pos, end_pos);
288-
self.peek_token = Token::new(kind, real);
289-
self.peek_span_src_raw = raw;
290-
}
291-
}
292-
293-
Ok(())
294-
}
295-
296231
#[inline]
297232
fn src_index(&self, pos: BytePos) -> usize {
298233
(pos - self.source_file.start_pos).to_usize()
@@ -1462,12 +1397,7 @@ mod tests {
14621397
teststr: String)
14631398
-> StringReader<'a> {
14641399
let sf = sm.new_source_file(PathBuf::from(teststr.clone()).into(), teststr);
1465-
let mut sr = StringReader::new_raw(sess, sf, None);
1466-
if sr.advance_token().is_err() {
1467-
sr.emit_fatal_errors();
1468-
FatalError.raise();
1469-
}
1470-
sr
1400+
StringReader::new(sess, sf, None)
14711401
}
14721402

14731403
#[test]
@@ -1489,17 +1419,17 @@ mod tests {
14891419
assert_eq!(tok1.kind, tok2.kind);
14901420
assert_eq!(tok1.span, tok2.span);
14911421
assert_eq!(string_reader.next_token(), token::Whitespace);
1492-
// the 'main' id is already read:
1493-
assert_eq!(string_reader.pos.clone(), BytePos(28));
14941422
// read another token:
14951423
let tok3 = string_reader.next_token();
1424+
assert_eq!(string_reader.pos.clone(), BytePos(28));
14961425
let tok4 = Token::new(
14971426
mk_ident("main"),
14981427
Span::new(BytePos(24), BytePos(28), NO_EXPANSION),
14991428
);
15001429
assert_eq!(tok3.kind, tok4.kind);
15011430
assert_eq!(tok3.span, tok4.span);
1502-
// the lparen is already read:
1431+
1432+
assert_eq!(string_reader.next_token(), token::OpenDelim(token::Paren));
15031433
assert_eq!(string_reader.pos.clone(), BytePos(29))
15041434
})
15051435
}

‎src/libsyntax/parse/lexer/tokentrees.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@ use crate::print::pprust::token_to_string;
44
use crate::parse::lexer::{StringReader, UnmatchedBrace};
55
use crate::parse::token::{self, Token};
66
use crate::parse::PResult;
7-
use crate::tokenstream::{DelimSpan, IsJoint::*, TokenStream, TokenTree, TreeAndJoint};
7+
use crate::tokenstream::{DelimSpan, IsJoint::{self, *}, TokenStream, TokenTree, TreeAndJoint};
88

99
impl<'a> StringReader<'a> {
1010
crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec<UnmatchedBrace>) {
1111
let mut tt_reader = TokenTreesReader {
1212
string_reader: self,
1313
token: Token::dummy(),
14+
joint_to_prev: Joint,
1415
open_braces: Vec::new(),
1516
unmatched_braces: Vec::new(),
1617
matching_delim_spans: Vec::new(),
@@ -24,6 +25,7 @@ impl<'a> StringReader<'a> {
2425
struct TokenTreesReader<'a> {
2526
string_reader: StringReader<'a>,
2627
token: Token,
28+
joint_to_prev: IsJoint,
2729
/// Stack of open delimiters and their spans. Used for error message.
2830
open_braces: Vec<(token::DelimToken, Span)>,
2931
unmatched_braces: Vec<UnmatchedBrace>,
@@ -203,21 +205,26 @@ impl<'a> TokenTreesReader<'a> {
203205
},
204206
_ => {
205207
let tt = TokenTree::Token(self.token.take());
206-
// Note that testing for joint-ness here is done via the raw
207-
// source span as the joint-ness is a property of the raw source
208-
// rather than wanting to take `override_span` into account.
209-
// Additionally, we actually check if the *next* pair of tokens
210-
// is joint, but this is equivalent to checking the current pair.
211-
let raw = self.string_reader.peek_span_src_raw;
212208
self.real_token();
213-
let is_joint = raw.hi() == self.string_reader.peek_span_src_raw.lo()
214-
&& self.token.is_op();
209+
let is_joint = self.joint_to_prev == Joint && self.token.is_op();
215210
Ok((tt, if is_joint { Joint } else { NonJoint }))
216211
}
217212
}
218213
}
219214

220215
fn real_token(&mut self) {
221-
self.token = self.string_reader.real_token();
216+
self.joint_to_prev = Joint;
217+
loop {
218+
let token = self.string_reader.next_token();
219+
match token.kind {
220+
token::Whitespace | token::Comment | token::Shebang(_) => {
221+
self.joint_to_prev = NonJoint;
222+
}
223+
_ => {
224+
self.token = token;
225+
return;
226+
},
227+
}
228+
}
222229
}
223230
}

‎src/libsyntax/parse/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ pub fn maybe_file_to_stream(
308308
source_file: Lrc<SourceFile>,
309309
override_span: Option<Span>,
310310
) -> Result<(TokenStream, Vec<lexer::UnmatchedBrace>), Vec<Diagnostic>> {
311-
let srdr = lexer::StringReader::new_or_buffered_errs(sess, source_file, override_span)?;
311+
let srdr = lexer::StringReader::new(sess, source_file, override_span);
312312
let (token_trees, unmatched_braces) = srdr.into_token_trees();
313313

314314
match token_trees {

‎src/test/ui/consts/const-eval/ub-enum.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,31 @@
11
#![allow(const_err)] // make sure we cannot allow away the errors tested here
22

3+
4+
#[repr(transparent)]
5+
#[derive(Copy, Clone)]
6+
struct Wrap<T>(T);
7+
38
#[repr(usize)]
49
#[derive(Copy, Clone)]
510
enum Enum {
611
A = 0,
712
}
813
union TransmuteEnum {
914
in1: &'static u8,
15+
in2: usize,
1016
out1: Enum,
17+
out2: Wrap<Enum>,
1118
}
1219

13-
// A pointer is guaranteed non-null
14-
const BAD_ENUM: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 };
20+
const GOOD_ENUM: Enum = unsafe { TransmuteEnum { in2: 0 }.out1 };
21+
22+
const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 };
23+
//~^ ERROR is undefined behavior
24+
25+
const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 };
26+
//~^ ERROR is undefined behavior
27+
28+
const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { TransmuteEnum { in1: &1 }.out2 };
1529
//~^ ERROR is undefined behavior
1630

1731
// (Potentially) invalid enum discriminant
@@ -20,9 +34,7 @@ const BAD_ENUM: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 };
2034
enum Enum2 {
2135
A = 2,
2236
}
23-
#[repr(transparent)]
24-
#[derive(Copy, Clone)]
25-
struct Wrap<T>(T);
37+
2638
union TransmuteEnum2 {
2739
in1: usize,
2840
in2: &'static u8,
@@ -33,17 +45,17 @@ union TransmuteEnum2 {
3345
}
3446
const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 };
3547
//~^ ERROR is undefined behavior
36-
const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
48+
const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
3749
//~^ ERROR is undefined behavior
38-
const BAD_ENUM4: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
50+
const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
3951
//~^ ERROR is undefined behavior
4052

4153
// Undef enum discriminant.
42-
const BAD_ENUM_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 };
54+
const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 };
4355
//~^ ERROR is undefined behavior
4456

4557
// Pointer value in an enum with a niche that is not just 0.
46-
const BAD_ENUM_PTR: Option<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out3 };
58+
const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out3 };
4759
//~^ ERROR is undefined behavior
4860

4961
// Invalid enum field content (mostly to test printing of paths for enum tuple
@@ -53,7 +65,7 @@ union TransmuteChar {
5365
b: char,
5466
}
5567
// Need to create something which does not clash with enum layout optimizations.
56-
const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
68+
const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
5769
//~^ ERROR is undefined behavior
5870

5971
fn main() {
Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,75 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/ub-enum.rs:14:1
2+
--> $DIR/ub-enum.rs:22:1
33
|
4-
LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
4+
LL | const BAD_ENUM: Enum = unsafe { TransmuteEnum { in2: 1 }.out1 };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 1, but expected a valid enum discriminant
66
|
77
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
88

99
error[E0080]: it is undefined behavior to use this value
10-
--> $DIR/ub-enum.rs:34:1
10+
--> $DIR/ub-enum.rs:25:1
11+
|
12+
LL | const BAD_ENUM_PTR: Enum = unsafe { TransmuteEnum { in1: &1 }.out1 };
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
14+
|
15+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
16+
17+
error[E0080]: it is undefined behavior to use this value
18+
--> $DIR/ub-enum.rs:28:1
19+
|
20+
LL | const BAD_ENUM_WRAPPED: Wrap<Enum> = unsafe { TransmuteEnum { in1: &1 }.out2 };
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 0
22+
|
23+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
24+
25+
error[E0080]: it is undefined behavior to use this value
26+
--> $DIR/ub-enum.rs:46:1
1127
|
1228
LL | const BAD_ENUM2: Enum2 = unsafe { TransmuteEnum2 { in1: 0 }.out1 };
1329
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected a valid enum discriminant
1430
|
1531
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
1632

1733
error[E0080]: it is undefined behavior to use this value
18-
--> $DIR/ub-enum.rs:36:1
34+
--> $DIR/ub-enum.rs:48:1
1935
|
20-
LL | const BAD_ENUM3: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
21-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
36+
LL | const BAD_ENUM2_PTR: Enum2 = unsafe { TransmuteEnum2 { in2: &0 }.out1 };
37+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
2238
|
2339
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
2440

2541
error[E0080]: it is undefined behavior to use this value
26-
--> $DIR/ub-enum.rs:38:1
42+
--> $DIR/ub-enum.rs:50:1
2743
|
28-
LL | const BAD_ENUM4: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
29-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be in the range 2..=2
44+
LL | const BAD_ENUM2_WRAPPED: Wrap<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out2 };
45+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected something that cannot possibly fail to be equal to 2
3046
|
3147
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
3248

3349
error[E0080]: it is undefined behavior to use this value
34-
--> $DIR/ub-enum.rs:42:1
50+
--> $DIR/ub-enum.rs:54:1
3551
|
36-
LL | const BAD_ENUM_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 };
37-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid enum discriminant
52+
LL | const BAD_ENUM2_UNDEF : Enum2 = unsafe { TransmuteEnum2 { in3: () }.out1 };
53+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid enum discriminant
3854
|
3955
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
4056

4157
error[E0080]: it is undefined behavior to use this value
42-
--> $DIR/ub-enum.rs:46:1
58+
--> $DIR/ub-enum.rs:58:1
4359
|
44-
LL | const BAD_ENUM_PTR: Option<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out3 };
45-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
60+
LL | const BAD_ENUM2_OPTION_PTR: Option<Enum2> = unsafe { TransmuteEnum2 { in2: &0 }.out3 };
61+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected a valid enum discriminant
4662
|
4763
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
4864

4965
error[E0080]: it is undefined behavior to use this value
50-
--> $DIR/ub-enum.rs:56:1
66+
--> $DIR/ub-enum.rs:68:1
5167
|
52-
LL | const BAD_ENUM_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
53-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .<downcast-variant(Some)>.0.1, but expected something less or equal to 1114111
68+
LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
69+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .<downcast-variant(Some)>.0.1, but expected something less or equal to 1114111
5470
|
5571
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
5672

57-
error: aborting due to 7 previous errors
73+
error: aborting due to 9 previous errors
5874

5975
For more information about this error, try `rustc --explain E0080`.

‎src/test/ui/consts/const-eval/ub-nonnull.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,19 @@ use std::mem;
55
use std::ptr::NonNull;
66
use std::num::{NonZeroU8, NonZeroUsize};
77

8+
const NON_NULL: NonNull<u8> = unsafe { mem::transmute(1usize) };
9+
const NON_NULL_PTR: NonNull<u8> = unsafe { mem::transmute(&1) };
10+
811
const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
912
//~^ ERROR it is undefined behavior to use this value
1013

14+
const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
15+
//~^ ERROR it is undefined behavior to use this value
16+
let ptr: &(u8, u8, u8) = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
17+
let out_of_bounds_ptr = &ptr.2; // use address-of-field for pointer arithmetic
18+
mem::transmute(out_of_bounds_ptr)
19+
} };
20+
1121
const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
1222
//~^ ERROR it is undefined behavior to use this value
1323
const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,64 @@
11
error[E0080]: it is undefined behavior to use this value
2-
--> $DIR/ub-nonnull.rs:8:1
2+
--> $DIR/ub-nonnull.rs:11:1
33
|
44
LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
66
|
77
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
88

99
error[E0080]: it is undefined behavior to use this value
10-
--> $DIR/ub-nonnull.rs:11:1
10+
--> $DIR/ub-nonnull.rs:14:1
11+
|
12+
LL | / const OUT_OF_BOUNDS_PTR: NonNull<u8> = { unsafe {
13+
LL | |
14+
LL | | let ptr: &(u8, u8, u8) = mem::transmute(&0u8); // &0 gets promoted so it does not dangle
15+
LL | | let out_of_bounds_ptr = &ptr.2; // use address-of-field for pointer arithmetic
16+
LL | | mem::transmute(out_of_bounds_ptr)
17+
LL | | } };
18+
| |____^ type validation failed: encountered a potentially NULL pointer, but expected something that cannot possibly fail to be greater or equal to 1
19+
|
20+
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
21+
22+
error[E0080]: it is undefined behavior to use this value
23+
--> $DIR/ub-nonnull.rs:21:1
1124
|
1225
LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
1326
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
1427
|
1528
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
1629

1730
error[E0080]: it is undefined behavior to use this value
18-
--> $DIR/ub-nonnull.rs:13:1
31+
--> $DIR/ub-nonnull.rs:23:1
1932
|
2033
LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
2134
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
2235
|
2336
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
2437

2538
error[E0080]: it is undefined behavior to use this value
26-
--> $DIR/ub-nonnull.rs:20:1
39+
--> $DIR/ub-nonnull.rs:30:1
2740
|
2841
LL | const UNINIT: NonZeroU8 = unsafe { Transmute { uninit: () }.out };
2942
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected something greater or equal to 1
3043
|
3144
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
3245

3346
error[E0080]: it is undefined behavior to use this value
34-
--> $DIR/ub-nonnull.rs:28:1
47+
--> $DIR/ub-nonnull.rs:38:1
3548
|
3649
LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) };
3750
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 42, but expected something in the range 10..=30
3851
|
3952
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
4053

4154
error[E0080]: it is undefined behavior to use this value
42-
--> $DIR/ub-nonnull.rs:34:1
55+
--> $DIR/ub-nonnull.rs:44:1
4356
|
4457
LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) };
4558
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 20, but expected something less or equal to 10, or greater or equal to 30
4659
|
4760
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
4861

49-
error: aborting due to 6 previous errors
62+
error: aborting due to 7 previous errors
5063

5164
For more information about this error, try `rustc --explain E0080`.

‎src/test/ui/issues/issue-62375.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
enum A {
2+
Value(())
3+
}
4+
5+
fn main() {
6+
let a = A::Value(());
7+
a == A::Value;
8+
//~^ ERROR binary operation `==` cannot be applied to type `A`
9+
}

‎src/test/ui/issues/issue-62375.stderr

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0369]: binary operation `==` cannot be applied to type `A`
2+
--> $DIR/issue-62375.rs:7:7
3+
|
4+
LL | a == A::Value;
5+
| - ^^ -------- fn(()) -> A {A::Value}
6+
| |
7+
| A
8+
|
9+
= note: an implementation of `std::cmp::PartialEq` might be missing for `A`
10+
11+
error: aborting due to previous error
12+
13+
For more information about this error, try `rustc --explain E0369`.

0 commit comments

Comments
 (0)
Please sign in to comment.