diff --git a/src/doc/reference.md b/src/doc/reference.md index 62e0f5e4f1f48..5ee03f1b1d338 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3557,17 +3557,14 @@ The machine types are the following: #### Machine-dependent integer types -The Rust type `uint` [^rustuint] is an -unsigned integer type with target-machine-dependent size. Its size, in -bits, is equal to the number of bits required to hold any memory address on -the target machine. - -The Rust type `int` [^rustint] is a two's complement signed integer type with -target-machine-dependent size. Its size, in bits, is equal to the size of the -rust type `uint` on the same target machine. - -[^rustuint]: A Rust `uint` is analogous to a C99 `uintptr_t`. -[^rustint]: A Rust `int` is analogous to a C99 `intptr_t`. +The `uint` type is an unsigned integer type with the same number of bits as the +platform's pointer type. It can represent every memory address in the process. + +The `int` type is a signed integer type with the same number of bits as the +platform's pointer type. The theoretical upper bound on object and array size +is the maximum `int` value. This ensures that `int` can be used to calculate +differences between pointers into an object or array and can address every byte +within an object along with one byte past the end. ### Textual types diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 806c4a68ba281..5ef78c1475bf5 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -464,17 +464,17 @@ fn ensure_struct_fits_in_address_space(ccx: &CrateContext, scapegoat: ty::t) { let mut offset = 0; for &llty in fields.iter() { - // Invariant: offset < ccx.max_obj_size() <= 1<<61 + // Invariant: offset < ccx.obj_size_bound() <= 1<<61 if !packed { let type_align = machine::llalign_of_min(ccx, llty); offset = roundup(offset, type_align); } - // type_align is a power-of-2, so still offset < ccx.max_obj_size() - // llsize_of_alloc(ccx, llty) is also less than ccx.max_obj_size() + // type_align is a power-of-2, so still offset < ccx.obj_size_bound() + // llsize_of_alloc(ccx, llty) is also less than ccx.obj_size_bound() // so the sum is less than 1<<62 (and therefore can't overflow). offset += machine::llsize_of_alloc(ccx, llty); - if offset >= ccx.max_obj_size() { + if offset >= ccx.obj_size_bound() { ccx.report_overbig_object(scapegoat); } } @@ -493,11 +493,11 @@ fn ensure_enum_fits_in_address_space(ccx: &CrateContext, let discr_size = machine::llsize_of_alloc(ccx, ll_inttype(ccx, discr)); let (field_size, field_align) = union_size_and_align(fields); - // field_align < 1<<32, discr_size <= 8, field_size < MAX_OBJ_SIZE <= 1<<61 + // field_align < 1<<32, discr_size <= 8, field_size < OBJ_SIZE_BOUND <= 1<<61 // so the sum is less than 1<<62 (and can't overflow). let total_size = roundup(discr_size, field_align) + field_size; - if total_size >= ccx.max_obj_size() { + if total_size >= ccx.obj_size_bound() { ccx.report_overbig_object(scapegoat); } } diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index c2c1f8bb5f5ac..c0066ff4d81e1 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -703,8 +703,23 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.trait_cache } - pub fn max_obj_size(&self) -> u64 { - 1<<31 /* FIXME #18069: select based on architecture */ + /// Return exclusive upper bound on object size. + /// + /// The theoretical maximum object size is defined as the maximum positive `int` value. This + /// ensures that the `offset` semantics remain well-defined by allowing it to correctly index + /// every address within an object along with one byte past the end, along with allowing `int` + /// to store the difference between any two pointers into an object. + /// + /// The upper bound on 64-bit currently needs to be lower because LLVM uses a 64-bit integer to + /// represent object size in bits. It would need to be 1 << 61 to account for this, but is + /// currently conservatively bounded to 1 << 47 as that is enough to cover the current usable + /// address space on 64-bit ARMv8 and x86_64. + pub fn obj_size_bound(&self) -> u64 { + match self.sess().target.target.target_word_size[] { + "32" => 1 << 31, + "64" => 1 << 47, + _ => unreachable!() // error handled by config::build_target_config + } } pub fn report_overbig_object(&self, obj: ty::t) -> ! { diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 5fa2198463793..6bba40ccc7a71 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -34,7 +34,7 @@ fn ensure_array_fits_in_address_space(ccx: &CrateContext, scapegoat: ty::t) { let esz = machine::llsize_of_alloc(ccx, llet); match esz.checked_mul(size) { - Some(n) if n < ccx.max_obj_size() => {} + Some(n) if n < ccx.obj_size_bound() => {} _ => { ccx.report_overbig_object(scapegoat) } } } diff --git a/src/test/compile-fail/huge-enum.rs b/src/test/compile-fail/huge-enum.rs index 92f9c41e7ea30..4a85cb5753b7f 100644 --- a/src/test/compile-fail/huge-enum.rs +++ b/src/test/compile-fail/huge-enum.rs @@ -12,6 +12,12 @@ // FIXME: work properly with higher limits +#[cfg(target_word_size = "32")] fn main() { let big: Option<[u32, ..(1<<29)-1]> = None; } + +#[cfg(target_word_size = "64")] +fn main() { + let big: Option<[u32, ..(1<<45)-1]> = None; +} diff --git a/src/test/run-pass/huge-largest-array.rs b/src/test/run-pass/huge-largest-array.rs new file mode 100644 index 0000000000000..d494e0bf40dea --- /dev/null +++ b/src/test/run-pass/huge-largest-array.rs @@ -0,0 +1,21 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::mem::size_of; + +#[cfg(target_word_size = "32")] +pub fn main() { + assert_eq!(size_of::<[u8, ..(1 << 31) - 1]>(), (1 << 31) - 1); +} + +#[cfg(target_word_size = "64")] +pub fn main() { + assert_eq!(size_of::<[u8, ..(1 << 47) - 1]>(), (1 << 47) - 1); +}