Merge branch 'master' into llvm6

This commit is contained in:
Andrew Kelley 2017-12-04 15:28:17 -05:00
commit 42004f9013
57 changed files with 2603 additions and 1581 deletions

View File

@ -47,15 +47,20 @@ option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF)
option(ZIG_FORCE_EXTERNAL_LLD "If your system has the LLD patches use it instead of the embedded LLD" OFF)
find_package(llvm)
include_directories(${LLVM_INCLUDE_DIRS})
find_package(clang)
include_directories(${CLANG_INCLUDE_DIRS})
if(ZIG_FORCE_EXTERNAL_LLD)
find_package(lld)
include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${LLD_INCLUDE_DIRS})
include_directories(${CLANG_INCLUDE_DIRS})
else()
# This goes first so that we find embedded LLD instead
# of system LLD.
include_directories("${CMAKE_SOURCE_DIR}/deps/lld/include")
include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${CLANG_INCLUDE_DIRS})
set(EMBEDDED_LLD_LIB_SOURCES
"${CMAKE_SOURCE_DIR}/deps/lld/lib/Driver/DarwinLdDriver.cpp"
"${CMAKE_SOURCE_DIR}/deps/lld/lib/Config/Version.cpp"

View File

@ -4543,37 +4543,6 @@ _mm512_maskz_unpacklo_epi64 (__mmask8 __U, __m512i __A, __m512i __B)
(__v8di)_mm512_setzero_si512());
}
/* Bit Test */
static __inline __mmask16 __DEFAULT_FN_ATTRS
_mm512_test_epi32_mask(__m512i __A, __m512i __B)
{
return (__mmask16) __builtin_ia32_ptestmd512 ((__v16si) __A,
(__v16si) __B,
(__mmask16) -1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_test_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B)
{
return (__mmask16) __builtin_ia32_ptestmd512 ((__v16si) __A,
(__v16si) __B, __U);
}
static __inline __mmask8 __DEFAULT_FN_ATTRS
_mm512_test_epi64_mask(__m512i __A, __m512i __B)
{
return (__mmask8) __builtin_ia32_ptestmq512 ((__v8di) __A,
(__v8di) __B,
(__mmask8) -1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_test_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B)
{
return (__mmask8) __builtin_ia32_ptestmq512 ((__v8di) __A, (__v8di) __B, __U);
}
/* SIMD load ops */
@ -4844,293 +4813,105 @@ _mm512_knot(__mmask16 __M)
/* Integer compare */
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmpeq_epi32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_pcmpeqd512_mask((__v16si)__a, (__v16si)__b,
(__mmask16)-1);
}
#define _mm512_cmpeq_epi32_mask(A, B) \
_mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_EQ)
#define _mm512_mask_cmpeq_epi32_mask(k, A, B) \
_mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_EQ)
#define _mm512_cmpge_epi32_mask(A, B) \
_mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_GE)
#define _mm512_mask_cmpge_epi32_mask(k, A, B) \
_mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_GE)
#define _mm512_cmpgt_epi32_mask(A, B) \
_mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_GT)
#define _mm512_mask_cmpgt_epi32_mask(k, A, B) \
_mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_GT)
#define _mm512_cmple_epi32_mask(A, B) \
_mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_LE)
#define _mm512_mask_cmple_epi32_mask(k, A, B) \
_mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_LE)
#define _mm512_cmplt_epi32_mask(A, B) \
_mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_LT)
#define _mm512_mask_cmplt_epi32_mask(k, A, B) \
_mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_LT)
#define _mm512_cmpneq_epi32_mask(A, B) \
_mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_NE)
#define _mm512_mask_cmpneq_epi32_mask(k, A, B) \
_mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_NE)
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmpeq_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_pcmpeqd512_mask((__v16si)__a, (__v16si)__b,
__u);
}
#define _mm512_cmpeq_epu32_mask(A, B) \
_mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_EQ)
#define _mm512_mask_cmpeq_epu32_mask(k, A, B) \
_mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_EQ)
#define _mm512_cmpge_epu32_mask(A, B) \
_mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_GE)
#define _mm512_mask_cmpge_epu32_mask(k, A, B) \
_mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_GE)
#define _mm512_cmpgt_epu32_mask(A, B) \
_mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_GT)
#define _mm512_mask_cmpgt_epu32_mask(k, A, B) \
_mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_GT)
#define _mm512_cmple_epu32_mask(A, B) \
_mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_LE)
#define _mm512_mask_cmple_epu32_mask(k, A, B) \
_mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_LE)
#define _mm512_cmplt_epu32_mask(A, B) \
_mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_LT)
#define _mm512_mask_cmplt_epu32_mask(k, A, B) \
_mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_LT)
#define _mm512_cmpneq_epu32_mask(A, B) \
_mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_NE)
#define _mm512_mask_cmpneq_epu32_mask(k, A, B) \
_mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_NE)
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmpeq_epu32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 0,
(__mmask16)-1);
}
#define _mm512_cmpeq_epi64_mask(A, B) \
_mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_EQ)
#define _mm512_mask_cmpeq_epi64_mask(k, A, B) \
_mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_EQ)
#define _mm512_cmpge_epi64_mask(A, B) \
_mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_GE)
#define _mm512_mask_cmpge_epi64_mask(k, A, B) \
_mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_GE)
#define _mm512_cmpgt_epi64_mask(A, B) \
_mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_GT)
#define _mm512_mask_cmpgt_epi64_mask(k, A, B) \
_mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_GT)
#define _mm512_cmple_epi64_mask(A, B) \
_mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_LE)
#define _mm512_mask_cmple_epi64_mask(k, A, B) \
_mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_LE)
#define _mm512_cmplt_epi64_mask(A, B) \
_mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_LT)
#define _mm512_mask_cmplt_epi64_mask(k, A, B) \
_mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_LT)
#define _mm512_cmpneq_epi64_mask(A, B) \
_mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_NE)
#define _mm512_mask_cmpneq_epi64_mask(k, A, B) \
_mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_NE)
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmpeq_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 0,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmpeq_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_pcmpeqq512_mask((__v8di)__a, (__v8di)__b,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmpeq_epi64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_pcmpeqq512_mask((__v8di)__a, (__v8di)__b,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmpeq_epu64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 0,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmpeq_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 0,
__u);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmpge_epi32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 5,
(__mmask16)-1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmpge_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 5,
__u);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmpge_epu32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 5,
(__mmask16)-1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmpge_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 5,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmpge_epi64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 5,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmpge_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 5,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmpge_epu64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 5,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmpge_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 5,
__u);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmpgt_epi32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_pcmpgtd512_mask((__v16si)__a, (__v16si)__b,
(__mmask16)-1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmpgt_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_pcmpgtd512_mask((__v16si)__a, (__v16si)__b,
__u);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmpgt_epu32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 6,
(__mmask16)-1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmpgt_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 6,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmpgt_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_pcmpgtq512_mask((__v8di)__a, (__v8di)__b,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmpgt_epi64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_pcmpgtq512_mask((__v8di)__a, (__v8di)__b,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmpgt_epu64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 6,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmpgt_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 6,
__u);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmple_epi32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 2,
(__mmask16)-1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmple_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 2,
__u);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmple_epu32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 2,
(__mmask16)-1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmple_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 2,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmple_epi64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 2,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmple_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 2,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmple_epu64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 2,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmple_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 2,
__u);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmplt_epi32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 1,
(__mmask16)-1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmplt_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 1,
__u);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmplt_epu32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 1,
(__mmask16)-1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmplt_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 1,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmplt_epi64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 1,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmplt_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 1,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmplt_epu64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 1,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmplt_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 1,
__u);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmpneq_epi32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 4,
(__mmask16)-1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmpneq_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 4,
__u);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_cmpneq_epu32_mask(__m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 4,
(__mmask16)-1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_cmpneq_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) {
return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 4,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmpneq_epi64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 4,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmpneq_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 4,
__u);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_cmpneq_epu64_mask(__m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 4,
(__mmask8)-1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_cmpneq_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) {
return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 4,
__u);
}
#define _mm512_cmpeq_epu64_mask(A, B) \
_mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_EQ)
#define _mm512_mask_cmpeq_epu64_mask(k, A, B) \
_mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_EQ)
#define _mm512_cmpge_epu64_mask(A, B) \
_mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_GE)
#define _mm512_mask_cmpge_epu64_mask(k, A, B) \
_mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_GE)
#define _mm512_cmpgt_epu64_mask(A, B) \
_mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_GT)
#define _mm512_mask_cmpgt_epu64_mask(k, A, B) \
_mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_GT)
#define _mm512_cmple_epu64_mask(A, B) \
_mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_LE)
#define _mm512_mask_cmple_epu64_mask(k, A, B) \
_mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_LE)
#define _mm512_cmplt_epu64_mask(A, B) \
_mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_LT)
#define _mm512_mask_cmplt_epu64_mask(k, A, B) \
_mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_LT)
#define _mm512_cmpneq_epu64_mask(A, B) \
_mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_NE)
#define _mm512_mask_cmpneq_epu64_mask(k, A, B) \
_mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_NE)
static __inline__ __m512i __DEFAULT_FN_ATTRS
_mm512_cvtepi8_epi32(__m128i __A)
@ -6797,35 +6578,6 @@ _mm512_maskz_permutex2var_ps (__mmask16 __U, __m512 __A, __m512i __I,
(__mmask16) __U);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_testn_epi32_mask (__m512i __A, __m512i __B)
{
return (__mmask16) __builtin_ia32_ptestnmd512 ((__v16si) __A,
(__v16si) __B,
(__mmask16) -1);
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_testn_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B)
{
return (__mmask16) __builtin_ia32_ptestnmd512 ((__v16si) __A,
(__v16si) __B, __U);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_testn_epi64_mask (__m512i __A, __m512i __B)
{
return (__mmask8) __builtin_ia32_ptestnmq512 ((__v8di) __A,
(__v8di) __B,
(__mmask8) -1);
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_testn_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B)
{
return (__mmask8) __builtin_ia32_ptestnmq512 ((__v8di) __A,
(__v8di) __B, __U);
}
#define _mm512_cvtt_roundpd_epu32(A, R) __extension__ ({ \
(__m256i)__builtin_ia32_cvttpd2udq512_mask((__v8df)(__m512d)(A), \
@ -7194,76 +6946,100 @@ _mm512_maskz_srai_epi64(__mmask8 __U, __m512i __A, int __B)
}
#define _mm512_shuffle_f32x4(A, B, imm) __extension__ ({ \
(__m512)__builtin_ia32_shuf_f32x4_mask((__v16sf)(__m512)(A), \
(__v16sf)(__m512)(B), (int)(imm), \
(__v16sf)_mm512_undefined_ps(), \
(__mmask16)-1); })
(__m512)__builtin_shufflevector((__v16sf)(__m512)(A), \
(__v16sf)(__m512)(B), \
0 + ((((imm) >> 0) & 0x3) * 4), \
1 + ((((imm) >> 0) & 0x3) * 4), \
2 + ((((imm) >> 0) & 0x3) * 4), \
3 + ((((imm) >> 0) & 0x3) * 4), \
0 + ((((imm) >> 2) & 0x3) * 4), \
1 + ((((imm) >> 2) & 0x3) * 4), \
2 + ((((imm) >> 2) & 0x3) * 4), \
3 + ((((imm) >> 2) & 0x3) * 4), \
16 + ((((imm) >> 4) & 0x3) * 4), \
17 + ((((imm) >> 4) & 0x3) * 4), \
18 + ((((imm) >> 4) & 0x3) * 4), \
19 + ((((imm) >> 4) & 0x3) * 4), \
16 + ((((imm) >> 6) & 0x3) * 4), \
17 + ((((imm) >> 6) & 0x3) * 4), \
18 + ((((imm) >> 6) & 0x3) * 4), \
19 + ((((imm) >> 6) & 0x3) * 4)); })
#define _mm512_mask_shuffle_f32x4(W, U, A, B, imm) __extension__ ({ \
(__m512)__builtin_ia32_shuf_f32x4_mask((__v16sf)(__m512)(A), \
(__v16sf)(__m512)(B), (int)(imm), \
(__v16sf)(__m512)(W), \
(__mmask16)(U)); })
(__m512)__builtin_ia32_selectps_512((__mmask16)(U), \
(__v16sf)_mm512_shuffle_f32x4((A), (B), (imm)), \
(__v16sf)(__m512)(W)); })
#define _mm512_maskz_shuffle_f32x4(U, A, B, imm) __extension__ ({ \
(__m512)__builtin_ia32_shuf_f32x4_mask((__v16sf)(__m512)(A), \
(__v16sf)(__m512)(B), (int)(imm), \
(__v16sf)_mm512_setzero_ps(), \
(__mmask16)(U)); })
(__m512)__builtin_ia32_selectps_512((__mmask16)(U), \
(__v16sf)_mm512_shuffle_f32x4((A), (B), (imm)), \
(__v16sf)_mm512_setzero_ps()); })
#define _mm512_shuffle_f64x2(A, B, imm) __extension__ ({ \
(__m512d)__builtin_ia32_shuf_f64x2_mask((__v8df)(__m512d)(A), \
(__v8df)(__m512d)(B), (int)(imm), \
(__v8df)_mm512_undefined_pd(), \
(__mmask8)-1); })
(__m512d)__builtin_shufflevector((__v8df)(__m512d)(A), \
(__v8df)(__m512d)(B), \
0 + ((((imm) >> 0) & 0x3) * 2), \
1 + ((((imm) >> 0) & 0x3) * 2), \
0 + ((((imm) >> 2) & 0x3) * 2), \
1 + ((((imm) >> 2) & 0x3) * 2), \
8 + ((((imm) >> 4) & 0x3) * 2), \
9 + ((((imm) >> 4) & 0x3) * 2), \
8 + ((((imm) >> 6) & 0x3) * 2), \
9 + ((((imm) >> 6) & 0x3) * 2)); })
#define _mm512_mask_shuffle_f64x2(W, U, A, B, imm) __extension__ ({ \
(__m512d)__builtin_ia32_shuf_f64x2_mask((__v8df)(__m512d)(A), \
(__v8df)(__m512d)(B), (int)(imm), \
(__v8df)(__m512d)(W), \
(__mmask8)(U)); })
(__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \
(__v8df)_mm512_shuffle_f64x2((A), (B), (imm)), \
(__v8df)(__m512d)(W)); })
#define _mm512_maskz_shuffle_f64x2(U, A, B, imm) __extension__ ({ \
(__m512d)__builtin_ia32_shuf_f64x2_mask((__v8df)(__m512d)(A), \
(__v8df)(__m512d)(B), (int)(imm), \
(__v8df)_mm512_setzero_pd(), \
(__mmask8)(U)); })
(__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \
(__v8df)_mm512_shuffle_f64x2((A), (B), (imm)), \
(__v8df)_mm512_setzero_pd()); })
#define _mm512_shuffle_i32x4(A, B, imm) __extension__ ({ \
(__m512i)__builtin_ia32_shuf_i32x4_mask((__v16si)(__m512i)(A), \
(__v16si)(__m512i)(B), (int)(imm), \
(__v16si)_mm512_setzero_si512(), \
(__mmask16)-1); })
(__m512i)__builtin_shufflevector((__v8di)(__m512i)(A), \
(__v8di)(__m512i)(B), \
0 + ((((imm) >> 0) & 0x3) * 2), \
1 + ((((imm) >> 0) & 0x3) * 2), \
0 + ((((imm) >> 2) & 0x3) * 2), \
1 + ((((imm) >> 2) & 0x3) * 2), \
8 + ((((imm) >> 4) & 0x3) * 2), \
9 + ((((imm) >> 4) & 0x3) * 2), \
8 + ((((imm) >> 6) & 0x3) * 2), \
9 + ((((imm) >> 6) & 0x3) * 2)); })
#define _mm512_mask_shuffle_i32x4(W, U, A, B, imm) __extension__ ({ \
(__m512i)__builtin_ia32_shuf_i32x4_mask((__v16si)(__m512i)(A), \
(__v16si)(__m512i)(B), (int)(imm), \
(__v16si)(__m512i)(W), \
(__mmask16)(U)); })
(__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \
(__v16si)_mm512_shuffle_i32x4((A), (B), (imm)), \
(__v16si)(__m512i)(W)); })
#define _mm512_maskz_shuffle_i32x4(U, A, B, imm) __extension__ ({ \
(__m512i)__builtin_ia32_shuf_i32x4_mask((__v16si)(__m512i)(A), \
(__v16si)(__m512i)(B), (int)(imm), \
(__v16si)_mm512_setzero_si512(), \
(__mmask16)(U)); })
(__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \
(__v16si)_mm512_shuffle_i32x4((A), (B), (imm)), \
(__v16si)_mm512_setzero_si512()); })
#define _mm512_shuffle_i64x2(A, B, imm) __extension__ ({ \
(__m512i)__builtin_ia32_shuf_i64x2_mask((__v8di)(__m512i)(A), \
(__v8di)(__m512i)(B), (int)(imm), \
(__v8di)_mm512_setzero_si512(), \
(__mmask8)-1); })
(__m512i)__builtin_shufflevector((__v8di)(__m512i)(A), \
(__v8di)(__m512i)(B), \
0 + ((((imm) >> 0) & 0x3) * 2), \
1 + ((((imm) >> 0) & 0x3) * 2), \
0 + ((((imm) >> 2) & 0x3) * 2), \
1 + ((((imm) >> 2) & 0x3) * 2), \
8 + ((((imm) >> 4) & 0x3) * 2), \
9 + ((((imm) >> 4) & 0x3) * 2), \
8 + ((((imm) >> 6) & 0x3) * 2), \
9 + ((((imm) >> 6) & 0x3) * 2)); })
#define _mm512_mask_shuffle_i64x2(W, U, A, B, imm) __extension__ ({ \
(__m512i)__builtin_ia32_shuf_i64x2_mask((__v8di)(__m512i)(A), \
(__v8di)(__m512i)(B), (int)(imm), \
(__v8di)(__m512i)(W), \
(__mmask8)(U)); })
(__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \
(__v8di)_mm512_shuffle_i64x2((A), (B), (imm)), \
(__v8di)(__m512i)(W)); })
#define _mm512_maskz_shuffle_i64x2(U, A, B, imm) __extension__ ({ \
(__m512i)__builtin_ia32_shuf_i64x2_mask((__v8di)(__m512i)(A), \
(__v8di)(__m512i)(B), (int)(imm), \
(__v8di)_mm512_setzero_si512(), \
(__mmask8)(U)); })
(__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \
(__v8di)_mm512_shuffle_i64x2((A), (B), (imm)), \
(__v8di)_mm512_setzero_si512()); })
#define _mm512_shuffle_pd(A, B, M) __extension__ ({ \
(__m512d)__builtin_shufflevector((__v8df)(__m512d)(A), \
@ -9166,6 +8942,64 @@ _mm512_maskz_compress_epi32 (__mmask16 __U, __m512i __A)
(__mmask8)(M), \
_MM_FROUND_CUR_DIRECTION); })
/* Bit Test */
static __inline __mmask16 __DEFAULT_FN_ATTRS
_mm512_test_epi32_mask (__m512i __A, __m512i __B)
{
return _mm512_cmpneq_epi32_mask (_mm512_and_epi32(__A, __B),
_mm512_setzero_epi32());
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_test_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B)
{
return _mm512_mask_cmpneq_epi32_mask (__U, _mm512_and_epi32 (__A, __B),
_mm512_setzero_epi32());
}
static __inline __mmask8 __DEFAULT_FN_ATTRS
_mm512_test_epi64_mask (__m512i __A, __m512i __B)
{
return _mm512_cmpneq_epi64_mask (_mm512_and_epi32 (__A, __B),
_mm512_setzero_epi32());
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_test_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B)
{
return _mm512_mask_cmpneq_epi64_mask (__U, _mm512_and_epi32 (__A, __B),
_mm512_setzero_epi32());
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_testn_epi32_mask (__m512i __A, __m512i __B)
{
return _mm512_cmpeq_epi32_mask (_mm512_and_epi32 (__A, __B),
_mm512_setzero_epi32());
}
static __inline__ __mmask16 __DEFAULT_FN_ATTRS
_mm512_mask_testn_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B)
{
return _mm512_mask_cmpeq_epi32_mask (__U, _mm512_and_epi32 (__A, __B),
_mm512_setzero_epi32());
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_testn_epi64_mask (__m512i __A, __m512i __B)
{
return _mm512_cmpeq_epi64_mask (_mm512_and_epi32 (__A, __B),
_mm512_setzero_epi32());
}
static __inline__ __mmask8 __DEFAULT_FN_ATTRS
_mm512_mask_testn_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B)
{
return _mm512_mask_cmpeq_epi64_mask (__U, _mm512_and_epi32 (__A, __B),
_mm512_setzero_epi32());
}
static __inline__ __m512 __DEFAULT_FN_ATTRS
_mm512_movehdup_ps (__m512 __A)
{

View File

@ -1,5 +1,5 @@
#define LLD_VERSION 5.0.0
#define LLD_VERSION_STRING "5.0.0"
#define LLD_VERSION 5.0.1
#define LLD_VERSION_STRING "5.0.1"
#define LLD_VERSION_MAJOR 5
#define LLD_VERSION_MINOR 0
#define LLD_REVISION_STRING ""

View File

@ -157,6 +157,7 @@ struct Configuration {
uint32_t MinorImageVersion = 0;
uint32_t MajorOSVersion = 6;
uint32_t MinorOSVersion = 0;
bool CanExitEarly = false;
bool DynamicBase = true;
bool NxCompat = true;
bool AllowIsolation = true;

View File

@ -52,15 +52,21 @@ BumpPtrAllocator BAlloc;
StringSaver Saver{BAlloc};
std::vector<SpecificAllocBase *> SpecificAllocBase::Instances;
bool link(ArrayRef<const char *> Args, raw_ostream &Diag) {
bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) {
ErrorCount = 0;
ErrorOS = &Diag;
Config = make<Configuration>();
Config->Argv = {Args.begin(), Args.end()};
Config->ColorDiagnostics =
(ErrorOS == &llvm::errs() && Process::StandardErrHasColors());
Config->CanExitEarly = CanExitEarly;
Driver = make<LinkerDriver>();
Driver->link(Args);
// Call exit() if we can to avoid calling destructors.
if (CanExitEarly)
exitLld(ErrorCount ? 1 : 0);
freeArena();
return !ErrorCount;
}
@ -1123,7 +1129,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// This is useful because MSVC link.exe can generate complete PDBs.
if (Args.hasArg(OPT_msvclto)) {
invokeMSVC(Args);
exit(0);
return;
}
// Do LTO by compiling bitcode input files to a set of native COFF files then

View File

@ -32,7 +32,7 @@ namespace coff {
uint64_t ErrorCount;
raw_ostream *ErrorOS;
static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) {
LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) {
// Dealloc/destroy ManagedStatic variables before calling
// _exit(). In a non-LTO build, this is a nop. In an LTO
// build allows us to get the output of -time-passes.
@ -78,7 +78,8 @@ void error(const Twine &Msg) {
print("error: ", raw_ostream::RED);
*ErrorOS << "too many errors emitted, stopping now"
<< " (use /ERRORLIMIT:0 to see all errors)\n";
exitLld(1);
if (Config->CanExitEarly)
exitLld(1);
}
++ErrorCount;

View File

@ -27,6 +27,8 @@ LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg);
LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix);
LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix);
LLVM_ATTRIBUTE_NORETURN void exitLld(int Val);
template <class T> T check(ErrorOr<T> V, const Twine &Prefix) {
if (auto EC = V.getError())
fatal(EC, Prefix);

View File

@ -427,10 +427,11 @@ CieRecord *EhFrameSection<ELFT>::addCie(EhSectionPiece &Piece,
&Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]);
// Search for an existing CIE by CIE contents/relocation target pair.
CieRecord *Cie = &CieMap[{Piece.data(), Personality}];
CieRecord *&Cie = CieMap[{Piece.data(), Personality}];
// If not found, create a new one.
if (Cie->Piece == nullptr) {
if (!Cie) {
Cie = make<CieRecord>();
Cie->Piece = &Piece;
Cies.push_back(Cie);
}
@ -522,9 +523,14 @@ template <class ELFT>
static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) {
memcpy(Buf, D.data(), D.size());
size_t Aligned = alignTo(D.size(), sizeof(typename ELFT::uint));
// Zero-clear trailing padding if it exists.
memset(Buf + D.size(), 0, Aligned - D.size());
// Fix the size field. -4 since size does not include the size field itself.
const endianness E = ELFT::TargetEndianness;
write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4);
write32<E>(Buf, Aligned - 4);
}
template <class ELFT> void EhFrameSection<ELFT>::finalizeContents() {

View File

@ -103,7 +103,8 @@ private:
std::vector<CieRecord *> Cies;
// CIE records are uniquified by their contents and personality functions.
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap;
llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord *>
CieMap;
};
class GotSection : public SyntheticSection {

View File

@ -15,7 +15,7 @@
namespace lld {
namespace coff {
bool link(llvm::ArrayRef<const char *> Args,
bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
llvm::raw_ostream &Diag = llvm::errs());
}

View File

@ -621,7 +621,6 @@ void ArchHandler_x86_64::applyFixupFinal(
// Fall into llvm_unreachable().
break;
}
return;
}
void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,

View File

@ -0,0 +1,64 @@
// REQUIRES: x86
.cfi_startproc
.cfi_personality 0x1b, bar
.cfi_endproc
.global bar
.hidden bar
bar:
// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
// Check the size of the CIE (0x18 + 4) and FDE (0x10 + 4)
// RUN: llvm-readobj -s -section-data %t.o | FileCheck --check-prefix=OBJ %s
// OBJ: Name: .eh_frame
// OBJ-NEXT: Type:
// OBJ-NEXT: Flags [
// OBJ-NEXT: SHF_ALLOC
// OBJ-NEXT: ]
// OBJ-NEXT: Address:
// OBJ-NEXT: Offset:
// OBJ-NEXT: Size:
// OBJ-NEXT: Link:
// OBJ-NEXT: Info:
// OBJ-NEXT: AddressAlignment:
// OBJ-NEXT: EntrySize:
// OBJ-NEXT: SectionData (
// OBJ-NEXT: 0000: 18000000 00000000 017A5052 00017810
// OBJ-NEXT: 0010: 061B0000 00001B0C 07089001 10000000
// OBJ-NEXT: 0020: 20000000 00000000 00000000 00000000
// OBJ-NEXT: )
// RUN: ld.lld %t.o -no-rosegment -o %t -shared
// Check that .eh_frame is in the same segment as .text
// RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=PHDR %s
// PHDR: Segment Sections
// PHDR: .text
// PHDR-SAME: .eh_frame
// Check that the CIE and FDE are padded with 0x00 and not 0xCC when the
// .eh_frame section is placed in the executable segment
// RUN: llvm-readobj -s -section-data %t | FileCheck %s
// CHECK: Name: .eh_frame
// CHECK-NEXT: Type:
// CHECK-NEXT: Flags
// CHECK-NEXT: SHF_ALLOC
// CHECK-NEXT: ]
// CHECK-NEXT: Address:
// CHECK-NEXT: Offset:
// CHECK-NEXT: Size:
// CHECK-NEXT: Link:
// CHECK-NEXT: Info:
// CHECK-NEXT: AddressAlignment:
// CHECK-NEXT: EntrySize:
// CHECK-NEXT: SectionData (
// CHECK-NEXT: 0000: 1C000000 00000000 017A5052 00017810
// CHECK-NEXT: 0010: 061BBEFF FFFF1B0C 07089001 00000000
// CHECK-NEXT: 0020: 14000000 24000000 A8FFFFFF 00000000
// CHECK-NEXT: 0030: 00000000 00000000
// CHECK-NEXT: )

View File

@ -103,7 +103,7 @@ int main(int Argc, const char **Argv) {
case Gnu:
return !elf::link(Args, true);
case WinLink:
return !coff::link(Args);
return !coff::link(Args, true);
case Darwin:
return !mach_o::link(Args);
default:

View File

@ -136,7 +136,8 @@
<li><a href="#builtin-divFloor">@divFloor</a></li>
<li><a href="#builtin-divTrunc">@divTrunc</a></li>
<li><a href="#builtin-embedFile">@embedFile</a></li>
<li><a href="#builtin-enumTagName">@enumTagName</a></li>
<li><a href="#builtin-tagName">@tagName</a></li>
<li><a href="#builtin-EnumTagType">@EnumTagType</a></li>
<li><a href="#builtin-errorName">@errorName</a></li>
<li><a href="#builtin-fence">@fence</a></li>
<li><a href="#builtin-fieldParentPtr">@fieldParentPtr</a></li>
@ -2095,30 +2096,38 @@ const Type = enum {
NotOk,
};
// Enums are sum types, and can hold more complex data of different types.
const ComplexType = enum {
Ok: u8,
NotOk: void,
};
// Declare a specific instance of the enum variant.
const c = ComplexType.Ok { 0 };
const c = Type.Ok;
// The ordinal value of a simple enum with no data members can be
// retrieved by a simple cast.
// The value starts from 0, counting up for each member.
const Value = enum {
// If you want access to the ordinal value of an enum, you
// can specify the tag type.
const Value = enum(u2) {
Zero,
One,
Two,
};
// Now you can cast between u2 and Value.
// The ordinal value starts from 0, counting up for each member.
test "enum ordinal value" {
assert(usize(Value.Zero) == 0);
assert(usize(Value.One) == 1);
assert(usize(Value.Two) == 2);
assert(u2(Value.Zero) == 0);
assert(u2(Value.One) == 1);
assert(u2(Value.Two) == 2);
}
// Enums can have methods, the same as structs.
// You can override the ordinal value for an enum.
const Value2 = enum(u32) {
Hundred = 100,
Thousand = 1000,
Million = 1000000,
};
test "set enum ordinal value" {
assert(u32(Value2.Hundred) == 100);
assert(u32(Value2.Thousand) == 1000);
assert(u32(Value2.Million) == 1000000);
}
// Enums can have methods, the same as structs and unions.
// Enum methods are not special, they are only namespaced
// functions that you can call with dot syntax.
const Suit = enum {
@ -2127,26 +2136,120 @@ const Suit = enum {
Diamonds,
Hearts,
pub fn ordinal(self: &amp;const Suit) -&gt; u8 {
u8(*self)
pub fn isClubs(self: Suit) -&gt; bool {
return self == Suit.Clubs;
}
};
test "enum method" {
const p = Suit.Spades;
assert(p.ordinal() == 1);
assert(!p.isClubs());
}
// An enum variant of different types can be switched upon.
// The associated data can be retrieved using `|...|` syntax.
//
// A void type is not required on a tag-only member.
const Foo = enum {
String: []const u8,
Number: u64,
String,
Number,
None,
};
test "enum variant switch" {
const p = Foo.Number { 54 };
const p = Foo.Number;
const what_is_it = switch (p) {
Foo.String =&gt; "this is a string",
Foo.Number =&gt; "this is a number",
Foo.None =&gt; "this is a none",
};
assert(mem.eql(u8, what_is_it, "this is a number"));
}
// @TagType can be used to access the integer tag type of an enum.
const Small = enum {
One,
Two,
Three,
Four,
};
test "@TagType" {
assert(@TagType(Small) == u2);
}
// @memberCount tells how many fields an enum has:
test "@memberCount" {
assert(@memberCount(Small) == 4);
}
// @memberName tells the name of a field in an enum:
test "@memberName" {
assert(mem.eql(u8, @memberName(Small, 1), "Two"));
}
// @tagName gives a []const u8 representation of an enum value:
test "@tagName" {
assert(mem.eql(u8, @tagName(Small.Three), "Three"));
}</code></pre>
<p>TODO extern enum</p>
<p>TODO packed enum</p>
<pre><code class="sh">$ zig test enum.zig
Test 1/8 enum ordinal value...OK
Test 2/8 set enum ordinal value...OK
Test 3/8 enum method...OK
Test 4/8 enum variant switch...OK
Test 5/8 @TagType...OK
Test 6/8 @memberCount...OK
Test 7/8 @memberName...OK
Test 8/8 @tagName...OK</code></pre>
<p>See also:</p>
<ul>
<li><a href="#builtin-memberName">@memberName</a></li>
<li><a href="#builtin-memberCount">@memberCount</a></li>
<li><a href="#builtin-tagName">@tagName</a></li>
</ul>
<h2 id="union">union</h2>
<pre><code class="zig">const assert = @import("std").debug.assert;
const mem = @import("std").mem;
// A union has only 1 active field at a time.
const Payload = union {
Int: i64,
Float: f64,
Bool: bool,
};
test "simple union" {
var payload = Payload {.Int = 1234};
// payload.Float = 12.34; // ERROR! field not active
assert(payload.Int == 1234);
// You can activate another field by assigning the entire union.
payload = Payload {.Float = 12.34};
assert(payload.Float == 12.34);
}
// Unions can be given an enum tag type:
const ComplexTypeTag = enum { Ok, NotOk };
const ComplexType = union(ComplexTypeTag) {
Ok: u8,
NotOk: void,
};
// Declare a specific instance of the union variant.
test "declare union value" {
const c = ComplexType { .Ok = 0 };
assert(ComplexTypeTag(c) == ComplexTypeTag.Ok);
}
// @TagType can be used to access the enum tag type of a union.
test "@TagType" {
assert(@TagType(ComplexType) == ComplexTypeTag);
}
// Unions can be made to infer the enum tag type.
const Foo = union(enum) {
String: []const u8,
Number: u64,
// void can be omitted when inferring enum tag type.
None,
};
test "union variant switch" {
const p = Foo { .Number = 54 };
const what_is_it = switch (p) {
// Capture by reference
Foo.String =&gt; |*x| {
@ -2155,6 +2258,7 @@ test "enum variant switch" {
// Capture by value
Foo.Number =&gt; |x| {
assert(x == 54);
"this is a number"
},
@ -2162,37 +2266,50 @@ test "enum variant switch" {
"this is a none"
}
};
assert(mem.eql(u8, what_is_it, "this is a number"));
}
// The @enumTagName and @memberCount builtin functions can be used to
// the string representation and number of members respectively.
const BuiltinType = enum {
A: f32,
B: u32,
C,
// TODO union methods
const Small = union {
A: i32,
B: bool,
C: u8,
};
test "enum builtins" {
assert(mem.eql(u8, @enumTagName(BuiltinType.A { 0 }), "A"));
assert(mem.eql(u8, @enumTagName(BuiltinType.C), "C"));
assert(@memberCount(BuiltinType) == 3);
// @memberCount tells how many fields a union has:
test "@memberCount" {
assert(@memberCount(Small) == 3);
}
// @memberName tells the name of a field in an enum:
test "@memberName" {
assert(mem.eql(u8, @memberName(Small, 1), "B"));
}
// @tagName gives a []const u8 representation of an enum value,
// but only if the union has an enum tag type.
const Small2 = union(enum) {
A: i32,
B: bool,
C: u8,
};
test "@tagName" {
assert(mem.eql(u8, @tagName(Small2.C), "C"));
}</code></pre>
<pre><code class="sh">$ zig test enum.zig
Test 1/4 enum ordinal value...OK
Test 2/4 enum method...OK
Test 3/4 enum variant switch...OK
Test 4/4 enum builtins...OK</code></pre>
<pre><code class="sh">$ zig test union.zig
Test 1/7 simple union...OK
Test 2/7 declare union value...OK
Test 3/7 @TagType...OK
Test 4/7 union variant switch...OK
Test 5/7 @memberCount...OK
Test 6/7 @memberName...OK
Test 7/7 @tagName...OK</code></pre>
<p>
Enums are generated as a struct with a tag field and union field. Zig
Unions with an enum tag are generated as a struct with a tag field and union field. Zig
sorts the order of the tag and union field by the largest alignment.
</p>
<p>See also:</p>
<ul>
<li><a href="#builtin-enumTagName">@enumTagName</a></li>
<li><a href="#builtin-memberCount">@memberCount</a></li>
</ul>
<h2 id="union">union</h2>
<p>TODO union documentation</p>
<h2 id="switch">switch</h2>
<pre><code class="zig">const assert = @import("std").debug.assert;
const builtin = @import("builtin");
@ -4251,10 +4368,15 @@ test.zig:6:2: error: found compile log statement
<ul>
<li><a href="#builtin-import">@import</a></li>
</ul>
<h3 id="builtin-enumTagName">@enumTagName</h3>
<pre><code class="zig">@enumTagName(value: var) -&gt; []const u8</code></pre>
<h3 id="builtin-tagName">@tagName</h3>
<pre><code class="zig">@tagName(value: var) -&gt; []const u8</code></pre>
<p>
Converts an enum tag name to a slice of bytes.
Converts an enum value or union value to a slice of bytes representing the name.
</p>
<h3 id="builtin-EnumTagType">@EnumTagType</h3>
<pre><code class="zig">@EnumTagType(T: type) -&gt; type</code></pre>
<p>
Returns the integer type that is used to store the enumeration value.
</p>
<h3 id="builtin-errorName">@errorName</h3>
<pre><code class="zig">@errorName(err: error) -&gt; []u8</code></pre>
@ -5703,7 +5825,7 @@ VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" Typ
ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
ContainerField = Symbol option(":" Expression) ","
ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression ","
UseDecl = "use" Expression ";"
@ -5837,7 +5959,9 @@ GroupedExpression = "(" Expression ")"
KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"</code></pre>
ContainerDecl = option("extern" | "packed")
("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression)))
"{" many(ContainerMember) "}"</code></pre>
<h2 id="zen">Zen</h2>
<ul>
<li>Communicate intent precisely.</li>

View File

@ -1,3 +1,4 @@
const builtin = @import("builtin");
const std = @import("std");
const io = std.io;
const fmt = std.fmt;
@ -15,7 +16,7 @@ pub fn main() -> %void {
var seed_bytes: [@sizeOf(usize)]u8 = undefined;
%%os.getRandomBytes(seed_bytes[0..]);
const seed = std.mem.readInt(seed_bytes, usize, true);
const seed = std.mem.readInt(seed_bytes, usize, builtin.Endian.Big);
var rand = Rand.init(seed);
const answer = rand.range(u8, 0, 100) + 1;

View File

@ -97,18 +97,13 @@ struct ConstParent {
} data;
};
struct ConstEnumValue {
uint64_t tag;
ConstExprValue *payload;
};
struct ConstStructValue {
ConstExprValue *fields;
ConstParent parent;
};
struct ConstUnionValue {
uint64_t tag;
BigInt tag;
ConstExprValue *payload;
ConstParent parent;
};
@ -249,7 +244,7 @@ struct ConstExprValue {
ConstExprValue *x_maybe;
ConstErrValue x_err_union;
ErrorTableEntry *x_pure_err;
ConstEnumValue x_enum;
BigInt x_enum_tag;
ConstStructValue x_struct;
ConstUnionValue x_union;
ConstArrayValue x_array;
@ -345,15 +340,14 @@ struct TldCompTime {
struct TypeEnumField {
Buf *name;
TypeTableEntry *type_entry;
uint32_t value;
uint32_t gen_index;
BigInt value;
uint32_t decl_index;
};
struct TypeUnionField {
Buf *name;
TypeEnumField *enum_field;
TypeTableEntry *type_entry;
uint32_t value;
uint32_t gen_index;
};
@ -773,13 +767,15 @@ struct AstNodeContainerDecl {
ZigList<AstNode *> fields;
ZigList<AstNode *> decls;
ContainerLayout layout;
AstNode *init_arg_expr; // enum(T) or struct(endianness)
AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T))
bool auto_enum; // union(enum)
};
struct AstNodeStructField {
VisibMod visib_mod;
Buf *name;
AstNode *type;
AstNode *value;
};
struct AstNodeStringLiteral {
@ -1009,12 +1005,9 @@ struct TypeTableEntryEnum {
AstNode *decl_node;
ContainerLayout layout;
uint32_t src_field_count;
// number of fields in the union. 0 if enum with no payload
uint32_t gen_field_count;
TypeEnumField *fields;
bool is_invalid; // true if any fields are invalid
TypeTableEntry *tag_type;
LLVMTypeRef union_type_ref;
TypeTableEntry *tag_int_type;
ScopeDecls *decls_scope;
@ -1026,18 +1019,7 @@ struct TypeTableEntryEnum {
bool zero_bits_loop_flag;
bool zero_bits_known;
uint32_t abi_alignment; // also figured out with zero_bits pass
size_t gen_union_index;
size_t gen_tag_index;
uint32_t union_size_bytes;
TypeTableEntry *most_aligned_union_member;
};
struct TypeTableEntryEnumTag {
TypeTableEntry *enum_type;
TypeTableEntry *int_type;
bool generate_name_table;
LLVMValueRef name_table;
};
@ -1052,7 +1034,7 @@ struct TypeTableEntryUnion {
uint32_t gen_field_count;
TypeUnionField *fields;
bool is_invalid; // true if any fields are invalid
TypeTableEntry *tag_type;
TypeTableEntry *tag_type; // always an enum or null
LLVMTypeRef union_type_ref;
ScopeDecls *decls_scope;
@ -1117,7 +1099,6 @@ enum TypeTableEntryId {
TypeTableEntryIdErrorUnion,
TypeTableEntryIdPureError,
TypeTableEntryIdEnum,
TypeTableEntryIdEnumTag,
TypeTableEntryIdUnion,
TypeTableEntryIdFn,
TypeTableEntryIdNamespace,
@ -1146,7 +1127,6 @@ struct TypeTableEntry {
TypeTableEntryMaybe maybe;
TypeTableEntryError error;
TypeTableEntryEnum enumeration;
TypeTableEntryEnumTag enum_tag;
TypeTableEntryUnion unionation;
TypeTableEntryFn fn;
TypeTableEntryBoundFn bound_fn;
@ -1285,7 +1265,8 @@ enum BuiltinFnId {
BuiltinFnIdBitCast,
BuiltinFnIdIntToPtr,
BuiltinFnIdPtrToInt,
BuiltinFnIdEnumTagName,
BuiltinFnIdTagName,
BuiltinFnIdTagType,
BuiltinFnIdFieldParentPtr,
BuiltinFnIdOffsetOf,
BuiltinFnIdInlineCall,
@ -1829,7 +1810,6 @@ enum IrInstructionId {
IrInstructionIdStorePtr,
IrInstructionIdFieldPtr,
IrInstructionIdStructFieldPtr,
IrInstructionIdEnumFieldPtr,
IrInstructionIdUnionFieldPtr,
IrInstructionIdElemPtr,
IrInstructionIdVarPtr,
@ -1854,7 +1834,7 @@ enum IrInstructionId {
IrInstructionIdTestNonNull,
IrInstructionIdUnwrapMaybe,
IrInstructionIdMaybeWrap,
IrInstructionIdEnumTag,
IrInstructionIdUnionTag,
IrInstructionIdClz,
IrInstructionIdCtz,
IrInstructionIdImport,
@ -1893,7 +1873,6 @@ enum IrInstructionId {
IrInstructionIdErrWrapPayload,
IrInstructionIdFnProto,
IrInstructionIdTestComptime,
IrInstructionIdInitEnum,
IrInstructionIdPtrCast,
IrInstructionIdBitCast,
IrInstructionIdWidenOrShorten,
@ -1910,7 +1889,8 @@ enum IrInstructionId {
IrInstructionIdSetGlobalLinkage,
IrInstructionIdDeclRef,
IrInstructionIdPanic,
IrInstructionIdEnumTagName,
IrInstructionIdTagName,
IrInstructionIdTagType,
IrInstructionIdFieldParentPtr,
IrInstructionIdOffsetOf,
IrInstructionIdTypeId,
@ -2088,14 +2068,6 @@ struct IrInstructionStructFieldPtr {
bool is_const;
};
struct IrInstructionEnumFieldPtr {
IrInstruction base;
IrInstruction *enum_ptr;
TypeEnumField *field;
bool is_const;
};
struct IrInstructionUnionFieldPtr {
IrInstruction base;
@ -2299,7 +2271,7 @@ struct IrInstructionClz {
IrInstruction *value;
};
struct IrInstructionEnumTag {
struct IrInstructionUnionTag {
IrInstruction base;
IrInstruction *value;
@ -2569,15 +2541,6 @@ struct IrInstructionTestComptime {
IrInstruction *value;
};
struct IrInstructionInitEnum {
IrInstruction base;
TypeTableEntry *enum_type;
TypeEnumField *field;
IrInstruction *init_value;
LLVMValueRef tmp_ptr;
};
struct IrInstructionPtrCast {
IrInstruction base;
@ -2689,7 +2652,13 @@ struct IrInstructionPanic {
IrInstruction *msg;
};
struct IrInstructionEnumTagName {
struct IrInstructionTagName {
IrInstruction base;
IrInstruction *target;
};
struct IrInstructionTagType {
IrInstruction base;
IrInstruction *target;

File diff suppressed because it is too large Load Diff

View File

@ -64,6 +64,9 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag);
TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag);
bool is_container_ref(TypeTableEntry *type_entry);
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
void scan_import(CodeGen *g, ImportTableEntry *import);
@ -109,6 +112,9 @@ ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);
void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *c_str);
ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *c_str);
void init_const_bigint(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *bigint);
ConstExprValue *create_const_bigint(TypeTableEntry *type, const BigInt *bigint);
void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative);
ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative);
@ -121,8 +127,8 @@ ConstExprValue *create_const_usize(CodeGen *g, uint64_t x);
void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value);
ConstExprValue *create_const_float(TypeTableEntry *type, double value);
void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, uint64_t tag);
ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag);
void init_const_enum(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag);
ConstExprValue *create_const_enum(TypeTableEntry *type, const BigInt *tag);
void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value);
ConstExprValue *create_const_bool(CodeGen *g, bool value);
@ -158,7 +164,6 @@ ConstExprValue *create_const_vals(size_t count);
TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value);
TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, TypeTableEntry *int_type);
void expand_undef_array(CodeGen *g, ConstExprValue *const_val);
void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);

View File

@ -660,7 +660,20 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
{
const char *layout_str = layout_string(node->data.container_decl.layout);
const char *container_str = container_string(node->data.container_decl.kind);
fprintf(ar->f, "%s%s {\n", layout_str, container_str);
fprintf(ar->f, "%s%s", layout_str, container_str);
if (node->data.container_decl.auto_enum) {
fprintf(ar->f, "(enum");
}
if (node->data.container_decl.init_arg_expr != nullptr) {
fprintf(ar->f, "(");
render_node_grouped(ar, node->data.container_decl.init_arg_expr);
fprintf(ar->f, ")");
}
if (node->data.container_decl.auto_enum) {
fprintf(ar->f, ")");
}
fprintf(ar->f, " {\n");
ar->indent += ar->indent_size;
for (size_t field_i = 0; field_i < node->data.container_decl.fields.length; field_i += 1) {
AstNode *field_node = node->data.container_decl.fields.at(field_i);
@ -671,6 +684,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
fprintf(ar->f, ": ");
render_node_grouped(ar, field_node->data.struct_field.type);
}
if (field_node->data.struct_field.value != nullptr) {
fprintf(ar->f, "= ");
render_node_grouped(ar, field_node->data.struct_field.value);
}
fprintf(ar->f, ",\n");
}

View File

@ -1224,3 +1224,35 @@ Cmp bigint_cmp_zero(const BigInt *op) {
}
return op->is_negative ? CmpLT : CmpGT;
}
uint32_t bigint_hash(BigInt x) {
if (x.digit_count == 0) {
return 0;
} else {
return bigint_ptr(&x)[0];
}
}
bool bigint_eql(BigInt a, BigInt b) {
return bigint_cmp(&a, &b) == CmpEQ;
}
void bigint_incr(BigInt *x) {
if (x->digit_count == 0) {
bigint_init_unsigned(x, 1);
return;
}
if (x->digit_count == 1 && x->data.digit != UINT64_MAX) {
x->data.digit += 1;
return;
}
BigInt copy;
bigint_init_bigint(&copy, x);
BigInt one;
bigint_init_unsigned(&one, 1);
bigint_add(x, &copy, &one);
}

View File

@ -88,6 +88,11 @@ size_t bigint_bits_needed(const BigInt *op);
// convenience functions
Cmp bigint_cmp_zero(const BigInt *op);
void bigint_incr(BigInt *value);
bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result);
uint32_t bigint_hash(BigInt x);
bool bigint_eql(BigInt a, BigInt b);
#endif

View File

@ -1362,8 +1362,12 @@ static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) {
if (bigint->digit_count == 0) {
return LLVMConstNull(type_ref);
}
LLVMValueRef unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref,
bigint->digit_count, bigint_ptr(bigint));
LLVMValueRef unsigned_val;
if (bigint->digit_count == 1) {
unsigned_val = LLVMConstInt(type_ref, bigint_ptr(bigint)[0], false);
} else {
unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref, bigint->digit_count, bigint_ptr(bigint));
}
if (bigint->is_negative) {
return LLVMConstNeg(unsigned_val);
} else {
@ -1627,12 +1631,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed);
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
} else if (type_entry->id == TypeTableEntryIdEnum) {
if (type_entry->data.enumeration.gen_field_count == 0) {
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
} else {
zig_unreachable();
}
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
} else if (type_entry->id == TypeTableEntryIdPureError ||
type_entry->id == TypeTableEntryIdPointer ||
type_entry->id == TypeTableEntryIdBool)
@ -1916,9 +1916,7 @@ static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executa
// enum_tag to the underlying int type
TypeTableEntry *int_type;
if (actual_type->id == TypeTableEntryIdEnum) {
TypeTableEntry *tag_type = actual_type->data.enumeration.tag_type;
assert(tag_type->id == TypeTableEntryIdEnumTag);
int_type = tag_type->data.enum_tag.int_type;
int_type = actual_type->data.enumeration.tag_int_type;
} else {
int_type = actual_type;
}
@ -1942,19 +1940,11 @@ static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, I
static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, IrInstructionIntToEnum *instruction) {
TypeTableEntry *wanted_type = instruction->base.value.type;
assert(wanted_type->id == TypeTableEntryIdEnum);
TypeTableEntry *tag_type = wanted_type->data.enumeration.tag_type;
TypeTableEntry *wanted_int_type;
if (tag_type->id == TypeTableEntryIdEnumTag) {
wanted_int_type = tag_type->data.enum_tag.int_type;
} else if (tag_type->id == TypeTableEntryIdInt) {
wanted_int_type = tag_type;
} else {
zig_unreachable();
}
TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type;
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base),
instruction->target->value.type, wanted_int_type, target_val);
instruction->target->value.type, tag_int_type, target_val);
}
static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {
@ -2374,27 +2364,6 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
return LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, "");
}
static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable,
IrInstructionEnumFieldPtr *instruction)
{
TypeTableEntry *enum_ptr_type = instruction->enum_ptr->value.type;
assert(enum_ptr_type->id == TypeTableEntryIdPointer);
TypeTableEntry *enum_type = enum_ptr_type->data.pointer.child_type;
assert(enum_type->id == TypeTableEntryIdEnum);
TypeEnumField *field = instruction->field;
if (!type_has_bits(field->type_entry))
return nullptr;
LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr);
LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_type->data.enumeration.gen_union_index, "");
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
return bitcasted_union_field_ptr;
}
static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable,
IrInstructionUnionFieldPtr *instruction)
{
@ -2420,9 +2389,10 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
if (ir_want_debug_safety(g, &instruction->base)) {
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, "");
LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, "");
LLVMValueRef expected_tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref,
field->value, false);
LLVMValueRef expected_tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
&field->enum_field->value);
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk");
LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail");
LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, tag_value, expected_tag_value, "");
@ -2747,21 +2717,21 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
}
static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable,
IrInstructionEnumTagName *instruction)
IrInstructionTagName *instruction)
{
TypeTableEntry *enum_tag_type = instruction->target->value.type;
assert(enum_tag_type->data.enum_tag.generate_name_table);
TypeTableEntry *enum_type = instruction->target->value.type;
assert(enum_type->id == TypeTableEntryIdEnum);
assert(enum_type->data.enumeration.generate_name_table);
TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
if (ir_want_debug_safety(g, &instruction->base)) {
TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type;
size_t field_count = enum_type->data.enumeration.src_field_count;
// if the field_count can't fit in the bits of the enum_tag_type, then it can't possibly
// if the field_count can't fit in the bits of the enum_type, then it can't possibly
// be the wrong value
BigInt field_bi;
bigint_init_unsigned(&field_bi, field_count);
TypeTableEntry *tag_int_type = enum_tag_type->data.enum_tag.int_type;
if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) {
LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false);
add_bounds_check(g, enum_tag_value, LLVMIntEQ, nullptr, LLVMIntULT, end_val);
@ -2770,10 +2740,10 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable
LLVMValueRef indices[] = {
LLVMConstNull(g->builtin_types.entry_usize->type_ref),
gen_widen_or_shorten(g, false, enum_tag_type->data.enum_tag.int_type,
gen_widen_or_shorten(g, false, tag_int_type,
g->builtin_types.entry_usize, enum_tag_value),
};
return LLVMBuildInBoundsGEP(g->builder, enum_tag_type->data.enum_tag.name_table, indices, 2, "");
return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, "");
}
static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable,
@ -3347,48 +3317,24 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
return instruction->tmp_ptr;
}
static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrInstructionEnumTag *instruction) {
TypeTableEntry *enum_type = instruction->value->value.type;
TypeTableEntry *tag_type = enum_type->data.enumeration.tag_type;
static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) {
TypeTableEntry *union_type = instruction->value->value.type;
assert(union_type->data.unionation.gen_tag_index != SIZE_MAX);
TypeTableEntry *tag_type = union_type->data.unionation.tag_type;
if (!type_has_bits(tag_type))
return nullptr;
LLVMValueRef enum_val = ir_llvm_value(g, instruction->value);
if (enum_type->data.enumeration.gen_field_count == 0)
return enum_val;
LLVMValueRef union_val = ir_llvm_value(g, instruction->value);
if (union_type->data.unionation.gen_field_count == 0)
return union_val;
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_type->data.enumeration.gen_tag_index, "");
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_val,
union_type->data.unionation.gen_tag_index, "");
TypeTableEntry *ptr_type = get_pointer_to_type(g, tag_type, false);
return get_handle_value(g, tag_field_ptr, tag_type, ptr_type);
}
static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) {
TypeTableEntry *enum_type = instruction->enum_type;
uint32_t value = instruction->field->value;
LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref;
LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, value, false);
if (enum_type->data.enumeration.gen_field_count == 0)
return tag_value;
LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_tag_index, "");
gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
TypeTableEntry *union_val_type = instruction->field->type_entry;
if (type_has_bits(union_val_type)) {
LLVMValueRef new_union_val = ir_llvm_value(g, instruction->init_value);
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_union_index, "");
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
LLVMPointerType(union_val_type->type_ref, 0), "");
gen_assign_raw(g, bitcasted_union_field_ptr, get_pointer_to_type(g, union_val_type, false), new_union_val);
}
return tmp_struct_ptr;
}
static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) {
for (size_t i = 0; i < instruction->field_count; i += 1) {
IrInstructionStructInitField *field = &instruction->fields[i];
@ -3429,8 +3375,9 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
if (union_type->data.unionation.gen_tag_index != SIZE_MAX) {
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
union_type->data.unionation.gen_tag_index, "");
LLVMValueRef tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref,
type_union_field->value, false);
LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
&type_union_field->enum_field->value);
gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
@ -3537,6 +3484,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
case IrInstructionIdOpaqueType:
case IrInstructionIdSetAlignStack:
case IrInstructionIdArgType:
case IrInstructionIdTagType:
zig_unreachable();
case IrInstructionIdReturn:
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
@ -3566,8 +3514,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_call(g, executable, (IrInstructionCall *)instruction);
case IrInstructionIdStructFieldPtr:
return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
case IrInstructionIdEnumFieldPtr:
return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction);
case IrInstructionIdUnionFieldPtr:
return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction);
case IrInstructionIdAsm:
@ -3622,10 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);
case IrInstructionIdErrWrapPayload:
return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction);
case IrInstructionIdEnumTag:
return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction);
case IrInstructionIdInitEnum:
return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);
case IrInstructionIdUnionTag:
return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction);
case IrInstructionIdStructInit:
return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
case IrInstructionIdUnionInit:
@ -3650,8 +3594,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction);
case IrInstructionIdPanic:
return ir_render_panic(g, executable, (IrInstructionPanic *)instruction);
case IrInstructionIdEnumTagName:
return ir_render_enum_tag_name(g, executable, (IrInstructionEnumTagName *)instruction);
case IrInstructionIdTagName:
return ir_render_enum_tag_name(g, executable, (IrInstructionTagName *)instruction);
case IrInstructionIdFieldParentPtr:
return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction);
case IrInstructionIdAlignCast:
@ -3761,8 +3705,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
case TypeTableEntryIdNullLit:
case TypeTableEntryIdErrorUnion:
case TypeTableEntryIdPureError:
case TypeTableEntryIdEnum:
case TypeTableEntryIdEnumTag:
case TypeTableEntryIdNamespace:
case TypeTableEntryIdBlock:
case TypeTableEntryIdBoundFn:
@ -3772,6 +3714,12 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
zig_unreachable();
case TypeTableEntryIdBool:
return LLVMConstInt(big_int_type_ref, const_val->data.x_bool ? 1 : 0, false);
case TypeTableEntryIdEnum:
{
assert(type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr);
LLVMValueRef int_val = gen_const_val(g, const_val);
return LLVMConstZExt(int_val, big_int_type_ref);
}
case TypeTableEntryIdInt:
{
LLVMValueRef int_val = gen_const_val(g, const_val);
@ -3813,6 +3761,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
}
return val;
}
}
zig_unreachable();
}
@ -3838,7 +3787,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
switch (type_entry->id) {
case TypeTableEntryIdInt:
case TypeTableEntryIdEnumTag:
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
case TypeTableEntryIdPureError:
assert(const_val->data.x_pure_err);
@ -4001,37 +3949,52 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
ConstExprValue *payload_value = const_val->data.x_union.payload;
assert(payload_value != nullptr);
if (!type_has_bits(payload_value->type)) {
return LLVMGetUndef(union_type_ref);
}
uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);
uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes;
LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
payload_value->type != type_entry->data.unionation.most_aligned_union_member;
LLVMValueRef union_value_ref;
{
if (pad_bytes == 0) {
union_value_ref = correctly_typed_value;
if (type_entry->data.unionation.gen_field_count == 0) {
if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
return nullptr;
} else {
LLVMValueRef fields[2];
fields[0] = correctly_typed_value;
fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes));
if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) {
union_value_ref = LLVMConstStruct(fields, 2, false);
} else {
union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2);
}
return bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
&const_val->data.x_union.tag);
}
}
if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
return union_value_ref;
LLVMValueRef union_value_ref;
bool make_unnamed_struct;
if (!type_has_bits(payload_value->type)) {
if (type_entry->data.unionation.gen_tag_index == SIZE_MAX)
return LLVMGetUndef(type_entry->type_ref);
union_value_ref = LLVMGetUndef(type_entry->data.unionation.most_aligned_union_member->type_ref);
make_unnamed_struct = false;
} else {
uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);
uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes;
LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
payload_value->type != type_entry->data.unionation.most_aligned_union_member;
{
if (pad_bytes == 0) {
union_value_ref = correctly_typed_value;
} else {
LLVMValueRef fields[2];
fields[0] = correctly_typed_value;
fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes));
if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) {
union_value_ref = LLVMConstStruct(fields, 2, false);
} else {
union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2);
}
}
}
if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
return union_value_ref;
}
}
LLVMValueRef tag_value = LLVMConstInt(type_entry->data.unionation.tag_type->type_ref, const_val->data.x_union.tag, false);
LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
&const_val->data.x_union.tag);
LLVMValueRef fields[2];
fields[type_entry->data.unionation.gen_union_index] = union_value_ref;
@ -4044,55 +4007,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
}
}
case TypeTableEntryIdEnum:
{
LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
if (type_entry->data.enumeration.gen_field_count == 0) {
return tag_value;
} else {
LLVMTypeRef union_type_ref = type_entry->data.enumeration.union_type_ref;
TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag];
assert(enum_field->value == const_val->data.x_enum.tag);
LLVMValueRef union_value;
bool make_unnamed_struct;
if (type_has_bits(enum_field->type_entry)) {
uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
enum_field->type_entry->type_ref);
uint64_t pad_bytes = type_entry->data.enumeration.union_size_bytes - field_type_bytes;
ConstExprValue *payload_value = const_val->data.x_enum.payload;
LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
payload_value->type != type_entry->data.enumeration.most_aligned_union_member;
if (pad_bytes == 0) {
union_value = correctly_typed_value;
} else {
LLVMValueRef fields[] = {
correctly_typed_value,
LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)),
};
union_value = LLVMConstStruct(fields, 2, false);
}
} else {
make_unnamed_struct = false;
union_value = LLVMGetUndef(union_type_ref);
}
LLVMValueRef fields[2];
fields[type_entry->data.enumeration.gen_tag_index] = tag_value;
fields[type_entry->data.enumeration.gen_union_index] = union_value;
if (make_unnamed_struct) {
return LLVMConstStruct(fields, 2, false);
} else {
return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
}
}
}
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_enum_tag);
case TypeTableEntryIdFn:
return fn_llvm_value(g, const_val->data.x_fn.fn_entry);
case TypeTableEntryIdPointer:
@ -4303,9 +4220,8 @@ static void generate_enum_name_tables(CodeGen *g) {
for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) {
TypeTableEntry *enum_tag_type = g->name_table_enums.at(enum_i);
assert(enum_tag_type->id == TypeTableEntryIdEnumTag);
TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type;
TypeTableEntry *enum_type = g->name_table_enums.at(enum_i);
assert(enum_type->id == TypeTableEntryIdEnum);
size_t field_count = enum_type->data.enumeration.src_field_count;
LLVMValueRef *values = allocate<LLVMValueRef>(field_count);
@ -4336,7 +4252,7 @@ static void generate_enum_name_tables(CodeGen *g) {
LLVMSetGlobalConstant(name_table, true);
LLVMSetUnnamedAddr(name_table, true);
LLVMSetAlignment(name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(name_table_init)));
enum_tag_type->data.enum_tag.name_table = name_table;
enum_type->data.enumeration.name_table = name_table;
}
}
@ -4540,9 +4456,6 @@ static void do_code_gen(CodeGen *g) {
} else if (instruction->id == IrInstructionIdErrWrapCode) {
IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
slot = &err_wrap_code_instruction->tmp_ptr;
} else if (instruction->id == IrInstructionIdInitEnum) {
IrInstructionInitEnum *init_enum_instruction = (IrInstructionInitEnum *)instruction;
slot = &init_enum_instruction->tmp_ptr;
} else {
zig_unreachable();
}
@ -5039,7 +4952,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2);
create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2);
create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2);
create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
@ -5049,7 +4962,8 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2);
create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);
create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1);
create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1);
create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1);
create_builtin_fn(g, BuiltinFnIdTagType, "TagType", 1);
create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3);
create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2);
create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2);
@ -5215,7 +5129,19 @@ static void define_builtin_compile_vars(CodeGen *g) {
assert(FloatModeOptimized == 0);
assert(FloatModeStrict == 1);
}
buf_appendf(contents, "pub const is_big_endian = %s;\n", bool_to_str(g->is_big_endian));
{
buf_appendf(contents,
"pub const Endian = enum {\n"
" Big,\n"
" Little,\n"
"};\n\n");
assert(FloatModeOptimized == 0);
assert(FloatModeStrict == 1);
}
{
const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little";
buf_appendf(contents, "pub const endian = %s;\n", endian_str);
}
buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
buf_appendf(contents, "pub const os = Os.%s;\n", cur_os);
buf_appendf(contents, "pub const arch = Arch.%s;\n", cur_arch);
@ -5665,7 +5591,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
case TypeTableEntryIdEnum:
case TypeTableEntryIdUnion:
case TypeTableEntryIdFn:
case TypeTableEntryIdEnumTag:
zig_panic("TODO implement get_c_type for more types");
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:

View File

@ -24,20 +24,20 @@ static void print_err_msg_type(ErrorMsg *err, ErrColor color, ErrType err_type)
bool is_tty = os_stderr_tty();
if (color == ErrColorOn || (color == ErrColorAuto && is_tty)) {
if (err_type == ErrTypeError) {
os_stderr_set_color(TermColorWhite);
os_stderr_set_color(TermColorBold);
fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", path, line, col);
os_stderr_set_color(TermColorRed);
fprintf(stderr, "error:");
os_stderr_set_color(TermColorWhite);
os_stderr_set_color(TermColorBold);
fprintf(stderr, " %s", text);
os_stderr_set_color(TermColorReset);
fprintf(stderr, "\n");
} else if (err_type == ErrTypeNote) {
os_stderr_set_color(TermColorWhite);
os_stderr_set_color(TermColorBold);
fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", path, line, col);
os_stderr_set_color(TermColorCyan);
fprintf(stderr, "note:");
os_stderr_set_color(TermColorWhite);
os_stderr_set_color(TermColorBold);
fprintf(stderr, " %s", text);
os_stderr_set_color(TermColorReset);
fprintf(stderr, "\n");

View File

@ -26,6 +26,7 @@ const char *err_str(int err) {
case ErrorExactDivRemainder: return "exact division had a remainder";
case ErrorNegativeDenominator: return "negative denominator";
case ErrorShiftedOutOneBits: return "exact shift shifted out one bits";
case ErrorCCompileErrors: return "C compile errors";
}
return "(invalid error)";
}

View File

@ -26,6 +26,7 @@ enum Error {
ErrorExactDivRemainder,
ErrorNegativeDenominator,
ErrorShiftedOutOneBits,
ErrorCCompileErrors,
};
const char *err_str(int err);

File diff suppressed because it is too large Load Diff

View File

@ -291,7 +291,7 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct
}
static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) {
Buf *field_name = instruction->field->name;
Buf *field_name = instruction->field->enum_field->name;
fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name));
fprintf(irp->f, ".%s = ", buf_ptr(field_name));
@ -361,17 +361,10 @@ static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr
fprintf(irp->f, ")");
}
static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *instruction) {
fprintf(irp->f, "@EnumFieldPtr(&");
ir_print_other_instruction(irp, instruction->enum_ptr);
fprintf(irp->f, ".%s", buf_ptr(instruction->field->name));
fprintf(irp->f, ")");
}
static void ir_print_union_field_ptr(IrPrint *irp, IrInstructionUnionFieldPtr *instruction) {
fprintf(irp->f, "@UnionFieldPtr(&");
ir_print_other_instruction(irp, instruction->union_ptr);
fprintf(irp->f, ".%s", buf_ptr(instruction->field->name));
fprintf(irp->f, ".%s", buf_ptr(instruction->field->enum_field->name));
fprintf(irp->f, ")");
}
@ -509,8 +502,8 @@ static void ir_print_switch_target(IrPrint *irp, IrInstructionSwitchTarget *inst
ir_print_other_instruction(irp, instruction->target_value_ptr);
}
static void ir_print_enum_tag(IrPrint *irp, IrInstructionEnumTag *instruction) {
fprintf(irp->f, "enumtag ");
static void ir_print_union_tag(IrPrint *irp, IrInstructionUnionTag *instruction) {
fprintf(irp->f, "uniontag ");
ir_print_other_instruction(irp, instruction->value);
}
@ -799,12 +792,6 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst
fprintf(irp->f, ")");
}
static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction) {
fprintf(irp->f, "%s.%s {", buf_ptr(&instruction->enum_type->name), buf_ptr(instruction->field->name));
ir_print_other_instruction(irp, instruction->init_value);
fprintf(irp->f, "}");
}
static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
fprintf(irp->f, "@ptrCast(");
if (instruction->dest_type) {
@ -885,8 +872,8 @@ static void ir_print_type_name(IrPrint *irp, IrInstructionTypeName *instruction)
ir_print_other_instruction(irp, instruction->type_value);
}
static void ir_print_enum_tag_name(IrPrint *irp, IrInstructionEnumTagName *instruction) {
fprintf(irp->f, "enumtagname ");
static void ir_print_tag_name(IrPrint *irp, IrInstructionTagName *instruction) {
fprintf(irp->f, "tagname ");
ir_print_other_instruction(irp, instruction->target);
}
@ -994,6 +981,12 @@ static void ir_print_arg_type(IrPrint *irp, IrInstructionArgType *instruction) {
fprintf(irp->f, ")");
}
static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionTagType *instruction) {
fprintf(irp->f, "@TagType(");
ir_print_other_instruction(irp, instruction->target);
fprintf(irp->f, ")");
}
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
@ -1072,9 +1065,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdStructFieldPtr:
ir_print_struct_field_ptr(irp, (IrInstructionStructFieldPtr *)instruction);
break;
case IrInstructionIdEnumFieldPtr:
ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction);
break;
case IrInstructionIdUnionFieldPtr:
ir_print_union_field_ptr(irp, (IrInstructionUnionFieldPtr *)instruction);
break;
@ -1117,8 +1107,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdSwitchTarget:
ir_print_switch_target(irp, (IrInstructionSwitchTarget *)instruction);
break;
case IrInstructionIdEnumTag:
ir_print_enum_tag(irp, (IrInstructionEnumTag *)instruction);
case IrInstructionIdUnionTag:
ir_print_union_tag(irp, (IrInstructionUnionTag *)instruction);
break;
case IrInstructionIdImport:
ir_print_import(irp, (IrInstructionImport *)instruction);
@ -1231,9 +1221,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdTestComptime:
ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction);
break;
case IrInstructionIdInitEnum:
ir_print_init_enum(irp, (IrInstructionInitEnum *)instruction);
break;
case IrInstructionIdPtrCast:
ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction);
break;
@ -1267,8 +1254,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdTypeName:
ir_print_type_name(irp, (IrInstructionTypeName *)instruction);
break;
case IrInstructionIdEnumTagName:
ir_print_enum_tag_name(irp, (IrInstructionEnumTagName *)instruction);
case IrInstructionIdTagName:
ir_print_tag_name(irp, (IrInstructionTagName *)instruction);
break;
case IrInstructionIdCanImplicitCast:
ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction);
@ -1312,6 +1299,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdArgType:
ir_print_arg_type(irp, (IrInstructionArgType *)instruction);
break;
case IrInstructionIdTagType:
ir_print_enum_tag_type(irp, (IrInstructionTagType *)instruction);
break;
}
fprintf(irp->f, "\n");
}

View File

@ -931,6 +931,7 @@ int os_self_exe_path(Buf *out_path) {
#define VT_GREEN "\x1b[32;1m"
#define VT_CYAN "\x1b[36;1m"
#define VT_WHITE "\x1b[37;1m"
#define VT_BOLD "\x1b[0;1m"
#define VT_RESET "\x1b[0m"
static void set_color_posix(TermColor color) {
@ -947,6 +948,9 @@ static void set_color_posix(TermColor color) {
case TermColorWhite:
fprintf(stderr, VT_WHITE);
break;
case TermColorBold:
fprintf(stderr, VT_BOLD);
break;
case TermColorReset:
fprintf(stderr, VT_RESET);
break;
@ -989,6 +993,7 @@ void os_stderr_set_color(TermColor color) {
SetConsoleTextAttribute(stderr_handle, FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
break;
case TermColorWhite:
case TermColorBold:
SetConsoleTextAttribute(stderr_handle,
FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
break;

View File

@ -21,6 +21,7 @@ enum TermColor {
TermColorGreen,
TermColorCyan,
TermColorWhite,
TermColorBold,
TermColorReset,
};

View File

@ -2377,9 +2377,11 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi
}
/*
ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"
ContainerDecl = option("extern" | "packed")
("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression)))
"{" many(ContainerMember) "}"
ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
ContainerField = Symbol option(":" Expression) ","
ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression ","
*/
static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory) {
Token *first_token = &pc->tokens->at(*token_index);
@ -2415,6 +2417,28 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
node->data.container_decl.layout = layout;
node->data.container_decl.kind = kind;
if (kind == ContainerKindUnion) {
Token *lparen_token = &pc->tokens->at(*token_index);
if (lparen_token->id == TokenIdLParen) {
Token *enum_token = &pc->tokens->at(*token_index + 1);
if (enum_token->id == TokenIdKeywordEnum) {
Token *paren_token = &pc->tokens->at(*token_index + 2);
if (paren_token->id == TokenIdLParen) {
node->data.container_decl.auto_enum = true;
*token_index += 2;
node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, true);
ast_eat_token(pc, token_index, TokenIdRParen);
} else if (paren_token->id == TokenIdRParen) {
node->data.container_decl.auto_enum = true;
*token_index += 3;
}
}
}
}
if (!node->data.container_decl.auto_enum) {
node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, false);
}
ast_eat_token(pc, token_index, TokenIdLBrace);
for (;;) {
@ -2452,31 +2476,33 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token);
*token_index += 1;
node->data.container_decl.fields.append(field_node);
field_node->data.struct_field.visib_mod = visib_mod;
field_node->data.struct_field.name = token_buf(token);
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdComma || token->id == TokenIdRBrace) {
field_node->data.struct_field.type = ast_create_void_type_node(pc, token);
Token *colon_token = &pc->tokens->at(*token_index);
if (colon_token->id == TokenIdColon) {
*token_index += 1;
node->data.container_decl.fields.append(field_node);
if (token->id == TokenIdRBrace) {
break;
}
} else {
ast_eat_token(pc, token_index, TokenIdColon);
field_node->data.struct_field.type = ast_parse_expression(pc, token_index, true);
node->data.container_decl.fields.append(field_node);
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdRBrace) {
*token_index += 1;
break;
} else {
ast_eat_token(pc, token_index, TokenIdComma);
}
field_node->data.struct_field.type = ast_parse_prefix_op_expr(pc, token_index, true);
}
Token *eq_token = &pc->tokens->at(*token_index);
if (eq_token->id == TokenIdEq) {
*token_index += 1;
field_node->data.struct_field.value = ast_parse_prefix_op_expr(pc, token_index, true);
}
Token *next_token = &pc->tokens->at(*token_index);
if (next_token->id == TokenIdComma) {
*token_index += 1;
continue;
}
if (next_token->id == TokenIdRBrace) {
*token_index += 1;
break;
}
ast_invalid_token_error(pc, next_token);
} else {
ast_invalid_token_error(pc, token);
}
@ -2804,9 +2830,11 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
case NodeTypeContainerDecl:
visit_node_list(&node->data.container_decl.fields, visit, context);
visit_node_list(&node->data.container_decl.decls, visit, context);
visit_field(&node->data.container_decl.init_arg_expr, visit, context);
break;
case NodeTypeStructField:
visit_field(&node->data.struct_field.type, visit, context);
visit_field(&node->data.struct_field.value, visit, context);
break;
case NodeTypeContainerInitExpr:
visit_field(&node->data.container_init_expr.type, visit, context);

View File

@ -651,6 +651,14 @@ static bool c_is_unsigned_integer(Context *c, QualType qt) {
}
}
static bool c_is_builtin_type(Context *c, QualType qt, BuiltinType::Kind kind) {
const Type *c_type = qual_type_canon(qt);
if (c_type->getTypeClass() != Type::Builtin)
return false;
const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type);
return builtin_ty->getKind() == kind;
}
static bool c_is_float(Context *c, QualType qt) {
const Type *c_type = qt.getTypePtr();
if (c_type->getTypeClass() != Type::Builtin)
@ -978,11 +986,23 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou
const AttributedType *attributed_ty = static_cast<const AttributedType *>(ty);
return trans_qual_type(c, attributed_ty->getEquivalentType(), source_loc);
}
case Type::IncompleteArray:
{
const IncompleteArrayType *incomplete_array_ty = static_cast<const IncompleteArrayType *>(ty);
QualType child_qt = incomplete_array_ty->getElementType();
AstNode *child_type_node = trans_qual_type(c, child_qt, source_loc);
if (child_type_node == nullptr) {
emit_warning(c, source_loc, "unresolved array element type");
return nullptr;
}
AstNode *pointer_node = trans_create_node_addr_of(c, child_qt.isConstQualified(),
child_qt.isVolatileQualified(), child_type_node);
return pointer_node;
}
case Type::BlockPointer:
case Type::LValueReference:
case Type::RValueReference:
case Type::MemberPointer:
case Type::IncompleteArray:
case Type::VariableArray:
case Type::DependentSizedArray:
case Type::DependentSizedExtVector:
@ -3417,7 +3437,14 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) {
AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl);
enum_node->data.container_decl.kind = ContainerKindEnum;
enum_node->data.container_decl.layout = ContainerLayoutExtern;
enum_node->data.container_decl.init_arg_expr = tag_int_type;
// TODO only emit this tag type if the enum tag type is not the default.
// I don't know what the default is, need to figure out how clang is deciding.
// it appears to at least be different across gcc/msvc
if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) &&
!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int))
{
enum_node->data.container_decl.init_arg_expr = tag_int_type;
}
enum_node->data.container_decl.fields.resize(field_count);
uint32_t i = 0;
@ -4304,7 +4331,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
}
}
return 0;
return ErrorCCompileErrors;
}
c->ctx = &ast_unit->getASTContext();

View File

@ -793,7 +793,7 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
zig_unreachable();
case ZigLLVM_COFF:
return lld::coff::link(array_ref_args, false);
return lld::coff::link(array_ref_args, false, diag);
case ZigLLVM_ELF:
return lld::elf::link(array_ref_args, false, diag);

View File

@ -4,6 +4,8 @@ const Allocator = mem.Allocator;
const assert = debug.assert;
const ArrayList = @import("array_list.zig").ArrayList;
const fmt = @import("fmt/index.zig");
/// A buffer that allocates memory and maintains a null byte at the end.
pub const Buffer = struct {
list: ArrayList(u8),
@ -96,6 +98,10 @@ pub const Buffer = struct {
mem.copy(u8, self.list.toSlice()[old_len..], m);
}
pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) -> %void {
return fmt.format(self, append, format, args);
}
pub fn appendByte(self: &Buffer, byte: u8) -> %void {
return self.appendByteNTimes(byte, 1);
}

View File

@ -69,8 +69,8 @@ pub const Builder = struct {
used: bool,
};
const UserValue = enum {
Flag,
const UserValue = union(enum) {
Flag: void,
Scalar: []const u8,
List: ArrayList([]const u8),
};
@ -450,7 +450,7 @@ pub const Builder = struct {
pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) -> bool {
if (%%self.user_input_options.put(name, UserInputOption {
.name = name,
.value = UserValue.Scalar { value },
.value = UserValue { .Scalar = value },
.used = false,
})) |*prev_value| {
// option already exists
@ -462,7 +462,7 @@ pub const Builder = struct {
%%list.append(value);
_ = %%self.user_input_options.put(name, UserInputOption {
.name = name,
.value = UserValue.List { list },
.value = UserValue { .List = list },
.used = false,
});
},
@ -471,7 +471,7 @@ pub const Builder = struct {
%%list.append(value);
_ = %%self.user_input_options.put(name, UserInputOption {
.name = name,
.value = UserValue.List { *list },
.value = UserValue { .List = *list },
.used = false,
});
},
@ -487,7 +487,7 @@ pub const Builder = struct {
pub fn addUserInputFlag(self: &Builder, name: []const u8) -> bool {
if (%%self.user_input_options.put(name, UserInputOption {
.name = name,
.value = UserValue.Flag,
.value = UserValue {.Flag = {} },
.used = false,
})) |*prev_value| {
switch (prev_value.value) {
@ -685,8 +685,8 @@ const CrossTarget = struct {
environ: builtin.Environ,
};
const Target = enum {
Native,
const Target = union(enum) {
Native: void,
Cross: CrossTarget,
pub fn oFileExt(self: &const Target) -> []const u8 {
@ -844,7 +844,7 @@ pub const LibExeObjStep = struct {
.kind = kind,
.root_src = root_src,
.name = name,
.target = Target.Native,
.target = Target { .Native = {} },
.linker_script = null,
.link_libs = BufSet.init(builder.allocator),
.frameworks = BufSet.init(builder.allocator),
@ -879,7 +879,7 @@ pub const LibExeObjStep = struct {
.kind = kind,
.version = *version,
.static = static,
.target = Target.Native,
.target = Target { .Native = {} },
.cflags = ArrayList([]const u8).init(builder.allocator),
.source_files = ArrayList([]const u8).init(builder.allocator),
.object_files = ArrayList([]const u8).init(builder.allocator),
@ -948,8 +948,8 @@ pub const LibExeObjStep = struct {
pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os,
target_environ: builtin.Environ)
{
self.target = Target.Cross {
CrossTarget {
self.target = Target {
.Cross = CrossTarget {
.arch = target_arch,
.os = target_os,
.environ = target_environ,
@ -1186,13 +1186,13 @@ pub const LibExeObjStep = struct {
Target.Native => {},
Target.Cross => |cross_target| {
%%zig_args.append("--target-arch");
%%zig_args.append(@enumTagName(cross_target.arch));
%%zig_args.append(@tagName(cross_target.arch));
%%zig_args.append("--target-os");
%%zig_args.append(@enumTagName(cross_target.os));
%%zig_args.append(@tagName(cross_target.os));
%%zig_args.append("--target-environ");
%%zig_args.append(@enumTagName(cross_target.environ));
%%zig_args.append(@tagName(cross_target.environ));
},
}
@ -1553,7 +1553,7 @@ pub const TestStep = struct {
.name_prefix = "",
.filter = null,
.link_libs = BufSet.init(builder.allocator),
.target = Target.Native,
.target = Target { .Native = {} },
.exec_cmd_args = null,
}
}
@ -1581,8 +1581,8 @@ pub const TestStep = struct {
pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os,
target_environ: builtin.Environ)
{
self.target = Target.Cross {
CrossTarget {
self.target = Target {
.Cross = CrossTarget {
.arch = target_arch,
.os = target_os,
.environ = target_environ,
@ -1620,13 +1620,13 @@ pub const TestStep = struct {
Target.Native => {},
Target.Cross => |cross_target| {
%%zig_args.append("--target-arch");
%%zig_args.append(@enumTagName(cross_target.arch));
%%zig_args.append(@tagName(cross_target.arch));
%%zig_args.append("--target-os");
%%zig_args.append(@enumTagName(cross_target.os));
%%zig_args.append(@tagName(cross_target.os));
%%zig_args.append("--target-environ");
%%zig_args.append(@enumTagName(cross_target.environ));
%%zig_args.append(@tagName(cross_target.environ));
},
}

View File

@ -280,7 +280,7 @@ const AbbrevAttr = struct {
form_id: u64,
};
const FormValue = enum {
const FormValue = union(enum) {
Address: u64,
Block: []u8,
Const: Constant,
@ -303,7 +303,7 @@ const Constant = struct {
return error.InvalidDebugInfo;
if (self.signed)
return error.InvalidDebugInfo;
return mem.readInt(self.payload, u64, false);
return mem.readInt(self.payload, u64, builtin.Endian.Little);
}
};
@ -475,16 +475,16 @@ fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usiz
fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
const buf = %return readAllocBytes(allocator, in_stream, size);
return FormValue.Block { buf };
return FormValue { .Block = buf };
}
fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
const block_len = %return in_stream.readVarInt(false, usize, size);
const block_len = %return in_stream.readVarInt(builtin.Endian.Little, usize, size);
return parseFormValueBlockLen(allocator, in_stream, block_len);
}
fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
FormValue.Const { Constant {
FormValue { .Const = Constant {
.signed = signed,
.payload = %return readAllocBytes(allocator, in_stream, size),
}}
@ -510,7 +510,7 @@ fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
const buf = %return readAllocBytes(allocator, in_stream, size);
return FormValue.Ref { buf };
return FormValue { .Ref = buf };
}
fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) -> %FormValue {
@ -520,7 +520,7 @@ fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptim
fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue {
return switch (form_id) {
DW.FORM_addr => FormValue.Address { %return parseFormValueTargetAddrSize(in_stream) },
DW.FORM_addr => FormValue { .Address = %return parseFormValueTargetAddrSize(in_stream) },
DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
@ -540,13 +540,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
DW.FORM_exprloc => {
const size = %return readULeb128(in_stream);
const buf = %return readAllocBytes(allocator, in_stream, size);
return FormValue.ExprLoc { buf };
},
DW.FORM_flag => FormValue.Flag { (%return in_stream.readByte()) != 0 },
DW.FORM_flag_present => FormValue.Flag { true },
DW.FORM_sec_offset => FormValue.SecOffset {
%return parseFormValueDwarfOffsetSize(in_stream, is_64)
return FormValue { .ExprLoc = buf };
},
DW.FORM_flag => FormValue { .Flag = (%return in_stream.readByte()) != 0 },
DW.FORM_flag_present => FormValue { .Flag = true },
DW.FORM_sec_offset => FormValue { .SecOffset = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
@ -557,11 +555,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
parseFormValueRefLen(allocator, in_stream, ref_len)
},
DW.FORM_ref_addr => FormValue.RefAddr { %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_ref_sig8 => FormValue.RefSig8 { %return in_stream.readIntLe(u64) },
DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_ref_sig8 => FormValue { .RefSig8 = %return in_stream.readIntLe(u64) },
DW.FORM_string => FormValue.String { %return readStringRaw(allocator, in_stream) },
DW.FORM_strp => FormValue.StrPtr { %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_string => FormValue { .String = %return readStringRaw(allocator, in_stream) },
DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_indirect => {
const child_form_id = %return readULeb128(in_stream);
parseFormValue(allocator, in_stream, child_form_id, is_64)
@ -671,10 +669,10 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
continue;
}
const version = %return in_stream.readInt(st.elf.is_big_endian, u16);
const version = %return in_stream.readInt(st.elf.endian, u16);
if (version != 2) return error.InvalidDebugInfo;
const prologue_length = %return in_stream.readInt(st.elf.is_big_endian, u32);
const prologue_length = %return in_stream.readInt(st.elf.endian, u32);
const prog_start_offset = (%return in_file.getPos()) + prologue_length;
const minimum_instruction_length = %return in_stream.readByte();
@ -741,7 +739,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
return error.MissingDebugInfo;
},
DW.LNE_set_address => {
const addr = %return in_stream.readInt(st.elf.is_big_endian, usize);
const addr = %return in_stream.readInt(st.elf.endian, usize);
prog.address = addr;
},
DW.LNE_define_file => {
@ -803,7 +801,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe
prog.address += inc_addr;
},
DW.LNS_fixed_advance_pc => {
const arg = %return in_stream.readInt(st.elf.is_big_endian, u16);
const arg = %return in_stream.readInt(st.elf.endian, u16);
prog.address += arg;
},
DW.LNS_set_prologue_end => {
@ -841,13 +839,13 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
return;
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
const version = %return in_stream.readInt(st.elf.is_big_endian, u16);
const version = %return in_stream.readInt(st.elf.endian, u16);
if (version < 2 or version > 5) return error.InvalidDebugInfo;
const debug_abbrev_offset = if (is_64) {
%return in_stream.readInt(st.elf.is_big_endian, u64)
%return in_stream.readInt(st.elf.endian, u64)
} else {
%return in_stream.readInt(st.elf.is_big_endian, u32)
%return in_stream.readInt(st.elf.endian, u32)
};
const address_size = %return in_stream.readByte();

View File

@ -1,3 +1,4 @@
const builtin = @import("builtin");
const std = @import("index.zig");
const io = std.io;
const math = std.math;
@ -67,7 +68,7 @@ pub const Elf = struct {
in_file: &io.File,
auto_close_stream: bool,
is_64: bool,
is_big_endian: bool,
endian: builtin.Endian,
file_type: FileType,
arch: Arch,
entry_addr: u64,
@ -105,9 +106,9 @@ pub const Elf = struct {
else => return error.InvalidFormat,
};
elf.is_big_endian = switch (%return in.readByte()) {
1 => false,
2 => true,
elf.endian = switch (%return in.readByte()) {
1 => builtin.Endian.Little,
2 => builtin.Endian.Big,
else => return error.InvalidFormat,
};
@ -117,7 +118,7 @@ pub const Elf = struct {
// skip over padding
%return elf.in_file.seekForward(9);
elf.file_type = switch (%return in.readInt(elf.is_big_endian, u16)) {
elf.file_type = switch (%return in.readInt(elf.endian, u16)) {
1 => FileType.Relocatable,
2 => FileType.Executable,
3 => FileType.Shared,
@ -125,7 +126,7 @@ pub const Elf = struct {
else => return error.InvalidFormat,
};
elf.arch = switch (%return in.readInt(elf.is_big_endian, u16)) {
elf.arch = switch (%return in.readInt(elf.endian, u16)) {
0x02 => Arch.Sparc,
0x03 => Arch.x86,
0x08 => Arch.Mips,
@ -138,34 +139,34 @@ pub const Elf = struct {
else => return error.InvalidFormat,
};
const elf_version = %return in.readInt(elf.is_big_endian, u32);
const elf_version = %return in.readInt(elf.endian, u32);
if (elf_version != 1) return error.InvalidFormat;
if (elf.is_64) {
elf.entry_addr = %return in.readInt(elf.is_big_endian, u64);
elf.program_header_offset = %return in.readInt(elf.is_big_endian, u64);
elf.section_header_offset = %return in.readInt(elf.is_big_endian, u64);
elf.entry_addr = %return in.readInt(elf.endian, u64);
elf.program_header_offset = %return in.readInt(elf.endian, u64);
elf.section_header_offset = %return in.readInt(elf.endian, u64);
} else {
elf.entry_addr = u64(%return in.readInt(elf.is_big_endian, u32));
elf.program_header_offset = u64(%return in.readInt(elf.is_big_endian, u32));
elf.section_header_offset = u64(%return in.readInt(elf.is_big_endian, u32));
elf.entry_addr = u64(%return in.readInt(elf.endian, u32));
elf.program_header_offset = u64(%return in.readInt(elf.endian, u32));
elf.section_header_offset = u64(%return in.readInt(elf.endian, u32));
}
// skip over flags
%return elf.in_file.seekForward(4);
const header_size = %return in.readInt(elf.is_big_endian, u16);
const header_size = %return in.readInt(elf.endian, u16);
if ((elf.is_64 and header_size != 64) or
(!elf.is_64 and header_size != 52))
{
return error.InvalidFormat;
}
const ph_entry_size = %return in.readInt(elf.is_big_endian, u16);
const ph_entry_count = %return in.readInt(elf.is_big_endian, u16);
const sh_entry_size = %return in.readInt(elf.is_big_endian, u16);
const sh_entry_count = %return in.readInt(elf.is_big_endian, u16);
elf.string_section_index = u64(%return in.readInt(elf.is_big_endian, u16));
const ph_entry_size = %return in.readInt(elf.endian, u16);
const ph_entry_count = %return in.readInt(elf.endian, u16);
const sh_entry_size = %return in.readInt(elf.endian, u16);
const sh_entry_count = %return in.readInt(elf.endian, u16);
elf.string_section_index = u64(%return in.readInt(elf.endian, u16));
if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat;
@ -188,32 +189,32 @@ pub const Elf = struct {
if (sh_entry_size != 64) return error.InvalidFormat;
for (elf.section_headers) |*section| {
section.name = %return in.readInt(elf.is_big_endian, u32);
section.sh_type = %return in.readInt(elf.is_big_endian, u32);
section.flags = %return in.readInt(elf.is_big_endian, u64);
section.addr = %return in.readInt(elf.is_big_endian, u64);
section.offset = %return in.readInt(elf.is_big_endian, u64);
section.size = %return in.readInt(elf.is_big_endian, u64);
section.link = %return in.readInt(elf.is_big_endian, u32);
section.info = %return in.readInt(elf.is_big_endian, u32);
section.addr_align = %return in.readInt(elf.is_big_endian, u64);
section.ent_size = %return in.readInt(elf.is_big_endian, u64);
section.name = %return in.readInt(elf.endian, u32);
section.sh_type = %return in.readInt(elf.endian, u32);
section.flags = %return in.readInt(elf.endian, u64);
section.addr = %return in.readInt(elf.endian, u64);
section.offset = %return in.readInt(elf.endian, u64);
section.size = %return in.readInt(elf.endian, u64);
section.link = %return in.readInt(elf.endian, u32);
section.info = %return in.readInt(elf.endian, u32);
section.addr_align = %return in.readInt(elf.endian, u64);
section.ent_size = %return in.readInt(elf.endian, u64);
}
} else {
if (sh_entry_size != 40) return error.InvalidFormat;
for (elf.section_headers) |*section| {
// TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ?
section.name = %return in.readInt(elf.is_big_endian, u32);
section.sh_type = %return in.readInt(elf.is_big_endian, u32);
section.flags = u64(%return in.readInt(elf.is_big_endian, u32));
section.addr = u64(%return in.readInt(elf.is_big_endian, u32));
section.offset = u64(%return in.readInt(elf.is_big_endian, u32));
section.size = u64(%return in.readInt(elf.is_big_endian, u32));
section.link = %return in.readInt(elf.is_big_endian, u32);
section.info = %return in.readInt(elf.is_big_endian, u32);
section.addr_align = u64(%return in.readInt(elf.is_big_endian, u32));
section.ent_size = u64(%return in.readInt(elf.is_big_endian, u32));
section.name = %return in.readInt(elf.endian, u32);
section.sh_type = %return in.readInt(elf.endian, u32);
section.flags = u64(%return in.readInt(elf.endian, u32));
section.addr = u64(%return in.readInt(elf.endian, u32));
section.offset = u64(%return in.readInt(elf.endian, u32));
section.size = u64(%return in.readInt(elf.endian, u32));
section.link = %return in.readInt(elf.endian, u32);
section.info = %return in.readInt(elf.endian, u32);
section.addr_align = u64(%return in.readInt(elf.endian, u32));
section.ent_size = u64(%return in.readInt(elf.endian, u32));
}
}

View File

@ -9,8 +9,8 @@ pub fn swapIfBe(comptime T: type, x: T) -> T {
swapIf(true, T, x)
}
pub fn swapIf(is_be: bool, comptime T: type, x: T) -> T {
if (builtin.is_big_endian == is_be) swap(T, x) else x
pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T {
if (builtin.endian == endian) swap(T, x) else x
}
pub fn swap(comptime T: type, x: T) -> T {

View File

@ -259,7 +259,7 @@ pub const File = struct {
if (err > 0) {
return switch (err) {
system.EBADF => error.BadFd,
system.ENOMEM => error.OutOfMemory,
system.ENOMEM => error.SystemResources,
else => os.unexpectedErrorPosix(err),
}
}
@ -441,26 +441,26 @@ pub const InStream = struct {
}
pub fn readIntLe(self: &InStream, comptime T: type) -> %T {
return self.readInt(false, T);
return self.readInt(builtin.Endian.Little, T);
}
pub fn readIntBe(self: &InStream, comptime T: type) -> %T {
return self.readInt(true, T);
return self.readInt(builtin.Endian.Big, T);
}
pub fn readInt(self: &InStream, is_be: bool, comptime T: type) -> %T {
pub fn readInt(self: &InStream, endian: builtin.Endian, comptime T: type) -> %T {
var bytes: [@sizeOf(T)]u8 = undefined;
%return self.readNoEof(bytes[0..]);
return mem.readInt(bytes, T, is_be);
return mem.readInt(bytes, T, endian);
}
pub fn readVarInt(self: &InStream, is_be: bool, comptime T: type, size: usize) -> %T {
pub fn readVarInt(self: &InStream, endian: builtin.Endian, comptime T: type, size: usize) -> %T {
assert(size <= @sizeOf(T));
assert(size <= 8);
var input_buf: [8]u8 = undefined;
const input_slice = input_buf[0..size];
%return self.readNoEof(input_slice);
return mem.readInt(input_slice, T, is_be);
return mem.readInt(input_slice, T, endian);
}

View File

@ -1,6 +1,7 @@
const debug = @import("debug.zig");
const assert = debug.assert;
const math = @import("math/index.zig");
const builtin = @import("builtin");
pub const Cmp = math.Cmp;
@ -180,43 +181,78 @@ test "mem.indexOf" {
/// Reads an integer from memory with size equal to bytes.len.
/// T specifies the return type, which must be large enough to store
/// the result.
pub fn readInt(bytes: []const u8, comptime T: type, big_endian: bool) -> T {
/// See also ::readIntBE or ::readIntLE.
pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) -> T {
if (T.bit_count == 8) {
return bytes[0];
}
var result: T = 0;
if (big_endian) {
for (bytes) |b| {
result = (result << 8) | b;
}
} else {
const ShiftType = math.Log2Int(T);
for (bytes) |b, index| {
result = result | (T(b) << ShiftType(index * 8));
}
switch (endian) {
builtin.Endian.Big => {
for (bytes) |b| {
result = (result << 8) | b;
}
},
builtin.Endian.Little => {
const ShiftType = math.Log2Int(T);
for (bytes) |b, index| {
result = result | (T(b) << ShiftType(index * 8));
}
},
}
return result;
}
/// Reads a big-endian int of type T from bytes.
/// bytes.len must be exactly @sizeOf(T).
pub fn readIntBE(comptime T: type, bytes: []const u8) -> T {
if (T.is_signed) {
return @bitCast(T, readIntBE(@IntType(false, T.bit_count), bytes));
}
assert(bytes.len == @sizeOf(T));
var result: T = 0;
{comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {
result = (result << 8) | T(bytes[i]);
}}
return result;
}
/// Reads a little-endian int of type T from bytes.
/// bytes.len must be exactly @sizeOf(T).
pub fn readIntLE(comptime T: type, bytes: []const u8) -> T {
if (T.is_signed) {
return @bitCast(T, readIntLE(@IntType(false, T.bit_count), bytes));
}
assert(bytes.len == @sizeOf(T));
var result: T = 0;
{comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) {
result |= T(bytes[i]) << i * 8;
}}
return result;
}
/// Writes an integer to memory with size equal to bytes.len. Pads with zeroes
/// to fill the entire buffer provided.
/// value must be an integer.
pub fn writeInt(buf: []u8, value: var, big_endian: bool) {
pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) {
const uint = @IntType(false, @typeOf(value).bit_count);
var bits = @truncate(uint, value);
if (big_endian) {
var index: usize = buf.len;
while (index != 0) {
index -= 1;
switch (endian) {
builtin.Endian.Big => {
var index: usize = buf.len;
while (index != 0) {
index -= 1;
buf[index] = @truncate(u8, bits);
bits >>= 8;
}
} else {
for (buf) |*b| {
*b = @truncate(u8, bits);
bits >>= 8;
}
buf[index] = @truncate(u8, bits);
bits >>= 8;
}
},
builtin.Endian.Little => {
for (buf) |*b| {
*b = @truncate(u8, bits);
bits >>= 8;
}
},
}
assert(bits == 0);
}
@ -348,19 +384,30 @@ test "testReadInt" {
fn testReadIntImpl() {
{
const bytes = []u8{ 0x12, 0x34, 0x56, 0x78 };
assert(readInt(bytes, u32, true) == 0x12345678);
assert(readInt(bytes, u32, false) == 0x78563412);
assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);
assert(readIntBE(u32, bytes) == 0x12345678);
assert(readIntBE(i32, bytes) == 0x12345678);
assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412);
assert(readIntLE(u32, bytes) == 0x78563412);
assert(readIntLE(i32, bytes) == 0x78563412);
}
{
const buf = []u8{0x00, 0x00, 0x12, 0x34};
const answer = readInt(buf, u64, true);
const answer = readInt(buf, u64, builtin.Endian.Big);
assert(answer == 0x00001234);
}
{
const buf = []u8{0x12, 0x34, 0x00, 0x00};
const answer = readInt(buf, u64, false);
const answer = readInt(buf, u64, builtin.Endian.Little);
assert(answer == 0x00003412);
}
{
const bytes = []u8{0xff, 0xfe};
assert(readIntBE(u16, bytes) == 0xfffe);
assert(readIntBE(i16, bytes) == -0x0002);
assert(readIntLE(u16, bytes) == 0xfeff);
assert(readIntLE(i16, bytes) == -0x0101);
}
}
test "testWriteInt" {
@ -370,16 +417,16 @@ test "testWriteInt" {
fn testWriteIntImpl() {
var bytes: [4]u8 = undefined;
writeInt(bytes[0..], u32(0x12345678), true);
writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big);
assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
writeInt(bytes[0..], u32(0x78563412), false);
writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little);
assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 }));
writeInt(bytes[0..], u16(0x1234), true);
writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big);
assert(eql(u8, bytes, []u8{ 0x00, 0x00, 0x12, 0x34 }));
writeInt(bytes[0..], u16(0x1234), false);
writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little);
assert(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, 0x00 }));
}

View File

@ -58,7 +58,7 @@ pub const ChildProcess = struct {
err_pipe: if (is_windows) void else [2]i32,
llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,
pub const Term = enum {
pub const Term = union(enum) {
Exited: i32,
Signal: i32,
Stopped: i32,
@ -213,9 +213,9 @@ pub const ChildProcess = struct {
self.term = (%Term)({
var exit_code: windows.DWORD = undefined;
if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) {
Term.Unknown{0}
Term { .Unknown = 0 }
} else {
Term.Exited {@bitCast(i32, exit_code)}
Term { .Exited = @bitCast(i32, exit_code)}
}
});
@ -281,13 +281,13 @@ pub const ChildProcess = struct {
fn statusToTerm(status: i32) -> Term {
return if (posix.WIFEXITED(status)) {
Term.Exited { posix.WEXITSTATUS(status) }
Term { .Exited = posix.WEXITSTATUS(status) }
} else if (posix.WIFSIGNALED(status)) {
Term.Signal { posix.WTERMSIG(status) }
Term { .Signal = posix.WTERMSIG(status) }
} else if (posix.WIFSTOPPED(status)) {
Term.Stopped { posix.WSTOPSIG(status) }
Term { .Stopped = posix.WSTOPSIG(status) }
} else {
Term.Unknown { status }
Term { .Unknown = status }
};
}
@ -722,14 +722,14 @@ const ErrInt = @IntType(false, @sizeOf(error) * 8);
fn writeIntFd(fd: i32, value: ErrInt) -> %void {
var bytes: [@sizeOf(ErrInt)]u8 = undefined;
mem.writeInt(bytes[0..], value, true);
mem.writeInt(bytes[0..], value, builtin.endian);
os.posixWrite(fd, bytes[0..]) %% return error.SystemResources;
}
fn readIntFd(fd: i32) -> %ErrInt {
var bytes: [@sizeOf(ErrInt)]u8 = undefined;
os.posixRead(fd, bytes[0..]) %% return error.SystemResources;
return mem.readInt(bytes[0..], ErrInt, true);
return mem.readInt(bytes[0..], ErrInt, builtin.endian);
}
extern fn sigchld_handler(_: i32) {

View File

@ -939,6 +939,7 @@ start_over:
}
pub const Dir = struct {
// See man getdents
fd: i32,
allocator: &Allocator,
buf: []u8,
@ -981,7 +982,7 @@ pub const Dir = struct {
pub fn close(self: &Dir) {
self.allocator.free(self.buf);
close(self.fd);
os.close(self.fd);
}
/// Memory such as file names referenced in this returned entry becomes invalid
@ -1013,7 +1014,7 @@ pub const Dir = struct {
break;
}
}
const linux_entry = @ptrCast(&LinuxEntry, &self.buf[self.index]);
const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]);
const next_index = self.index + linux_entry.d_reclen;
self.index = next_index;

View File

@ -1016,7 +1016,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
return os.readLink(allocator, proc_path);
},
else => @compileError("TODO implement os.path.real for " ++ @enumTagName(builtin.os)),
else => @compileError("TODO implement os.path.real for " ++ @tagName(builtin.os)),
}
}

View File

@ -50,12 +50,12 @@ pub const Rand = struct {
pub fn fillBytes(r: &Rand, buf: []u8) {
var bytes_left = buf.len;
while (bytes_left >= @sizeOf(usize)) {
mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), false);
mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), builtin.Endian.Little);
bytes_left -= @sizeOf(usize);
}
if (bytes_left > 0) {
var rand_val_array: [@sizeOf(usize)]u8 = undefined;
mem.writeInt(rand_val_array[0..], r.rng.get(), false);
mem.writeInt(rand_val_array[0..], r.rng.get(), builtin.Endian.Little);
while (bytes_left > 0) {
buf[buf.len - bytes_left] = rand_val_array[@sizeOf(usize) - bytes_left];
bytes_left -= 1;
@ -98,7 +98,7 @@ pub const Rand = struct {
while (true) {
r.fillBytes(rand_val_array[0..]);
const rand_val = mem.readInt(rand_val_array, T, false);
const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little);
if (rand_val < upper_bound) {
return start + (rand_val % total_range);
}

View File

@ -4,6 +4,19 @@ const math = @import("math/index.zig");
pub const Cmp = math.Cmp;
/// Stable sort using O(1) space. Currently implemented as insertion sort.
pub fn sort_stable(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) {
{var i: usize = 1; while (i < array.len) : (i += 1) {
const x = array[i];
var j: usize = i;
while (j > 0 and cmp(array[j - 1], x) == Cmp.Greater) : (j -= 1) {
array[j] = array[j - 1];
}
array[j] = x;
}}
}
/// Unstable sort using O(n) stack space. Currently implemented as quicksort.
pub fn sort(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) {
if (array.len > 0) {
quicksort(T, array, 0, array.len - 1, cmp);
@ -58,6 +71,63 @@ fn reverse(was: Cmp) -> Cmp {
// ---------------------------------------
// tests
test "stable sort" {
testStableSort();
// TODO: uncomment this after https://github.com/zig-lang/zig/issues/639
//comptime testStableSort();
}
fn testStableSort() {
var expected = []IdAndValue {
IdAndValue{.id = 0, .value = 0},
IdAndValue{.id = 1, .value = 0},
IdAndValue{.id = 2, .value = 0},
IdAndValue{.id = 0, .value = 1},
IdAndValue{.id = 1, .value = 1},
IdAndValue{.id = 2, .value = 1},
IdAndValue{.id = 0, .value = 2},
IdAndValue{.id = 1, .value = 2},
IdAndValue{.id = 2, .value = 2},
};
var cases = [][9]IdAndValue {
[]IdAndValue {
IdAndValue{.id = 0, .value = 0},
IdAndValue{.id = 0, .value = 1},
IdAndValue{.id = 0, .value = 2},
IdAndValue{.id = 1, .value = 0},
IdAndValue{.id = 1, .value = 1},
IdAndValue{.id = 1, .value = 2},
IdAndValue{.id = 2, .value = 0},
IdAndValue{.id = 2, .value = 1},
IdAndValue{.id = 2, .value = 2},
},
[]IdAndValue {
IdAndValue{.id = 0, .value = 2},
IdAndValue{.id = 0, .value = 1},
IdAndValue{.id = 0, .value = 0},
IdAndValue{.id = 1, .value = 2},
IdAndValue{.id = 1, .value = 1},
IdAndValue{.id = 1, .value = 0},
IdAndValue{.id = 2, .value = 2},
IdAndValue{.id = 2, .value = 1},
IdAndValue{.id = 2, .value = 0},
},
};
for (cases) |*case| {
sort_stable(IdAndValue, (*case)[0..], cmpByValue);
for (*case) |item, i| {
assert(item.id == expected[i].id);
assert(item.value == expected[i].value);
}
}
}
const IdAndValue = struct {
id: i32,
value: i32,
};
fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> Cmp {
return i32asc(a.value, b.value);
}
test "testSort" {
const u8cases = [][]const []const u8 {
[][]const u8{"", ""},

View File

@ -1,7 +1,7 @@
const builtin = @import("builtin");
const is_test = builtin.is_test;
const low = if (builtin.is_big_endian) 1 else 0;
const low = switch (builtin.endian) { builtin.Endian.Big => 1, builtin.Endian.Little => 0 };
const high = 1 - low;
pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?&DoubleInt) -> DoubleInt {

View File

@ -1,9 +1,9 @@
const E = enum { A: [9]u8, B: u64, };
const E = union(enum) { A: [9]u8, B: u64, };
const S = struct { x: u8, y: E, };
const assert = @import("std").debug.assert;
test "bug 394 fixed" {
const x = S { .x = 3, .y = E.B {1} };
const x = S { .x = 3, .y = E {.B = 1 } };
assert(x.x == 3);
}

View File

@ -2,8 +2,8 @@ const assert = @import("std").debug.assert;
const mem = @import("std").mem;
test "enum type" {
const foo1 = Foo.One {13};
const foo2 = Foo.Two { Point { .x = 1234, .y = 5678, }};
const foo1 = Foo{ .One = 13};
const foo2 = Foo{. Two = Point { .x = 1234, .y = 5678, }};
const bar = Bar.B;
assert(bar == Bar.B);
@ -24,12 +24,12 @@ const Point = struct {
x: u64,
y: u64,
};
const Foo = enum {
const Foo = union(enum) {
One: i32,
Two: Point,
Three: void,
};
const FooNoVoid = enum {
const FooNoVoid = union(enum) {
One: i32,
Two: Point,
};
@ -41,13 +41,13 @@ const Bar = enum {
};
fn returnAnInt(x: i32) -> Foo {
Foo.One { x }
Foo { .One = x }
}
test "constant enum with payload" {
var empty = AnEnumWithPayload.Empty;
var full = AnEnumWithPayload.Full {13};
var empty = AnEnumWithPayload {.Empty = {}};
var full = AnEnumWithPayload {.Full = 13};
shouldBeEmpty(empty);
shouldBeNotEmpty(full);
}
@ -66,8 +66,8 @@ fn shouldBeNotEmpty(x: &const AnEnumWithPayload) {
}
}
const AnEnumWithPayload = enum {
Empty,
const AnEnumWithPayload = union(enum) {
Empty: void,
Full: i32,
};
@ -89,8 +89,8 @@ test "enum to int" {
shouldEqual(Number.Four, 4);
}
fn shouldEqual(n: Number, expected: usize) {
assert(usize(n) == expected);
fn shouldEqual(n: Number, expected: u3) {
assert(u3(n) == expected);
}
@ -98,7 +98,7 @@ test "int to enum" {
testIntToEnumEval(3);
}
fn testIntToEnumEval(x: i32) {
assert(IntToEnumNumber(x) == IntToEnumNumber.Three);
assert(IntToEnumNumber(u3(x)) == IntToEnumNumber.Three);
}
const IntToEnumNumber = enum {
Zero,
@ -109,13 +109,13 @@ const IntToEnumNumber = enum {
};
test "@enumTagName" {
test "@tagName" {
assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
}
fn testEnumTagNameBare(n: BareNumber) -> []const u8 {
return @enumTagName(n);
return @tagName(n);
}
const BareNumber = enum {
@ -132,12 +132,11 @@ test "enum alignment" {
}
}
const AlignTestEnum = enum {
const AlignTestEnum = union(enum) {
A: [9]u8,
B: u64,
};
const ValueCount0 = enum {};
const ValueCount1 = enum { I0 };
const ValueCount2 = enum { I0, I1 };
const ValueCount256 = enum {
@ -183,10 +182,165 @@ const ValueCount257 = enum {
test "enum sizes" {
comptime {
assert(@sizeOf(ValueCount0) == 0);
assert(@sizeOf(ValueCount1) == 0);
assert(@sizeOf(ValueCount2) == 1);
assert(@sizeOf(ValueCount256) == 1);
assert(@sizeOf(ValueCount257) == 2);
}
}
const Small2 = enum (u2) {
One,
Two,
};
const Small = enum (u2) {
One,
Two,
Three,
Four,
};
test "set enum tag type" {
{
var x = Small.One;
x = Small.Two;
comptime assert(@TagType(Small) == u2);
}
{
var x = Small2.One;
x = Small2.Two;
comptime assert(@TagType(Small2) == u2);
}
}
const A = enum (u3) {
One,
Two,
Three,
Four,
One2,
Two2,
Three2,
Four2,
};
const B = enum (u3) {
One3,
Two3,
Three3,
Four3,
One23,
Two23,
Three23,
Four23,
};
const C = enum (u2) {
One4,
Two4,
Three4,
Four4,
};
const BitFieldOfEnums = packed struct {
a: A,
b: B,
c: C,
};
const bit_field_1 = BitFieldOfEnums {
.a = A.Two,
.b = B.Three3,
.c = C.Four4,
};
test "bit field access with enum fields" {
var data = bit_field_1;
assert(getA(&data) == A.Two);
assert(getB(&data) == B.Three3);
assert(getC(&data) == C.Four4);
comptime assert(@sizeOf(BitFieldOfEnums) == 1);
data.b = B.Four3;
assert(data.b == B.Four3);
data.a = A.Three;
assert(data.a == A.Three);
assert(data.b == B.Four3);
}
fn getA(data: &const BitFieldOfEnums) -> A {
return data.a;
}
fn getB(data: &const BitFieldOfEnums) -> B {
return data.b;
}
fn getC(data: &const BitFieldOfEnums) -> C {
return data.c;
}
test "casting enum to its tag type" {
testCastEnumToTagType(Small2.Two);
comptime testCastEnumToTagType(Small2.Two);
}
fn testCastEnumToTagType(value: Small2) {
assert(u2(value) == 1);
}
const MultipleChoice = enum(u32) {
A = 20,
B = 40,
C = 60,
D = 1000,
};
test "enum with specified tag values" {
testEnumWithSpecifiedTagValues(MultipleChoice.C);
comptime testEnumWithSpecifiedTagValues(MultipleChoice.C);
}
fn testEnumWithSpecifiedTagValues(x: MultipleChoice) {
assert(u32(x) == 60);
assert(1234 == switch (x) {
MultipleChoice.A => 1,
MultipleChoice.B => 2,
MultipleChoice.C => u32(1234),
MultipleChoice.D => 4,
});
}
const MultipleChoice2 = enum(u32) {
Unspecified1,
A = 20,
Unspecified2,
B = 40,
Unspecified3,
C = 60,
Unspecified4,
D = 1000,
Unspecified5,
};
test "enum with specified and unspecified tag values" {
testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
}
fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) {
assert(u32(x) == 1000);
assert(1234 == switch (x) {
MultipleChoice2.A => 1,
MultipleChoice2.B => 2,
MultipleChoice2.C => 3,
MultipleChoice2.D => u32(1234),
MultipleChoice2.Unspecified1 => 5,
MultipleChoice2.Unspecified2 => 6,
MultipleChoice2.Unspecified3 => 7,
MultipleChoice2.Unspecified4 => 8,
MultipleChoice2.Unspecified5 => 9,
});
}

View File

@ -2,7 +2,7 @@ const assert = @import("std").debug.assert;
const mem = @import("std").mem;
const fmt = @import("std").fmt;
const ET = enum {
const ET = union(enum) {
SINT: i32,
UINT: u32,
@ -15,8 +15,8 @@ const ET = enum {
};
test "enum with members" {
const a = ET.SINT { -42 };
const b = ET.UINT { 42 };
const a = ET { .SINT = -42 };
const b = ET { .UINT = 42 };
var buf: [20]u8 = undefined;
assert(%%a.print(buf[0..]) == 3);

View File

@ -324,8 +324,8 @@ test "constant enum initialization with differing sizes" {
test3_1(test3_foo);
test3_2(test3_bar);
}
const Test3Foo = enum {
One,
const Test3Foo = union(enum) {
One: void,
Two: f32,
Three: Test3Point,
};
@ -333,8 +333,8 @@ const Test3Point = struct {
x: i32,
y: i32,
};
const test3_foo = Test3Foo.Three{Test3Point {.x = 3, .y = 4}};
const test3_bar = Test3Foo.Two{13};
const test3_foo = Test3Foo { .Three = Test3Point {.x = 3, .y = 4}};
const test3_bar = Test3Foo { .Two = 13};
fn test3_1(f: &const Test3Foo) {
switch (*f) {
Test3Foo.Three => |pt| {
@ -449,7 +449,8 @@ fn testArray2DConstDoublePtr(ptr: &const f32) {
const Tid = builtin.TypeId;
const AStruct = struct { x: i32, };
const AnEnum = enum { One, Two, };
const AnEnumWithPayload = enum { One: i32, Two, };
const AUnionEnum = union(enum) { One: i32, Two: void, };
const AUnion = union { One: void, Two: void };
test "@typeId" {
comptime {
@ -474,8 +475,9 @@ test "@typeId" {
assert(@typeId(%i32) == Tid.ErrorUnion);
assert(@typeId(error) == Tid.Error);
assert(@typeId(AnEnum) == Tid.Enum);
assert(@typeId(@typeOf(AnEnumWithPayload.One)) == Tid.EnumTag);
// TODO union
assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
assert(@typeId(AUnionEnum) == Tid.Union);
assert(@typeId(AUnion) == Tid.Union);
assert(@typeId(fn()) == Tid.Fn);
assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
assert(@typeId(@typeOf({this})) == Tid.Block);

View File

@ -62,8 +62,8 @@ const Foo = struct {
three: void,
};
const Bar = enum {
One,
const Bar = union(enum) {
One: void,
Two: i32,
Three: bool,
Four: f64,

View File

@ -83,14 +83,14 @@ const SwitchStatmentFoo = enum {
test "switch prong with variable" {
switchProngWithVarFn(SwitchProngWithVarEnum.One {13});
switchProngWithVarFn(SwitchProngWithVarEnum.Two {13.0});
switchProngWithVarFn(SwitchProngWithVarEnum.Meh);
switchProngWithVarFn(SwitchProngWithVarEnum { .One = 13});
switchProngWithVarFn(SwitchProngWithVarEnum { .Two = 13.0});
switchProngWithVarFn(SwitchProngWithVarEnum { .Meh = {}});
}
const SwitchProngWithVarEnum = enum {
const SwitchProngWithVarEnum = union(enum) {
One: i32,
Two: f32,
Meh,
Meh: void,
};
fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) {
switch(*a) {
@ -112,7 +112,7 @@ test "switch on enum using pointer capture" {
}
fn testSwitchEnumPtrCapture() {
var value = SwitchProngWithVarEnum.One { 1234 };
var value = SwitchProngWithVarEnum { .One = 1234 };
switch (value) {
SwitchProngWithVarEnum.One => |*x| *x += 1,
else => unreachable,
@ -136,13 +136,13 @@ fn returnsFive() -> i32 {
}
const Number = enum {
const Number = union(enum) {
One: u64,
Two: u8,
Three: f32,
};
const number = Number.Three { 1.23 };
const number = Number { .Three = 1.23 };
fn returnsFalse() -> bool {
switch (number) {
@ -224,3 +224,14 @@ fn switchWithUnreachable(x: i32) -> i32 {
}
return 10;
}
fn return_a_number() -> %i32 {
return 1;
}
test "capture value of switch with all unreachable prongs" {
const x = return_a_number() %% |err| switch (err) {
else => unreachable,
};
assert(x == 1);
}

View File

@ -9,14 +9,14 @@ fn readOnce() -> %u64 {
error InvalidDebugInfo;
const FormValue = enum {
const FormValue = union(enum) {
Address: u64,
Other: bool,
};
fn doThing(form_id: u64) -> %FormValue {
return switch (form_id) {
17 => FormValue.Address { %return readOnce() },
17 => FormValue { .Address = %return readOnce() },
else => error.InvalidDebugInfo,
}
}

View File

@ -1,7 +1,7 @@
const assert = @import("std").debug.assert;
const FormValue = enum {
One,
const FormValue = union(enum) {
One: void,
Two: bool,
};
@ -9,8 +9,8 @@ error Whatever;
fn foo(id: u64) -> %FormValue {
switch (id) {
2 => FormValue.Two { true },
1 => FormValue.One,
2 => FormValue { .Two = true },
1 => FormValue { .One = {} },
else => return error.Whatever,
}
}

View File

@ -1,6 +1,6 @@
const assert = @import("std").debug.assert;
const Value = enum {
const Value = union(enum) {
Int: u64,
Array: [9]u8,
};
@ -10,8 +10,8 @@ const Agg = struct {
val2: Value,
};
const v1 = Value.Int { 1234 };
const v2 = Value.Array { []u8{3} ** 9 };
const v1 = Value { .Int = 1234 };
const v2 = Value { .Array = []u8{3} ** 9 };
const err = (%Agg)(Agg {
.val1 = v1,
@ -75,3 +75,118 @@ test "basic extern unions" {
assert(foo.float == 12.34);
}
const Letter = enum {
A,
B,
C,
};
const Payload = union(Letter) {
A: i32,
B: f64,
C: bool,
};
test "union with specified enum tag" {
doTest();
comptime doTest();
}
fn doTest() {
assert(bar(Payload {.A = 1234}) == -10);
}
fn bar(value: &const Payload) -> i32 {
assert(Letter(*value) == Letter.A);
return switch (*value) {
Payload.A => |x| return x - 1244,
Payload.B => |x| if (x == 12.34) i32(20) else 21,
Payload.C => |x| if (x) i32(30) else 31,
};
}
const MultipleChoice = union(enum(u32)) {
A = 20,
B = 40,
C = 60,
D = 1000,
};
test "simple union(enum(u32))" {
var x = MultipleChoice.C;
assert(x == MultipleChoice.C);
assert(u32(@TagType(MultipleChoice)(x)) == 60);
}
const MultipleChoice2 = union(enum(u32)) {
Unspecified1: i32,
A: f32 = 20,
Unspecified2: void,
B: bool = 40,
Unspecified3: i32,
C: i8 = 60,
Unspecified4: void,
D: void = 1000,
Unspecified5: i32,
};
test "union(enum(u32)) with specified and unspecified tag values" {
comptime assert(@TagType(@TagType(MultipleChoice2)) == u32);
testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 {.C = 123});
comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 { .C = 123} );
}
fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) {
assert(u32(@TagType(MultipleChoice2)(*x)) == 60);
assert(1123 == switch (*x) {
MultipleChoice2.A => 1,
MultipleChoice2.B => 2,
MultipleChoice2.C => |v| i32(1000) + v,
MultipleChoice2.D => 4,
MultipleChoice2.Unspecified1 => 5,
MultipleChoice2.Unspecified2 => 6,
MultipleChoice2.Unspecified3 => 7,
MultipleChoice2.Unspecified4 => 8,
MultipleChoice2.Unspecified5 => 9,
});
}
const ExternPtrOrInt = extern union {
ptr: &u8,
int: u64
};
test "extern union size" {
comptime assert(@sizeOf(ExternPtrOrInt) == 8);
}
const PackedPtrOrInt = packed union {
ptr: &u8,
int: u64
};
test "extern union size" {
comptime assert(@sizeOf(PackedPtrOrInt) == 8);
}
const ZeroBits = union {
OnlyField: void,
};
test "union with only 1 field which is void should be zero bits" {
comptime assert(@sizeOf(ZeroBits) == 0);
}
const TheTag = enum {A, B, C};
const TheUnion = union(TheTag) { A: i32, B: i32, C: i32 };
test "union field access gives the enum values" {
assert(TheUnion.A == TheTag.A);
assert(TheUnion.B == TheTag.B);
assert(TheUnion.C == TheTag.C);
}
test "cast union to tag type of union" {
testCastUnionToTagType(TheUnion {.B = 1234});
comptime testCastUnionToTagType(TheUnion {.B = 1234});
}
fn testCastUnionToTagType(x: &const TheUnion) {
assert(TheTag(*x) == TheTag.B);
}

View File

@ -930,8 +930,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\fn bad_eql_1(a: []u8, b: []u8) -> bool {
\\ a == b
\\}
\\const EnumWithData = enum {
\\ One,
\\const EnumWithData = union(enum) {
\\ One: void,
\\ Two: i32,
\\};
\\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool {
@ -1145,19 +1145,19 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\const JasonHM = u8;
\\const JasonList = &JsonNode;
\\
\\const JsonOA = enum {
\\const JsonOA = union(enum) {
\\ JSONArray: JsonList,
\\ JSONObject: JasonHM,
\\};
\\
\\const JsonType = enum {
\\const JsonType = union(enum) {
\\ JSONNull: void,
\\ JSONInteger: isize,
\\ JSONDouble: f64,
\\ JSONBool: bool,
\\ JSONString: []u8,
\\ JSONArray,
\\ JSONObject,
\\ JSONArray: void,
\\ JSONObject: void,
\\};
\\
\\pub const JsonNode = struct {
@ -2138,7 +2138,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
\\
\\const MdText = ArrayList(u8);
\\
\\const MdNode = enum {
\\const MdNode = union(enum) {
\\ Header: struct {
\\ text: MdText,
\\ weight: HeaderValue,
@ -2297,6 +2297,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:2:21: error: type 'i32' does not support @memberType");
cases.add("@memberType on enum",
\\comptime {
\\ _ = @memberType(Foo, 0);
\\}
\\const Foo = enum {A,};
,
".tmp_source.zig:2:21: error: type 'Foo' does not support @memberType");
cases.add("@memberType struct out of bounds",
\\comptime {
\\ _ = @memberType(Foo, 0);
@ -2305,13 +2313,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
cases.add("@memberType enum out of bounds",
cases.add("@memberType union out of bounds",
\\comptime {
\\ _ = @memberType(Foo, 0);
\\ _ = @memberType(Foo, 1);
\\}
\\const Foo = enum {};
\\const Foo = union {A: void,};
,
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
cases.add("@memberName on unsupported type",
\\comptime {
@ -2330,11 +2338,19 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
cases.add("@memberName enum out of bounds",
\\comptime {
\\ _ = @memberName(Foo, 0);
\\ _ = @memberName(Foo, 1);
\\}
\\const Foo = enum {};
\\const Foo = enum {A,};
,
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
cases.add("@memberName union out of bounds",
\\comptime {
\\ _ = @memberName(Foo, 1);
\\}
\\const Foo = union {A:i32,};
,
".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
cases.add("calling var args extern function, passing array instead of pointer",
\\export fn entry() {
@ -2362,4 +2378,310 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
".tmp_source.zig:4:25: error: aoeu",
".tmp_source.zig:1:36: note: called from here",
".tmp_source.zig:12:20: note: referenced here");
cases.add("specify enum tag type that is too small",
\\const Small = enum (u2) {
\\ One,
\\ Two,
\\ Three,
\\ Four,
\\ Five,
\\};
\\
\\export fn entry() {
\\ var x = Small.One;
\\}
,
".tmp_source.zig:1:20: error: 'u2' too small to hold all bits; must be at least 'u3'");
cases.add("specify non-integer enum tag type",
\\const Small = enum (f32) {
\\ One,
\\ Two,
\\ Three,
\\};
\\
\\export fn entry() {
\\ var x = Small.One;
\\}
,
".tmp_source.zig:1:20: error: expected integer, found 'f32'");
cases.add("implicitly casting enum to tag type",
\\const Small = enum(u2) {
\\ One,
\\ Two,
\\ Three,
\\ Four,
\\};
\\
\\export fn entry() {
\\ var x: u2 = Small.Two;
\\}
,
".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'");
cases.add("explicitly casting enum to non tag type",
\\const Small = enum(u2) {
\\ One,
\\ Two,
\\ Three,
\\ Four,
\\};
\\
\\export fn entry() {
\\ var x = u3(Small.Two);
\\}
,
".tmp_source.zig:9:15: error: enum to integer cast to 'u3' instead of its tag type, 'u2'");
cases.add("explicitly casting non tag type to enum",
\\const Small = enum(u2) {
\\ One,
\\ Two,
\\ Three,
\\ Four,
\\};
\\
\\export fn entry() {
\\ var y = u3(3);
\\ var x = Small(y);
\\}
,
".tmp_source.zig:10:18: error: integer to enum cast from 'u3' instead of its tag type, 'u2'");
cases.add("non unsigned integer enum tag type",
\\const Small = enum(i2) {
\\ One,
\\ Two,
\\ Three,
\\ Four,
\\};
\\
\\export fn entry() {
\\ var y = Small.Two;
\\}
,
".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'");
cases.add("struct fields with value assignments",
\\const MultipleChoice = struct {
\\ A: i32 = 20,
\\};
\\export fn entry() {
\\ var x: MultipleChoice = undefined;
\\}
,
".tmp_source.zig:2:14: error: enums, not structs, support field assignment");
cases.add("union fields with value assignments",
\\const MultipleChoice = union {
\\ A: i32 = 20,
\\};
\\export fn entry() {
\\ var x: MultipleChoice = undefined;
\\}
,
".tmp_source.zig:2:14: error: non-enum union field assignment",
".tmp_source.zig:1:24: note: consider 'union(enum)' here");
cases.add("enum with 0 fields",
\\const Foo = enum {};
\\export fn entry() -> usize {
\\ return @sizeOf(Foo);
\\}
,
".tmp_source.zig:1:13: error: enums must have 1 or more fields");
cases.add("union with 0 fields",
\\const Foo = union {};
\\export fn entry() -> usize {
\\ return @sizeOf(Foo);
\\}
,
".tmp_source.zig:1:13: error: unions must have 1 or more fields");
cases.add("enum value already taken",
\\const MultipleChoice = enum(u32) {
\\ A = 20,
\\ B = 40,
\\ C = 60,
\\ D = 1000,
\\ E = 60,
\\};
\\export fn entry() {
\\ var x = MultipleChoice.C;
\\}
,
".tmp_source.zig:6:9: error: enum tag value 60 already taken",
".tmp_source.zig:4:9: note: other occurrence here");
cases.add("union with specified enum omits field",
\\const Letter = enum {
\\ A,
\\ B,
\\ C,
\\};
\\const Payload = union(Letter) {
\\ A: i32,
\\ B: f64,
\\};
\\export fn entry() -> usize {
\\ return @sizeOf(Payload);
\\}
,
".tmp_source.zig:6:17: error: enum field missing: 'C'",
".tmp_source.zig:4:5: note: declared here");
cases.add("@TagType when union has no attached enum",
\\const Foo = union {
\\ A: i32,
\\};
\\export fn entry() {
\\ const x = @TagType(Foo);
\\}
,
".tmp_source.zig:5:24: error: union 'Foo' has no tag",
".tmp_source.zig:1:13: note: consider 'union(enum)' here");
cases.add("non-integer tag type to automatic union enum",
\\const Foo = union(enum(f32)) {
\\ A: i32,
\\};
\\export fn entry() {
\\ const x = @TagType(Foo);
\\}
,
".tmp_source.zig:1:23: error: expected integer tag type, found 'f32'");
cases.add("non-enum tag type passed to union",
\\const Foo = union(u32) {
\\ A: i32,
\\};
\\export fn entry() {
\\ const x = @TagType(Foo);
\\}
,
".tmp_source.zig:1:18: error: expected enum tag type, found 'u32'");
cases.add("union auto-enum value already taken",
\\const MultipleChoice = union(enum(u32)) {
\\ A = 20,
\\ B = 40,
\\ C = 60,
\\ D = 1000,
\\ E = 60,
\\};
\\export fn entry() {
\\ var x = MultipleChoice { .C = {} };
\\}
,
".tmp_source.zig:6:9: error: enum tag value 60 already taken",
".tmp_source.zig:4:9: note: other occurrence here");
cases.add("union enum field does not match enum",
\\const Letter = enum {
\\ A,
\\ B,
\\ C,
\\};
\\const Payload = union(Letter) {
\\ A: i32,
\\ B: f64,
\\ C: bool,
\\ D: bool,
\\};
\\export fn entry() {
\\ var a = Payload {.A = 1234};
\\}
,
".tmp_source.zig:10:5: error: enum field not found: 'D'",
".tmp_source.zig:1:16: note: enum declared here");
cases.add("field type supplied in an enum",
\\const Letter = enum {
\\ A: void,
\\ B,
\\ C,
\\};
\\export fn entry() {
\\ var b = Letter.B;
\\}
,
".tmp_source.zig:2:8: error: structs and unions, not enums, support field types",
".tmp_source.zig:1:16: note: consider 'union(enum)' here");
cases.add("struct field missing type",
\\const Letter = struct {
\\ A,
\\};
\\export fn entry() {
\\ var a = Letter { .A = {} };
\\}
,
".tmp_source.zig:2:5: error: struct field missing type");
cases.add("extern union field missing type",
\\const Letter = extern union {
\\ A,
\\};
\\export fn entry() {
\\ var a = Letter { .A = {} };
\\}
,
".tmp_source.zig:2:5: error: union field missing type");
cases.add("extern union given enum tag type",
\\const Letter = enum {
\\ A,
\\ B,
\\ C,
\\};
\\const Payload = extern union(Letter) {
\\ A: i32,
\\ B: f64,
\\ C: bool,
\\};
\\export fn entry() {
\\ var a = Payload { .A = { 1234 } };
\\}
,
".tmp_source.zig:6:29: error: extern union does not support enum tag type");
cases.add("packed union given enum tag type",
\\const Letter = enum {
\\ A,
\\ B,
\\ C,
\\};
\\const Payload = packed union(Letter) {
\\ A: i32,
\\ B: f64,
\\ C: bool,
\\};
\\export fn entry() {
\\ var a = Payload { .A = { 1234 } };
\\}
,
".tmp_source.zig:6:29: error: packed union does not support enum tag type");
cases.add("switch on union with no attached enum",
\\const Payload = union {
\\ A: i32,
\\ B: f64,
\\ C: bool,
\\};
\\export fn entry() {
\\ const a = Payload { .A = { 1234 } };
\\ foo(a);
\\}
\\fn foo(a: &const Payload) {
\\ switch (*a) {
\\ Payload.A => {},
\\ else => unreachable,
\\ }
\\}
,
".tmp_source.zig:11:13: error: switch on union which has no attached enum",
".tmp_source.zig:1:17: note: consider 'union(enum)' here");
}

View File

@ -150,8 +150,8 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons
continue;
}
const these_tests = b.addTest(root_src);
these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @enumTagName(test_target.os),
@enumTagName(test_target.arch), @enumTagName(mode), if (link_libc) "c" else "bare"));
these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os),
@tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare"));
these_tests.setFilter(test_filter);
these_tests.setBuildMode(mode);
if (!is_native) {
@ -428,7 +428,7 @@ pub const CompareOutputContext = struct {
Special.None => {
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "{} {} ({})",
"compare-output", case.name, @enumTagName(mode));
"compare-output", case.name, @tagName(mode));
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null)
continue;
@ -682,7 +682,7 @@ pub const CompileErrorContext = struct {
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "compile-error {} ({})",
case.name, @enumTagName(mode));
case.name, @tagName(mode));
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null)
continue;
@ -750,7 +750,7 @@ pub const BuildExamplesContext = struct {
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "build {} ({})",
root_src, @enumTagName(mode));
root_src, @tagName(mode));
if (self.test_filter) |filter| {
if (mem.indexOf(u8, annotated_case_name, filter) == null)
continue;

View File

@ -1178,4 +1178,14 @@ pub fn addCases(cases: &tests.TranslateCContext) {
,
\\pub var v0: ?&const u8 = c"0.0.0";
);
cases.add("static incomplete array inside function",
\\void foo(void) {
\\ static const char v2[] = "2.2.2";
\\}
,
\\pub fn foo() {
\\ const v2: &const u8 = c"2.2.2";
\\}
);
}