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 <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);
+}