Change:
LLVM does not support objects larger than bytes, because it represents sizes as counts of bits. Currently, to be safe, I'm blocking compile-time objects bigger than 2 GiB (in case LLVM uses an int count of bytes somewhere). It would be nice to find out how much can we increase this, especially on 64-bit targets.
bounds object size by 2 GiB on 32-bit architectures and 128 TiB () on 64-bit architectures.

Discussion:
#### Machine-dependent integer types <del> 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`. </del> <ins> 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. </ins> ### Textual types

scapegoat: ty::t) { let mut offset = 0; for &llty in fields.iter() { <del> // Invariant: offset < ccx.max_obj_size() <= 1<<61 </del> <ins> // Invariant: offset < ccx.obj_size_bound() <= 1<<61 </ins> if !packed { let type_align = machine::llalign_of_min(ccx, llty); offset = roundup(offset, type_align); } <del> // 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() </del> <ins> // 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() </ins> // so the sum is less than 1<<62 (and therefore can't overflow). offset += machine::llsize_of_alloc(ccx, llty); <del> if offset >= ccx.max_obj_size() { </del> <ins> if offset >= ccx.obj_size_bound() { </ins> ccx.report_overbig_object(scapegoat); } }

let discr_size = machine::llsize_of_alloc(ccx, ll_inttype(ccx, discr)); let (field_size, field_align) = union_size_and_align(fields); <del> // field_align < 1<<32, discr_size <= 8, field_size < MAX_OBJ_SIZE <= 1<<61 </del> <ins> // field_align < 1<<32, discr_size <= 8, field_size < OBJ_SIZE_BOUND <= 1<<61 </ins> // so the sum is less than 1<<62 (and can't overflow). let total_size = roundup(discr_size, field_align) + field_size; <del> if total_size >= ccx.max_obj_size() { </del> <ins> if total_size >= ccx.obj_size_bound() { </ins> ccx.report_overbig_object(scapegoat); } }

&self.local.trait_cache } <del> pub fn max_obj_size(&self) -> u64 { 1<<31 /* FIXME #18069: select based on architecture */ </del> <ins> /// 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 } </ins> } pub fn report_overbig_object(&self, obj: ty::t) -> ! {

scapegoat: ty::t) { let esz = machine::llsize_of_alloc(ccx, llet); match esz.checked_mul(size) { <del> Some(n) if n < ccx.max_obj_size() => {} </del> <ins> Some(n) if n < ccx.obj_size_bound() => {} </ins> _ => { ccx.report_overbig_object(scapegoat) } } }

// FIXME: work properly with higher limits <ins> #[cfg(target_word_size = "32")] </ins> fn main() { let big: Option<[u32, ..(1<<29)-1]> = None; } <ins> #[cfg(target_word_size = "64")] fn main() { let big: Option<[u32, ..(1<<45)-1]> = None; } </ins>

<ins> // 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 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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); } </ins>