| author | |
| committer | |
| log | 42004f9013ba2d06b457f858e0e269ef4ad23554 |
| tree | ee99dd89c9ce7e7c30a76e7bf0d9f7da7c0c64c7 |
| parent | afe3aae582d5051406832e32fc01374f2a0029b7 |
| parent | a966275e509670e750ef54a37f7202078aa4cf07 |
57 files changed, 2602 insertions(+), 1580 deletions(-)
CMakeLists.txt+8-3| ... | ... | @@ -47,15 +47,20 @@ option(ZIG_TEST_COVERAGE "Build Zig with test coverage instrumentation" OFF) |
| 47 | 47 | option(ZIG_FORCE_EXTERNAL_LLD "If your system has the LLD patches use it instead of the embedded LLD" OFF) |
| 48 | 48 | |
| 49 | 49 | find_package(llvm) |
| 50 | include_directories(${LLVM_INCLUDE_DIRS}) | |
| 51 | ||
| 52 | 50 | find_package(clang) |
| 53 | include_directories(${CLANG_INCLUDE_DIRS}) | |
| 54 | 51 | |
| 55 | 52 | if(ZIG_FORCE_EXTERNAL_LLD) |
| 56 | 53 | find_package(lld) |
| 54 | include_directories(${LLVM_INCLUDE_DIRS}) | |
| 57 | 55 | include_directories(${LLD_INCLUDE_DIRS}) |
| 56 | include_directories(${CLANG_INCLUDE_DIRS}) | |
| 58 | 57 | else() |
| 58 | # This goes first so that we find embedded LLD instead | |
| 59 | # of system LLD. | |
| 60 | include_directories("${CMAKE_SOURCE_DIR}/deps/lld/include") | |
| 61 | ||
| 62 | include_directories(${LLVM_INCLUDE_DIRS}) | |
| 63 | include_directories(${CLANG_INCLUDE_DIRS}) | |
| 59 | 64 | set(EMBEDDED_LLD_LIB_SOURCES |
| 60 | 65 | "${CMAKE_SOURCE_DIR}/deps/lld/lib/Driver/DarwinLdDriver.cpp" |
| 61 | 66 | "${CMAKE_SOURCE_DIR}/deps/lld/lib/Config/Version.cpp" |
c_headers/avx512fintrin.h+229-395| ... | ... | @@ -4543,37 +4543,6 @@ _mm512_maskz_unpacklo_epi64 (__mmask8 __U, __m512i __A, __m512i __B) |
| 4543 | 4543 | (__v8di)_mm512_setzero_si512()); |
| 4544 | 4544 | } |
| 4545 | 4545 | |
| 4546 | /* Bit Test */ | |
| 4547 | ||
| 4548 | static __inline __mmask16 __DEFAULT_FN_ATTRS | |
| 4549 | _mm512_test_epi32_mask(__m512i __A, __m512i __B) | |
| 4550 | { | |
| 4551 | return (__mmask16) __builtin_ia32_ptestmd512 ((__v16si) __A, | |
| 4552 | (__v16si) __B, | |
| 4553 | (__mmask16) -1); | |
| 4554 | } | |
| 4555 | ||
| 4556 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4557 | _mm512_mask_test_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B) | |
| 4558 | { | |
| 4559 | return (__mmask16) __builtin_ia32_ptestmd512 ((__v16si) __A, | |
| 4560 | (__v16si) __B, __U); | |
| 4561 | } | |
| 4562 | ||
| 4563 | static __inline __mmask8 __DEFAULT_FN_ATTRS | |
| 4564 | _mm512_test_epi64_mask(__m512i __A, __m512i __B) | |
| 4565 | { | |
| 4566 | return (__mmask8) __builtin_ia32_ptestmq512 ((__v8di) __A, | |
| 4567 | (__v8di) __B, | |
| 4568 | (__mmask8) -1); | |
| 4569 | } | |
| 4570 | ||
| 4571 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4572 | _mm512_mask_test_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B) | |
| 4573 | { | |
| 4574 | return (__mmask8) __builtin_ia32_ptestmq512 ((__v8di) __A, (__v8di) __B, __U); | |
| 4575 | } | |
| 4576 | ||
| 4577 | 4546 | |
| 4578 | 4547 | /* SIMD load ops */ |
| 4579 | 4548 | |
| ... | ... | @@ -4844,293 +4813,105 @@ _mm512_knot(__mmask16 __M) |
| 4844 | 4813 | |
| 4845 | 4814 | /* Integer compare */ |
| 4846 | 4815 | |
| 4847 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4848 | _mm512_cmpeq_epi32_mask(__m512i __a, __m512i __b) { | |
| 4849 | return (__mmask16)__builtin_ia32_pcmpeqd512_mask((__v16si)__a, (__v16si)__b, | |
| 4850 | (__mmask16)-1); | |
| 4851 | } | |
| 4852 | ||
| 4853 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4854 | _mm512_mask_cmpeq_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 4855 | return (__mmask16)__builtin_ia32_pcmpeqd512_mask((__v16si)__a, (__v16si)__b, | |
| 4856 | __u); | |
| 4857 | } | |
| 4858 | ||
| 4859 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4860 | _mm512_cmpeq_epu32_mask(__m512i __a, __m512i __b) { | |
| 4861 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 0, | |
| 4862 | (__mmask16)-1); | |
| 4863 | } | |
| 4864 | ||
| 4865 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4866 | _mm512_mask_cmpeq_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 4867 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 0, | |
| 4868 | __u); | |
| 4869 | } | |
| 4870 | ||
| 4871 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4872 | _mm512_mask_cmpeq_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 4873 | return (__mmask8)__builtin_ia32_pcmpeqq512_mask((__v8di)__a, (__v8di)__b, | |
| 4874 | __u); | |
| 4875 | } | |
| 4876 | ||
| 4877 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4878 | _mm512_cmpeq_epi64_mask(__m512i __a, __m512i __b) { | |
| 4879 | return (__mmask8)__builtin_ia32_pcmpeqq512_mask((__v8di)__a, (__v8di)__b, | |
| 4880 | (__mmask8)-1); | |
| 4881 | } | |
| 4882 | ||
| 4883 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4884 | _mm512_cmpeq_epu64_mask(__m512i __a, __m512i __b) { | |
| 4885 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 0, | |
| 4886 | (__mmask8)-1); | |
| 4887 | } | |
| 4888 | ||
| 4889 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4890 | _mm512_mask_cmpeq_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 4891 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 0, | |
| 4892 | __u); | |
| 4893 | } | |
| 4894 | ||
| 4895 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4896 | _mm512_cmpge_epi32_mask(__m512i __a, __m512i __b) { | |
| 4897 | return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 5, | |
| 4898 | (__mmask16)-1); | |
| 4899 | } | |
| 4900 | ||
| 4901 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4902 | _mm512_mask_cmpge_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 4903 | return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 5, | |
| 4904 | __u); | |
| 4905 | } | |
| 4906 | ||
| 4907 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4908 | _mm512_cmpge_epu32_mask(__m512i __a, __m512i __b) { | |
| 4909 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 5, | |
| 4910 | (__mmask16)-1); | |
| 4911 | } | |
| 4912 | ||
| 4913 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4914 | _mm512_mask_cmpge_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 4915 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 5, | |
| 4916 | __u); | |
| 4917 | } | |
| 4918 | ||
| 4919 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4920 | _mm512_cmpge_epi64_mask(__m512i __a, __m512i __b) { | |
| 4921 | return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 5, | |
| 4922 | (__mmask8)-1); | |
| 4923 | } | |
| 4924 | ||
| 4925 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4926 | _mm512_mask_cmpge_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 4927 | return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 5, | |
| 4928 | __u); | |
| 4929 | } | |
| 4930 | ||
| 4931 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4932 | _mm512_cmpge_epu64_mask(__m512i __a, __m512i __b) { | |
| 4933 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 5, | |
| 4934 | (__mmask8)-1); | |
| 4935 | } | |
| 4936 | ||
| 4937 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4938 | _mm512_mask_cmpge_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 4939 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 5, | |
| 4940 | __u); | |
| 4941 | } | |
| 4942 | ||
| 4943 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4944 | _mm512_cmpgt_epi32_mask(__m512i __a, __m512i __b) { | |
| 4945 | return (__mmask16)__builtin_ia32_pcmpgtd512_mask((__v16si)__a, (__v16si)__b, | |
| 4946 | (__mmask16)-1); | |
| 4947 | } | |
| 4948 | ||
| 4949 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4950 | _mm512_mask_cmpgt_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 4951 | return (__mmask16)__builtin_ia32_pcmpgtd512_mask((__v16si)__a, (__v16si)__b, | |
| 4952 | __u); | |
| 4953 | } | |
| 4954 | ||
| 4955 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4956 | _mm512_cmpgt_epu32_mask(__m512i __a, __m512i __b) { | |
| 4957 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 6, | |
| 4958 | (__mmask16)-1); | |
| 4959 | } | |
| 4960 | ||
| 4961 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4962 | _mm512_mask_cmpgt_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 4963 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 6, | |
| 4964 | __u); | |
| 4965 | } | |
| 4966 | ||
| 4967 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4968 | _mm512_mask_cmpgt_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 4969 | return (__mmask8)__builtin_ia32_pcmpgtq512_mask((__v8di)__a, (__v8di)__b, | |
| 4970 | __u); | |
| 4971 | } | |
| 4972 | ||
| 4973 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4974 | _mm512_cmpgt_epi64_mask(__m512i __a, __m512i __b) { | |
| 4975 | return (__mmask8)__builtin_ia32_pcmpgtq512_mask((__v8di)__a, (__v8di)__b, | |
| 4976 | (__mmask8)-1); | |
| 4977 | } | |
| 4978 | ||
| 4979 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4980 | _mm512_cmpgt_epu64_mask(__m512i __a, __m512i __b) { | |
| 4981 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 6, | |
| 4982 | (__mmask8)-1); | |
| 4983 | } | |
| 4984 | ||
| 4985 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 4986 | _mm512_mask_cmpgt_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 4987 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 6, | |
| 4988 | __u); | |
| 4989 | } | |
| 4990 | ||
| 4991 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4992 | _mm512_cmple_epi32_mask(__m512i __a, __m512i __b) { | |
| 4993 | return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 2, | |
| 4994 | (__mmask16)-1); | |
| 4995 | } | |
| 4996 | ||
| 4997 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 4998 | _mm512_mask_cmple_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 4999 | return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 2, | |
| 5000 | __u); | |
| 5001 | } | |
| 5002 | ||
| 5003 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 5004 | _mm512_cmple_epu32_mask(__m512i __a, __m512i __b) { | |
| 5005 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 2, | |
| 5006 | (__mmask16)-1); | |
| 5007 | } | |
| 5008 | ||
| 5009 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 5010 | _mm512_mask_cmple_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 5011 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 2, | |
| 5012 | __u); | |
| 5013 | } | |
| 5014 | ||
| 5015 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5016 | _mm512_cmple_epi64_mask(__m512i __a, __m512i __b) { | |
| 5017 | return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 2, | |
| 5018 | (__mmask8)-1); | |
| 5019 | } | |
| 5020 | ||
| 5021 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5022 | _mm512_mask_cmple_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 5023 | return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 2, | |
| 5024 | __u); | |
| 5025 | } | |
| 5026 | ||
| 5027 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5028 | _mm512_cmple_epu64_mask(__m512i __a, __m512i __b) { | |
| 5029 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 2, | |
| 5030 | (__mmask8)-1); | |
| 5031 | } | |
| 5032 | ||
| 5033 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5034 | _mm512_mask_cmple_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 5035 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 2, | |
| 5036 | __u); | |
| 5037 | } | |
| 5038 | ||
| 5039 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 5040 | _mm512_cmplt_epi32_mask(__m512i __a, __m512i __b) { | |
| 5041 | return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 1, | |
| 5042 | (__mmask16)-1); | |
| 5043 | } | |
| 5044 | ||
| 5045 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 5046 | _mm512_mask_cmplt_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 5047 | return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 1, | |
| 5048 | __u); | |
| 5049 | } | |
| 5050 | ||
| 5051 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 5052 | _mm512_cmplt_epu32_mask(__m512i __a, __m512i __b) { | |
| 5053 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 1, | |
| 5054 | (__mmask16)-1); | |
| 5055 | } | |
| 5056 | ||
| 5057 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 5058 | _mm512_mask_cmplt_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 5059 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 1, | |
| 5060 | __u); | |
| 5061 | } | |
| 5062 | ||
| 5063 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5064 | _mm512_cmplt_epi64_mask(__m512i __a, __m512i __b) { | |
| 5065 | return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 1, | |
| 5066 | (__mmask8)-1); | |
| 5067 | } | |
| 5068 | ||
| 5069 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5070 | _mm512_mask_cmplt_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 5071 | return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 1, | |
| 5072 | __u); | |
| 5073 | } | |
| 5074 | ||
| 5075 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5076 | _mm512_cmplt_epu64_mask(__m512i __a, __m512i __b) { | |
| 5077 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 1, | |
| 5078 | (__mmask8)-1); | |
| 5079 | } | |
| 5080 | ||
| 5081 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5082 | _mm512_mask_cmplt_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 5083 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 1, | |
| 5084 | __u); | |
| 5085 | } | |
| 5086 | ||
| 5087 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 5088 | _mm512_cmpneq_epi32_mask(__m512i __a, __m512i __b) { | |
| 5089 | return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 4, | |
| 5090 | (__mmask16)-1); | |
| 5091 | } | |
| 5092 | ||
| 5093 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 5094 | _mm512_mask_cmpneq_epi32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 5095 | return (__mmask16)__builtin_ia32_cmpd512_mask((__v16si)__a, (__v16si)__b, 4, | |
| 5096 | __u); | |
| 5097 | } | |
| 5098 | ||
| 5099 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 5100 | _mm512_cmpneq_epu32_mask(__m512i __a, __m512i __b) { | |
| 5101 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 4, | |
| 5102 | (__mmask16)-1); | |
| 5103 | } | |
| 5104 | ||
| 5105 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 5106 | _mm512_mask_cmpneq_epu32_mask(__mmask16 __u, __m512i __a, __m512i __b) { | |
| 5107 | return (__mmask16)__builtin_ia32_ucmpd512_mask((__v16si)__a, (__v16si)__b, 4, | |
| 5108 | __u); | |
| 5109 | } | |
| 5110 | ||
| 5111 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5112 | _mm512_cmpneq_epi64_mask(__m512i __a, __m512i __b) { | |
| 5113 | return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 4, | |
| 5114 | (__mmask8)-1); | |
| 5115 | } | |
| 5116 | ||
| 5117 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5118 | _mm512_mask_cmpneq_epi64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 5119 | return (__mmask8)__builtin_ia32_cmpq512_mask((__v8di)__a, (__v8di)__b, 4, | |
| 5120 | __u); | |
| 5121 | } | |
| 5122 | ||
| 5123 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5124 | _mm512_cmpneq_epu64_mask(__m512i __a, __m512i __b) { | |
| 5125 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 4, | |
| 5126 | (__mmask8)-1); | |
| 5127 | } | |
| 5128 | ||
| 5129 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 5130 | _mm512_mask_cmpneq_epu64_mask(__mmask8 __u, __m512i __a, __m512i __b) { | |
| 5131 | return (__mmask8)__builtin_ia32_ucmpq512_mask((__v8di)__a, (__v8di)__b, 4, | |
| 5132 | __u); | |
| 5133 | } | |
| 4816 | #define _mm512_cmpeq_epi32_mask(A, B) \ | |
| 4817 | _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_EQ) | |
| 4818 | #define _mm512_mask_cmpeq_epi32_mask(k, A, B) \ | |
| 4819 | _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_EQ) | |
| 4820 | #define _mm512_cmpge_epi32_mask(A, B) \ | |
| 4821 | _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_GE) | |
| 4822 | #define _mm512_mask_cmpge_epi32_mask(k, A, B) \ | |
| 4823 | _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_GE) | |
| 4824 | #define _mm512_cmpgt_epi32_mask(A, B) \ | |
| 4825 | _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_GT) | |
| 4826 | #define _mm512_mask_cmpgt_epi32_mask(k, A, B) \ | |
| 4827 | _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_GT) | |
| 4828 | #define _mm512_cmple_epi32_mask(A, B) \ | |
| 4829 | _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_LE) | |
| 4830 | #define _mm512_mask_cmple_epi32_mask(k, A, B) \ | |
| 4831 | _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_LE) | |
| 4832 | #define _mm512_cmplt_epi32_mask(A, B) \ | |
| 4833 | _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_LT) | |
| 4834 | #define _mm512_mask_cmplt_epi32_mask(k, A, B) \ | |
| 4835 | _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_LT) | |
| 4836 | #define _mm512_cmpneq_epi32_mask(A, B) \ | |
| 4837 | _mm512_cmp_epi32_mask((A), (B), _MM_CMPINT_NE) | |
| 4838 | #define _mm512_mask_cmpneq_epi32_mask(k, A, B) \ | |
| 4839 | _mm512_mask_cmp_epi32_mask((k), (A), (B), _MM_CMPINT_NE) | |
| 4840 | ||
| 4841 | #define _mm512_cmpeq_epu32_mask(A, B) \ | |
| 4842 | _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_EQ) | |
| 4843 | #define _mm512_mask_cmpeq_epu32_mask(k, A, B) \ | |
| 4844 | _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_EQ) | |
| 4845 | #define _mm512_cmpge_epu32_mask(A, B) \ | |
| 4846 | _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_GE) | |
| 4847 | #define _mm512_mask_cmpge_epu32_mask(k, A, B) \ | |
| 4848 | _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_GE) | |
| 4849 | #define _mm512_cmpgt_epu32_mask(A, B) \ | |
| 4850 | _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_GT) | |
| 4851 | #define _mm512_mask_cmpgt_epu32_mask(k, A, B) \ | |
| 4852 | _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_GT) | |
| 4853 | #define _mm512_cmple_epu32_mask(A, B) \ | |
| 4854 | _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_LE) | |
| 4855 | #define _mm512_mask_cmple_epu32_mask(k, A, B) \ | |
| 4856 | _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_LE) | |
| 4857 | #define _mm512_cmplt_epu32_mask(A, B) \ | |
| 4858 | _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_LT) | |
| 4859 | #define _mm512_mask_cmplt_epu32_mask(k, A, B) \ | |
| 4860 | _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_LT) | |
| 4861 | #define _mm512_cmpneq_epu32_mask(A, B) \ | |
| 4862 | _mm512_cmp_epu32_mask((A), (B), _MM_CMPINT_NE) | |
| 4863 | #define _mm512_mask_cmpneq_epu32_mask(k, A, B) \ | |
| 4864 | _mm512_mask_cmp_epu32_mask((k), (A), (B), _MM_CMPINT_NE) | |
| 4865 | ||
| 4866 | #define _mm512_cmpeq_epi64_mask(A, B) \ | |
| 4867 | _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_EQ) | |
| 4868 | #define _mm512_mask_cmpeq_epi64_mask(k, A, B) \ | |
| 4869 | _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_EQ) | |
| 4870 | #define _mm512_cmpge_epi64_mask(A, B) \ | |
| 4871 | _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_GE) | |
| 4872 | #define _mm512_mask_cmpge_epi64_mask(k, A, B) \ | |
| 4873 | _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_GE) | |
| 4874 | #define _mm512_cmpgt_epi64_mask(A, B) \ | |
| 4875 | _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_GT) | |
| 4876 | #define _mm512_mask_cmpgt_epi64_mask(k, A, B) \ | |
| 4877 | _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_GT) | |
| 4878 | #define _mm512_cmple_epi64_mask(A, B) \ | |
| 4879 | _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_LE) | |
| 4880 | #define _mm512_mask_cmple_epi64_mask(k, A, B) \ | |
| 4881 | _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_LE) | |
| 4882 | #define _mm512_cmplt_epi64_mask(A, B) \ | |
| 4883 | _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_LT) | |
| 4884 | #define _mm512_mask_cmplt_epi64_mask(k, A, B) \ | |
| 4885 | _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_LT) | |
| 4886 | #define _mm512_cmpneq_epi64_mask(A, B) \ | |
| 4887 | _mm512_cmp_epi64_mask((A), (B), _MM_CMPINT_NE) | |
| 4888 | #define _mm512_mask_cmpneq_epi64_mask(k, A, B) \ | |
| 4889 | _mm512_mask_cmp_epi64_mask((k), (A), (B), _MM_CMPINT_NE) | |
| 4890 | ||
| 4891 | #define _mm512_cmpeq_epu64_mask(A, B) \ | |
| 4892 | _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_EQ) | |
| 4893 | #define _mm512_mask_cmpeq_epu64_mask(k, A, B) \ | |
| 4894 | _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_EQ) | |
| 4895 | #define _mm512_cmpge_epu64_mask(A, B) \ | |
| 4896 | _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_GE) | |
| 4897 | #define _mm512_mask_cmpge_epu64_mask(k, A, B) \ | |
| 4898 | _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_GE) | |
| 4899 | #define _mm512_cmpgt_epu64_mask(A, B) \ | |
| 4900 | _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_GT) | |
| 4901 | #define _mm512_mask_cmpgt_epu64_mask(k, A, B) \ | |
| 4902 | _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_GT) | |
| 4903 | #define _mm512_cmple_epu64_mask(A, B) \ | |
| 4904 | _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_LE) | |
| 4905 | #define _mm512_mask_cmple_epu64_mask(k, A, B) \ | |
| 4906 | _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_LE) | |
| 4907 | #define _mm512_cmplt_epu64_mask(A, B) \ | |
| 4908 | _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_LT) | |
| 4909 | #define _mm512_mask_cmplt_epu64_mask(k, A, B) \ | |
| 4910 | _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_LT) | |
| 4911 | #define _mm512_cmpneq_epu64_mask(A, B) \ | |
| 4912 | _mm512_cmp_epu64_mask((A), (B), _MM_CMPINT_NE) | |
| 4913 | #define _mm512_mask_cmpneq_epu64_mask(k, A, B) \ | |
| 4914 | _mm512_mask_cmp_epu64_mask((k), (A), (B), _MM_CMPINT_NE) | |
| 5134 | 4915 | |
| 5135 | 4916 | static __inline__ __m512i __DEFAULT_FN_ATTRS |
| 5136 | 4917 | _mm512_cvtepi8_epi32(__m128i __A) |
| ... | ... | @@ -6797,35 +6578,6 @@ _mm512_maskz_permutex2var_ps (__mmask16 __U, __m512 __A, __m512i __I, |
| 6797 | 6578 | (__mmask16) __U); |
| 6798 | 6579 | } |
| 6799 | 6580 | |
| 6800 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 6801 | _mm512_testn_epi32_mask (__m512i __A, __m512i __B) | |
| 6802 | { | |
| 6803 | return (__mmask16) __builtin_ia32_ptestnmd512 ((__v16si) __A, | |
| 6804 | (__v16si) __B, | |
| 6805 | (__mmask16) -1); | |
| 6806 | } | |
| 6807 | ||
| 6808 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 6809 | _mm512_mask_testn_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B) | |
| 6810 | { | |
| 6811 | return (__mmask16) __builtin_ia32_ptestnmd512 ((__v16si) __A, | |
| 6812 | (__v16si) __B, __U); | |
| 6813 | } | |
| 6814 | ||
| 6815 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 6816 | _mm512_testn_epi64_mask (__m512i __A, __m512i __B) | |
| 6817 | { | |
| 6818 | return (__mmask8) __builtin_ia32_ptestnmq512 ((__v8di) __A, | |
| 6819 | (__v8di) __B, | |
| 6820 | (__mmask8) -1); | |
| 6821 | } | |
| 6822 | ||
| 6823 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 6824 | _mm512_mask_testn_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B) | |
| 6825 | { | |
| 6826 | return (__mmask8) __builtin_ia32_ptestnmq512 ((__v8di) __A, | |
| 6827 | (__v8di) __B, __U); | |
| 6828 | } | |
| 6829 | 6581 | |
| 6830 | 6582 | #define _mm512_cvtt_roundpd_epu32(A, R) __extension__ ({ \ |
| 6831 | 6583 | (__m256i)__builtin_ia32_cvttpd2udq512_mask((__v8df)(__m512d)(A), \ |
| ... | ... | @@ -7194,76 +6946,100 @@ _mm512_maskz_srai_epi64(__mmask8 __U, __m512i __A, int __B) |
| 7194 | 6946 | } |
| 7195 | 6947 | |
| 7196 | 6948 | #define _mm512_shuffle_f32x4(A, B, imm) __extension__ ({ \ |
| 7197 | (__m512)__builtin_ia32_shuf_f32x4_mask((__v16sf)(__m512)(A), \ | |
| 7198 | (__v16sf)(__m512)(B), (int)(imm), \ | |
| 7199 | (__v16sf)_mm512_undefined_ps(), \ | |
| 7200 | (__mmask16)-1); }) | |
| 6949 | (__m512)__builtin_shufflevector((__v16sf)(__m512)(A), \ | |
| 6950 | (__v16sf)(__m512)(B), \ | |
| 6951 | 0 + ((((imm) >> 0) & 0x3) * 4), \ | |
| 6952 | 1 + ((((imm) >> 0) & 0x3) * 4), \ | |
| 6953 | 2 + ((((imm) >> 0) & 0x3) * 4), \ | |
| 6954 | 3 + ((((imm) >> 0) & 0x3) * 4), \ | |
| 6955 | 0 + ((((imm) >> 2) & 0x3) * 4), \ | |
| 6956 | 1 + ((((imm) >> 2) & 0x3) * 4), \ | |
| 6957 | 2 + ((((imm) >> 2) & 0x3) * 4), \ | |
| 6958 | 3 + ((((imm) >> 2) & 0x3) * 4), \ | |
| 6959 | 16 + ((((imm) >> 4) & 0x3) * 4), \ | |
| 6960 | 17 + ((((imm) >> 4) & 0x3) * 4), \ | |
| 6961 | 18 + ((((imm) >> 4) & 0x3) * 4), \ | |
| 6962 | 19 + ((((imm) >> 4) & 0x3) * 4), \ | |
| 6963 | 16 + ((((imm) >> 6) & 0x3) * 4), \ | |
| 6964 | 17 + ((((imm) >> 6) & 0x3) * 4), \ | |
| 6965 | 18 + ((((imm) >> 6) & 0x3) * 4), \ | |
| 6966 | 19 + ((((imm) >> 6) & 0x3) * 4)); }) | |
| 7201 | 6967 | |
| 7202 | 6968 | #define _mm512_mask_shuffle_f32x4(W, U, A, B, imm) __extension__ ({ \ |
| 7203 | (__m512)__builtin_ia32_shuf_f32x4_mask((__v16sf)(__m512)(A), \ | |
| 7204 | (__v16sf)(__m512)(B), (int)(imm), \ | |
| 7205 | (__v16sf)(__m512)(W), \ | |
| 7206 | (__mmask16)(U)); }) | |
| 6969 | (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ | |
| 6970 | (__v16sf)_mm512_shuffle_f32x4((A), (B), (imm)), \ | |
| 6971 | (__v16sf)(__m512)(W)); }) | |
| 7207 | 6972 | |
| 7208 | 6973 | #define _mm512_maskz_shuffle_f32x4(U, A, B, imm) __extension__ ({ \ |
| 7209 | (__m512)__builtin_ia32_shuf_f32x4_mask((__v16sf)(__m512)(A), \ | |
| 7210 | (__v16sf)(__m512)(B), (int)(imm), \ | |
| 7211 | (__v16sf)_mm512_setzero_ps(), \ | |
| 7212 | (__mmask16)(U)); }) | |
| 6974 | (__m512)__builtin_ia32_selectps_512((__mmask16)(U), \ | |
| 6975 | (__v16sf)_mm512_shuffle_f32x4((A), (B), (imm)), \ | |
| 6976 | (__v16sf)_mm512_setzero_ps()); }) | |
| 7213 | 6977 | |
| 7214 | 6978 | #define _mm512_shuffle_f64x2(A, B, imm) __extension__ ({ \ |
| 7215 | (__m512d)__builtin_ia32_shuf_f64x2_mask((__v8df)(__m512d)(A), \ | |
| 7216 | (__v8df)(__m512d)(B), (int)(imm), \ | |
| 7217 | (__v8df)_mm512_undefined_pd(), \ | |
| 7218 | (__mmask8)-1); }) | |
| 6979 | (__m512d)__builtin_shufflevector((__v8df)(__m512d)(A), \ | |
| 6980 | (__v8df)(__m512d)(B), \ | |
| 6981 | 0 + ((((imm) >> 0) & 0x3) * 2), \ | |
| 6982 | 1 + ((((imm) >> 0) & 0x3) * 2), \ | |
| 6983 | 0 + ((((imm) >> 2) & 0x3) * 2), \ | |
| 6984 | 1 + ((((imm) >> 2) & 0x3) * 2), \ | |
| 6985 | 8 + ((((imm) >> 4) & 0x3) * 2), \ | |
| 6986 | 9 + ((((imm) >> 4) & 0x3) * 2), \ | |
| 6987 | 8 + ((((imm) >> 6) & 0x3) * 2), \ | |
| 6988 | 9 + ((((imm) >> 6) & 0x3) * 2)); }) | |
| 7219 | 6989 | |
| 7220 | 6990 | #define _mm512_mask_shuffle_f64x2(W, U, A, B, imm) __extension__ ({ \ |
| 7221 | (__m512d)__builtin_ia32_shuf_f64x2_mask((__v8df)(__m512d)(A), \ | |
| 7222 | (__v8df)(__m512d)(B), (int)(imm), \ | |
| 7223 | (__v8df)(__m512d)(W), \ | |
| 7224 | (__mmask8)(U)); }) | |
| 6991 | (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ | |
| 6992 | (__v8df)_mm512_shuffle_f64x2((A), (B), (imm)), \ | |
| 6993 | (__v8df)(__m512d)(W)); }) | |
| 7225 | 6994 | |
| 7226 | 6995 | #define _mm512_maskz_shuffle_f64x2(U, A, B, imm) __extension__ ({ \ |
| 7227 | (__m512d)__builtin_ia32_shuf_f64x2_mask((__v8df)(__m512d)(A), \ | |
| 7228 | (__v8df)(__m512d)(B), (int)(imm), \ | |
| 7229 | (__v8df)_mm512_setzero_pd(), \ | |
| 7230 | (__mmask8)(U)); }) | |
| 6996 | (__m512d)__builtin_ia32_selectpd_512((__mmask8)(U), \ | |
| 6997 | (__v8df)_mm512_shuffle_f64x2((A), (B), (imm)), \ | |
| 6998 | (__v8df)_mm512_setzero_pd()); }) | |
| 7231 | 6999 | |
| 7232 | 7000 | #define _mm512_shuffle_i32x4(A, B, imm) __extension__ ({ \ |
| 7233 | (__m512i)__builtin_ia32_shuf_i32x4_mask((__v16si)(__m512i)(A), \ | |
| 7234 | (__v16si)(__m512i)(B), (int)(imm), \ | |
| 7235 | (__v16si)_mm512_setzero_si512(), \ | |
| 7236 | (__mmask16)-1); }) | |
| 7001 | (__m512i)__builtin_shufflevector((__v8di)(__m512i)(A), \ | |
| 7002 | (__v8di)(__m512i)(B), \ | |
| 7003 | 0 + ((((imm) >> 0) & 0x3) * 2), \ | |
| 7004 | 1 + ((((imm) >> 0) & 0x3) * 2), \ | |
| 7005 | 0 + ((((imm) >> 2) & 0x3) * 2), \ | |
| 7006 | 1 + ((((imm) >> 2) & 0x3) * 2), \ | |
| 7007 | 8 + ((((imm) >> 4) & 0x3) * 2), \ | |
| 7008 | 9 + ((((imm) >> 4) & 0x3) * 2), \ | |
| 7009 | 8 + ((((imm) >> 6) & 0x3) * 2), \ | |
| 7010 | 9 + ((((imm) >> 6) & 0x3) * 2)); }) | |
| 7237 | 7011 | |
| 7238 | 7012 | #define _mm512_mask_shuffle_i32x4(W, U, A, B, imm) __extension__ ({ \ |
| 7239 | (__m512i)__builtin_ia32_shuf_i32x4_mask((__v16si)(__m512i)(A), \ | |
| 7240 | (__v16si)(__m512i)(B), (int)(imm), \ | |
| 7241 | (__v16si)(__m512i)(W), \ | |
| 7242 | (__mmask16)(U)); }) | |
| 7013 | (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ | |
| 7014 | (__v16si)_mm512_shuffle_i32x4((A), (B), (imm)), \ | |
| 7015 | (__v16si)(__m512i)(W)); }) | |
| 7243 | 7016 | |
| 7244 | 7017 | #define _mm512_maskz_shuffle_i32x4(U, A, B, imm) __extension__ ({ \ |
| 7245 | (__m512i)__builtin_ia32_shuf_i32x4_mask((__v16si)(__m512i)(A), \ | |
| 7246 | (__v16si)(__m512i)(B), (int)(imm), \ | |
| 7247 | (__v16si)_mm512_setzero_si512(), \ | |
| 7248 | (__mmask16)(U)); }) | |
| 7018 | (__m512i)__builtin_ia32_selectd_512((__mmask16)(U), \ | |
| 7019 | (__v16si)_mm512_shuffle_i32x4((A), (B), (imm)), \ | |
| 7020 | (__v16si)_mm512_setzero_si512()); }) | |
| 7249 | 7021 | |
| 7250 | 7022 | #define _mm512_shuffle_i64x2(A, B, imm) __extension__ ({ \ |
| 7251 | (__m512i)__builtin_ia32_shuf_i64x2_mask((__v8di)(__m512i)(A), \ | |
| 7252 | (__v8di)(__m512i)(B), (int)(imm), \ | |
| 7253 | (__v8di)_mm512_setzero_si512(), \ | |
| 7254 | (__mmask8)-1); }) | |
| 7023 | (__m512i)__builtin_shufflevector((__v8di)(__m512i)(A), \ | |
| 7024 | (__v8di)(__m512i)(B), \ | |
| 7025 | 0 + ((((imm) >> 0) & 0x3) * 2), \ | |
| 7026 | 1 + ((((imm) >> 0) & 0x3) * 2), \ | |
| 7027 | 0 + ((((imm) >> 2) & 0x3) * 2), \ | |
| 7028 | 1 + ((((imm) >> 2) & 0x3) * 2), \ | |
| 7029 | 8 + ((((imm) >> 4) & 0x3) * 2), \ | |
| 7030 | 9 + ((((imm) >> 4) & 0x3) * 2), \ | |
| 7031 | 8 + ((((imm) >> 6) & 0x3) * 2), \ | |
| 7032 | 9 + ((((imm) >> 6) & 0x3) * 2)); }) | |
| 7255 | 7033 | |
| 7256 | 7034 | #define _mm512_mask_shuffle_i64x2(W, U, A, B, imm) __extension__ ({ \ |
| 7257 | (__m512i)__builtin_ia32_shuf_i64x2_mask((__v8di)(__m512i)(A), \ | |
| 7258 | (__v8di)(__m512i)(B), (int)(imm), \ | |
| 7259 | (__v8di)(__m512i)(W), \ | |
| 7260 | (__mmask8)(U)); }) | |
| 7035 | (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ | |
| 7036 | (__v8di)_mm512_shuffle_i64x2((A), (B), (imm)), \ | |
| 7037 | (__v8di)(__m512i)(W)); }) | |
| 7261 | 7038 | |
| 7262 | 7039 | #define _mm512_maskz_shuffle_i64x2(U, A, B, imm) __extension__ ({ \ |
| 7263 | (__m512i)__builtin_ia32_shuf_i64x2_mask((__v8di)(__m512i)(A), \ | |
| 7264 | (__v8di)(__m512i)(B), (int)(imm), \ | |
| 7265 | (__v8di)_mm512_setzero_si512(), \ | |
| 7266 | (__mmask8)(U)); }) | |
| 7040 | (__m512i)__builtin_ia32_selectq_512((__mmask8)(U), \ | |
| 7041 | (__v8di)_mm512_shuffle_i64x2((A), (B), (imm)), \ | |
| 7042 | (__v8di)_mm512_setzero_si512()); }) | |
| 7267 | 7043 | |
| 7268 | 7044 | #define _mm512_shuffle_pd(A, B, M) __extension__ ({ \ |
| 7269 | 7045 | (__m512d)__builtin_shufflevector((__v8df)(__m512d)(A), \ |
| ... | ... | @@ -9166,6 +8942,64 @@ _mm512_maskz_compress_epi32 (__mmask16 __U, __m512i __A) |
| 9166 | 8942 | (__mmask8)(M), \ |
| 9167 | 8943 | _MM_FROUND_CUR_DIRECTION); }) |
| 9168 | 8944 | |
| 8945 | /* Bit Test */ | |
| 8946 | ||
| 8947 | static __inline __mmask16 __DEFAULT_FN_ATTRS | |
| 8948 | _mm512_test_epi32_mask (__m512i __A, __m512i __B) | |
| 8949 | { | |
| 8950 | return _mm512_cmpneq_epi32_mask (_mm512_and_epi32(__A, __B), | |
| 8951 | _mm512_setzero_epi32()); | |
| 8952 | } | |
| 8953 | ||
| 8954 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 8955 | _mm512_mask_test_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B) | |
| 8956 | { | |
| 8957 | return _mm512_mask_cmpneq_epi32_mask (__U, _mm512_and_epi32 (__A, __B), | |
| 8958 | _mm512_setzero_epi32()); | |
| 8959 | } | |
| 8960 | ||
| 8961 | static __inline __mmask8 __DEFAULT_FN_ATTRS | |
| 8962 | _mm512_test_epi64_mask (__m512i __A, __m512i __B) | |
| 8963 | { | |
| 8964 | return _mm512_cmpneq_epi64_mask (_mm512_and_epi32 (__A, __B), | |
| 8965 | _mm512_setzero_epi32()); | |
| 8966 | } | |
| 8967 | ||
| 8968 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 8969 | _mm512_mask_test_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B) | |
| 8970 | { | |
| 8971 | return _mm512_mask_cmpneq_epi64_mask (__U, _mm512_and_epi32 (__A, __B), | |
| 8972 | _mm512_setzero_epi32()); | |
| 8973 | } | |
| 8974 | ||
| 8975 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 8976 | _mm512_testn_epi32_mask (__m512i __A, __m512i __B) | |
| 8977 | { | |
| 8978 | return _mm512_cmpeq_epi32_mask (_mm512_and_epi32 (__A, __B), | |
| 8979 | _mm512_setzero_epi32()); | |
| 8980 | } | |
| 8981 | ||
| 8982 | static __inline__ __mmask16 __DEFAULT_FN_ATTRS | |
| 8983 | _mm512_mask_testn_epi32_mask (__mmask16 __U, __m512i __A, __m512i __B) | |
| 8984 | { | |
| 8985 | return _mm512_mask_cmpeq_epi32_mask (__U, _mm512_and_epi32 (__A, __B), | |
| 8986 | _mm512_setzero_epi32()); | |
| 8987 | } | |
| 8988 | ||
| 8989 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 8990 | _mm512_testn_epi64_mask (__m512i __A, __m512i __B) | |
| 8991 | { | |
| 8992 | return _mm512_cmpeq_epi64_mask (_mm512_and_epi32 (__A, __B), | |
| 8993 | _mm512_setzero_epi32()); | |
| 8994 | } | |
| 8995 | ||
| 8996 | static __inline__ __mmask8 __DEFAULT_FN_ATTRS | |
| 8997 | _mm512_mask_testn_epi64_mask (__mmask8 __U, __m512i __A, __m512i __B) | |
| 8998 | { | |
| 8999 | return _mm512_mask_cmpeq_epi64_mask (__U, _mm512_and_epi32 (__A, __B), | |
| 9000 | _mm512_setzero_epi32()); | |
| 9001 | } | |
| 9002 | ||
| 9169 | 9003 | static __inline__ __m512 __DEFAULT_FN_ATTRS |
| 9170 | 9004 | _mm512_movehdup_ps (__m512 __A) |
| 9171 | 9005 | { |
deps/lld-prebuilt/lld/Config/Version.inc+2-2| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | #define LLD_VERSION 5.0.0 | |
| 2 | #define LLD_VERSION_STRING "5.0.0" | |
| 1 | #define LLD_VERSION 5.0.1 | |
| 2 | #define LLD_VERSION_STRING "5.0.1" | |
| 3 | 3 | #define LLD_VERSION_MAJOR 5 |
| 4 | 4 | #define LLD_VERSION_MINOR 0 |
| 5 | 5 | #define LLD_REVISION_STRING "" |
deps/lld/COFF/Config.h+1| ... | ... | @@ -157,6 +157,7 @@ struct Configuration { |
| 157 | 157 | uint32_t MinorImageVersion = 0; |
| 158 | 158 | uint32_t MajorOSVersion = 6; |
| 159 | 159 | uint32_t MinorOSVersion = 0; |
| 160 | bool CanExitEarly = false; | |
| 160 | 161 | bool DynamicBase = true; |
| 161 | 162 | bool NxCompat = true; |
| 162 | 163 | bool AllowIsolation = true; |
deps/lld/COFF/Driver.cpp+8-2| ... | ... | @@ -52,15 +52,21 @@ BumpPtrAllocator BAlloc; |
| 52 | 52 | StringSaver Saver{BAlloc}; |
| 53 | 53 | std::vector<SpecificAllocBase *> SpecificAllocBase::Instances; |
| 54 | 54 | |
| 55 | bool link(ArrayRef<const char *> Args, raw_ostream &Diag) { | |
| 55 | bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) { | |
| 56 | 56 | ErrorCount = 0; |
| 57 | 57 | ErrorOS = &Diag; |
| 58 | 58 | Config = make<Configuration>(); |
| 59 | 59 | Config->Argv = {Args.begin(), Args.end()}; |
| 60 | 60 | Config->ColorDiagnostics = |
| 61 | 61 | (ErrorOS == &llvm::errs() && Process::StandardErrHasColors()); |
| 62 | Config->CanExitEarly = CanExitEarly; | |
| 62 | 63 | Driver = make<LinkerDriver>(); |
| 63 | 64 | Driver->link(Args); |
| 65 | ||
| 66 | // Call exit() if we can to avoid calling destructors. | |
| 67 | if (CanExitEarly) | |
| 68 | exitLld(ErrorCount ? 1 : 0); | |
| 69 | ||
| 64 | 70 | freeArena(); |
| 65 | 71 | return !ErrorCount; |
| 66 | 72 | } |
| ... | ... | @@ -1123,7 +1129,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { |
| 1123 | 1129 | // This is useful because MSVC link.exe can generate complete PDBs. |
| 1124 | 1130 | if (Args.hasArg(OPT_msvclto)) { |
| 1125 | 1131 | invokeMSVC(Args); |
| 1126 | exit(0); | |
| 1132 | return; | |
| 1127 | 1133 | } |
| 1128 | 1134 | |
| 1129 | 1135 | // Do LTO by compiling bitcode input files to a set of native COFF files then |
deps/lld/COFF/Error.cpp+3-2| ... | ... | @@ -32,7 +32,7 @@ namespace coff { |
| 32 | 32 | uint64_t ErrorCount; |
| 33 | 33 | raw_ostream *ErrorOS; |
| 34 | 34 | |
| 35 | static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) { | |
| 35 | LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) { | |
| 36 | 36 | // Dealloc/destroy ManagedStatic variables before calling |
| 37 | 37 | // _exit(). In a non-LTO build, this is a nop. In an LTO |
| 38 | 38 | // build allows us to get the output of -time-passes. |
| ... | ... | @@ -78,7 +78,8 @@ void error(const Twine &Msg) { |
| 78 | 78 | print("error: ", raw_ostream::RED); |
| 79 | 79 | *ErrorOS << "too many errors emitted, stopping now" |
| 80 | 80 | << " (use /ERRORLIMIT:0 to see all errors)\n"; |
| 81 | exitLld(1); | |
| 81 | if (Config->CanExitEarly) | |
| 82 | exitLld(1); | |
| 82 | 83 | } |
| 83 | 84 | |
| 84 | 85 | ++ErrorCount; |
deps/lld/COFF/Error.h+2| ... | ... | @@ -27,6 +27,8 @@ LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); |
| 27 | 27 | LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix); |
| 28 | 28 | LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix); |
| 29 | 29 | |
| 30 | LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); | |
| 31 | ||
| 30 | 32 | template <class T> T check(ErrorOr<T> V, const Twine &Prefix) { |
| 31 | 33 | if (auto EC = V.getError()) |
| 32 | 34 | fatal(EC, Prefix); |
deps/lld/ELF/SyntheticSections.cpp+9-3| ... | ... | @@ -427,10 +427,11 @@ CieRecord *EhFrameSection<ELFT>::addCie(EhSectionPiece &Piece, |
| 427 | 427 | &Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]); |
| 428 | 428 | |
| 429 | 429 | // Search for an existing CIE by CIE contents/relocation target pair. |
| 430 | CieRecord *Cie = &CieMap[{Piece.data(), Personality}]; | |
| 430 | CieRecord *&Cie = CieMap[{Piece.data(), Personality}]; | |
| 431 | 431 | |
| 432 | 432 | // If not found, create a new one. |
| 433 | if (Cie->Piece == nullptr) { | |
| 433 | if (!Cie) { | |
| 434 | Cie = make<CieRecord>(); | |
| 434 | 435 | Cie->Piece = &Piece; |
| 435 | 436 | Cies.push_back(Cie); |
| 436 | 437 | } |
| ... | ... | @@ -522,9 +523,14 @@ template <class ELFT> |
| 522 | 523 | static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) { |
| 523 | 524 | memcpy(Buf, D.data(), D.size()); |
| 524 | 525 | |
| 526 | size_t Aligned = alignTo(D.size(), sizeof(typename ELFT::uint)); | |
| 527 | ||
| 528 | // Zero-clear trailing padding if it exists. | |
| 529 | memset(Buf + D.size(), 0, Aligned - D.size()); | |
| 530 | ||
| 525 | 531 | // Fix the size field. -4 since size does not include the size field itself. |
| 526 | 532 | const endianness E = ELFT::TargetEndianness; |
| 527 | write32<E>(Buf, alignTo(D.size(), sizeof(typename ELFT::uint)) - 4); | |
| 533 | write32<E>(Buf, Aligned - 4); | |
| 528 | 534 | } |
| 529 | 535 | |
| 530 | 536 | template <class ELFT> void EhFrameSection<ELFT>::finalizeContents() { |
deps/lld/ELF/SyntheticSections.h+2-1| ... | ... | @@ -103,7 +103,8 @@ private: |
| 103 | 103 | std::vector<CieRecord *> Cies; |
| 104 | 104 | |
| 105 | 105 | // CIE records are uniquified by their contents and personality functions. |
| 106 | llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord> CieMap; | |
| 106 | llvm::DenseMap<std::pair<ArrayRef<uint8_t>, SymbolBody *>, CieRecord *> | |
| 107 | CieMap; | |
| 107 | 108 | }; |
| 108 | 109 | |
| 109 | 110 | class GotSection : public SyntheticSection { |
deps/lld/include/lld/Driver/Driver.h+1-1| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | |
| 16 | 16 | namespace lld { |
| 17 | 17 | namespace coff { |
| 18 | bool link(llvm::ArrayRef<const char *> Args, | |
| 18 | bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly, | |
| 19 | 19 | llvm::raw_ostream &Diag = llvm::errs()); |
| 20 | 20 | } |
| 21 | 21 |
deps/lld/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp-1| ... | ... | @@ -621,7 +621,6 @@ void ArchHandler_x86_64::applyFixupFinal( |
| 621 | 621 | // Fall into llvm_unreachable(). |
| 622 | 622 | break; |
| 623 | 623 | } |
| 624 | return; | |
| 625 | 624 | } |
| 626 | 625 | |
| 627 | 626 | void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref, |
deps/lld/test/ELF/eh-frame-padding-no-rosegment.s created+64| ... | ... | @@ -0,0 +1,64 @@ |
| 1 | // REQUIRES: x86 | |
| 2 | ||
| 3 | .cfi_startproc | |
| 4 | .cfi_personality 0x1b, bar | |
| 5 | .cfi_endproc | |
| 6 | ||
| 7 | .global bar | |
| 8 | .hidden bar | |
| 9 | bar: | |
| 10 | ||
| 11 | // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o | |
| 12 | ||
| 13 | // Check the size of the CIE (0x18 + 4) and FDE (0x10 + 4) | |
| 14 | // RUN: llvm-readobj -s -section-data %t.o | FileCheck --check-prefix=OBJ %s | |
| 15 | ||
| 16 | // OBJ: Name: .eh_frame | |
| 17 | // OBJ-NEXT: Type: | |
| 18 | // OBJ-NEXT: Flags [ | |
| 19 | // OBJ-NEXT: SHF_ALLOC | |
| 20 | // OBJ-NEXT: ] | |
| 21 | // OBJ-NEXT: Address: | |
| 22 | // OBJ-NEXT: Offset: | |
| 23 | // OBJ-NEXT: Size: | |
| 24 | // OBJ-NEXT: Link: | |
| 25 | // OBJ-NEXT: Info: | |
| 26 | // OBJ-NEXT: AddressAlignment: | |
| 27 | // OBJ-NEXT: EntrySize: | |
| 28 | // OBJ-NEXT: SectionData ( | |
| 29 | // OBJ-NEXT: 0000: 18000000 00000000 017A5052 00017810 | |
| 30 | // OBJ-NEXT: 0010: 061B0000 00001B0C 07089001 10000000 | |
| 31 | // OBJ-NEXT: 0020: 20000000 00000000 00000000 00000000 | |
| 32 | // OBJ-NEXT: ) | |
| 33 | ||
| 34 | // RUN: ld.lld %t.o -no-rosegment -o %t -shared | |
| 35 | ||
| 36 | // Check that .eh_frame is in the same segment as .text | |
| 37 | // RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=PHDR %s | |
| 38 | ||
| 39 | // PHDR: Segment Sections | |
| 40 | // PHDR: .text | |
| 41 | // PHDR-SAME: .eh_frame | |
| 42 | ||
| 43 | // Check that the CIE and FDE are padded with 0x00 and not 0xCC when the | |
| 44 | // .eh_frame section is placed in the executable segment | |
| 45 | // RUN: llvm-readobj -s -section-data %t | FileCheck %s | |
| 46 | ||
| 47 | // CHECK: Name: .eh_frame | |
| 48 | // CHECK-NEXT: Type: | |
| 49 | // CHECK-NEXT: Flags | |
| 50 | // CHECK-NEXT: SHF_ALLOC | |
| 51 | // CHECK-NEXT: ] | |
| 52 | // CHECK-NEXT: Address: | |
| 53 | // CHECK-NEXT: Offset: | |
| 54 | // CHECK-NEXT: Size: | |
| 55 | // CHECK-NEXT: Link: | |
| 56 | // CHECK-NEXT: Info: | |
| 57 | // CHECK-NEXT: AddressAlignment: | |
| 58 | // CHECK-NEXT: EntrySize: | |
| 59 | // CHECK-NEXT: SectionData ( | |
| 60 | // CHECK-NEXT: 0000: 1C000000 00000000 017A5052 00017810 | |
| 61 | // CHECK-NEXT: 0010: 061BBEFF FFFF1B0C 07089001 00000000 | |
| 62 | // CHECK-NEXT: 0020: 14000000 24000000 A8FFFFFF 00000000 | |
| 63 | // CHECK-NEXT: 0030: 00000000 00000000 | |
| 64 | // CHECK-NEXT: ) |
deps/lld/tools/lld/lld.cpp+1-1| ... | ... | @@ -103,7 +103,7 @@ int main(int Argc, const char **Argv) { |
| 103 | 103 | case Gnu: |
| 104 | 104 | return !elf::link(Args, true); |
| 105 | 105 | case WinLink: |
| 106 | return !coff::link(Args); | |
| 106 | return !coff::link(Args, true); | |
| 107 | 107 | case Darwin: |
| 108 | 108 | return !mach_o::link(Args); |
| 109 | 109 | default: |
doc/langref.html.in+177-53| ... | ... | @@ -136,7 +136,8 @@ |
| 136 | 136 | <li><a href="#builtin-divFloor">@divFloor</a></li> |
| 137 | 137 | <li><a href="#builtin-divTrunc">@divTrunc</a></li> |
| 138 | 138 | <li><a href="#builtin-embedFile">@embedFile</a></li> |
| 139 | <li><a href="#builtin-enumTagName">@enumTagName</a></li> | |
| 139 | <li><a href="#builtin-tagName">@tagName</a></li> | |
| 140 | <li><a href="#builtin-EnumTagType">@EnumTagType</a></li> | |
| 140 | 141 | <li><a href="#builtin-errorName">@errorName</a></li> |
| 141 | 142 | <li><a href="#builtin-fence">@fence</a></li> |
| 142 | 143 | <li><a href="#builtin-fieldParentPtr">@fieldParentPtr</a></li> |
| ... | ... | @@ -2095,30 +2096,38 @@ const Type = enum { |
| 2095 | 2096 | NotOk, |
| 2096 | 2097 | }; |
| 2097 | 2098 | |
| 2098 | // Enums are sum types, and can hold more complex data of different types. | |
| 2099 | const ComplexType = enum { | |
| 2100 | Ok: u8, | |
| 2101 | NotOk: void, | |
| 2102 | }; | |
| 2103 | ||
| 2104 | 2099 | // Declare a specific instance of the enum variant. |
| 2105 | const c = ComplexType.Ok { 0 }; | |
| 2100 | const c = Type.Ok; | |
| 2106 | 2101 | |
| 2107 | // The ordinal value of a simple enum with no data members can be | |
| 2108 | // retrieved by a simple cast. | |
| 2109 | // The value starts from 0, counting up for each member. | |
| 2110 | const Value = enum { | |
| 2102 | // If you want access to the ordinal value of an enum, you | |
| 2103 | // can specify the tag type. | |
| 2104 | const Value = enum(u2) { | |
| 2111 | 2105 | Zero, |
| 2112 | 2106 | One, |
| 2113 | 2107 | Two, |
| 2114 | 2108 | }; |
| 2109 | ||
| 2110 | // Now you can cast between u2 and Value. | |
| 2111 | // The ordinal value starts from 0, counting up for each member. | |
| 2115 | 2112 | test "enum ordinal value" { |
| 2116 | assert(usize(Value.Zero) == 0); | |
| 2117 | assert(usize(Value.One) == 1); | |
| 2118 | assert(usize(Value.Two) == 2); | |
| 2113 | assert(u2(Value.Zero) == 0); | |
| 2114 | assert(u2(Value.One) == 1); | |
| 2115 | assert(u2(Value.Two) == 2); | |
| 2116 | } | |
| 2117 | ||
| 2118 | // You can override the ordinal value for an enum. | |
| 2119 | const Value2 = enum(u32) { | |
| 2120 | Hundred = 100, | |
| 2121 | Thousand = 1000, | |
| 2122 | Million = 1000000, | |
| 2123 | }; | |
| 2124 | test "set enum ordinal value" { | |
| 2125 | assert(u32(Value2.Hundred) == 100); | |
| 2126 | assert(u32(Value2.Thousand) == 1000); | |
| 2127 | assert(u32(Value2.Million) == 1000000); | |
| 2119 | 2128 | } |
| 2120 | 2129 | |
| 2121 | // Enums can have methods, the same as structs. | |
| 2130 | // Enums can have methods, the same as structs and unions. | |
| 2122 | 2131 | // Enum methods are not special, they are only namespaced |
| 2123 | 2132 | // functions that you can call with dot syntax. |
| 2124 | 2133 | const Suit = enum { |
| ... | ... | @@ -2127,26 +2136,120 @@ const Suit = enum { |
| 2127 | 2136 | Diamonds, |
| 2128 | 2137 | Hearts, |
| 2129 | 2138 | |
| 2130 | pub fn ordinal(self: &amp;const Suit) -&gt; u8 { | |
| 2131 | u8(*self) | |
| 2139 | pub fn isClubs(self: Suit) -&gt; bool { | |
| 2140 | return self == Suit.Clubs; | |
| 2132 | 2141 | } |
| 2133 | 2142 | }; |
| 2134 | 2143 | test "enum method" { |
| 2135 | 2144 | const p = Suit.Spades; |
| 2136 | assert(p.ordinal() == 1); | |
| 2145 | assert(!p.isClubs()); | |
| 2137 | 2146 | } |
| 2138 | 2147 | |
| 2139 | 2148 | // An enum variant of different types can be switched upon. |
| 2140 | // The associated data can be retrieved using `|...|` syntax. | |
| 2141 | // | |
| 2142 | // A void type is not required on a tag-only member. | |
| 2143 | 2149 | const Foo = enum { |
| 2150 | String, | |
| 2151 | Number, | |
| 2152 | None, | |
| 2153 | }; | |
| 2154 | test "enum variant switch" { | |
| 2155 | const p = Foo.Number; | |
| 2156 | const what_is_it = switch (p) { | |
| 2157 | Foo.String =&gt; "this is a string", | |
| 2158 | Foo.Number =&gt; "this is a number", | |
| 2159 | Foo.None =&gt; "this is a none", | |
| 2160 | }; | |
| 2161 | assert(mem.eql(u8, what_is_it, "this is a number")); | |
| 2162 | } | |
| 2163 | ||
| 2164 | // @TagType can be used to access the integer tag type of an enum. | |
| 2165 | const Small = enum { | |
| 2166 | One, | |
| 2167 | Two, | |
| 2168 | Three, | |
| 2169 | Four, | |
| 2170 | }; | |
| 2171 | test "@TagType" { | |
| 2172 | assert(@TagType(Small) == u2); | |
| 2173 | } | |
| 2174 | ||
| 2175 | // @memberCount tells how many fields an enum has: | |
| 2176 | test "@memberCount" { | |
| 2177 | assert(@memberCount(Small) == 4); | |
| 2178 | } | |
| 2179 | ||
| 2180 | // @memberName tells the name of a field in an enum: | |
| 2181 | test "@memberName" { | |
| 2182 | assert(mem.eql(u8, @memberName(Small, 1), "Two")); | |
| 2183 | } | |
| 2184 | ||
| 2185 | // @tagName gives a []const u8 representation of an enum value: | |
| 2186 | test "@tagName" { | |
| 2187 | assert(mem.eql(u8, @tagName(Small.Three), "Three")); | |
| 2188 | }</code></pre> | |
| 2189 | <p>TODO extern enum</p> | |
| 2190 | <p>TODO packed enum</p> | |
| 2191 | <pre><code class="sh">$ zig test enum.zig | |
| 2192 | Test 1/8 enum ordinal value...OK | |
| 2193 | Test 2/8 set enum ordinal value...OK | |
| 2194 | Test 3/8 enum method...OK | |
| 2195 | Test 4/8 enum variant switch...OK | |
| 2196 | Test 5/8 @TagType...OK | |
| 2197 | Test 6/8 @memberCount...OK | |
| 2198 | Test 7/8 @memberName...OK | |
| 2199 | Test 8/8 @tagName...OK</code></pre> | |
| 2200 | <p>See also:</p> | |
| 2201 | <ul> | |
| 2202 | <li><a href="#builtin-memberName">@memberName</a></li> | |
| 2203 | <li><a href="#builtin-memberCount">@memberCount</a></li> | |
| 2204 | <li><a href="#builtin-tagName">@tagName</a></li> | |
| 2205 | </ul> | |
| 2206 | <h2 id="union">union</h2> | |
| 2207 | <pre><code class="zig">const assert = @import("std").debug.assert; | |
| 2208 | const mem = @import("std").mem; | |
| 2209 | ||
| 2210 | // A union has only 1 active field at a time. | |
| 2211 | const Payload = union { | |
| 2212 | Int: i64, | |
| 2213 | Float: f64, | |
| 2214 | Bool: bool, | |
| 2215 | }; | |
| 2216 | test "simple union" { | |
| 2217 | var payload = Payload {.Int = 1234}; | |
| 2218 | // payload.Float = 12.34; // ERROR! field not active | |
| 2219 | assert(payload.Int == 1234); | |
| 2220 | // You can activate another field by assigning the entire union. | |
| 2221 | payload = Payload {.Float = 12.34}; | |
| 2222 | assert(payload.Float == 12.34); | |
| 2223 | } | |
| 2224 | ||
| 2225 | // Unions can be given an enum tag type: | |
| 2226 | const ComplexTypeTag = enum { Ok, NotOk }; | |
| 2227 | const ComplexType = union(ComplexTypeTag) { | |
| 2228 | Ok: u8, | |
| 2229 | NotOk: void, | |
| 2230 | }; | |
| 2231 | ||
| 2232 | // Declare a specific instance of the union variant. | |
| 2233 | test "declare union value" { | |
| 2234 | const c = ComplexType { .Ok = 0 }; | |
| 2235 | assert(ComplexTypeTag(c) == ComplexTypeTag.Ok); | |
| 2236 | } | |
| 2237 | ||
| 2238 | // @TagType can be used to access the enum tag type of a union. | |
| 2239 | test "@TagType" { | |
| 2240 | assert(@TagType(ComplexType) == ComplexTypeTag); | |
| 2241 | } | |
| 2242 | ||
| 2243 | // Unions can be made to infer the enum tag type. | |
| 2244 | const Foo = union(enum) { | |
| 2144 | 2245 | String: []const u8, |
| 2145 | 2246 | Number: u64, |
| 2247 | ||
| 2248 | // void can be omitted when inferring enum tag type. | |
| 2146 | 2249 | None, |
| 2147 | 2250 | }; |
| 2148 | test "enum variant switch" { | |
| 2149 | const p = Foo.Number { 54 }; | |
| 2251 | test "union variant switch" { | |
| 2252 | const p = Foo { .Number = 54 }; | |
| 2150 | 2253 | const what_is_it = switch (p) { |
| 2151 | 2254 | // Capture by reference |
| 2152 | 2255 | Foo.String =&gt; |*x| { |
| ... | ... | @@ -2155,6 +2258,7 @@ test "enum variant switch" { |
| 2155 | 2258 | |
| 2156 | 2259 | // Capture by value |
| 2157 | 2260 | Foo.Number =&gt; |x| { |
| 2261 | assert(x == 54); | |
| 2158 | 2262 | "this is a number" |
| 2159 | 2263 | }, |
| 2160 | 2264 | |
| ... | ... | @@ -2162,37 +2266,50 @@ test "enum variant switch" { |
| 2162 | 2266 | "this is a none" |
| 2163 | 2267 | } |
| 2164 | 2268 | }; |
| 2269 | assert(mem.eql(u8, what_is_it, "this is a number")); | |
| 2165 | 2270 | } |
| 2166 | 2271 | |
| 2167 | // The @enumTagName and @memberCount builtin functions can be used to | |
| 2168 | // the string representation and number of members respectively. | |
| 2169 | const BuiltinType = enum { | |
| 2170 | A: f32, | |
| 2171 | B: u32, | |
| 2172 | C, | |
| 2272 | // TODO union methods | |
| 2273 | ||
| 2274 | ||
| 2275 | const Small = union { | |
| 2276 | A: i32, | |
| 2277 | B: bool, | |
| 2278 | C: u8, | |
| 2173 | 2279 | }; |
| 2174 | 2280 | |
| 2175 | test "enum builtins" { | |
| 2176 | assert(mem.eql(u8, @enumTagName(BuiltinType.A { 0 }), "A")); | |
| 2177 | assert(mem.eql(u8, @enumTagName(BuiltinType.C), "C")); | |
| 2178 | assert(@memberCount(BuiltinType) == 3); | |
| 2281 | // @memberCount tells how many fields a union has: | |
| 2282 | test "@memberCount" { | |
| 2283 | assert(@memberCount(Small) == 3); | |
| 2284 | } | |
| 2285 | ||
| 2286 | // @memberName tells the name of a field in an enum: | |
| 2287 | test "@memberName" { | |
| 2288 | assert(mem.eql(u8, @memberName(Small, 1), "B")); | |
| 2289 | } | |
| 2290 | ||
| 2291 | // @tagName gives a []const u8 representation of an enum value, | |
| 2292 | // but only if the union has an enum tag type. | |
| 2293 | const Small2 = union(enum) { | |
| 2294 | A: i32, | |
| 2295 | B: bool, | |
| 2296 | C: u8, | |
| 2297 | }; | |
| 2298 | test "@tagName" { | |
| 2299 | assert(mem.eql(u8, @tagName(Small2.C), "C")); | |
| 2179 | 2300 | }</code></pre> |
| 2180 | <pre><code class="sh">$ zig test enum.zig | |
| 2181 | Test 1/4 enum ordinal value...OK | |
| 2182 | Test 2/4 enum method...OK | |
| 2183 | Test 3/4 enum variant switch...OK | |
| 2184 | Test 4/4 enum builtins...OK</code></pre> | |
| 2185 | <p> | |
| 2186 | Enums are generated as a struct with a tag field and union field. Zig | |
| 2301 | <pre><code class="sh">$ zig test union.zig | |
| 2302 | Test 1/7 simple union...OK | |
| 2303 | Test 2/7 declare union value...OK | |
| 2304 | Test 3/7 @TagType...OK | |
| 2305 | Test 4/7 union variant switch...OK | |
| 2306 | Test 5/7 @memberCount...OK | |
| 2307 | Test 6/7 @memberName...OK | |
| 2308 | Test 7/7 @tagName...OK</code></pre> | |
| 2309 | <p> | |
| 2310 | Unions with an enum tag are generated as a struct with a tag field and union field. Zig | |
| 2187 | 2311 | sorts the order of the tag and union field by the largest alignment. |
| 2188 | 2312 | </p> |
| 2189 | <p>See also:</p> | |
| 2190 | <ul> | |
| 2191 | <li><a href="#builtin-enumTagName">@enumTagName</a></li> | |
| 2192 | <li><a href="#builtin-memberCount">@memberCount</a></li> | |
| 2193 | </ul> | |
| 2194 | <h2 id="union">union</h2> | |
| 2195 | <p>TODO union documentation</p> | |
| 2196 | 2313 | <h2 id="switch">switch</h2> |
| 2197 | 2314 | <pre><code class="zig">const assert = @import("std").debug.assert; |
| 2198 | 2315 | const builtin = @import("builtin"); |
| ... | ... | @@ -4251,10 +4368,15 @@ test.zig:6:2: error: found compile log statement |
| 4251 | 4368 | <ul> |
| 4252 | 4369 | <li><a href="#builtin-import">@import</a></li> |
| 4253 | 4370 | </ul> |
| 4254 | <h3 id="builtin-enumTagName">@enumTagName</h3> | |
| 4255 | <pre><code class="zig">@enumTagName(value: var) -&gt; []const u8</code></pre> | |
| 4371 | <h3 id="builtin-tagName">@tagName</h3> | |
| 4372 | <pre><code class="zig">@tagName(value: var) -&gt; []const u8</code></pre> | |
| 4373 | <p> | |
| 4374 | Converts an enum value or union value to a slice of bytes representing the name. | |
| 4375 | </p> | |
| 4376 | <h3 id="builtin-EnumTagType">@EnumTagType</h3> | |
| 4377 | <pre><code class="zig">@EnumTagType(T: type) -&gt; type</code></pre> | |
| 4256 | 4378 | <p> |
| 4257 | Converts an enum tag name to a slice of bytes. | |
| 4379 | Returns the integer type that is used to store the enumeration value. | |
| 4258 | 4380 | </p> |
| 4259 | 4381 | <h3 id="builtin-errorName">@errorName</h3> |
| 4260 | 4382 | <pre><code class="zig">@errorName(err: error) -&gt; []u8</code></pre> |
| ... | ... | @@ -5703,7 +5825,7 @@ VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" Typ |
| 5703 | 5825 | |
| 5704 | 5826 | ContainerMember = (ContainerField | FnDef | GlobalVarDecl) |
| 5705 | 5827 | |
| 5706 | ContainerField = Symbol option(":" Expression) "," | |
| 5828 | ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression "," | |
| 5707 | 5829 | |
| 5708 | 5830 | UseDecl = "use" Expression ";" |
| 5709 | 5831 | |
| ... | ... | @@ -5837,7 +5959,9 @@ GroupedExpression = "(" Expression ")" |
| 5837 | 5959 | |
| 5838 | 5960 | KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable" |
| 5839 | 5961 | |
| 5840 | ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}"</code></pre> | |
| 5962 | ContainerDecl = option("extern" | "packed") | |
| 5963 | ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression))) | |
| 5964 | "{" many(ContainerMember) "}"</code></pre> | |
| 5841 | 5965 | <h2 id="zen">Zen</h2> |
| 5842 | 5966 | <ul> |
| 5843 | 5967 | <li>Communicate intent precisely.</li> |
example/guess_number/main.zig+2-1| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | const builtin = @import("builtin"); | |
| 1 | 2 | const std = @import("std"); |
| 2 | 3 | const io = std.io; |
| 3 | 4 | const fmt = std.fmt; |
| ... | ... | @@ -15,7 +16,7 @@ pub fn main() -> %void { |
| 15 | 16 | |
| 16 | 17 | var seed_bytes: [@sizeOf(usize)]u8 = undefined; |
| 17 | 18 | %%os.getRandomBytes(seed_bytes[0..]); |
| 18 | const seed = std.mem.readInt(seed_bytes, usize, true); | |
| 19 | const seed = std.mem.readInt(seed_bytes, usize, builtin.Endian.Big); | |
| 19 | 20 | var rand = Rand.init(seed); |
| 20 | 21 | |
| 21 | 22 | const answer = rand.range(u8, 0, 100) + 1; |
src/all_types.hpp+23-54| ... | ... | @@ -97,18 +97,13 @@ struct ConstParent { |
| 97 | 97 | } data; |
| 98 | 98 | }; |
| 99 | 99 | |
| 100 | struct ConstEnumValue { | |
| 101 | uint64_t tag; | |
| 102 | ConstExprValue *payload; | |
| 103 | }; | |
| 104 | ||
| 105 | 100 | struct ConstStructValue { |
| 106 | 101 | ConstExprValue *fields; |
| 107 | 102 | ConstParent parent; |
| 108 | 103 | }; |
| 109 | 104 | |
| 110 | 105 | struct ConstUnionValue { |
| 111 | uint64_t tag; | |
| 106 | BigInt tag; | |
| 112 | 107 | ConstExprValue *payload; |
| 113 | 108 | ConstParent parent; |
| 114 | 109 | }; |
| ... | ... | @@ -249,7 +244,7 @@ struct ConstExprValue { |
| 249 | 244 | ConstExprValue *x_maybe; |
| 250 | 245 | ConstErrValue x_err_union; |
| 251 | 246 | ErrorTableEntry *x_pure_err; |
| 252 | ConstEnumValue x_enum; | |
| 247 | BigInt x_enum_tag; | |
| 253 | 248 | ConstStructValue x_struct; |
| 254 | 249 | ConstUnionValue x_union; |
| 255 | 250 | ConstArrayValue x_array; |
| ... | ... | @@ -345,15 +340,14 @@ struct TldCompTime { |
| 345 | 340 | |
| 346 | 341 | struct TypeEnumField { |
| 347 | 342 | Buf *name; |
| 348 | TypeTableEntry *type_entry; | |
| 349 | uint32_t value; | |
| 350 | uint32_t gen_index; | |
| 343 | BigInt value; | |
| 344 | uint32_t decl_index; | |
| 351 | 345 | }; |
| 352 | 346 | |
| 353 | 347 | struct TypeUnionField { |
| 354 | 348 | Buf *name; |
| 349 | TypeEnumField *enum_field; | |
| 355 | 350 | TypeTableEntry *type_entry; |
| 356 | uint32_t value; | |
| 357 | 351 | uint32_t gen_index; |
| 358 | 352 | }; |
| 359 | 353 | |
| ... | ... | @@ -773,13 +767,15 @@ struct AstNodeContainerDecl { |
| 773 | 767 | ZigList<AstNode *> fields; |
| 774 | 768 | ZigList<AstNode *> decls; |
| 775 | 769 | ContainerLayout layout; |
| 776 | AstNode *init_arg_expr; // enum(T) or struct(endianness) | |
| 770 | AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T)) | |
| 771 | bool auto_enum; // union(enum) | |
| 777 | 772 | }; |
| 778 | 773 | |
| 779 | 774 | struct AstNodeStructField { |
| 780 | 775 | VisibMod visib_mod; |
| 781 | 776 | Buf *name; |
| 782 | 777 | AstNode *type; |
| 778 | AstNode *value; | |
| 783 | 779 | }; |
| 784 | 780 | |
| 785 | 781 | struct AstNodeStringLiteral { |
| ... | ... | @@ -1009,12 +1005,9 @@ struct TypeTableEntryEnum { |
| 1009 | 1005 | AstNode *decl_node; |
| 1010 | 1006 | ContainerLayout layout; |
| 1011 | 1007 | uint32_t src_field_count; |
| 1012 | // number of fields in the union. 0 if enum with no payload | |
| 1013 | uint32_t gen_field_count; | |
| 1014 | 1008 | TypeEnumField *fields; |
| 1015 | 1009 | bool is_invalid; // true if any fields are invalid |
| 1016 | TypeTableEntry *tag_type; | |
| 1017 | LLVMTypeRef union_type_ref; | |
| 1010 | TypeTableEntry *tag_int_type; | |
| 1018 | 1011 | |
| 1019 | 1012 | ScopeDecls *decls_scope; |
| 1020 | 1013 | |
| ... | ... | @@ -1026,18 +1019,7 @@ struct TypeTableEntryEnum { |
| 1026 | 1019 | |
| 1027 | 1020 | bool zero_bits_loop_flag; |
| 1028 | 1021 | bool zero_bits_known; |
| 1029 | uint32_t abi_alignment; // also figured out with zero_bits pass | |
| 1030 | ||
| 1031 | size_t gen_union_index; | |
| 1032 | size_t gen_tag_index; | |
| 1033 | ||
| 1034 | uint32_t union_size_bytes; | |
| 1035 | TypeTableEntry *most_aligned_union_member; | |
| 1036 | }; | |
| 1037 | 1022 | |
| 1038 | struct TypeTableEntryEnumTag { | |
| 1039 | TypeTableEntry *enum_type; | |
| 1040 | TypeTableEntry *int_type; | |
| 1041 | 1023 | bool generate_name_table; |
| 1042 | 1024 | LLVMValueRef name_table; |
| 1043 | 1025 | }; |
| ... | ... | @@ -1052,7 +1034,7 @@ struct TypeTableEntryUnion { |
| 1052 | 1034 | uint32_t gen_field_count; |
| 1053 | 1035 | TypeUnionField *fields; |
| 1054 | 1036 | bool is_invalid; // true if any fields are invalid |
| 1055 | TypeTableEntry *tag_type; | |
| 1037 | TypeTableEntry *tag_type; // always an enum or null | |
| 1056 | 1038 | LLVMTypeRef union_type_ref; |
| 1057 | 1039 | |
| 1058 | 1040 | ScopeDecls *decls_scope; |
| ... | ... | @@ -1117,7 +1099,6 @@ enum TypeTableEntryId { |
| 1117 | 1099 | TypeTableEntryIdErrorUnion, |
| 1118 | 1100 | TypeTableEntryIdPureError, |
| 1119 | 1101 | TypeTableEntryIdEnum, |
| 1120 | TypeTableEntryIdEnumTag, | |
| 1121 | 1102 | TypeTableEntryIdUnion, |
| 1122 | 1103 | TypeTableEntryIdFn, |
| 1123 | 1104 | TypeTableEntryIdNamespace, |
| ... | ... | @@ -1146,7 +1127,6 @@ struct TypeTableEntry { |
| 1146 | 1127 | TypeTableEntryMaybe maybe; |
| 1147 | 1128 | TypeTableEntryError error; |
| 1148 | 1129 | TypeTableEntryEnum enumeration; |
| 1149 | TypeTableEntryEnumTag enum_tag; | |
| 1150 | 1130 | TypeTableEntryUnion unionation; |
| 1151 | 1131 | TypeTableEntryFn fn; |
| 1152 | 1132 | TypeTableEntryBoundFn bound_fn; |
| ... | ... | @@ -1285,7 +1265,8 @@ enum BuiltinFnId { |
| 1285 | 1265 | BuiltinFnIdBitCast, |
| 1286 | 1266 | BuiltinFnIdIntToPtr, |
| 1287 | 1267 | BuiltinFnIdPtrToInt, |
| 1288 | BuiltinFnIdEnumTagName, | |
| 1268 | BuiltinFnIdTagName, | |
| 1269 | BuiltinFnIdTagType, | |
| 1289 | 1270 | BuiltinFnIdFieldParentPtr, |
| 1290 | 1271 | BuiltinFnIdOffsetOf, |
| 1291 | 1272 | BuiltinFnIdInlineCall, |
| ... | ... | @@ -1829,7 +1810,6 @@ enum IrInstructionId { |
| 1829 | 1810 | IrInstructionIdStorePtr, |
| 1830 | 1811 | IrInstructionIdFieldPtr, |
| 1831 | 1812 | IrInstructionIdStructFieldPtr, |
| 1832 | IrInstructionIdEnumFieldPtr, | |
| 1833 | 1813 | IrInstructionIdUnionFieldPtr, |
| 1834 | 1814 | IrInstructionIdElemPtr, |
| 1835 | 1815 | IrInstructionIdVarPtr, |
| ... | ... | @@ -1854,7 +1834,7 @@ enum IrInstructionId { |
| 1854 | 1834 | IrInstructionIdTestNonNull, |
| 1855 | 1835 | IrInstructionIdUnwrapMaybe, |
| 1856 | 1836 | IrInstructionIdMaybeWrap, |
| 1857 | IrInstructionIdEnumTag, | |
| 1837 | IrInstructionIdUnionTag, | |
| 1858 | 1838 | IrInstructionIdClz, |
| 1859 | 1839 | IrInstructionIdCtz, |
| 1860 | 1840 | IrInstructionIdImport, |
| ... | ... | @@ -1893,7 +1873,6 @@ enum IrInstructionId { |
| 1893 | 1873 | IrInstructionIdErrWrapPayload, |
| 1894 | 1874 | IrInstructionIdFnProto, |
| 1895 | 1875 | IrInstructionIdTestComptime, |
| 1896 | IrInstructionIdInitEnum, | |
| 1897 | 1876 | IrInstructionIdPtrCast, |
| 1898 | 1877 | IrInstructionIdBitCast, |
| 1899 | 1878 | IrInstructionIdWidenOrShorten, |
| ... | ... | @@ -1910,7 +1889,8 @@ enum IrInstructionId { |
| 1910 | 1889 | IrInstructionIdSetGlobalLinkage, |
| 1911 | 1890 | IrInstructionIdDeclRef, |
| 1912 | 1891 | IrInstructionIdPanic, |
| 1913 | IrInstructionIdEnumTagName, | |
| 1892 | IrInstructionIdTagName, | |
| 1893 | IrInstructionIdTagType, | |
| 1914 | 1894 | IrInstructionIdFieldParentPtr, |
| 1915 | 1895 | IrInstructionIdOffsetOf, |
| 1916 | 1896 | IrInstructionIdTypeId, |
| ... | ... | @@ -2088,14 +2068,6 @@ struct IrInstructionStructFieldPtr { |
| 2088 | 2068 | bool is_const; |
| 2089 | 2069 | }; |
| 2090 | 2070 | |
| 2091 | struct IrInstructionEnumFieldPtr { | |
| 2092 | IrInstruction base; | |
| 2093 | ||
| 2094 | IrInstruction *enum_ptr; | |
| 2095 | TypeEnumField *field; | |
| 2096 | bool is_const; | |
| 2097 | }; | |
| 2098 | ||
| 2099 | 2071 | struct IrInstructionUnionFieldPtr { |
| 2100 | 2072 | IrInstruction base; |
| 2101 | 2073 | |
| ... | ... | @@ -2299,7 +2271,7 @@ struct IrInstructionClz { |
| 2299 | 2271 | IrInstruction *value; |
| 2300 | 2272 | }; |
| 2301 | 2273 | |
| 2302 | struct IrInstructionEnumTag { | |
| 2274 | struct IrInstructionUnionTag { | |
| 2303 | 2275 | IrInstruction base; |
| 2304 | 2276 | |
| 2305 | 2277 | IrInstruction *value; |
| ... | ... | @@ -2569,15 +2541,6 @@ struct IrInstructionTestComptime { |
| 2569 | 2541 | IrInstruction *value; |
| 2570 | 2542 | }; |
| 2571 | 2543 | |
| 2572 | struct IrInstructionInitEnum { | |
| 2573 | IrInstruction base; | |
| 2574 | ||
| 2575 | TypeTableEntry *enum_type; | |
| 2576 | TypeEnumField *field; | |
| 2577 | IrInstruction *init_value; | |
| 2578 | LLVMValueRef tmp_ptr; | |
| 2579 | }; | |
| 2580 | ||
| 2581 | 2544 | struct IrInstructionPtrCast { |
| 2582 | 2545 | IrInstruction base; |
| 2583 | 2546 | |
| ... | ... | @@ -2689,7 +2652,13 @@ struct IrInstructionPanic { |
| 2689 | 2652 | IrInstruction *msg; |
| 2690 | 2653 | }; |
| 2691 | 2654 | |
| 2692 | struct IrInstructionEnumTagName { | |
| 2655 | struct IrInstructionTagName { | |
| 2656 | IrInstruction base; | |
| 2657 | ||
| 2658 | IrInstruction *target; | |
| 2659 | }; | |
| 2660 | ||
| 2661 | struct IrInstructionTagType { | |
| 2693 | 2662 | IrInstruction base; |
| 2694 | 2663 | |
| 2695 | 2664 | IrInstruction *target; |
src/analyze.cpp+501-317| ... | ... | @@ -223,7 +223,6 @@ bool type_is_complete(TypeTableEntry *type_entry) { |
| 223 | 223 | case TypeTableEntryIdNamespace: |
| 224 | 224 | case TypeTableEntryIdBlock: |
| 225 | 225 | case TypeTableEntryIdBoundFn: |
| 226 | case TypeTableEntryIdEnumTag: | |
| 227 | 226 | case TypeTableEntryIdArgTuple: |
| 228 | 227 | return true; |
| 229 | 228 | } |
| ... | ... | @@ -260,7 +259,6 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) { |
| 260 | 259 | case TypeTableEntryIdNamespace: |
| 261 | 260 | case TypeTableEntryIdBlock: |
| 262 | 261 | case TypeTableEntryIdBoundFn: |
| 263 | case TypeTableEntryIdEnumTag: | |
| 264 | 262 | case TypeTableEntryIdArgTuple: |
| 265 | 263 | case TypeTableEntryIdOpaque: |
| 266 | 264 | return true; |
| ... | ... | @@ -1175,7 +1173,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1175 | 1173 | case TypeTableEntryIdEnum: |
| 1176 | 1174 | case TypeTableEntryIdUnion: |
| 1177 | 1175 | case TypeTableEntryIdFn: |
| 1178 | case TypeTableEntryIdEnumTag: | |
| 1179 | 1176 | ensure_complete_type(g, type_entry); |
| 1180 | 1177 | if (fn_type_id.cc == CallingConventionUnspecified && !type_is_copyable(g, type_entry)) { |
| 1181 | 1178 | add_node_error(g, param_node->data.param_decl.type, |
| ... | ... | @@ -1239,7 +1236,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c |
| 1239 | 1236 | case TypeTableEntryIdEnum: |
| 1240 | 1237 | case TypeTableEntryIdUnion: |
| 1241 | 1238 | case TypeTableEntryIdFn: |
| 1242 | case TypeTableEntryIdEnumTag: | |
| 1243 | 1239 | break; |
| 1244 | 1240 | } |
| 1245 | 1241 | |
| ... | ... | @@ -1263,22 +1259,6 @@ bool type_is_invalid(TypeTableEntry *type_entry) { |
| 1263 | 1259 | } |
| 1264 | 1260 | |
| 1265 | 1261 | |
| 1266 | TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, TypeTableEntry *int_type) { | |
| 1267 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnumTag); | |
| 1268 | ||
| 1269 | buf_resize(&entry->name, 0); | |
| 1270 | buf_appendf(&entry->name, "@enumTagType(%s)", buf_ptr(&enum_type->name)); | |
| 1271 | ||
| 1272 | entry->is_copyable = true; | |
| 1273 | entry->data.enum_tag.enum_type = enum_type; | |
| 1274 | entry->data.enum_tag.int_type = int_type; | |
| 1275 | entry->type_ref = int_type->type_ref; | |
| 1276 | entry->di_type = int_type->di_type; | |
| 1277 | entry->zero_bits = int_type->zero_bits; | |
| 1278 | ||
| 1279 | return entry; | |
| 1280 | } | |
| 1281 | ||
| 1282 | 1262 | static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1283 | 1263 | assert(enum_type->id == TypeTableEntryIdEnum); |
| 1284 | 1264 | |
| ... | ... | @@ -1308,14 +1288,6 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1308 | 1288 | assert(enum_type->data.enumeration.fields); |
| 1309 | 1289 | ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count); |
| 1310 | 1290 | |
| 1311 | uint32_t gen_field_count = enum_type->data.enumeration.gen_field_count; | |
| 1312 | ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count); | |
| 1313 | ||
| 1314 | TypeTableEntry *most_aligned_union_member = nullptr; | |
| 1315 | uint64_t size_of_most_aligned_member_in_bits = 0; | |
| 1316 | uint64_t biggest_align_in_bits = 0; | |
| 1317 | uint64_t biggest_size_in_bits = 0; | |
| 1318 | ||
| 1319 | 1291 | Scope *scope = &enum_type->data.enumeration.decls_scope->base; |
| 1320 | 1292 | ImportTableEntry *import = get_scope_import(scope); |
| 1321 | 1293 | |
| ... | ... | @@ -1323,49 +1295,17 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1323 | 1295 | enum_type->data.enumeration.embedded_in_current = true; |
| 1324 | 1296 | |
| 1325 | 1297 | for (uint32_t i = 0; i < field_count; i += 1) { |
| 1326 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); | |
| 1327 | TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; | |
| 1328 | TypeTableEntry *field_type = type_enum_field->type_entry; | |
| 1329 | ||
| 1330 | di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i); | |
| 1331 | ||
| 1332 | ensure_complete_type(g, field_type); | |
| 1333 | if (type_is_invalid(field_type)) { | |
| 1334 | enum_type->data.enumeration.is_invalid = true; | |
| 1335 | continue; | |
| 1336 | } | |
| 1337 | ||
| 1338 | if (!type_has_bits(field_type)) | |
| 1339 | continue; | |
| 1340 | ||
| 1341 | uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref); | |
| 1342 | uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref); | |
| 1343 | ||
| 1344 | assert(store_size_in_bits > 0); | |
| 1345 | assert(abi_align_in_bits > 0); | |
| 1346 | ||
| 1347 | union_inner_di_types[type_enum_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1348 | ZigLLVMTypeToScope(enum_type->di_type), buf_ptr(type_enum_field->name), | |
| 1349 | import->di_file, (unsigned)(field_node->line + 1), | |
| 1350 | store_size_in_bits, | |
| 1351 | abi_align_in_bits, | |
| 1352 | 0, | |
| 1353 | 0, field_type->di_type); | |
| 1354 | ||
| 1355 | biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits); | |
| 1298 | TypeEnumField *enum_field = &enum_type->data.enumeration.fields[i]; | |
| 1356 | 1299 | |
| 1357 | if (!most_aligned_union_member || abi_align_in_bits > biggest_align_in_bits) { | |
| 1358 | most_aligned_union_member = field_type; | |
| 1359 | biggest_align_in_bits = abi_align_in_bits; | |
| 1360 | size_of_most_aligned_member_in_bits = store_size_in_bits; | |
| 1361 | } | |
| 1300 | // TODO send patch to LLVM to support APInt in createEnumerator instead of int64_t | |
| 1301 | // http://lists.llvm.org/pipermail/llvm-dev/2017-December/119456.html | |
| 1302 | di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(enum_field->name), | |
| 1303 | bigint_as_signed(&enum_field->value)); | |
| 1362 | 1304 | } |
| 1363 | 1305 | |
| 1364 | 1306 | // unset temporary flag |
| 1365 | 1307 | enum_type->data.enumeration.embedded_in_current = false; |
| 1366 | 1308 | enum_type->data.enumeration.complete = true; |
| 1367 | enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8; | |
| 1368 | enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member; | |
| 1369 | 1309 | |
| 1370 | 1310 | if (enum_type->data.enumeration.is_invalid) |
| 1371 | 1311 | return; |
| ... | ... | @@ -1390,118 +1330,21 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1390 | 1330 | return; |
| 1391 | 1331 | } |
| 1392 | 1332 | |
| 1393 | TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); | |
| 1394 | TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type); | |
| 1395 | enum_type->data.enumeration.tag_type = tag_type_entry; | |
| 1396 | ||
| 1397 | uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref); | |
| 1398 | ||
| 1399 | if (most_aligned_union_member) { | |
| 1400 | // create llvm type for union | |
| 1401 | uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits; | |
| 1402 | LLVMTypeRef union_type_ref; | |
| 1403 | if (padding_in_bits > 0) { | |
| 1404 | TypeTableEntry *u8_type = get_int_type(g, false, 8); | |
| 1405 | TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8); | |
| 1406 | LLVMTypeRef union_element_types[] = { | |
| 1407 | most_aligned_union_member->type_ref, | |
| 1408 | padding_array->type_ref, | |
| 1409 | }; | |
| 1410 | union_type_ref = LLVMStructType(union_element_types, 2, false); | |
| 1411 | } else { | |
| 1412 | union_type_ref = most_aligned_union_member->type_ref; | |
| 1413 | } | |
| 1414 | enum_type->data.enumeration.union_type_ref = union_type_ref; | |
| 1415 | ||
| 1416 | assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits); | |
| 1417 | assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits); | |
| 1418 | ||
| 1419 | if (align_of_tag_in_bits >= biggest_align_in_bits) { | |
| 1420 | enum_type->data.enumeration.gen_tag_index = 0; | |
| 1421 | enum_type->data.enumeration.gen_union_index = 1; | |
| 1422 | } else { | |
| 1423 | enum_type->data.enumeration.gen_union_index = 0; | |
| 1424 | enum_type->data.enumeration.gen_tag_index = 1; | |
| 1425 | } | |
| 1426 | ||
| 1427 | // create llvm type for root struct | |
| 1428 | LLVMTypeRef root_struct_element_types[2]; | |
| 1429 | root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref; | |
| 1430 | root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref; | |
| 1431 | LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false); | |
| 1432 | ||
| 1433 | // create debug type for tag | |
| 1434 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1435 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1436 | ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | |
| 1437 | ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum", | |
| 1438 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1439 | tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count, | |
| 1440 | tag_type_entry->di_type, ""); | |
| 1441 | ||
| 1442 | // create debug type for union | |
| 1443 | ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | |
| 1444 | ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion", | |
| 1445 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1446 | biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types, | |
| 1447 | gen_field_count, 0, ""); | |
| 1448 | ||
| 1449 | // create debug types for members of root struct | |
| 1450 | uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, | |
| 1451 | enum_type->data.enumeration.gen_tag_index); | |
| 1452 | ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1453 | ZigLLVMTypeToScope(enum_type->di_type), "tag_field", | |
| 1454 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1455 | tag_debug_size_in_bits, | |
| 1456 | tag_debug_align_in_bits, | |
| 1457 | tag_offset_in_bits, | |
| 1458 | 0, tag_di_type); | |
| 1459 | ||
| 1460 | uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref, | |
| 1461 | enum_type->data.enumeration.gen_union_index); | |
| 1462 | ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1463 | ZigLLVMTypeToScope(enum_type->di_type), "union_field", | |
| 1464 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1465 | biggest_size_in_bits, | |
| 1466 | biggest_align_in_bits, | |
| 1467 | union_offset_in_bits, | |
| 1468 | 0, union_di_type); | |
| 1469 | ||
| 1470 | // create debug type for root struct | |
| 1471 | ZigLLVMDIType *di_root_members[2]; | |
| 1472 | di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type; | |
| 1473 | di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type; | |
| 1474 | ||
| 1475 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref); | |
| 1476 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref); | |
| 1477 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, | |
| 1478 | ZigLLVMFileToScope(import->di_file), | |
| 1479 | buf_ptr(&enum_type->name), | |
| 1480 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1481 | debug_size_in_bits, | |
| 1482 | debug_align_in_bits, | |
| 1483 | 0, nullptr, di_root_members, 2, 0, nullptr, ""); | |
| 1484 | ||
| 1485 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type); | |
| 1486 | enum_type->di_type = replacement_di_type; | |
| 1487 | } else { | |
| 1488 | // create llvm type for root struct | |
| 1489 | enum_type->type_ref = tag_type_entry->type_ref; | |
| 1333 | TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type; | |
| 1490 | 1334 | |
| 1491 | // create debug type for tag | |
| 1492 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1493 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 1494 | ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | |
| 1495 | ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name), | |
| 1496 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1497 | tag_debug_size_in_bits, | |
| 1498 | tag_debug_align_in_bits, | |
| 1499 | di_enumerators, field_count, | |
| 1500 | tag_type_entry->di_type, ""); | |
| 1335 | // create debug type for tag | |
| 1336 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_int_type->type_ref); | |
| 1337 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref); | |
| 1338 | ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | |
| 1339 | ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name), | |
| 1340 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1341 | tag_debug_size_in_bits, | |
| 1342 | tag_debug_align_in_bits, | |
| 1343 | di_enumerators, field_count, | |
| 1344 | tag_int_type->di_type, ""); | |
| 1501 | 1345 | |
| 1502 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type); | |
| 1503 | enum_type->di_type = tag_di_type; | |
| 1504 | } | |
| 1346 | ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type); | |
| 1347 | enum_type->di_type = tag_di_type; | |
| 1505 | 1348 | } |
| 1506 | 1349 | |
| 1507 | 1350 | static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) { |
| ... | ... | @@ -1517,8 +1360,6 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) { |
| 1517 | 1360 | case TypeTableEntryIdNullLit: |
| 1518 | 1361 | case TypeTableEntryIdErrorUnion: |
| 1519 | 1362 | case TypeTableEntryIdPureError: |
| 1520 | case TypeTableEntryIdEnum: | |
| 1521 | case TypeTableEntryIdEnumTag: | |
| 1522 | 1363 | case TypeTableEntryIdNamespace: |
| 1523 | 1364 | case TypeTableEntryIdBlock: |
| 1524 | 1365 | case TypeTableEntryIdBoundFn: |
| ... | ... | @@ -1541,6 +1382,8 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) { |
| 1541 | 1382 | TypeTableEntry *child_type = type_entry->data.maybe.child_type; |
| 1542 | 1383 | return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn; |
| 1543 | 1384 | } |
| 1385 | case TypeTableEntryIdEnum: | |
| 1386 | return type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr; | |
| 1544 | 1387 | } |
| 1545 | 1388 | zig_unreachable(); |
| 1546 | 1389 | } |
| ... | ... | @@ -1658,7 +1501,6 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1658 | 1501 | TypeTableEntry *field_type = type_struct_field->type_entry; |
| 1659 | 1502 | |
| 1660 | 1503 | ensure_complete_type(g, field_type); |
| 1661 | ||
| 1662 | 1504 | if (type_is_invalid(field_type)) { |
| 1663 | 1505 | struct_type->data.structure.is_invalid = true; |
| 1664 | 1506 | break; |
| ... | ... | @@ -1849,6 +1691,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 1849 | 1691 | if (union_type->data.unionation.embedded_in_current) { |
| 1850 | 1692 | if (!union_type->data.unionation.reported_infinite_err) { |
| 1851 | 1693 | union_type->data.unionation.reported_infinite_err = true; |
| 1694 | union_type->data.unionation.is_invalid = true; | |
| 1852 | 1695 | add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name))); |
| 1853 | 1696 | } |
| 1854 | 1697 | return; |
| ... | ... | @@ -1870,19 +1713,17 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 1870 | 1713 | uint64_t biggest_align_in_bits = 0; |
| 1871 | 1714 | uint64_t biggest_size_in_bits = 0; |
| 1872 | 1715 | |
| 1873 | bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); | |
| 1874 | ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count); | |
| 1875 | ||
| 1876 | 1716 | Scope *scope = &union_type->data.unionation.decls_scope->base; |
| 1877 | 1717 | ImportTableEntry *import = get_scope_import(scope); |
| 1878 | 1718 | |
| 1879 | 1719 | // set temporary flag |
| 1880 | 1720 | union_type->data.unionation.embedded_in_current = true; |
| 1881 | 1721 | |
| 1722 | ||
| 1882 | 1723 | for (uint32_t i = 0; i < field_count; i += 1) { |
| 1883 | 1724 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); |
| 1884 | TypeUnionField *type_union_field = &union_type->data.unionation.fields[i]; | |
| 1885 | TypeTableEntry *field_type = type_union_field->type_entry; | |
| 1725 | TypeUnionField *union_field = &union_type->data.unionation.fields[i]; | |
| 1726 | TypeTableEntry *field_type = union_field->type_entry; | |
| 1886 | 1727 | |
| 1887 | 1728 | ensure_complete_type(g, field_type); |
| 1888 | 1729 | if (type_is_invalid(field_type)) { |
| ... | ... | @@ -1893,16 +1734,14 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 1893 | 1734 | if (!type_has_bits(field_type)) |
| 1894 | 1735 | continue; |
| 1895 | 1736 | |
| 1896 | di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_union_field->name), i); | |
| 1897 | ||
| 1898 | 1737 | uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref); |
| 1899 | 1738 | uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref); |
| 1900 | 1739 | |
| 1901 | 1740 | assert(store_size_in_bits > 0); |
| 1902 | 1741 | assert(abi_align_in_bits > 0); |
| 1903 | 1742 | |
| 1904 | union_inner_di_types[type_union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1905 | ZigLLVMTypeToScope(union_type->di_type), buf_ptr(type_union_field->name), | |
| 1743 | union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1744 | ZigLLVMTypeToScope(union_type->di_type), buf_ptr(union_field->enum_field->name), | |
| 1906 | 1745 | import->di_file, (unsigned)(field_node->line + 1), |
| 1907 | 1746 | store_size_in_bits, |
| 1908 | 1747 | abi_align_in_bits, |
| ... | ... | @@ -1918,6 +1757,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 1918 | 1757 | } |
| 1919 | 1758 | } |
| 1920 | 1759 | |
| 1760 | ||
| 1921 | 1761 | // unset temporary flag |
| 1922 | 1762 | union_type->data.unionation.embedded_in_current = false; |
| 1923 | 1763 | union_type->data.unionation.complete = true; |
| ... | ... | @@ -1947,13 +1787,12 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 1947 | 1787 | return; |
| 1948 | 1788 | } |
| 1949 | 1789 | |
| 1950 | assert(most_aligned_union_member != nullptr); | |
| 1951 | ||
| 1952 | bool want_safety = auto_layout && (field_count >= 2); | |
| 1953 | 1790 | uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits; |
| 1954 | 1791 | |
| 1792 | TypeTableEntry *tag_type = union_type->data.unionation.tag_type; | |
| 1793 | if (tag_type == nullptr) { | |
| 1794 | assert(most_aligned_union_member != nullptr); | |
| 1955 | 1795 | |
| 1956 | if (!want_safety) { | |
| 1957 | 1796 | if (padding_in_bits > 0) { |
| 1958 | 1797 | TypeTableEntry *u8_type = get_int_type(g, false, 8); |
| 1959 | 1798 | TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8); |
| ... | ... | @@ -1993,6 +1832,14 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 1993 | 1832 | padding_array->type_ref, |
| 1994 | 1833 | }; |
| 1995 | 1834 | union_type_ref = LLVMStructType(union_element_types, 2, false); |
| 1835 | } else if (most_aligned_union_member == nullptr) { | |
| 1836 | union_type->data.unionation.gen_tag_index = SIZE_MAX; | |
| 1837 | union_type->data.unionation.gen_union_index = SIZE_MAX; | |
| 1838 | union_type->type_ref = tag_type->type_ref; | |
| 1839 | ||
| 1840 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, tag_type->di_type); | |
| 1841 | union_type->di_type = tag_type->di_type; | |
| 1842 | return; | |
| 1996 | 1843 | } else { |
| 1997 | 1844 | union_type_ref = most_aligned_union_member->type_ref; |
| 1998 | 1845 | } |
| ... | ... | @@ -2002,9 +1849,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 2002 | 1849 | assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits); |
| 2003 | 1850 | |
| 2004 | 1851 | // create llvm type for root struct |
| 2005 | TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); | |
| 2006 | TypeTableEntry *tag_type_entry = tag_int_type; | |
| 2007 | union_type->data.unionation.tag_type = tag_type_entry; | |
| 1852 | TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type; | |
| 2008 | 1853 | uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref); |
| 2009 | 1854 | |
| 2010 | 1855 | if (align_of_tag_in_bits >= biggest_align_in_bits) { |
| ... | ... | @@ -2016,22 +1861,11 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 2016 | 1861 | } |
| 2017 | 1862 | |
| 2018 | 1863 | LLVMTypeRef root_struct_element_types[2]; |
| 2019 | root_struct_element_types[union_type->data.unionation.gen_tag_index] = tag_type_entry->type_ref; | |
| 1864 | root_struct_element_types[union_type->data.unionation.gen_tag_index] = tag_type->type_ref; | |
| 2020 | 1865 | root_struct_element_types[union_type->data.unionation.gen_union_index] = union_type_ref; |
| 2021 | 1866 | LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false); |
| 2022 | 1867 | |
| 2023 | 1868 | |
| 2024 | // create debug type for root struct | |
| 2025 | ||
| 2026 | // create debug type for tag | |
| 2027 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 2028 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref); | |
| 2029 | ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | |
| 2030 | ZigLLVMTypeToScope(union_type->di_type), "AnonEnum", | |
| 2031 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 2032 | tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count, | |
| 2033 | tag_type_entry->di_type, ""); | |
| 2034 | ||
| 2035 | 1869 | // create debug type for union |
| 2036 | 1870 | ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, |
| 2037 | 1871 | ZigLLVMTypeToScope(union_type->di_type), "AnonUnion", |
| ... | ... | @@ -2045,19 +1879,23 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 2045 | 1879 | union_type->data.unionation.gen_tag_index); |
| 2046 | 1880 | |
| 2047 | 1881 | ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, |
| 2048 | ZigLLVMTypeToScope(union_type->di_type), "union_field", | |
| 1882 | ZigLLVMTypeToScope(union_type->di_type), "payload", | |
| 2049 | 1883 | import->di_file, (unsigned)(decl_node->line + 1), |
| 2050 | 1884 | biggest_size_in_bits, |
| 2051 | 1885 | biggest_align_in_bits, |
| 2052 | 1886 | union_offset_in_bits, |
| 2053 | 1887 | 0, union_di_type); |
| 1888 | ||
| 1889 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref); | |
| 1890 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref); | |
| 1891 | ||
| 2054 | 1892 | ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, |
| 2055 | ZigLLVMTypeToScope(union_type->di_type), "tag_field", | |
| 1893 | ZigLLVMTypeToScope(union_type->di_type), "tag", | |
| 2056 | 1894 | import->di_file, (unsigned)(decl_node->line + 1), |
| 2057 | 1895 | tag_debug_size_in_bits, |
| 2058 | 1896 | tag_debug_align_in_bits, |
| 2059 | 1897 | tag_offset_in_bits, |
| 2060 | 0, tag_di_type); | |
| 1898 | 0, tag_type->di_type); | |
| 2061 | 1899 | |
| 2062 | 1900 | ZigLLVMDIType *di_root_members[2]; |
| 2063 | 1901 | di_root_members[union_type->data.unionation.gen_tag_index] = tag_member_di_type; |
| ... | ... | @@ -2096,51 +1934,124 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| 2096 | 1934 | |
| 2097 | 1935 | assert(!enum_type->data.enumeration.fields); |
| 2098 | 1936 | uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; |
| 1937 | if (field_count == 0) { | |
| 1938 | add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields")); | |
| 1939 | ||
| 1940 | enum_type->data.enumeration.src_field_count = field_count; | |
| 1941 | enum_type->data.enumeration.fields = nullptr; | |
| 1942 | enum_type->data.enumeration.is_invalid = true; | |
| 1943 | enum_type->data.enumeration.zero_bits_loop_flag = false; | |
| 1944 | enum_type->data.enumeration.zero_bits_known = true; | |
| 1945 | return; | |
| 1946 | } | |
| 1947 | ||
| 2099 | 1948 | enum_type->data.enumeration.src_field_count = field_count; |
| 2100 | 1949 | enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count); |
| 2101 | 1950 | |
| 2102 | uint32_t biggest_align_bytes = 0; | |
| 2103 | ||
| 2104 | 1951 | Scope *scope = &enum_type->data.enumeration.decls_scope->base; |
| 2105 | 1952 | |
| 2106 | uint32_t gen_field_index = 0; | |
| 2107 | for (uint32_t i = 0; i < field_count; i += 1) { | |
| 2108 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); | |
| 2109 | TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; | |
| 2110 | type_enum_field->name = field_node->data.struct_field.name; | |
| 2111 | TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); | |
| 2112 | type_enum_field->type_entry = field_type; | |
| 2113 | type_enum_field->value = i; | |
| 1953 | HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {}; | |
| 1954 | occupied_tag_values.init(field_count); | |
| 2114 | 1955 | |
| 2115 | type_ensure_zero_bits_known(g, field_type); | |
| 2116 | if (type_is_invalid(field_type)) { | |
| 1956 | TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); | |
| 1957 | ||
| 1958 | if (decl_node->data.container_decl.init_arg_expr != nullptr) { | |
| 1959 | TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); | |
| 1960 | if (type_is_invalid(wanted_tag_int_type)) { | |
| 2117 | 1961 | enum_type->data.enumeration.is_invalid = true; |
| 2118 | continue; | |
| 1962 | } else if (wanted_tag_int_type->id != TypeTableEntryIdInt) { | |
| 1963 | enum_type->data.enumeration.is_invalid = true; | |
| 1964 | add_node_error(g, decl_node->data.container_decl.init_arg_expr, | |
| 1965 | buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name))); | |
| 1966 | } else if (wanted_tag_int_type->data.integral.is_signed) { | |
| 1967 | enum_type->data.enumeration.is_invalid = true; | |
| 1968 | add_node_error(g, decl_node->data.container_decl.init_arg_expr, | |
| 1969 | buf_sprintf("expected unsigned integer, found '%s'", buf_ptr(&wanted_tag_int_type->name))); | |
| 1970 | } else if (wanted_tag_int_type->data.integral.bit_count < tag_int_type->data.integral.bit_count) { | |
| 1971 | enum_type->data.enumeration.is_invalid = true; | |
| 1972 | add_node_error(g, decl_node->data.container_decl.init_arg_expr, | |
| 1973 | buf_sprintf("'%s' too small to hold all bits; must be at least '%s'", | |
| 1974 | buf_ptr(&wanted_tag_int_type->name), buf_ptr(&tag_int_type->name))); | |
| 1975 | } else { | |
| 1976 | tag_int_type = wanted_tag_int_type; | |
| 2119 | 1977 | } |
| 1978 | } | |
| 1979 | enum_type->data.enumeration.tag_int_type = tag_int_type; | |
| 1980 | enum_type->type_ref = tag_int_type->type_ref; | |
| 2120 | 1981 | |
| 2121 | if (!type_has_bits(field_type)) | |
| 2122 | continue; | |
| 1982 | for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { | |
| 1983 | AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); | |
| 1984 | TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i]; | |
| 1985 | type_enum_field->name = field_node->data.struct_field.name; | |
| 1986 | type_enum_field->decl_index = field_i; | |
| 2123 | 1987 | |
| 2124 | type_enum_field->gen_index = gen_field_index; | |
| 2125 | gen_field_index += 1; | |
| 1988 | if (field_node->data.struct_field.type != nullptr) { | |
| 1989 | ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.type, | |
| 1990 | buf_sprintf("structs and unions, not enums, support field types")); | |
| 1991 | add_error_note(g, msg, decl_node, | |
| 1992 | buf_sprintf("consider 'union(enum)' here")); | |
| 1993 | } | |
| 2126 | 1994 | |
| 2127 | uint32_t field_align_bytes = get_abi_alignment(g, field_type); | |
| 2128 | if (field_align_bytes > biggest_align_bytes) { | |
| 2129 | biggest_align_bytes = field_align_bytes; | |
| 1995 | AstNode *tag_value = field_node->data.struct_field.value; | |
| 1996 | ||
| 1997 | // In this first pass we resolve explicit tag values. | |
| 1998 | // In a second pass we will fill in the unspecified ones. | |
| 1999 | if (tag_value != nullptr) { | |
| 2000 | IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); | |
| 2001 | if (result_inst->value.type->id == TypeTableEntryIdInvalid) { | |
| 2002 | enum_type->data.enumeration.is_invalid = true; | |
| 2003 | continue; | |
| 2004 | } | |
| 2005 | assert(result_inst->value.special != ConstValSpecialRuntime); | |
| 2006 | assert(result_inst->value.type->id == TypeTableEntryIdInt); | |
| 2007 | auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); | |
| 2008 | if (entry == nullptr) { | |
| 2009 | bigint_init_bigint(&type_enum_field->value, &result_inst->value.data.x_bigint); | |
| 2010 | } else { | |
| 2011 | Buf *val_buf = buf_alloc(); | |
| 2012 | bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10); | |
| 2013 | ||
| 2014 | ErrorMsg *msg = add_node_error(g, tag_value, | |
| 2015 | buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); | |
| 2016 | add_error_note(g, msg, entry->value, | |
| 2017 | buf_sprintf("other occurrence here")); | |
| 2018 | enum_type->data.enumeration.is_invalid = true; | |
| 2019 | continue; | |
| 2020 | } | |
| 2130 | 2021 | } |
| 2131 | 2022 | } |
| 2132 | 2023 | |
| 2133 | enum_type->data.enumeration.zero_bits_loop_flag = false; | |
| 2134 | enum_type->data.enumeration.gen_field_count = gen_field_index; | |
| 2135 | enum_type->zero_bits = (gen_field_index == 0 && field_count < 2); | |
| 2136 | enum_type->data.enumeration.zero_bits_known = true; | |
| 2024 | // Now iterate again and populate the unspecified tag values | |
| 2025 | uint32_t next_maybe_unoccupied_index = 0; | |
| 2026 | ||
| 2027 | for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { | |
| 2028 | AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); | |
| 2029 | TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i]; | |
| 2030 | AstNode *tag_value = field_node->data.struct_field.value; | |
| 2137 | 2031 | |
| 2138 | // also compute abi_alignment | |
| 2139 | if (!enum_type->zero_bits) { | |
| 2140 | TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count); | |
| 2141 | uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref); | |
| 2142 | enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes); | |
| 2032 | if (tag_value == nullptr) { | |
| 2033 | if (occupied_tag_values.size() == 0) { | |
| 2034 | bigint_init_unsigned(&type_enum_field->value, next_maybe_unoccupied_index); | |
| 2035 | next_maybe_unoccupied_index += 1; | |
| 2036 | } else { | |
| 2037 | BigInt proposed_value; | |
| 2038 | for (;;) { | |
| 2039 | bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index); | |
| 2040 | next_maybe_unoccupied_index += 1; | |
| 2041 | auto entry = occupied_tag_values.put_unique(proposed_value, field_node); | |
| 2042 | if (entry != nullptr) { | |
| 2043 | continue; | |
| 2044 | } | |
| 2045 | break; | |
| 2046 | } | |
| 2047 | bigint_init_bigint(&type_enum_field->value, &proposed_value); | |
| 2048 | } | |
| 2049 | } | |
| 2143 | 2050 | } |
| 2051 | ||
| 2052 | enum_type->data.enumeration.zero_bits_loop_flag = false; | |
| 2053 | enum_type->zero_bits = (field_count < 2); | |
| 2054 | enum_type->data.enumeration.zero_bits_known = true; | |
| 2144 | 2055 | } |
| 2145 | 2056 | |
| 2146 | 2057 | static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| ... | ... | @@ -2184,11 +2095,23 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| 2184 | 2095 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); |
| 2185 | 2096 | TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; |
| 2186 | 2097 | type_struct_field->name = field_node->data.struct_field.name; |
| 2098 | ||
| 2099 | if (field_node->data.struct_field.type == nullptr) { | |
| 2100 | add_node_error(g, field_node, buf_sprintf("struct field missing type")); | |
| 2101 | struct_type->data.structure.is_invalid = true; | |
| 2102 | continue; | |
| 2103 | } | |
| 2104 | ||
| 2187 | 2105 | TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); |
| 2188 | 2106 | type_struct_field->type_entry = field_type; |
| 2189 | 2107 | type_struct_field->src_index = i; |
| 2190 | 2108 | type_struct_field->gen_index = SIZE_MAX; |
| 2191 | 2109 | |
| 2110 | if (field_node->data.struct_field.value != nullptr) { | |
| 2111 | add_node_error(g, field_node->data.struct_field.value, | |
| 2112 | buf_sprintf("enums, not structs, support field assignment")); | |
| 2113 | } | |
| 2114 | ||
| 2192 | 2115 | type_ensure_zero_bits_known(g, field_type); |
| 2193 | 2116 | if (type_is_invalid(field_type)) { |
| 2194 | 2117 | struct_type->data.structure.is_invalid = true; |
| ... | ... | @@ -2225,8 +2148,23 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2225 | 2148 | if (union_type->data.unionation.zero_bits_known) |
| 2226 | 2149 | return; |
| 2227 | 2150 | |
| 2151 | if (type_is_invalid(union_type)) | |
| 2152 | return; | |
| 2153 | ||
| 2228 | 2154 | if (union_type->data.unionation.zero_bits_loop_flag) { |
| 2155 | // If we get here it's due to recursion. From this we conclude that the struct is | |
| 2156 | // not zero bits, and if abi_alignment == 0 we further conclude that the first field | |
| 2157 | // is a pointer to this very struct, or a function pointer with parameters that | |
| 2158 | // reference such a type. | |
| 2229 | 2159 | union_type->data.unionation.zero_bits_known = true; |
| 2160 | if (union_type->data.unionation.abi_alignment == 0) { | |
| 2161 | if (union_type->data.unionation.layout == ContainerLayoutPacked) { | |
| 2162 | union_type->data.unionation.abi_alignment = 1; | |
| 2163 | } else { | |
| 2164 | union_type->data.unionation.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref, | |
| 2165 | LLVMPointerType(LLVMInt8Type(), 0)); | |
| 2166 | } | |
| 2167 | } | |
| 2230 | 2168 | return; |
| 2231 | 2169 | } |
| 2232 | 2170 | |
| ... | ... | @@ -2238,6 +2176,16 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2238 | 2176 | |
| 2239 | 2177 | assert(!union_type->data.unionation.fields); |
| 2240 | 2178 | uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; |
| 2179 | if (field_count == 0) { | |
| 2180 | add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields")); | |
| 2181 | ||
| 2182 | union_type->data.unionation.src_field_count = field_count; | |
| 2183 | union_type->data.unionation.fields = nullptr; | |
| 2184 | union_type->data.unionation.is_invalid = true; | |
| 2185 | union_type->data.unionation.zero_bits_loop_flag = false; | |
| 2186 | union_type->data.unionation.zero_bits_known = true; | |
| 2187 | return; | |
| 2188 | } | |
| 2241 | 2189 | union_type->data.unionation.src_field_count = field_count; |
| 2242 | 2190 | union_type->data.unionation.fields = allocate<TypeUnionField>(field_count); |
| 2243 | 2191 | |
| ... | ... | @@ -2245,44 +2193,261 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 2245 | 2193 | |
| 2246 | 2194 | Scope *scope = &union_type->data.unionation.decls_scope->base; |
| 2247 | 2195 | |
| 2196 | HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {}; | |
| 2197 | ||
| 2198 | AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr; | |
| 2199 | bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); | |
| 2200 | bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr); | |
| 2201 | TypeTableEntry *tag_type; | |
| 2202 | bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety); | |
| 2203 | bool *covered_enum_fields; | |
| 2204 | ZigLLVMDIEnumerator **di_enumerators; | |
| 2205 | if (create_enum_type) { | |
| 2206 | occupied_tag_values.init(field_count); | |
| 2207 | ||
| 2208 | di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count); | |
| 2209 | ||
| 2210 | TypeTableEntry *tag_int_type; | |
| 2211 | if (enum_type_node != nullptr) { | |
| 2212 | tag_int_type = analyze_type_expr(g, scope, enum_type_node); | |
| 2213 | if (type_is_invalid(tag_int_type)) { | |
| 2214 | union_type->data.unionation.is_invalid = true; | |
| 2215 | return; | |
| 2216 | } | |
| 2217 | if (tag_int_type->id != TypeTableEntryIdInt) { | |
| 2218 | add_node_error(g, enum_type_node, | |
| 2219 | buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name))); | |
| 2220 | union_type->data.unionation.is_invalid = true; | |
| 2221 | return; | |
| 2222 | } | |
| 2223 | } else { | |
| 2224 | tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); | |
| 2225 | } | |
| 2226 | union_type->data.unionation.abi_alignment = get_abi_alignment(g, tag_int_type); | |
| 2227 | ||
| 2228 | tag_type = new_type_table_entry(TypeTableEntryIdEnum); | |
| 2229 | buf_resize(&tag_type->name, 0); | |
| 2230 | buf_appendf(&tag_type->name, "@EnumTagType(%s)", buf_ptr(&union_type->name)); | |
| 2231 | tag_type->is_copyable = true; | |
| 2232 | tag_type->type_ref = tag_int_type->type_ref; | |
| 2233 | tag_type->zero_bits = tag_int_type->zero_bits; | |
| 2234 | ||
| 2235 | tag_type->data.enumeration.tag_int_type = tag_int_type; | |
| 2236 | tag_type->data.enumeration.zero_bits_known = true; | |
| 2237 | tag_type->data.enumeration.decl_node = decl_node; | |
| 2238 | tag_type->data.enumeration.layout = ContainerLayoutAuto; | |
| 2239 | tag_type->data.enumeration.src_field_count = field_count; | |
| 2240 | tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count); | |
| 2241 | tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope; | |
| 2242 | tag_type->data.enumeration.complete = true; | |
| 2243 | } else if (enum_type_node != nullptr) { | |
| 2244 | TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node); | |
| 2245 | if (type_is_invalid(enum_type)) { | |
| 2246 | union_type->data.unionation.is_invalid = true; | |
| 2247 | union_type->data.unionation.embedded_in_current = false; | |
| 2248 | return; | |
| 2249 | } | |
| 2250 | if (enum_type->id != TypeTableEntryIdEnum) { | |
| 2251 | union_type->data.unionation.is_invalid = true; | |
| 2252 | union_type->data.unionation.embedded_in_current = false; | |
| 2253 | add_node_error(g, enum_type_node, | |
| 2254 | buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name))); | |
| 2255 | return; | |
| 2256 | } | |
| 2257 | tag_type = enum_type; | |
| 2258 | covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count); | |
| 2259 | union_type->data.unionation.abi_alignment = get_abi_alignment(g, enum_type); | |
| 2260 | } else { | |
| 2261 | tag_type = nullptr; | |
| 2262 | } | |
| 2263 | union_type->data.unionation.tag_type = tag_type; | |
| 2264 | ||
| 2248 | 2265 | uint32_t gen_field_index = 0; |
| 2249 | 2266 | for (uint32_t i = 0; i < field_count; i += 1) { |
| 2250 | 2267 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); |
| 2251 | TypeUnionField *type_union_field = &union_type->data.unionation.fields[i]; | |
| 2252 | type_union_field->name = field_node->data.struct_field.name; | |
| 2253 | TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); | |
| 2254 | type_union_field->type_entry = field_type; | |
| 2255 | type_union_field->value = i; | |
| 2268 | Buf *field_name = field_node->data.struct_field.name; | |
| 2269 | TypeUnionField *union_field = &union_type->data.unionation.fields[i]; | |
| 2270 | union_field->name = field_node->data.struct_field.name; | |
| 2271 | ||
| 2272 | TypeTableEntry *field_type; | |
| 2273 | if (field_node->data.struct_field.type == nullptr) { | |
| 2274 | if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) { | |
| 2275 | field_type = g->builtin_types.entry_void; | |
| 2276 | } else { | |
| 2277 | add_node_error(g, field_node, buf_sprintf("union field missing type")); | |
| 2278 | union_type->data.unionation.is_invalid = true; | |
| 2279 | continue; | |
| 2280 | } | |
| 2281 | } else { | |
| 2282 | field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); | |
| 2283 | type_ensure_zero_bits_known(g, field_type); | |
| 2284 | if (type_is_invalid(field_type)) { | |
| 2285 | union_type->data.unionation.is_invalid = true; | |
| 2286 | continue; | |
| 2287 | } | |
| 2288 | } | |
| 2289 | union_field->type_entry = field_type; | |
| 2256 | 2290 | |
| 2257 | type_ensure_zero_bits_known(g, field_type); | |
| 2258 | if (type_is_invalid(field_type)) { | |
| 2259 | union_type->data.unionation.is_invalid = true; | |
| 2260 | continue; | |
| 2291 | if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) { | |
| 2292 | ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, | |
| 2293 | buf_sprintf("non-enum union field assignment")); | |
| 2294 | add_error_note(g, msg, decl_node, | |
| 2295 | buf_sprintf("consider 'union(enum)' here")); | |
| 2296 | } | |
| 2297 | ||
| 2298 | if (create_enum_type) { | |
| 2299 | di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i); | |
| 2300 | union_field->enum_field = &tag_type->data.enumeration.fields[i]; | |
| 2301 | union_field->enum_field->name = field_name; | |
| 2302 | union_field->enum_field->decl_index = i; | |
| 2303 | ||
| 2304 | AstNode *tag_value = field_node->data.struct_field.value; | |
| 2305 | // In this first pass we resolve explicit tag values. | |
| 2306 | // In a second pass we will fill in the unspecified ones. | |
| 2307 | if (tag_value != nullptr) { | |
| 2308 | TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type; | |
| 2309 | IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); | |
| 2310 | if (result_inst->value.type->id == TypeTableEntryIdInvalid) { | |
| 2311 | union_type->data.unionation.is_invalid = true; | |
| 2312 | continue; | |
| 2313 | } | |
| 2314 | assert(result_inst->value.special != ConstValSpecialRuntime); | |
| 2315 | assert(result_inst->value.type->id == TypeTableEntryIdInt); | |
| 2316 | auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value); | |
| 2317 | if (entry == nullptr) { | |
| 2318 | bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint); | |
| 2319 | } else { | |
| 2320 | Buf *val_buf = buf_alloc(); | |
| 2321 | bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10); | |
| 2322 | ||
| 2323 | ErrorMsg *msg = add_node_error(g, tag_value, | |
| 2324 | buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf))); | |
| 2325 | add_error_note(g, msg, entry->value, | |
| 2326 | buf_sprintf("other occurrence here")); | |
| 2327 | union_type->data.unionation.is_invalid = true; | |
| 2328 | continue; | |
| 2329 | } | |
| 2330 | } | |
| 2331 | } else if (enum_type_node != nullptr) { | |
| 2332 | union_field->enum_field = find_enum_type_field(tag_type, field_name); | |
| 2333 | if (union_field->enum_field == nullptr) { | |
| 2334 | ErrorMsg *msg = add_node_error(g, field_node, | |
| 2335 | buf_sprintf("enum field not found: '%s'", buf_ptr(field_name))); | |
| 2336 | add_error_note(g, msg, tag_type->data.enumeration.decl_node, | |
| 2337 | buf_sprintf("enum declared here")); | |
| 2338 | union_type->data.unionation.is_invalid = true; | |
| 2339 | continue; | |
| 2340 | } | |
| 2341 | covered_enum_fields[union_field->enum_field->decl_index] = true; | |
| 2342 | } else { | |
| 2343 | union_field->enum_field = allocate<TypeEnumField>(1); | |
| 2344 | union_field->enum_field->name = field_name; | |
| 2345 | union_field->enum_field->decl_index = i; | |
| 2346 | bigint_init_unsigned(&union_field->enum_field->value, i); | |
| 2261 | 2347 | } |
| 2348 | assert(union_field->enum_field != nullptr); | |
| 2262 | 2349 | |
| 2263 | 2350 | if (!type_has_bits(field_type)) |
| 2264 | 2351 | continue; |
| 2265 | 2352 | |
| 2266 | type_union_field->gen_index = gen_field_index; | |
| 2353 | union_field->gen_index = gen_field_index; | |
| 2267 | 2354 | gen_field_index += 1; |
| 2268 | 2355 | |
| 2269 | 2356 | uint32_t field_align_bytes = get_abi_alignment(g, field_type); |
| 2270 | 2357 | if (field_align_bytes > biggest_align_bytes) { |
| 2271 | 2358 | biggest_align_bytes = field_align_bytes; |
| 2359 | if (biggest_align_bytes > union_type->data.unionation.abi_alignment) { | |
| 2360 | union_type->data.unionation.abi_alignment = biggest_align_bytes; | |
| 2361 | } | |
| 2272 | 2362 | } |
| 2273 | 2363 | } |
| 2274 | 2364 | |
| 2275 | bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); | |
| 2365 | if (union_type->data.unionation.is_invalid) | |
| 2366 | return; | |
| 2367 | ||
| 2368 | bool src_have_tag = decl_node->data.container_decl.auto_enum || | |
| 2369 | decl_node->data.container_decl.init_arg_expr != nullptr; | |
| 2370 | ||
| 2371 | if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) { | |
| 2372 | const char *qual_str; | |
| 2373 | switch (union_type->data.unionation.layout) { | |
| 2374 | case ContainerLayoutAuto: | |
| 2375 | zig_unreachable(); | |
| 2376 | case ContainerLayoutPacked: | |
| 2377 | qual_str = "packed"; | |
| 2378 | break; | |
| 2379 | case ContainerLayoutExtern: | |
| 2380 | qual_str = "extern"; | |
| 2381 | break; | |
| 2382 | } | |
| 2383 | AstNode *source_node = (decl_node->data.container_decl.init_arg_expr != nullptr) ? | |
| 2384 | decl_node->data.container_decl.init_arg_expr : decl_node; | |
| 2385 | add_node_error(g, source_node, | |
| 2386 | buf_sprintf("%s union does not support enum tag type", qual_str)); | |
| 2387 | union_type->data.unionation.is_invalid = true; | |
| 2388 | return; | |
| 2389 | } | |
| 2390 | ||
| 2391 | if (create_enum_type) { | |
| 2392 | // Now iterate again and populate the unspecified tag values | |
| 2393 | uint32_t next_maybe_unoccupied_index = 0; | |
| 2394 | ||
| 2395 | for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { | |
| 2396 | AstNode *field_node = decl_node->data.container_decl.fields.at(field_i); | |
| 2397 | TypeUnionField *union_field = &union_type->data.unionation.fields[field_i]; | |
| 2398 | AstNode *tag_value = field_node->data.struct_field.value; | |
| 2399 | ||
| 2400 | if (tag_value == nullptr) { | |
| 2401 | if (occupied_tag_values.size() == 0) { | |
| 2402 | bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index); | |
| 2403 | next_maybe_unoccupied_index += 1; | |
| 2404 | } else { | |
| 2405 | BigInt proposed_value; | |
| 2406 | for (;;) { | |
| 2407 | bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index); | |
| 2408 | next_maybe_unoccupied_index += 1; | |
| 2409 | auto entry = occupied_tag_values.put_unique(proposed_value, field_node); | |
| 2410 | if (entry != nullptr) { | |
| 2411 | continue; | |
| 2412 | } | |
| 2413 | break; | |
| 2414 | } | |
| 2415 | bigint_init_bigint(&union_field->enum_field->value, &proposed_value); | |
| 2416 | } | |
| 2417 | } | |
| 2418 | } | |
| 2419 | } else if (enum_type_node != nullptr) { | |
| 2420 | for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) { | |
| 2421 | TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i]; | |
| 2422 | if (!covered_enum_fields[i]) { | |
| 2423 | AstNode *enum_decl_node = tag_type->data.enumeration.decl_node; | |
| 2424 | AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i); | |
| 2425 | ErrorMsg *msg = add_node_error(g, decl_node, | |
| 2426 | buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name))); | |
| 2427 | add_error_note(g, msg, field_node, | |
| 2428 | buf_sprintf("declared here")); | |
| 2429 | union_type->data.unionation.is_invalid = true; | |
| 2430 | } | |
| 2431 | } | |
| 2432 | } | |
| 2433 | ||
| 2434 | if (create_enum_type) { | |
| 2435 | ImportTableEntry *import = get_scope_import(scope); | |
| 2436 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref); | |
| 2437 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref); | |
| 2438 | // TODO get a more accurate debug scope | |
| 2439 | ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | |
| 2440 | ZigLLVMFileToScope(import->di_file), buf_ptr(&tag_type->name), | |
| 2441 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 2442 | tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count, | |
| 2443 | tag_type->di_type, ""); | |
| 2444 | tag_type->di_type = tag_di_type; | |
| 2445 | } | |
| 2276 | 2446 | |
| 2277 | 2447 | union_type->data.unionation.zero_bits_loop_flag = false; |
| 2278 | 2448 | union_type->data.unionation.gen_field_count = gen_field_index; |
| 2279 | union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !auto_layout)); | |
| 2449 | union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !src_have_tag)); | |
| 2280 | 2450 | union_type->data.unionation.zero_bits_known = true; |
| 2281 | ||
| 2282 | // also compute abi_alignment | |
| 2283 | if (!union_type->zero_bits) { | |
| 2284 | union_type->data.unionation.abi_alignment = biggest_align_bytes; | |
| 2285 | } | |
| 2286 | 2451 | } |
| 2287 | 2452 | |
| 2288 | 2453 | static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) { |
| ... | ... | @@ -2741,7 +2906,6 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt |
| 2741 | 2906 | case TypeTableEntryIdUnion: |
| 2742 | 2907 | case TypeTableEntryIdFn: |
| 2743 | 2908 | case TypeTableEntryIdBoundFn: |
| 2744 | case TypeTableEntryIdEnumTag: | |
| 2745 | 2909 | return type_entry; |
| 2746 | 2910 | } |
| 2747 | 2911 | zig_unreachable(); |
| ... | ... | @@ -3158,13 +3322,37 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 3158 | 3322 | assert(type_entry->data.unionation.complete); |
| 3159 | 3323 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { |
| 3160 | 3324 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; |
| 3161 | if (buf_eql_buf(field->name, name)) { | |
| 3325 | if (buf_eql_buf(field->enum_field->name, name)) { | |
| 3162 | 3326 | return field; |
| 3163 | 3327 | } |
| 3164 | 3328 | } |
| 3165 | 3329 | return nullptr; |
| 3166 | 3330 | } |
| 3167 | 3331 | |
| 3332 | TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) { | |
| 3333 | assert(type_entry->id == TypeTableEntryIdUnion); | |
| 3334 | assert(type_entry->data.unionation.complete); | |
| 3335 | assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX); | |
| 3336 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { | |
| 3337 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; | |
| 3338 | if (bigint_cmp(&field->enum_field->value, tag) == CmpEQ) { | |
| 3339 | return field; | |
| 3340 | } | |
| 3341 | } | |
| 3342 | return nullptr; | |
| 3343 | } | |
| 3344 | ||
| 3345 | TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag) { | |
| 3346 | for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) { | |
| 3347 | TypeEnumField *field = &enum_type->data.enumeration.fields[i]; | |
| 3348 | if (bigint_cmp(&field->value, tag) == CmpEQ) { | |
| 3349 | return field; | |
| 3350 | } | |
| 3351 | } | |
| 3352 | return nullptr; | |
| 3353 | } | |
| 3354 | ||
| 3355 | ||
| 3168 | 3356 | static bool is_container(TypeTableEntry *type_entry) { |
| 3169 | 3357 | switch (type_entry->id) { |
| 3170 | 3358 | case TypeTableEntryIdInvalid: |
| ... | ... | @@ -3193,7 +3381,6 @@ static bool is_container(TypeTableEntry *type_entry) { |
| 3193 | 3381 | case TypeTableEntryIdNamespace: |
| 3194 | 3382 | case TypeTableEntryIdBlock: |
| 3195 | 3383 | case TypeTableEntryIdBoundFn: |
| 3196 | case TypeTableEntryIdEnumTag: | |
| 3197 | 3384 | case TypeTableEntryIdArgTuple: |
| 3198 | 3385 | case TypeTableEntryIdOpaque: |
| 3199 | 3386 | return false; |
| ... | ... | @@ -3244,7 +3431,6 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { |
| 3244 | 3431 | case TypeTableEntryIdBoundFn: |
| 3245 | 3432 | case TypeTableEntryIdInvalid: |
| 3246 | 3433 | case TypeTableEntryIdVar: |
| 3247 | case TypeTableEntryIdEnumTag: | |
| 3248 | 3434 | case TypeTableEntryIdArgTuple: |
| 3249 | 3435 | case TypeTableEntryIdOpaque: |
| 3250 | 3436 | zig_unreachable(); |
| ... | ... | @@ -3698,7 +3884,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 3698 | 3884 | case TypeTableEntryIdPointer: |
| 3699 | 3885 | case TypeTableEntryIdPureError: |
| 3700 | 3886 | case TypeTableEntryIdFn: |
| 3701 | case TypeTableEntryIdEnumTag: | |
| 3887 | case TypeTableEntryIdEnum: | |
| 3702 | 3888 | return false; |
| 3703 | 3889 | case TypeTableEntryIdArray: |
| 3704 | 3890 | case TypeTableEntryIdStruct: |
| ... | ... | @@ -3706,9 +3892,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 3706 | 3892 | return type_has_bits(type_entry); |
| 3707 | 3893 | case TypeTableEntryIdErrorUnion: |
| 3708 | 3894 | return type_has_bits(type_entry->data.error.child_type); |
| 3709 | case TypeTableEntryIdEnum: | |
| 3710 | assert(type_entry->data.enumeration.complete); | |
| 3711 | return type_entry->data.enumeration.gen_field_count != 0; | |
| 3712 | 3895 | case TypeTableEntryIdMaybe: |
| 3713 | 3896 | return type_has_bits(type_entry->data.maybe.child_type) && |
| 3714 | 3897 | type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer && |
| ... | ... | @@ -3850,7 +4033,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 3850 | 4033 | return (uint32_t)4149439618; |
| 3851 | 4034 | case TypeTableEntryIdInt: |
| 3852 | 4035 | case TypeTableEntryIdNumLitInt: |
| 3853 | case TypeTableEntryIdEnumTag: | |
| 3854 | 4036 | { |
| 3855 | 4037 | uint32_t result = 1331471175; |
| 3856 | 4038 | for (size_t i = 0; i < const_val->data.x_bigint.digit_count; i += 1) { |
| ... | ... | @@ -3859,6 +4041,15 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 3859 | 4041 | } |
| 3860 | 4042 | return result; |
| 3861 | 4043 | } |
| 4044 | case TypeTableEntryIdEnum: | |
| 4045 | { | |
| 4046 | uint32_t result = 31643936; | |
| 4047 | for (size_t i = 0; i < const_val->data.x_enum_tag.digit_count; i += 1) { | |
| 4048 | uint64_t digit = bigint_ptr(&const_val->data.x_enum_tag)[i]; | |
| 4049 | result ^= ((uint32_t)(digit >> 32)) ^ (uint32_t)(result); | |
| 4050 | } | |
| 4051 | return result; | |
| 4052 | } | |
| 3862 | 4053 | case TypeTableEntryIdFloat: |
| 3863 | 4054 | switch (const_val->type->data.floating.bit_count) { |
| 3864 | 4055 | case 32: |
| ... | ... | @@ -3959,9 +4150,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { |
| 3959 | 4150 | case TypeTableEntryIdPureError: |
| 3960 | 4151 | // TODO better hashing algorithm |
| 3961 | 4152 | return 2630160122; |
| 3962 | case TypeTableEntryIdEnum: | |
| 3963 | // TODO better hashing algorithm | |
| 3964 | return 31643936; | |
| 3965 | 4153 | case TypeTableEntryIdFn: |
| 3966 | 4154 | return 4133894920 ^ hash_ptr(const_val->data.x_fn.fn_entry); |
| 3967 | 4155 | case TypeTableEntryIdNamespace: |
| ... | ... | @@ -4094,7 +4282,6 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { |
| 4094 | 4282 | case TypeTableEntryIdInt: |
| 4095 | 4283 | case TypeTableEntryIdFloat: |
| 4096 | 4284 | case TypeTableEntryIdPointer: |
| 4097 | case TypeTableEntryIdEnumTag: | |
| 4098 | 4285 | case TypeTableEntryIdVoid: |
| 4099 | 4286 | case TypeTableEntryIdUnreachable: |
| 4100 | 4287 | return false; |
| ... | ... | @@ -4153,6 +4340,19 @@ ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *str) { |
| 4153 | 4340 | return const_val; |
| 4154 | 4341 | } |
| 4155 | 4342 | |
| 4343 | void init_const_bigint(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *bigint) { | |
| 4344 | const_val->special = ConstValSpecialStatic; | |
| 4345 | const_val->type = type; | |
| 4346 | bigint_init_bigint(&const_val->data.x_bigint, bigint); | |
| 4347 | } | |
| 4348 | ||
| 4349 | ConstExprValue *create_const_bigint(TypeTableEntry *type, const BigInt *bigint) { | |
| 4350 | ConstExprValue *const_val = create_const_vals(1); | |
| 4351 | init_const_bigint(const_val, type, bigint); | |
| 4352 | return const_val; | |
| 4353 | } | |
| 4354 | ||
| 4355 | ||
| 4156 | 4356 | void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative) { |
| 4157 | 4357 | const_val->special = ConstValSpecialStatic; |
| 4158 | 4358 | const_val->type = type; |
| ... | ... | @@ -4216,18 +4416,19 @@ ConstExprValue *create_const_float(TypeTableEntry *type, double value) { |
| 4216 | 4416 | return const_val; |
| 4217 | 4417 | } |
| 4218 | 4418 | |
| 4219 | void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, uint64_t tag) { | |
| 4419 | void init_const_enum(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag) { | |
| 4220 | 4420 | const_val->special = ConstValSpecialStatic; |
| 4221 | 4421 | const_val->type = type; |
| 4222 | const_val->data.x_enum.tag = tag; | |
| 4422 | bigint_init_bigint(&const_val->data.x_enum_tag, tag); | |
| 4223 | 4423 | } |
| 4224 | 4424 | |
| 4225 | ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag) { | |
| 4425 | ConstExprValue *create_const_enum(TypeTableEntry *type, const BigInt *tag) { | |
| 4226 | 4426 | ConstExprValue *const_val = create_const_vals(1); |
| 4227 | init_const_enum_tag(const_val, type, tag); | |
| 4427 | init_const_enum(const_val, type, tag); | |
| 4228 | 4428 | return const_val; |
| 4229 | 4429 | } |
| 4230 | 4430 | |
| 4431 | ||
| 4231 | 4432 | void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value) { |
| 4232 | 4433 | const_val->special = ConstValSpecialStatic; |
| 4233 | 4434 | const_val->type = g->builtin_types.entry_bool; |
| ... | ... | @@ -4426,19 +4627,22 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { |
| 4426 | 4627 | case TypeTableEntryIdOpaque: |
| 4427 | 4628 | zig_unreachable(); |
| 4428 | 4629 | case TypeTableEntryIdEnum: |
| 4429 | { | |
| 4430 | ConstEnumValue *enum1 = &a->data.x_enum; | |
| 4431 | ConstEnumValue *enum2 = &b->data.x_enum; | |
| 4432 | if (enum1->tag == enum2->tag) { | |
| 4433 | TypeEnumField *enum_field = &a->type->data.enumeration.fields[enum1->tag]; | |
| 4434 | if (type_has_bits(enum_field->type_entry)) { | |
| 4435 | zig_panic("TODO const expr analyze enum special value for equality"); | |
| 4436 | } else { | |
| 4437 | return true; | |
| 4438 | } | |
| 4630 | return bigint_cmp(&a->data.x_enum_tag, &b->data.x_enum_tag) == CmpEQ; | |
| 4631 | case TypeTableEntryIdUnion: { | |
| 4632 | ConstUnionValue *union1 = &a->data.x_union; | |
| 4633 | ConstUnionValue *union2 = &b->data.x_union; | |
| 4634 | ||
| 4635 | if (bigint_cmp(&union1->tag, &union2->tag) == CmpEQ) { | |
| 4636 | TypeUnionField *field = find_union_field_by_tag(a->type, &union1->tag); | |
| 4637 | assert(field != nullptr); | |
| 4638 | if (type_has_bits(field->type_entry)) { | |
| 4639 | zig_panic("TODO const expr analyze union field value for equality"); | |
| 4640 | } else { | |
| 4641 | return true; | |
| 4439 | 4642 | } |
| 4440 | return false; | |
| 4441 | 4643 | } |
| 4644 | return false; | |
| 4645 | } | |
| 4442 | 4646 | case TypeTableEntryIdMetaType: |
| 4443 | 4647 | return a->data.x_type == b->data.x_type; |
| 4444 | 4648 | case TypeTableEntryIdVoid: |
| ... | ... | @@ -4465,7 +4669,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { |
| 4465 | 4669 | return bigfloat_cmp(&a->data.x_bigfloat, &b->data.x_bigfloat) == CmpEQ; |
| 4466 | 4670 | case TypeTableEntryIdInt: |
| 4467 | 4671 | case TypeTableEntryIdNumLitInt: |
| 4468 | case TypeTableEntryIdEnumTag: | |
| 4469 | 4672 | return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ; |
| 4470 | 4673 | case TypeTableEntryIdPointer: |
| 4471 | 4674 | if (a->data.x_ptr.special != b->data.x_ptr.special) |
| ... | ... | @@ -4519,8 +4722,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { |
| 4519 | 4722 | return false; |
| 4520 | 4723 | } |
| 4521 | 4724 | return true; |
| 4522 | case TypeTableEntryIdUnion: | |
| 4523 | zig_panic("TODO"); | |
| 4524 | 4725 | case TypeTableEntryIdUndefLit: |
| 4525 | 4726 | zig_panic("TODO"); |
| 4526 | 4727 | case TypeTableEntryIdNullLit: |
| ... | ... | @@ -4664,7 +4865,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 4664 | 4865 | buf_appendf(buf, "%s", buf_ptr(&const_val->data.x_type->name)); |
| 4665 | 4866 | return; |
| 4666 | 4867 | case TypeTableEntryIdUnreachable: |
| 4667 | buf_appendf(buf, "@unreachable()"); | |
| 4868 | buf_appendf(buf, "unreachable"); | |
| 4668 | 4869 | return; |
| 4669 | 4870 | case TypeTableEntryIdBool: |
| 4670 | 4871 | { |
| ... | ... | @@ -4794,7 +4995,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 4794 | 4995 | } |
| 4795 | 4996 | case TypeTableEntryIdEnum: |
| 4796 | 4997 | { |
| 4797 | buf_appendf(buf, "(enum %s constant)", buf_ptr(&type_entry->name)); | |
| 4998 | TypeEnumField *field = find_enum_field_by_tag(type_entry, &const_val->data.x_enum_tag); | |
| 4999 | buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(field->name)); | |
| 4798 | 5000 | return; |
| 4799 | 5001 | } |
| 4800 | 5002 | case TypeTableEntryIdErrorUnion: |
| ... | ... | @@ -4812,14 +5014,6 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 4812 | 5014 | buf_appendf(buf, "(pure error constant)"); |
| 4813 | 5015 | return; |
| 4814 | 5016 | } |
| 4815 | case TypeTableEntryIdEnumTag: | |
| 4816 | { | |
| 4817 | TypeTableEntry *enum_type = type_entry->data.enum_tag.enum_type; | |
| 4818 | size_t field_index = bigint_as_unsigned(&const_val->data.x_bigint); | |
| 4819 | TypeEnumField *field = &enum_type->data.enumeration.fields[field_index]; | |
| 4820 | buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name)); | |
| 4821 | return; | |
| 4822 | } | |
| 4823 | 5017 | case TypeTableEntryIdArgTuple: |
| 4824 | 5018 | { |
| 4825 | 5019 | buf_appendf(buf, "(args value)"); |
| ... | ... | @@ -4830,11 +5024,10 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 4830 | 5024 | } |
| 4831 | 5025 | |
| 4832 | 5026 | TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { |
| 4833 | assert(size_in_bits > 0); | |
| 4834 | ||
| 4835 | 5027 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); |
| 4836 | 5028 | entry->is_copyable = true; |
| 4837 | entry->type_ref = LLVMIntType(size_in_bits); | |
| 5029 | entry->type_ref = (size_in_bits == 0) ? LLVMVoidType() : LLVMIntType(size_in_bits); | |
| 5030 | entry->zero_bits = (size_in_bits == 0); | |
| 4838 | 5031 | |
| 4839 | 5032 | const char u_or_i = is_signed ? 'i' : 'u'; |
| 4840 | 5033 | buf_resize(&entry->name, 0); |
| ... | ... | @@ -4855,7 +5048,8 @@ TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) |
| 4855 | 5048 | } |
| 4856 | 5049 | } |
| 4857 | 5050 | |
| 4858 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); | |
| 5051 | uint64_t debug_size_in_bits = (size_in_bits == 0) ? | |
| 5052 | 0 : (8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref)); | |
| 4859 | 5053 | entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), debug_size_in_bits, dwarf_tag); |
| 4860 | 5054 | entry->data.integral.is_signed = is_signed; |
| 4861 | 5055 | entry->data.integral.bit_count = size_in_bits; |
| ... | ... | @@ -4881,7 +5075,6 @@ uint32_t type_id_hash(TypeId x) { |
| 4881 | 5075 | case TypeTableEntryIdErrorUnion: |
| 4882 | 5076 | case TypeTableEntryIdPureError: |
| 4883 | 5077 | case TypeTableEntryIdEnum: |
| 4884 | case TypeTableEntryIdEnumTag: | |
| 4885 | 5078 | case TypeTableEntryIdUnion: |
| 4886 | 5079 | case TypeTableEntryIdFn: |
| 4887 | 5080 | case TypeTableEntryIdNamespace: |
| ... | ... | @@ -4926,7 +5119,6 @@ bool type_id_eql(TypeId a, TypeId b) { |
| 4926 | 5119 | case TypeTableEntryIdErrorUnion: |
| 4927 | 5120 | case TypeTableEntryIdPureError: |
| 4928 | 5121 | case TypeTableEntryIdEnum: |
| 4929 | case TypeTableEntryIdEnumTag: | |
| 4930 | 5122 | case TypeTableEntryIdUnion: |
| 4931 | 5123 | case TypeTableEntryIdFn: |
| 4932 | 5124 | case TypeTableEntryIdNamespace: |
| ... | ... | @@ -5041,7 +5233,6 @@ static const TypeTableEntryId all_type_ids[] = { |
| 5041 | 5233 | TypeTableEntryIdErrorUnion, |
| 5042 | 5234 | TypeTableEntryIdPureError, |
| 5043 | 5235 | TypeTableEntryIdEnum, |
| 5044 | TypeTableEntryIdEnumTag, | |
| 5045 | 5236 | TypeTableEntryIdUnion, |
| 5046 | 5237 | TypeTableEntryIdFn, |
| 5047 | 5238 | TypeTableEntryIdNamespace, |
| ... | ... | @@ -5099,22 +5290,20 @@ size_t type_id_index(TypeTableEntryId id) { |
| 5099 | 5290 | return 15; |
| 5100 | 5291 | case TypeTableEntryIdEnum: |
| 5101 | 5292 | return 16; |
| 5102 | case TypeTableEntryIdEnumTag: | |
| 5103 | return 17; | |
| 5104 | 5293 | case TypeTableEntryIdUnion: |
| 5105 | return 18; | |
| 5294 | return 17; | |
| 5106 | 5295 | case TypeTableEntryIdFn: |
| 5107 | return 19; | |
| 5296 | return 18; | |
| 5108 | 5297 | case TypeTableEntryIdNamespace: |
| 5109 | return 20; | |
| 5298 | return 19; | |
| 5110 | 5299 | case TypeTableEntryIdBlock: |
| 5111 | return 21; | |
| 5300 | return 20; | |
| 5112 | 5301 | case TypeTableEntryIdBoundFn: |
| 5113 | return 22; | |
| 5302 | return 21; | |
| 5114 | 5303 | case TypeTableEntryIdArgTuple: |
| 5115 | return 23; | |
| 5304 | return 22; | |
| 5116 | 5305 | case TypeTableEntryIdOpaque: |
| 5117 | return 24; | |
| 5306 | return 23; | |
| 5118 | 5307 | } |
| 5119 | 5308 | zig_unreachable(); |
| 5120 | 5309 | } |
| ... | ... | @@ -5158,8 +5347,6 @@ const char *type_id_name(TypeTableEntryId id) { |
| 5158 | 5347 | return "Error"; |
| 5159 | 5348 | case TypeTableEntryIdEnum: |
| 5160 | 5349 | return "Enum"; |
| 5161 | case TypeTableEntryIdEnumTag: | |
| 5162 | return "EnumTag"; | |
| 5163 | 5350 | case TypeTableEntryIdUnion: |
| 5164 | 5351 | return "Union"; |
| 5165 | 5352 | case TypeTableEntryIdFn: |
| ... | ... | @@ -5226,9 +5413,6 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { |
| 5226 | 5413 | if (type_entry->id == TypeTableEntryIdStruct) { |
| 5227 | 5414 | assert(type_entry->data.structure.abi_alignment != 0); |
| 5228 | 5415 | return type_entry->data.structure.abi_alignment; |
| 5229 | } else if (type_entry->id == TypeTableEntryIdEnum) { | |
| 5230 | assert(type_entry->data.enumeration.abi_alignment != 0); | |
| 5231 | return type_entry->data.enumeration.abi_alignment; | |
| 5232 | 5416 | } else if (type_entry->id == TypeTableEntryIdUnion) { |
| 5233 | 5417 | assert(type_entry->data.unionation.abi_alignment != 0); |
| 5234 | 5418 | return type_entry->data.unionation.abi_alignment; |
src/analyze.hpp+8-3| ... | ... | @@ -64,6 +64,9 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name); |
| 64 | 64 | ScopeDecls *get_container_scope(TypeTableEntry *type_entry); |
| 65 | 65 | TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name); |
| 66 | 66 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name); |
| 67 | TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag); | |
| 68 | TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag); | |
| 69 | ||
| 67 | 70 | bool is_container_ref(TypeTableEntry *type_entry); |
| 68 | 71 | void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); |
| 69 | 72 | void scan_import(CodeGen *g, ImportTableEntry *import); |
| ... | ... | @@ -109,6 +112,9 @@ ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); |
| 109 | 112 | void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *c_str); |
| 110 | 113 | ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *c_str); |
| 111 | 114 | |
| 115 | void init_const_bigint(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *bigint); | |
| 116 | ConstExprValue *create_const_bigint(TypeTableEntry *type, const BigInt *bigint); | |
| 117 | ||
| 112 | 118 | void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative); |
| 113 | 119 | ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative); |
| 114 | 120 | |
| ... | ... | @@ -121,8 +127,8 @@ ConstExprValue *create_const_usize(CodeGen *g, uint64_t x); |
| 121 | 127 | void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value); |
| 122 | 128 | ConstExprValue *create_const_float(TypeTableEntry *type, double value); |
| 123 | 129 | |
| 124 | void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, uint64_t tag); | |
| 125 | ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag); | |
| 130 | void init_const_enum(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag); | |
| 131 | ConstExprValue *create_const_enum(TypeTableEntry *type, const BigInt *tag); | |
| 126 | 132 | |
| 127 | 133 | void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value); |
| 128 | 134 | ConstExprValue *create_const_bool(CodeGen *g, bool value); |
| ... | ... | @@ -158,7 +164,6 @@ ConstExprValue *create_const_vals(size_t count); |
| 158 | 164 | |
| 159 | 165 | TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); |
| 160 | 166 | ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value); |
| 161 | TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, TypeTableEntry *int_type); | |
| 162 | 167 | void expand_undef_array(CodeGen *g, ConstExprValue *const_val); |
| 163 | 168 | void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value); |
| 164 | 169 |
src/ast_render.cpp+18-1| ... | ... | @@ -660,7 +660,20 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 660 | 660 | { |
| 661 | 661 | const char *layout_str = layout_string(node->data.container_decl.layout); |
| 662 | 662 | const char *container_str = container_string(node->data.container_decl.kind); |
| 663 | fprintf(ar->f, "%s%s {\n", layout_str, container_str); | |
| 663 | fprintf(ar->f, "%s%s", layout_str, container_str); | |
| 664 | if (node->data.container_decl.auto_enum) { | |
| 665 | fprintf(ar->f, "(enum"); | |
| 666 | } | |
| 667 | if (node->data.container_decl.init_arg_expr != nullptr) { | |
| 668 | fprintf(ar->f, "("); | |
| 669 | render_node_grouped(ar, node->data.container_decl.init_arg_expr); | |
| 670 | fprintf(ar->f, ")"); | |
| 671 | } | |
| 672 | if (node->data.container_decl.auto_enum) { | |
| 673 | fprintf(ar->f, ")"); | |
| 674 | } | |
| 675 | ||
| 676 | fprintf(ar->f, " {\n"); | |
| 664 | 677 | ar->indent += ar->indent_size; |
| 665 | 678 | for (size_t field_i = 0; field_i < node->data.container_decl.fields.length; field_i += 1) { |
| 666 | 679 | 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) { |
| 671 | 684 | fprintf(ar->f, ": "); |
| 672 | 685 | render_node_grouped(ar, field_node->data.struct_field.type); |
| 673 | 686 | } |
| 687 | if (field_node->data.struct_field.value != nullptr) { | |
| 688 | fprintf(ar->f, "= "); | |
| 689 | render_node_grouped(ar, field_node->data.struct_field.value); | |
| 690 | } | |
| 674 | 691 | fprintf(ar->f, ",\n"); |
| 675 | 692 | } |
| 676 | 693 |
src/bigint.cpp+32| ... | ... | @@ -1224,3 +1224,35 @@ Cmp bigint_cmp_zero(const BigInt *op) { |
| 1224 | 1224 | } |
| 1225 | 1225 | return op->is_negative ? CmpLT : CmpGT; |
| 1226 | 1226 | } |
| 1227 | ||
| 1228 | uint32_t bigint_hash(BigInt x) { | |
| 1229 | if (x.digit_count == 0) { | |
| 1230 | return 0; | |
| 1231 | } else { | |
| 1232 | return bigint_ptr(&x)[0]; | |
| 1233 | } | |
| 1234 | } | |
| 1235 | ||
| 1236 | bool bigint_eql(BigInt a, BigInt b) { | |
| 1237 | return bigint_cmp(&a, &b) == CmpEQ; | |
| 1238 | } | |
| 1239 | ||
| 1240 | void bigint_incr(BigInt *x) { | |
| 1241 | if (x->digit_count == 0) { | |
| 1242 | bigint_init_unsigned(x, 1); | |
| 1243 | return; | |
| 1244 | } | |
| 1245 | ||
| 1246 | if (x->digit_count == 1 && x->data.digit != UINT64_MAX) { | |
| 1247 | x->data.digit += 1; | |
| 1248 | return; | |
| 1249 | } | |
| 1250 | ||
| 1251 | BigInt copy; | |
| 1252 | bigint_init_bigint(&copy, x); | |
| 1253 | ||
| 1254 | BigInt one; | |
| 1255 | bigint_init_unsigned(&one, 1); | |
| 1256 | ||
| 1257 | bigint_add(x, &copy, &one); | |
| 1258 | } |
src/bigint.hpp+5| ... | ... | @@ -88,6 +88,11 @@ size_t bigint_bits_needed(const BigInt *op); |
| 88 | 88 | // convenience functions |
| 89 | 89 | Cmp bigint_cmp_zero(const BigInt *op); |
| 90 | 90 | |
| 91 | void bigint_incr(BigInt *value); | |
| 92 | ||
| 91 | 93 | bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result); |
| 92 | 94 | |
| 95 | uint32_t bigint_hash(BigInt x); | |
| 96 | bool bigint_eql(BigInt a, BigInt b); | |
| 97 | ||
| 93 | 98 | #endif |
src/codegen.cpp+105-180| ... | ... | @@ -1362,8 +1362,12 @@ static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) { |
| 1362 | 1362 | if (bigint->digit_count == 0) { |
| 1363 | 1363 | return LLVMConstNull(type_ref); |
| 1364 | 1364 | } |
| 1365 | LLVMValueRef unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref, | |
| 1366 | bigint->digit_count, bigint_ptr(bigint)); | |
| 1365 | LLVMValueRef unsigned_val; | |
| 1366 | if (bigint->digit_count == 1) { | |
| 1367 | unsigned_val = LLVMConstInt(type_ref, bigint_ptr(bigint)[0], false); | |
| 1368 | } else { | |
| 1369 | unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref, bigint->digit_count, bigint_ptr(bigint)); | |
| 1370 | } | |
| 1367 | 1371 | if (bigint->is_negative) { |
| 1368 | 1372 | return LLVMConstNeg(unsigned_val); |
| 1369 | 1373 | } else { |
| ... | ... | @@ -1627,12 +1631,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable, |
| 1627 | 1631 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed); |
| 1628 | 1632 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); |
| 1629 | 1633 | } else if (type_entry->id == TypeTableEntryIdEnum) { |
| 1630 | if (type_entry->data.enumeration.gen_field_count == 0) { | |
| 1631 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); | |
| 1632 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); | |
| 1633 | } else { | |
| 1634 | zig_unreachable(); | |
| 1635 | } | |
| 1634 | LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false); | |
| 1635 | return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, ""); | |
| 1636 | 1636 | } else if (type_entry->id == TypeTableEntryIdPureError || |
| 1637 | 1637 | type_entry->id == TypeTableEntryIdPointer || |
| 1638 | 1638 | type_entry->id == TypeTableEntryIdBool) |
| ... | ... | @@ -1916,9 +1916,7 @@ static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executa |
| 1916 | 1916 | // enum_tag to the underlying int type |
| 1917 | 1917 | TypeTableEntry *int_type; |
| 1918 | 1918 | if (actual_type->id == TypeTableEntryIdEnum) { |
| 1919 | TypeTableEntry *tag_type = actual_type->data.enumeration.tag_type; | |
| 1920 | assert(tag_type->id == TypeTableEntryIdEnumTag); | |
| 1921 | int_type = tag_type->data.enum_tag.int_type; | |
| 1919 | int_type = actual_type->data.enumeration.tag_int_type; | |
| 1922 | 1920 | } else { |
| 1923 | 1921 | int_type = actual_type; |
| 1924 | 1922 | } |
| ... | ... | @@ -1942,19 +1940,11 @@ static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, I |
| 1942 | 1940 | static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, IrInstructionIntToEnum *instruction) { |
| 1943 | 1941 | TypeTableEntry *wanted_type = instruction->base.value.type; |
| 1944 | 1942 | assert(wanted_type->id == TypeTableEntryIdEnum); |
| 1945 | TypeTableEntry *tag_type = wanted_type->data.enumeration.tag_type; | |
| 1946 | TypeTableEntry *wanted_int_type; | |
| 1947 | if (tag_type->id == TypeTableEntryIdEnumTag) { | |
| 1948 | wanted_int_type = tag_type->data.enum_tag.int_type; | |
| 1949 | } else if (tag_type->id == TypeTableEntryIdInt) { | |
| 1950 | wanted_int_type = tag_type; | |
| 1951 | } else { | |
| 1952 | zig_unreachable(); | |
| 1953 | } | |
| 1943 | TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type; | |
| 1954 | 1944 | |
| 1955 | 1945 | LLVMValueRef target_val = ir_llvm_value(g, instruction->target); |
| 1956 | 1946 | return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base), |
| 1957 | instruction->target->value.type, wanted_int_type, target_val); | |
| 1947 | instruction->target->value.type, tag_int_type, target_val); | |
| 1958 | 1948 | } |
| 1959 | 1949 | |
| 1960 | 1950 | 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 |
| 2374 | 2364 | return LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, ""); |
| 2375 | 2365 | } |
| 2376 | 2366 | |
| 2377 | static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable, | |
| 2378 | IrInstructionEnumFieldPtr *instruction) | |
| 2379 | { | |
| 2380 | TypeTableEntry *enum_ptr_type = instruction->enum_ptr->value.type; | |
| 2381 | assert(enum_ptr_type->id == TypeTableEntryIdPointer); | |
| 2382 | TypeTableEntry *enum_type = enum_ptr_type->data.pointer.child_type; | |
| 2383 | assert(enum_type->id == TypeTableEntryIdEnum); | |
| 2384 | ||
| 2385 | TypeEnumField *field = instruction->field; | |
| 2386 | ||
| 2387 | if (!type_has_bits(field->type_entry)) | |
| 2388 | return nullptr; | |
| 2389 | ||
| 2390 | LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr); | |
| 2391 | LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0); | |
| 2392 | LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_type->data.enumeration.gen_union_index, ""); | |
| 2393 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); | |
| 2394 | ||
| 2395 | return bitcasted_union_field_ptr; | |
| 2396 | } | |
| 2397 | ||
| 2398 | 2367 | static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable, |
| 2399 | 2368 | IrInstructionUnionFieldPtr *instruction) |
| 2400 | 2369 | { |
| ... | ... | @@ -2420,9 +2389,10 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab |
| 2420 | 2389 | if (ir_want_debug_safety(g, &instruction->base)) { |
| 2421 | 2390 | LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, ""); |
| 2422 | 2391 | LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, ""); |
| 2423 | LLVMValueRef expected_tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref, | |
| 2424 | field->value, false); | |
| 2425 | 2392 | |
| 2393 | ||
| 2394 | LLVMValueRef expected_tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref, | |
| 2395 | &field->enum_field->value); | |
| 2426 | 2396 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk"); |
| 2427 | 2397 | LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail"); |
| 2428 | 2398 | 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 |
| 2747 | 2717 | } |
| 2748 | 2718 | |
| 2749 | 2719 | static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable, |
| 2750 | IrInstructionEnumTagName *instruction) | |
| 2720 | IrInstructionTagName *instruction) | |
| 2751 | 2721 | { |
| 2752 | TypeTableEntry *enum_tag_type = instruction->target->value.type; | |
| 2753 | assert(enum_tag_type->data.enum_tag.generate_name_table); | |
| 2722 | TypeTableEntry *enum_type = instruction->target->value.type; | |
| 2723 | assert(enum_type->id == TypeTableEntryIdEnum); | |
| 2724 | assert(enum_type->data.enumeration.generate_name_table); | |
| 2754 | 2725 | |
| 2726 | TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type; | |
| 2755 | 2727 | LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); |
| 2756 | 2728 | if (ir_want_debug_safety(g, &instruction->base)) { |
| 2757 | TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type; | |
| 2758 | 2729 | size_t field_count = enum_type->data.enumeration.src_field_count; |
| 2759 | 2730 | |
| 2760 | // if the field_count can't fit in the bits of the enum_tag_type, then it can't possibly | |
| 2731 | // if the field_count can't fit in the bits of the enum_type, then it can't possibly | |
| 2761 | 2732 | // be the wrong value |
| 2762 | 2733 | BigInt field_bi; |
| 2763 | 2734 | bigint_init_unsigned(&field_bi, field_count); |
| 2764 | TypeTableEntry *tag_int_type = enum_tag_type->data.enum_tag.int_type; | |
| 2765 | 2735 | if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) { |
| 2766 | 2736 | LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false); |
| 2767 | 2737 | 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 |
| 2770 | 2740 | |
| 2771 | 2741 | LLVMValueRef indices[] = { |
| 2772 | 2742 | LLVMConstNull(g->builtin_types.entry_usize->type_ref), |
| 2773 | gen_widen_or_shorten(g, false, enum_tag_type->data.enum_tag.int_type, | |
| 2743 | gen_widen_or_shorten(g, false, tag_int_type, | |
| 2774 | 2744 | g->builtin_types.entry_usize, enum_tag_value), |
| 2775 | 2745 | }; |
| 2776 | return LLVMBuildInBoundsGEP(g->builder, enum_tag_type->data.enum_tag.name_table, indices, 2, ""); | |
| 2746 | return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, ""); | |
| 2777 | 2747 | } |
| 2778 | 2748 | |
| 2779 | 2749 | 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 |
| 3347 | 3317 | return instruction->tmp_ptr; |
| 3348 | 3318 | } |
| 3349 | 3319 | |
| 3350 | static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrInstructionEnumTag *instruction) { | |
| 3351 | TypeTableEntry *enum_type = instruction->value->value.type; | |
| 3352 | TypeTableEntry *tag_type = enum_type->data.enumeration.tag_type; | |
| 3320 | static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) { | |
| 3321 | TypeTableEntry *union_type = instruction->value->value.type; | |
| 3322 | assert(union_type->data.unionation.gen_tag_index != SIZE_MAX); | |
| 3323 | ||
| 3324 | TypeTableEntry *tag_type = union_type->data.unionation.tag_type; | |
| 3353 | 3325 | if (!type_has_bits(tag_type)) |
| 3354 | 3326 | return nullptr; |
| 3355 | 3327 | |
| 3356 | LLVMValueRef enum_val = ir_llvm_value(g, instruction->value); | |
| 3357 | if (enum_type->data.enumeration.gen_field_count == 0) | |
| 3358 | return enum_val; | |
| 3328 | LLVMValueRef union_val = ir_llvm_value(g, instruction->value); | |
| 3329 | if (union_type->data.unionation.gen_field_count == 0) | |
| 3330 | return union_val; | |
| 3359 | 3331 | |
| 3360 | LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_type->data.enumeration.gen_tag_index, ""); | |
| 3332 | LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_val, | |
| 3333 | union_type->data.unionation.gen_tag_index, ""); | |
| 3361 | 3334 | TypeTableEntry *ptr_type = get_pointer_to_type(g, tag_type, false); |
| 3362 | 3335 | return get_handle_value(g, tag_field_ptr, tag_type, ptr_type); |
| 3363 | 3336 | } |
| 3364 | 3337 | |
| 3365 | static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) { | |
| 3366 | TypeTableEntry *enum_type = instruction->enum_type; | |
| 3367 | uint32_t value = instruction->field->value; | |
| 3368 | LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref; | |
| 3369 | LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, value, false); | |
| 3370 | ||
| 3371 | if (enum_type->data.enumeration.gen_field_count == 0) | |
| 3372 | return tag_value; | |
| 3373 | ||
| 3374 | LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr; | |
| 3375 | ||
| 3376 | LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_tag_index, ""); | |
| 3377 | gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); | |
| 3378 | ||
| 3379 | TypeTableEntry *union_val_type = instruction->field->type_entry; | |
| 3380 | if (type_has_bits(union_val_type)) { | |
| 3381 | LLVMValueRef new_union_val = ir_llvm_value(g, instruction->init_value); | |
| 3382 | LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_union_index, ""); | |
| 3383 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, | |
| 3384 | LLVMPointerType(union_val_type->type_ref, 0), ""); | |
| 3385 | ||
| 3386 | gen_assign_raw(g, bitcasted_union_field_ptr, get_pointer_to_type(g, union_val_type, false), new_union_val); | |
| 3387 | } | |
| 3388 | ||
| 3389 | return tmp_struct_ptr; | |
| 3390 | } | |
| 3391 | ||
| 3392 | 3338 | static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) { |
| 3393 | 3339 | for (size_t i = 0; i < instruction->field_count; i += 1) { |
| 3394 | 3340 | IrInstructionStructInitField *field = &instruction->fields[i]; |
| ... | ... | @@ -3429,8 +3375,9 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I |
| 3429 | 3375 | if (union_type->data.unionation.gen_tag_index != SIZE_MAX) { |
| 3430 | 3376 | LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, |
| 3431 | 3377 | union_type->data.unionation.gen_tag_index, ""); |
| 3432 | LLVMValueRef tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref, | |
| 3433 | type_union_field->value, false); | |
| 3378 | ||
| 3379 | LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref, | |
| 3380 | &type_union_field->enum_field->value); | |
| 3434 | 3381 | gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); |
| 3435 | 3382 | |
| 3436 | 3383 | uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, |
| ... | ... | @@ -3537,6 +3484,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3537 | 3484 | case IrInstructionIdOpaqueType: |
| 3538 | 3485 | case IrInstructionIdSetAlignStack: |
| 3539 | 3486 | case IrInstructionIdArgType: |
| 3487 | case IrInstructionIdTagType: | |
| 3540 | 3488 | zig_unreachable(); |
| 3541 | 3489 | case IrInstructionIdReturn: |
| 3542 | 3490 | return ir_render_return(g, executable, (IrInstructionReturn *)instruction); |
| ... | ... | @@ -3566,8 +3514,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3566 | 3514 | return ir_render_call(g, executable, (IrInstructionCall *)instruction); |
| 3567 | 3515 | case IrInstructionIdStructFieldPtr: |
| 3568 | 3516 | return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); |
| 3569 | case IrInstructionIdEnumFieldPtr: | |
| 3570 | return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction); | |
| 3571 | 3517 | case IrInstructionIdUnionFieldPtr: |
| 3572 | 3518 | return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction); |
| 3573 | 3519 | case IrInstructionIdAsm: |
| ... | ... | @@ -3622,10 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3622 | 3568 | return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction); |
| 3623 | 3569 | case IrInstructionIdErrWrapPayload: |
| 3624 | 3570 | return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction); |
| 3625 | case IrInstructionIdEnumTag: | |
| 3626 | return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction); | |
| 3627 | case IrInstructionIdInitEnum: | |
| 3628 | return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); | |
| 3571 | case IrInstructionIdUnionTag: | |
| 3572 | return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction); | |
| 3629 | 3573 | case IrInstructionIdStructInit: |
| 3630 | 3574 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); |
| 3631 | 3575 | case IrInstructionIdUnionInit: |
| ... | ... | @@ -3650,8 +3594,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3650 | 3594 | return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction); |
| 3651 | 3595 | case IrInstructionIdPanic: |
| 3652 | 3596 | return ir_render_panic(g, executable, (IrInstructionPanic *)instruction); |
| 3653 | case IrInstructionIdEnumTagName: | |
| 3654 | return ir_render_enum_tag_name(g, executable, (IrInstructionEnumTagName *)instruction); | |
| 3597 | case IrInstructionIdTagName: | |
| 3598 | return ir_render_enum_tag_name(g, executable, (IrInstructionTagName *)instruction); | |
| 3655 | 3599 | case IrInstructionIdFieldParentPtr: |
| 3656 | 3600 | return ir_render_field_parent_ptr(g, executable, (IrInstructionFieldParentPtr *)instruction); |
| 3657 | 3601 | case IrInstructionIdAlignCast: |
| ... | ... | @@ -3761,8 +3705,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con |
| 3761 | 3705 | case TypeTableEntryIdNullLit: |
| 3762 | 3706 | case TypeTableEntryIdErrorUnion: |
| 3763 | 3707 | case TypeTableEntryIdPureError: |
| 3764 | case TypeTableEntryIdEnum: | |
| 3765 | case TypeTableEntryIdEnumTag: | |
| 3766 | 3708 | case TypeTableEntryIdNamespace: |
| 3767 | 3709 | case TypeTableEntryIdBlock: |
| 3768 | 3710 | case TypeTableEntryIdBoundFn: |
| ... | ... | @@ -3772,6 +3714,12 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con |
| 3772 | 3714 | zig_unreachable(); |
| 3773 | 3715 | case TypeTableEntryIdBool: |
| 3774 | 3716 | return LLVMConstInt(big_int_type_ref, const_val->data.x_bool ? 1 : 0, false); |
| 3717 | case TypeTableEntryIdEnum: | |
| 3718 | { | |
| 3719 | assert(type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr); | |
| 3720 | LLVMValueRef int_val = gen_const_val(g, const_val); | |
| 3721 | return LLVMConstZExt(int_val, big_int_type_ref); | |
| 3722 | } | |
| 3775 | 3723 | case TypeTableEntryIdInt: |
| 3776 | 3724 | { |
| 3777 | 3725 | 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 |
| 3813 | 3761 | } |
| 3814 | 3762 | return val; |
| 3815 | 3763 | } |
| 3764 | ||
| 3816 | 3765 | } |
| 3817 | 3766 | zig_unreachable(); |
| 3818 | 3767 | } |
| ... | ... | @@ -3838,7 +3787,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3838 | 3787 | |
| 3839 | 3788 | switch (type_entry->id) { |
| 3840 | 3789 | case TypeTableEntryIdInt: |
| 3841 | case TypeTableEntryIdEnumTag: | |
| 3842 | 3790 | return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint); |
| 3843 | 3791 | case TypeTableEntryIdPureError: |
| 3844 | 3792 | assert(const_val->data.x_pure_err); |
| ... | ... | @@ -4001,37 +3949,52 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 4001 | 3949 | ConstExprValue *payload_value = const_val->data.x_union.payload; |
| 4002 | 3950 | assert(payload_value != nullptr); |
| 4003 | 3951 | |
| 4004 | if (!type_has_bits(payload_value->type)) { | |
| 4005 | return LLVMGetUndef(union_type_ref); | |
| 3952 | if (type_entry->data.unionation.gen_field_count == 0) { | |
| 3953 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { | |
| 3954 | return nullptr; | |
| 3955 | } else { | |
| 3956 | return bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref, | |
| 3957 | &const_val->data.x_union.tag); | |
| 3958 | } | |
| 4006 | 3959 | } |
| 4007 | 3960 | |
| 4008 | uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref); | |
| 4009 | uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes; | |
| 4010 | LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value); | |
| 4011 | bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) || | |
| 4012 | payload_value->type != type_entry->data.unionation.most_aligned_union_member; | |
| 4013 | ||
| 4014 | 3961 | LLVMValueRef union_value_ref; |
| 4015 | { | |
| 4016 | if (pad_bytes == 0) { | |
| 4017 | union_value_ref = correctly_typed_value; | |
| 4018 | } else { | |
| 4019 | LLVMValueRef fields[2]; | |
| 4020 | fields[0] = correctly_typed_value; | |
| 4021 | fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)); | |
| 4022 | if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) { | |
| 4023 | union_value_ref = LLVMConstStruct(fields, 2, false); | |
| 3962 | bool make_unnamed_struct; | |
| 3963 | if (!type_has_bits(payload_value->type)) { | |
| 3964 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) | |
| 3965 | return LLVMGetUndef(type_entry->type_ref); | |
| 3966 | ||
| 3967 | union_value_ref = LLVMGetUndef(type_entry->data.unionation.most_aligned_union_member->type_ref); | |
| 3968 | make_unnamed_struct = false; | |
| 3969 | } else { | |
| 3970 | uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref); | |
| 3971 | uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes; | |
| 3972 | LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value); | |
| 3973 | make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) || | |
| 3974 | payload_value->type != type_entry->data.unionation.most_aligned_union_member; | |
| 3975 | ||
| 3976 | { | |
| 3977 | if (pad_bytes == 0) { | |
| 3978 | union_value_ref = correctly_typed_value; | |
| 4024 | 3979 | } else { |
| 4025 | union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2); | |
| 3980 | LLVMValueRef fields[2]; | |
| 3981 | fields[0] = correctly_typed_value; | |
| 3982 | fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)); | |
| 3983 | if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) { | |
| 3984 | union_value_ref = LLVMConstStruct(fields, 2, false); | |
| 3985 | } else { | |
| 3986 | union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2); | |
| 3987 | } | |
| 4026 | 3988 | } |
| 4027 | 3989 | } |
| 4028 | } | |
| 4029 | 3990 | |
| 4030 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { | |
| 4031 | return union_value_ref; | |
| 3991 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { | |
| 3992 | return union_value_ref; | |
| 3993 | } | |
| 4032 | 3994 | } |
| 4033 | 3995 | |
| 4034 | LLVMValueRef tag_value = LLVMConstInt(type_entry->data.unionation.tag_type->type_ref, const_val->data.x_union.tag, false); | |
| 3996 | LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref, | |
| 3997 | &const_val->data.x_union.tag); | |
| 4035 | 3998 | |
| 4036 | 3999 | LLVMValueRef fields[2]; |
| 4037 | 4000 | 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) { |
| 4044 | 4007 | } |
| 4045 | 4008 | |
| 4046 | 4009 | } |
| 4047 | case TypeTableEntryIdEnum: | |
| 4048 | { | |
| 4049 | LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref; | |
| 4050 | LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false); | |
| 4051 | if (type_entry->data.enumeration.gen_field_count == 0) { | |
| 4052 | return tag_value; | |
| 4053 | } else { | |
| 4054 | LLVMTypeRef union_type_ref = type_entry->data.enumeration.union_type_ref; | |
| 4055 | TypeEnumField *enum_field = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag]; | |
| 4056 | assert(enum_field->value == const_val->data.x_enum.tag); | |
| 4057 | LLVMValueRef union_value; | |
| 4058 | 4010 | |
| 4059 | bool make_unnamed_struct; | |
| 4060 | ||
| 4061 | if (type_has_bits(enum_field->type_entry)) { | |
| 4062 | uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, | |
| 4063 | enum_field->type_entry->type_ref); | |
| 4064 | uint64_t pad_bytes = type_entry->data.enumeration.union_size_bytes - field_type_bytes; | |
| 4065 | ||
| 4066 | ConstExprValue *payload_value = const_val->data.x_enum.payload; | |
| 4067 | LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value); | |
| 4068 | ||
| 4069 | make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) || | |
| 4070 | payload_value->type != type_entry->data.enumeration.most_aligned_union_member; | |
| 4071 | ||
| 4072 | if (pad_bytes == 0) { | |
| 4073 | union_value = correctly_typed_value; | |
| 4074 | } else { | |
| 4075 | LLVMValueRef fields[] = { | |
| 4076 | correctly_typed_value, | |
| 4077 | LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)), | |
| 4078 | }; | |
| 4079 | union_value = LLVMConstStruct(fields, 2, false); | |
| 4080 | } | |
| 4081 | } else { | |
| 4082 | make_unnamed_struct = false; | |
| 4083 | union_value = LLVMGetUndef(union_type_ref); | |
| 4084 | } | |
| 4085 | LLVMValueRef fields[2]; | |
| 4086 | fields[type_entry->data.enumeration.gen_tag_index] = tag_value; | |
| 4087 | fields[type_entry->data.enumeration.gen_union_index] = union_value; | |
| 4088 | ||
| 4089 | if (make_unnamed_struct) { | |
| 4090 | return LLVMConstStruct(fields, 2, false); | |
| 4091 | } else { | |
| 4092 | return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); | |
| 4093 | } | |
| 4094 | } | |
| 4095 | } | |
| 4011 | case TypeTableEntryIdEnum: | |
| 4012 | return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_enum_tag); | |
| 4096 | 4013 | case TypeTableEntryIdFn: |
| 4097 | 4014 | return fn_llvm_value(g, const_val->data.x_fn.fn_entry); |
| 4098 | 4015 | case TypeTableEntryIdPointer: |
| ... | ... | @@ -4303,9 +4220,8 @@ static void generate_enum_name_tables(CodeGen *g) { |
| 4303 | 4220 | |
| 4304 | 4221 | |
| 4305 | 4222 | for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) { |
| 4306 | TypeTableEntry *enum_tag_type = g->name_table_enums.at(enum_i); | |
| 4307 | assert(enum_tag_type->id == TypeTableEntryIdEnumTag); | |
| 4308 | TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type; | |
| 4223 | TypeTableEntry *enum_type = g->name_table_enums.at(enum_i); | |
| 4224 | assert(enum_type->id == TypeTableEntryIdEnum); | |
| 4309 | 4225 | |
| 4310 | 4226 | size_t field_count = enum_type->data.enumeration.src_field_count; |
| 4311 | 4227 | LLVMValueRef *values = allocate<LLVMValueRef>(field_count); |
| ... | ... | @@ -4336,7 +4252,7 @@ static void generate_enum_name_tables(CodeGen *g) { |
| 4336 | 4252 | LLVMSetGlobalConstant(name_table, true); |
| 4337 | 4253 | LLVMSetUnnamedAddr(name_table, true); |
| 4338 | 4254 | LLVMSetAlignment(name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(name_table_init))); |
| 4339 | enum_tag_type->data.enum_tag.name_table = name_table; | |
| 4255 | enum_type->data.enumeration.name_table = name_table; | |
| 4340 | 4256 | } |
| 4341 | 4257 | } |
| 4342 | 4258 | |
| ... | ... | @@ -4540,9 +4456,6 @@ static void do_code_gen(CodeGen *g) { |
| 4540 | 4456 | } else if (instruction->id == IrInstructionIdErrWrapCode) { |
| 4541 | 4457 | IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; |
| 4542 | 4458 | slot = &err_wrap_code_instruction->tmp_ptr; |
| 4543 | } else if (instruction->id == IrInstructionIdInitEnum) { | |
| 4544 | IrInstructionInitEnum *init_enum_instruction = (IrInstructionInitEnum *)instruction; | |
| 4545 | slot = &init_enum_instruction->tmp_ptr; | |
| 4546 | 4459 | } else { |
| 4547 | 4460 | zig_unreachable(); |
| 4548 | 4461 | } |
| ... | ... | @@ -5039,7 +4952,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 5039 | 4952 | create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2); |
| 5040 | 4953 | create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1); |
| 5041 | 4954 | create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); |
| 5042 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); | |
| 4955 | create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int | |
| 5043 | 4956 | create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); |
| 5044 | 4957 | create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2); |
| 5045 | 4958 | create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2); |
| ... | ... | @@ -5049,7 +4962,8 @@ static void define_builtin_fns(CodeGen *g) { |
| 5049 | 4962 | create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2); |
| 5050 | 4963 | create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2); |
| 5051 | 4964 | create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1); |
| 5052 | create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1); | |
| 4965 | create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1); | |
| 4966 | create_builtin_fn(g, BuiltinFnIdTagType, "TagType", 1); | |
| 5053 | 4967 | create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3); |
| 5054 | 4968 | create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2); |
| 5055 | 4969 | create_builtin_fn(g, BuiltinFnIdDivExact, "divExact", 2); |
| ... | ... | @@ -5215,7 +5129,19 @@ static void define_builtin_compile_vars(CodeGen *g) { |
| 5215 | 5129 | assert(FloatModeOptimized == 0); |
| 5216 | 5130 | assert(FloatModeStrict == 1); |
| 5217 | 5131 | } |
| 5218 | buf_appendf(contents, "pub const is_big_endian = %s;\n", bool_to_str(g->is_big_endian)); | |
| 5132 | { | |
| 5133 | buf_appendf(contents, | |
| 5134 | "pub const Endian = enum {\n" | |
| 5135 | " Big,\n" | |
| 5136 | " Little,\n" | |
| 5137 | "};\n\n"); | |
| 5138 | assert(FloatModeOptimized == 0); | |
| 5139 | assert(FloatModeStrict == 1); | |
| 5140 | } | |
| 5141 | { | |
| 5142 | const char *endian_str = g->is_big_endian ? "Endian.Big" : "Endian.Little"; | |
| 5143 | buf_appendf(contents, "pub const endian = %s;\n", endian_str); | |
| 5144 | } | |
| 5219 | 5145 | buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build)); |
| 5220 | 5146 | buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); |
| 5221 | 5147 | 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) { |
| 5665 | 5591 | case TypeTableEntryIdEnum: |
| 5666 | 5592 | case TypeTableEntryIdUnion: |
| 5667 | 5593 | case TypeTableEntryIdFn: |
| 5668 | case TypeTableEntryIdEnumTag: | |
| 5669 | 5594 | zig_panic("TODO implement get_c_type for more types"); |
| 5670 | 5595 | case TypeTableEntryIdInvalid: |
| 5671 | 5596 | case TypeTableEntryIdMetaType: |
src/errmsg.cpp+4-4| ... | ... | @@ -24,20 +24,20 @@ static void print_err_msg_type(ErrorMsg *err, ErrColor color, ErrType err_type) |
| 24 | 24 | bool is_tty = os_stderr_tty(); |
| 25 | 25 | if (color == ErrColorOn || (color == ErrColorAuto && is_tty)) { |
| 26 | 26 | if (err_type == ErrTypeError) { |
| 27 | os_stderr_set_color(TermColorWhite); | |
| 27 | os_stderr_set_color(TermColorBold); | |
| 28 | 28 | fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", path, line, col); |
| 29 | 29 | os_stderr_set_color(TermColorRed); |
| 30 | 30 | fprintf(stderr, "error:"); |
| 31 | os_stderr_set_color(TermColorWhite); | |
| 31 | os_stderr_set_color(TermColorBold); | |
| 32 | 32 | fprintf(stderr, " %s", text); |
| 33 | 33 | os_stderr_set_color(TermColorReset); |
| 34 | 34 | fprintf(stderr, "\n"); |
| 35 | 35 | } else if (err_type == ErrTypeNote) { |
| 36 | os_stderr_set_color(TermColorWhite); | |
| 36 | os_stderr_set_color(TermColorBold); | |
| 37 | 37 | fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize ": ", path, line, col); |
| 38 | 38 | os_stderr_set_color(TermColorCyan); |
| 39 | 39 | fprintf(stderr, "note:"); |
| 40 | os_stderr_set_color(TermColorWhite); | |
| 40 | os_stderr_set_color(TermColorBold); | |
| 41 | 41 | fprintf(stderr, " %s", text); |
| 42 | 42 | os_stderr_set_color(TermColorReset); |
| 43 | 43 | fprintf(stderr, "\n"); |
src/error.cpp+1| ... | ... | @@ -26,6 +26,7 @@ const char *err_str(int err) { |
| 26 | 26 | case ErrorExactDivRemainder: return "exact division had a remainder"; |
| 27 | 27 | case ErrorNegativeDenominator: return "negative denominator"; |
| 28 | 28 | case ErrorShiftedOutOneBits: return "exact shift shifted out one bits"; |
| 29 | case ErrorCCompileErrors: return "C compile errors"; | |
| 29 | 30 | } |
| 30 | 31 | return "(invalid error)"; |
| 31 | 32 | } |
src/error.hpp+1| ... | ... | @@ -26,6 +26,7 @@ enum Error { |
| 26 | 26 | ErrorExactDivRemainder, |
| 27 | 27 | ErrorNegativeDenominator, |
| 28 | 28 | ErrorShiftedOutOneBits, |
| 29 | ErrorCCompileErrors, | |
| 29 | 30 | }; |
| 30 | 31 | |
| 31 | 32 | const char *err_str(int err); |
src/ir.cpp+346-295| ... | ... | @@ -223,10 +223,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructFieldPtr * |
| 223 | 223 | return IrInstructionIdStructFieldPtr; |
| 224 | 224 | } |
| 225 | 225 | |
| 226 | static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) { | |
| 227 | return IrInstructionIdEnumFieldPtr; | |
| 228 | } | |
| 229 | ||
| 230 | 226 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) { |
| 231 | 227 | return IrInstructionIdUnionFieldPtr; |
| 232 | 228 | } |
| ... | ... | @@ -319,8 +315,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCtz *) { |
| 319 | 315 | return IrInstructionIdCtz; |
| 320 | 316 | } |
| 321 | 317 | |
| 322 | static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTag *) { | |
| 323 | return IrInstructionIdEnumTag; | |
| 318 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionTag *) { | |
| 319 | return IrInstructionIdUnionTag; | |
| 324 | 320 | } |
| 325 | 321 | |
| 326 | 322 | static constexpr IrInstructionId ir_instruction_id(IrInstructionImport *) { |
| ... | ... | @@ -479,10 +475,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *) |
| 479 | 475 | return IrInstructionIdTestComptime; |
| 480 | 476 | } |
| 481 | 477 | |
| 482 | static constexpr IrInstructionId ir_instruction_id(IrInstructionInitEnum *) { | |
| 483 | return IrInstructionIdInitEnum; | |
| 484 | } | |
| 485 | ||
| 486 | 478 | static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) { |
| 487 | 479 | return IrInstructionIdPtrCast; |
| 488 | 480 | } |
| ... | ... | @@ -547,8 +539,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPanic *) { |
| 547 | 539 | return IrInstructionIdPanic; |
| 548 | 540 | } |
| 549 | 541 | |
| 550 | static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTagName *) { | |
| 551 | return IrInstructionIdEnumTagName; | |
| 542 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTagName *) { | |
| 543 | return IrInstructionIdTagName; | |
| 544 | } | |
| 545 | ||
| 546 | static constexpr IrInstructionId ir_instruction_id(IrInstructionTagType *) { | |
| 547 | return IrInstructionIdTagType; | |
| 552 | 548 | } |
| 553 | 549 | |
| 554 | 550 | static constexpr IrInstructionId ir_instruction_id(IrInstructionFieldParentPtr *) { |
| ... | ... | @@ -909,27 +905,6 @@ static IrInstruction *ir_build_struct_field_ptr_from(IrBuilder *irb, IrInstructi |
| 909 | 905 | return new_instruction; |
| 910 | 906 | } |
| 911 | 907 | |
| 912 | static IrInstruction *ir_build_enum_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 913 | IrInstruction *enum_ptr, TypeEnumField *field) | |
| 914 | { | |
| 915 | IrInstructionEnumFieldPtr *instruction = ir_build_instruction<IrInstructionEnumFieldPtr>(irb, scope, source_node); | |
| 916 | instruction->enum_ptr = enum_ptr; | |
| 917 | instruction->field = field; | |
| 918 | ||
| 919 | ir_ref_instruction(enum_ptr, irb->current_basic_block); | |
| 920 | ||
| 921 | return &instruction->base; | |
| 922 | } | |
| 923 | ||
| 924 | static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, | |
| 925 | IrInstruction *enum_ptr, TypeEnumField *type_enum_field) | |
| 926 | { | |
| 927 | IrInstruction *new_instruction = ir_build_enum_field_ptr(irb, old_instruction->scope, | |
| 928 | old_instruction->source_node, enum_ptr, type_enum_field); | |
| 929 | ir_link_new_instruction(new_instruction, old_instruction); | |
| 930 | return new_instruction; | |
| 931 | } | |
| 932 | ||
| 933 | 908 | static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 934 | 909 | IrInstruction *union_ptr, TypeUnionField *field) |
| 935 | 910 | { |
| ... | ... | @@ -1524,8 +1499,8 @@ static IrInstruction *ir_build_switch_var(IrBuilder *irb, Scope *scope, AstNode |
| 1524 | 1499 | return &instruction->base; |
| 1525 | 1500 | } |
| 1526 | 1501 | |
| 1527 | static IrInstruction *ir_build_enum_tag(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { | |
| 1528 | IrInstructionEnumTag *instruction = ir_build_instruction<IrInstructionEnumTag>(irb, scope, source_node); | |
| 1502 | static IrInstruction *ir_build_union_tag(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { | |
| 1503 | IrInstructionUnionTag *instruction = ir_build_instruction<IrInstructionUnionTag>(irb, scope, source_node); | |
| 1529 | 1504 | instruction->value = value; |
| 1530 | 1505 | |
| 1531 | 1506 | ir_ref_instruction(value, irb->current_basic_block); |
| ... | ... | @@ -1533,13 +1508,6 @@ static IrInstruction *ir_build_enum_tag(IrBuilder *irb, Scope *scope, AstNode *s |
| 1533 | 1508 | return &instruction->base; |
| 1534 | 1509 | } |
| 1535 | 1510 | |
| 1536 | static IrInstruction *ir_build_enum_tag_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) { | |
| 1537 | IrInstruction *new_instruction = ir_build_enum_tag(irb, old_instruction->scope, | |
| 1538 | old_instruction->source_node, value); | |
| 1539 | ir_link_new_instruction(new_instruction, old_instruction); | |
| 1540 | return new_instruction; | |
| 1541 | } | |
| 1542 | ||
| 1543 | 1511 | static IrInstruction *ir_build_import(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *name) { |
| 1544 | 1512 | IrInstructionImport *instruction = ir_build_instruction<IrInstructionImport>(irb, scope, source_node); |
| 1545 | 1513 | instruction->name = name; |
| ... | ... | @@ -2029,28 +1997,6 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo |
| 2029 | 1997 | return &instruction->base; |
| 2030 | 1998 | } |
| 2031 | 1999 | |
| 2032 | static IrInstruction *ir_build_init_enum(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2033 | TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value) | |
| 2034 | { | |
| 2035 | IrInstructionInitEnum *instruction = ir_build_instruction<IrInstructionInitEnum>(irb, scope, source_node); | |
| 2036 | instruction->enum_type = enum_type; | |
| 2037 | instruction->field = field; | |
| 2038 | instruction->init_value = init_value; | |
| 2039 | ||
| 2040 | ir_ref_instruction(init_value, irb->current_basic_block); | |
| 2041 | ||
| 2042 | return &instruction->base; | |
| 2043 | } | |
| 2044 | ||
| 2045 | static IrInstruction *ir_build_init_enum_from(IrBuilder *irb, IrInstruction *old_instruction, | |
| 2046 | TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value) | |
| 2047 | { | |
| 2048 | IrInstruction *new_instruction = ir_build_init_enum(irb, old_instruction->scope, old_instruction->source_node, | |
| 2049 | enum_type, field, init_value); | |
| 2050 | ir_link_new_instruction(new_instruction, old_instruction); | |
| 2051 | return new_instruction; | |
| 2052 | } | |
| 2053 | ||
| 2054 | 2000 | static IrInstruction *ir_build_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 2055 | 2001 | IrInstruction *dest_type, IrInstruction *ptr) |
| 2056 | 2002 | { |
| ... | ... | @@ -2259,10 +2205,21 @@ static IrInstruction *ir_build_panic(IrBuilder *irb, Scope *scope, AstNode *sour |
| 2259 | 2205 | return &instruction->base; |
| 2260 | 2206 | } |
| 2261 | 2207 | |
| 2262 | static IrInstruction *ir_build_enum_tag_name(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2208 | static IrInstruction *ir_build_tag_name(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2263 | 2209 | IrInstruction *target) |
| 2264 | 2210 | { |
| 2265 | IrInstructionEnumTagName *instruction = ir_build_instruction<IrInstructionEnumTagName>(irb, scope, source_node); | |
| 2211 | IrInstructionTagName *instruction = ir_build_instruction<IrInstructionTagName>(irb, scope, source_node); | |
| 2212 | instruction->target = target; | |
| 2213 | ||
| 2214 | ir_ref_instruction(target, irb->current_basic_block); | |
| 2215 | ||
| 2216 | return &instruction->base; | |
| 2217 | } | |
| 2218 | ||
| 2219 | static IrInstruction *ir_build_tag_type(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 2220 | IrInstruction *target) | |
| 2221 | { | |
| 2222 | IrInstructionTagType *instruction = ir_build_instruction<IrInstructionTagType>(irb, scope, source_node); | |
| 2266 | 2223 | instruction->target = target; |
| 2267 | 2224 | |
| 2268 | 2225 | ir_ref_instruction(target, irb->current_basic_block); |
| ... | ... | @@ -2466,13 +2423,6 @@ static IrInstruction *ir_instruction_structfieldptr_get_dep(IrInstructionStructF |
| 2466 | 2423 | } |
| 2467 | 2424 | } |
| 2468 | 2425 | |
| 2469 | static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumFieldPtr *instruction, size_t index) { | |
| 2470 | switch (index) { | |
| 2471 | case 0: return instruction->enum_ptr; | |
| 2472 | default: return nullptr; | |
| 2473 | } | |
| 2474 | } | |
| 2475 | ||
| 2476 | 2426 | static IrInstruction *ir_instruction_unionfieldptr_get_dep(IrInstructionUnionFieldPtr *instruction, size_t index) { |
| 2477 | 2427 | switch (index) { |
| 2478 | 2428 | case 0: return instruction->union_ptr; |
| ... | ... | @@ -2642,7 +2592,7 @@ static IrInstruction *ir_instruction_maybewrap_get_dep(IrInstructionMaybeWrap *i |
| 2642 | 2592 | } |
| 2643 | 2593 | } |
| 2644 | 2594 | |
| 2645 | static IrInstruction *ir_instruction_enumtag_get_dep(IrInstructionEnumTag *instruction, size_t index) { | |
| 2595 | static IrInstruction *ir_instruction_uniontag_get_dep(IrInstructionUnionTag *instruction, size_t index) { | |
| 2646 | 2596 | switch (index) { |
| 2647 | 2597 | case 0: return instruction->value; |
| 2648 | 2598 | default: return nullptr; |
| ... | ... | @@ -2928,13 +2878,6 @@ static IrInstruction *ir_instruction_testcomptime_get_dep(IrInstructionTestCompt |
| 2928 | 2878 | } |
| 2929 | 2879 | } |
| 2930 | 2880 | |
| 2931 | static IrInstruction *ir_instruction_initenum_get_dep(IrInstructionInitEnum *instruction, size_t index) { | |
| 2932 | switch (index) { | |
| 2933 | case 0: return instruction->init_value; | |
| 2934 | default: return nullptr; | |
| 2935 | } | |
| 2936 | } | |
| 2937 | ||
| 2938 | 2881 | static IrInstruction *ir_instruction_ptrcast_get_dep(IrInstructionPtrCast *instruction, |
| 2939 | 2882 | size_t index) |
| 2940 | 2883 | { |
| ... | ... | @@ -3059,7 +3002,14 @@ static IrInstruction *ir_instruction_panic_get_dep(IrInstructionPanic *instructi |
| 3059 | 3002 | } |
| 3060 | 3003 | } |
| 3061 | 3004 | |
| 3062 | static IrInstruction *ir_instruction_enumtagname_get_dep(IrInstructionEnumTagName *instruction, size_t index) { | |
| 3005 | static IrInstruction *ir_instruction_enumtagname_get_dep(IrInstructionTagName *instruction, size_t index) { | |
| 3006 | switch (index) { | |
| 3007 | case 0: return instruction->target; | |
| 3008 | default: return nullptr; | |
| 3009 | } | |
| 3010 | } | |
| 3011 | ||
| 3012 | static IrInstruction *ir_instruction_enumtagtype_get_dep(IrInstructionTagType *instruction, size_t index) { | |
| 3063 | 3013 | switch (index) { |
| 3064 | 3014 | case 0: return instruction->target; |
| 3065 | 3015 | default: return nullptr; |
| ... | ... | @@ -3162,8 +3112,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3162 | 3112 | return ir_instruction_fieldptr_get_dep((IrInstructionFieldPtr *) instruction, index); |
| 3163 | 3113 | case IrInstructionIdStructFieldPtr: |
| 3164 | 3114 | return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index); |
| 3165 | case IrInstructionIdEnumFieldPtr: | |
| 3166 | return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index); | |
| 3167 | 3115 | case IrInstructionIdUnionFieldPtr: |
| 3168 | 3116 | return ir_instruction_unionfieldptr_get_dep((IrInstructionUnionFieldPtr *) instruction, index); |
| 3169 | 3117 | case IrInstructionIdElemPtr: |
| ... | ... | @@ -3212,8 +3160,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3212 | 3160 | return ir_instruction_unwrapmaybe_get_dep((IrInstructionUnwrapMaybe *) instruction, index); |
| 3213 | 3161 | case IrInstructionIdMaybeWrap: |
| 3214 | 3162 | return ir_instruction_maybewrap_get_dep((IrInstructionMaybeWrap *) instruction, index); |
| 3215 | case IrInstructionIdEnumTag: | |
| 3216 | return ir_instruction_enumtag_get_dep((IrInstructionEnumTag *) instruction, index); | |
| 3163 | case IrInstructionIdUnionTag: | |
| 3164 | return ir_instruction_uniontag_get_dep((IrInstructionUnionTag *) instruction, index); | |
| 3217 | 3165 | case IrInstructionIdClz: |
| 3218 | 3166 | return ir_instruction_clz_get_dep((IrInstructionClz *) instruction, index); |
| 3219 | 3167 | case IrInstructionIdCtz: |
| ... | ... | @@ -3290,8 +3238,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3290 | 3238 | return ir_instruction_fnproto_get_dep((IrInstructionFnProto *) instruction, index); |
| 3291 | 3239 | case IrInstructionIdTestComptime: |
| 3292 | 3240 | return ir_instruction_testcomptime_get_dep((IrInstructionTestComptime *) instruction, index); |
| 3293 | case IrInstructionIdInitEnum: | |
| 3294 | return ir_instruction_initenum_get_dep((IrInstructionInitEnum *) instruction, index); | |
| 3295 | 3241 | case IrInstructionIdPtrCast: |
| 3296 | 3242 | return ir_instruction_ptrcast_get_dep((IrInstructionPtrCast *) instruction, index); |
| 3297 | 3243 | case IrInstructionIdBitCast: |
| ... | ... | @@ -3324,8 +3270,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3324 | 3270 | return ir_instruction_declref_get_dep((IrInstructionDeclRef *) instruction, index); |
| 3325 | 3271 | case IrInstructionIdPanic: |
| 3326 | 3272 | return ir_instruction_panic_get_dep((IrInstructionPanic *) instruction, index); |
| 3327 | case IrInstructionIdEnumTagName: | |
| 3328 | return ir_instruction_enumtagname_get_dep((IrInstructionEnumTagName *) instruction, index); | |
| 3273 | case IrInstructionIdTagName: | |
| 3274 | return ir_instruction_enumtagname_get_dep((IrInstructionTagName *) instruction, index); | |
| 3275 | case IrInstructionIdTagType: | |
| 3276 | return ir_instruction_enumtagtype_get_dep((IrInstructionTagType *) instruction, index); | |
| 3329 | 3277 | case IrInstructionIdFieldParentPtr: |
| 3330 | 3278 | return ir_instruction_fieldparentptr_get_dep((IrInstructionFieldParentPtr *) instruction, index); |
| 3331 | 3279 | case IrInstructionIdOffsetOf: |
| ... | ... | @@ -4671,15 +4619,24 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 4671 | 4619 | |
| 4672 | 4620 | return ir_build_ptr_to_int(irb, scope, node, arg0_value); |
| 4673 | 4621 | } |
| 4674 | case BuiltinFnIdEnumTagName: | |
| 4622 | case BuiltinFnIdTagName: | |
| 4623 | { | |
| 4624 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); | |
| 4625 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); | |
| 4626 | if (arg0_value == irb->codegen->invalid_instruction) | |
| 4627 | return arg0_value; | |
| 4628 | ||
| 4629 | IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value); | |
| 4630 | return ir_build_tag_name(irb, scope, node, actual_tag); | |
| 4631 | } | |
| 4632 | case BuiltinFnIdTagType: | |
| 4675 | 4633 | { |
| 4676 | 4634 | AstNode *arg0_node = node->data.fn_call_expr.params.at(0); |
| 4677 | 4635 | IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); |
| 4678 | 4636 | if (arg0_value == irb->codegen->invalid_instruction) |
| 4679 | 4637 | return arg0_value; |
| 4680 | 4638 | |
| 4681 | IrInstruction *actual_tag = ir_build_enum_tag(irb, scope, node, arg0_value); | |
| 4682 | return ir_build_enum_tag_name(irb, scope, node, actual_tag); | |
| 4639 | return ir_build_tag_type(irb, scope, node, arg0_value); | |
| 4683 | 4640 | } |
| 4684 | 4641 | case BuiltinFnIdFieldParentPtr: |
| 4685 | 4642 | { |
| ... | ... | @@ -8348,13 +8305,28 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour |
| 8348 | 8305 | { |
| 8349 | 8306 | assert(wanted_type->id == TypeTableEntryIdInt); |
| 8350 | 8307 | |
| 8308 | TypeTableEntry *actual_type = target->value.type; | |
| 8309 | ensure_complete_type(ira->codegen, actual_type); | |
| 8310 | if (type_is_invalid(actual_type)) | |
| 8311 | return ira->codegen->invalid_instruction; | |
| 8312 | ||
| 8313 | if (wanted_type != actual_type->data.enumeration.tag_int_type) { | |
| 8314 | ir_add_error(ira, source_instr, | |
| 8315 | buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'", | |
| 8316 | buf_ptr(&wanted_type->name), | |
| 8317 | buf_ptr(&actual_type->data.enumeration.tag_int_type->name))); | |
| 8318 | return ira->codegen->invalid_instruction; | |
| 8319 | } | |
| 8320 | ||
| 8321 | assert(actual_type->id == TypeTableEntryIdEnum); | |
| 8322 | ||
| 8351 | 8323 | if (instr_is_comptime(target)) { |
| 8352 | 8324 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); |
| 8353 | 8325 | if (!val) |
| 8354 | 8326 | return ira->codegen->invalid_instruction; |
| 8355 | 8327 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, |
| 8356 | 8328 | source_instr->source_node, wanted_type); |
| 8357 | init_const_unsigned_negative(&result->value, wanted_type, val->data.x_enum.tag, false); | |
| 8329 | init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag); | |
| 8358 | 8330 | return result; |
| 8359 | 8331 | } |
| 8360 | 8332 | |
| ... | ... | @@ -8364,6 +8336,31 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour |
| 8364 | 8336 | return result; |
| 8365 | 8337 | } |
| 8366 | 8338 | |
| 8339 | static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *source_instr, | |
| 8340 | IrInstruction *target, TypeTableEntry *wanted_type) | |
| 8341 | { | |
| 8342 | assert(target->value.type->id == TypeTableEntryIdUnion); | |
| 8343 | assert(wanted_type->id == TypeTableEntryIdEnum); | |
| 8344 | assert(wanted_type == target->value.type->data.unionation.tag_type); | |
| 8345 | ||
| 8346 | if (instr_is_comptime(target)) { | |
| 8347 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); | |
| 8348 | if (!val) | |
| 8349 | return ira->codegen->invalid_instruction; | |
| 8350 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, | |
| 8351 | source_instr->source_node, wanted_type); | |
| 8352 | result->value.special = ConstValSpecialStatic; | |
| 8353 | result->value.type = wanted_type; | |
| 8354 | bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_union.tag); | |
| 8355 | return result; | |
| 8356 | } | |
| 8357 | ||
| 8358 | IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope, | |
| 8359 | source_instr->source_node, target); | |
| 8360 | result->value.type = wanted_type; | |
| 8361 | return result; | |
| 8362 | } | |
| 8363 | ||
| 8367 | 8364 | static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr, |
| 8368 | 8365 | IrInstruction *target, TypeTableEntry *wanted_type) |
| 8369 | 8366 | { |
| ... | ... | @@ -8419,6 +8416,22 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour |
| 8419 | 8416 | { |
| 8420 | 8417 | assert(wanted_type->id == TypeTableEntryIdEnum); |
| 8421 | 8418 | |
| 8419 | TypeTableEntry *actual_type = target->value.type; | |
| 8420 | ||
| 8421 | ensure_complete_type(ira->codegen, wanted_type); | |
| 8422 | if (type_is_invalid(wanted_type)) | |
| 8423 | return ira->codegen->invalid_instruction; | |
| 8424 | ||
| 8425 | if (actual_type != wanted_type->data.enumeration.tag_int_type) { | |
| 8426 | ir_add_error(ira, source_instr, | |
| 8427 | buf_sprintf("integer to enum cast from '%s' instead of its tag type, '%s'", | |
| 8428 | buf_ptr(&actual_type->name), | |
| 8429 | buf_ptr(&wanted_type->data.enumeration.tag_int_type->name))); | |
| 8430 | return ira->codegen->invalid_instruction; | |
| 8431 | } | |
| 8432 | ||
| 8433 | assert(actual_type->id == TypeTableEntryIdInt); | |
| 8434 | ||
| 8422 | 8435 | if (instr_is_comptime(target)) { |
| 8423 | 8436 | ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); |
| 8424 | 8437 | if (!val) |
| ... | ... | @@ -8436,7 +8449,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour |
| 8436 | 8449 | |
| 8437 | 8450 | IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, |
| 8438 | 8451 | source_instr->source_node, wanted_type); |
| 8439 | result->value.data.x_enum.tag = bigint_as_unsigned(&val->data.x_bigint); | |
| 8452 | bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint); | |
| 8440 | 8453 | return result; |
| 8441 | 8454 | } |
| 8442 | 8455 | |
| ... | ... | @@ -8874,21 +8887,26 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst |
| 8874 | 8887 | } |
| 8875 | 8888 | |
| 8876 | 8889 | // explicit cast from integer to enum type with no payload |
| 8877 | if (actual_type->id == TypeTableEntryIdInt && | |
| 8878 | wanted_type->id == TypeTableEntryIdEnum && | |
| 8879 | wanted_type->data.enumeration.gen_field_count == 0) | |
| 8880 | { | |
| 8890 | if (actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdEnum) { | |
| 8881 | 8891 | return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type); |
| 8882 | 8892 | } |
| 8883 | 8893 | |
| 8884 | 8894 | // explicit cast from enum type with no payload to integer |
| 8885 | if (wanted_type->id == TypeTableEntryIdInt && | |
| 8886 | actual_type->id == TypeTableEntryIdEnum && | |
| 8887 | actual_type->data.enumeration.gen_field_count == 0) | |
| 8888 | { | |
| 8895 | if (wanted_type->id == TypeTableEntryIdInt && actual_type->id == TypeTableEntryIdEnum) { | |
| 8889 | 8896 | return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type); |
| 8890 | 8897 | } |
| 8891 | 8898 | |
| 8899 | // explicit cast from union to the enum type of the union | |
| 8900 | if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) { | |
| 8901 | type_ensure_zero_bits_known(ira->codegen, actual_type); | |
| 8902 | if (type_is_invalid(actual_type)) | |
| 8903 | return ira->codegen->invalid_instruction; | |
| 8904 | ||
| 8905 | if (actual_type->data.unionation.tag_type == wanted_type) { | |
| 8906 | return ir_analyze_union_to_tag(ira, source_instr, value, wanted_type); | |
| 8907 | } | |
| 8908 | } | |
| 8909 | ||
| 8892 | 8910 | // explicit cast from undefined to anything |
| 8893 | 8911 | if (actual_type->id == TypeTableEntryIdUndefLit) { |
| 8894 | 8912 | return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type); |
| ... | ... | @@ -9095,7 +9113,7 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic |
| 9095 | 9113 | if (!const_val) |
| 9096 | 9114 | return false; |
| 9097 | 9115 | |
| 9098 | *out = (AtomicOrder)const_val->data.x_enum.tag; | |
| 9116 | *out = (AtomicOrder)bigint_as_unsigned(&const_val->data.x_enum_tag); | |
| 9099 | 9117 | return true; |
| 9100 | 9118 | } |
| 9101 | 9119 | |
| ... | ... | @@ -9115,7 +9133,27 @@ static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, Glob |
| 9115 | 9133 | if (!const_val) |
| 9116 | 9134 | return false; |
| 9117 | 9135 | |
| 9118 | *out = (GlobalLinkageId)const_val->data.x_enum.tag; | |
| 9136 | *out = (GlobalLinkageId)bigint_as_unsigned(&const_val->data.x_enum_tag); | |
| 9137 | return true; | |
| 9138 | } | |
| 9139 | ||
| 9140 | static bool ir_resolve_float_mode(IrAnalyze *ira, IrInstruction *value, FloatMode *out) { | |
| 9141 | if (type_is_invalid(value->value.type)) | |
| 9142 | return false; | |
| 9143 | ||
| 9144 | ConstExprValue *float_mode_val = get_builtin_value(ira->codegen, "FloatMode"); | |
| 9145 | assert(float_mode_val->type->id == TypeTableEntryIdMetaType); | |
| 9146 | TypeTableEntry *float_mode_type = float_mode_val->data.x_type; | |
| 9147 | ||
| 9148 | IrInstruction *casted_value = ir_implicit_cast(ira, value, float_mode_type); | |
| 9149 | if (type_is_invalid(casted_value->value.type)) | |
| 9150 | return false; | |
| 9151 | ||
| 9152 | ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); | |
| 9153 | if (!const_val) | |
| 9154 | return false; | |
| 9155 | ||
| 9156 | *out = (FloatMode)bigint_as_unsigned(&const_val->data.x_enum_tag); | |
| 9119 | 9157 | return true; |
| 9120 | 9158 | } |
| 9121 | 9159 | |
| ... | ... | @@ -9327,7 +9365,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 9327 | 9365 | break; |
| 9328 | 9366 | |
| 9329 | 9367 | case TypeTableEntryIdEnum: |
| 9330 | if (!is_equality_cmp || resolved_type->data.enumeration.gen_field_count != 0) { | |
| 9368 | if (!is_equality_cmp) { | |
| 9331 | 9369 | ir_add_error_node(ira, source_node, |
| 9332 | 9370 | buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); |
| 9333 | 9371 | return ira->codegen->builtin_types.entry_invalid; |
| ... | ... | @@ -9346,9 +9384,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp |
| 9346 | 9384 | buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); |
| 9347 | 9385 | return ira->codegen->builtin_types.entry_invalid; |
| 9348 | 9386 | |
| 9349 | case TypeTableEntryIdEnumTag: | |
| 9350 | zig_panic("TODO implement comparison for enum tag type"); | |
| 9351 | ||
| 9352 | 9387 | case TypeTableEntryIdVar: |
| 9353 | 9388 | zig_unreachable(); |
| 9354 | 9389 | } |
| ... | ... | @@ -10097,7 +10132,6 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) { |
| 10097 | 10132 | case TypeTableEntryIdVoid: |
| 10098 | 10133 | case TypeTableEntryIdPureError: |
| 10099 | 10134 | case TypeTableEntryIdFn: |
| 10100 | case TypeTableEntryIdEnumTag: | |
| 10101 | 10135 | return VarClassRequiredAny; |
| 10102 | 10136 | case TypeTableEntryIdNumLitFloat: |
| 10103 | 10137 | case TypeTableEntryIdNumLitInt: |
| ... | ... | @@ -10840,7 +10874,6 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct |
| 10840 | 10874 | case TypeTableEntryIdUnion: |
| 10841 | 10875 | case TypeTableEntryIdFn: |
| 10842 | 10876 | case TypeTableEntryIdBoundFn: |
| 10843 | case TypeTableEntryIdEnumTag: | |
| 10844 | 10877 | { |
| 10845 | 10878 | ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base); |
| 10846 | 10879 | TypeTableEntry *result_type = get_error_type(ira->codegen, meta_type); |
| ... | ... | @@ -10928,7 +10961,6 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op |
| 10928 | 10961 | case TypeTableEntryIdNamespace: |
| 10929 | 10962 | case TypeTableEntryIdBlock: |
| 10930 | 10963 | case TypeTableEntryIdBoundFn: |
| 10931 | case TypeTableEntryIdEnumTag: | |
| 10932 | 10964 | case TypeTableEntryIdArgTuple: |
| 10933 | 10965 | { |
| 10934 | 10966 | ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base); |
| ... | ... | @@ -11154,8 +11186,8 @@ static TypeTableEntry *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionP |
| 11154 | 11186 | } |
| 11155 | 11187 | |
| 11156 | 11188 | if (new_incoming_blocks.length == 0) { |
| 11157 | ir_build_const_from(ira, &phi_instruction->base); | |
| 11158 | return ira->codegen->builtin_types.entry_void; | |
| 11189 | ir_build_unreachable_from(&ira->new_irb, &phi_instruction->base); | |
| 11190 | return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable); | |
| 11159 | 11191 | } |
| 11160 | 11192 | |
| 11161 | 11193 | if (new_incoming_blocks.length == 1) { |
| ... | ... | @@ -11589,15 +11621,8 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11589 | 11621 | field_ptr_instruction, container_ptr, container_type); |
| 11590 | 11622 | } |
| 11591 | 11623 | } else if (bare_type->id == TypeTableEntryIdEnum) { |
| 11592 | TypeEnumField *field = find_enum_type_field(bare_type, field_name); | |
| 11593 | if (field) { | |
| 11594 | ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field); | |
| 11595 | return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, | |
| 11596 | get_abi_alignment(ira->codegen, field->type_entry), 0, 0); | |
| 11597 | } else { | |
| 11598 | return ir_analyze_container_member_access_inner(ira, bare_type, field_name, | |
| 11599 | field_ptr_instruction, container_ptr, container_type); | |
| 11600 | } | |
| 11624 | return ir_analyze_container_member_access_inner(ira, bare_type, field_name, | |
| 11625 | field_ptr_instruction, container_ptr, container_type); | |
| 11601 | 11626 | } else if (bare_type->id == TypeTableEntryIdUnion) { |
| 11602 | 11627 | TypeUnionField *field = find_union_type_field(bare_type, field_name); |
| 11603 | 11628 | if (field) { |
| ... | ... | @@ -11768,20 +11793,27 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru |
| 11768 | 11793 | |
| 11769 | 11794 | TypeEnumField *field = find_enum_type_field(child_type, field_name); |
| 11770 | 11795 | if (field) { |
| 11771 | if (field->type_entry->id == TypeTableEntryIdVoid) { | |
| 11772 | bool ptr_is_const = true; | |
| 11773 | bool ptr_is_volatile = false; | |
| 11774 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | |
| 11775 | create_const_enum_tag(child_type, field->value), child_type, | |
| 11776 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | |
| 11777 | } else { | |
| 11778 | bool ptr_is_const = true; | |
| 11779 | bool ptr_is_volatile = false; | |
| 11780 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | |
| 11781 | create_const_unsigned_negative(child_type->data.enumeration.tag_type, field->value, false), | |
| 11782 | child_type->data.enumeration.tag_type, | |
| 11796 | bool ptr_is_const = true; | |
| 11797 | bool ptr_is_volatile = false; | |
| 11798 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | |
| 11799 | create_const_enum(child_type, &field->value), child_type, | |
| 11800 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); | |
| 11801 | } | |
| 11802 | } else if (child_type->id == TypeTableEntryIdUnion && | |
| 11803 | (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr || | |
| 11804 | child_type->data.unionation.decl_node->data.container_decl.auto_enum)) | |
| 11805 | { | |
| 11806 | ensure_complete_type(ira->codegen, child_type); | |
| 11807 | if (type_is_invalid(child_type)) | |
| 11808 | return ira->codegen->builtin_types.entry_invalid; | |
| 11809 | TypeUnionField *field = find_union_type_field(child_type, field_name); | |
| 11810 | if (field) { | |
| 11811 | TypeTableEntry *enum_type = child_type->data.unionation.tag_type; | |
| 11812 | bool ptr_is_const = true; | |
| 11813 | bool ptr_is_volatile = false; | |
| 11814 | return ir_analyze_const_ptr(ira, &field_ptr_instruction->base, | |
| 11815 | create_const_enum(enum_type, &field->enum_field->value), enum_type, | |
| 11783 | 11816 | ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile); |
| 11784 | } | |
| 11785 | 11817 | } |
| 11786 | 11818 | } |
| 11787 | 11819 | ScopeDecls *container_scope = get_container_scope(child_type); |
| ... | ... | @@ -12090,7 +12122,6 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi |
| 12090 | 12122 | case TypeTableEntryIdEnum: |
| 12091 | 12123 | case TypeTableEntryIdUnion: |
| 12092 | 12124 | case TypeTableEntryIdFn: |
| 12093 | case TypeTableEntryIdEnumTag: | |
| 12094 | 12125 | case TypeTableEntryIdArgTuple: |
| 12095 | 12126 | case TypeTableEntryIdOpaque: |
| 12096 | 12127 | { |
| ... | ... | @@ -12367,21 +12398,11 @@ static TypeTableEntry *ir_analyze_instruction_set_float_mode(IrAnalyze *ira, |
| 12367 | 12398 | return ira->codegen->builtin_types.entry_invalid; |
| 12368 | 12399 | } |
| 12369 | 12400 | |
| 12370 | ConstExprValue *float_mode_val = get_builtin_value(ira->codegen, "FloatMode"); | |
| 12371 | assert(float_mode_val->type->id == TypeTableEntryIdMetaType); | |
| 12372 | TypeTableEntry *float_mode_enum_type = float_mode_val->data.x_type; | |
| 12373 | ||
| 12374 | 12401 | IrInstruction *float_mode_value = instruction->mode_value->other; |
| 12375 | if (type_is_invalid(float_mode_value->value.type)) | |
| 12376 | return ira->codegen->builtin_types.entry_invalid; | |
| 12377 | IrInstruction *casted_value = ir_implicit_cast(ira, float_mode_value, float_mode_enum_type); | |
| 12378 | if (type_is_invalid(casted_value->value.type)) | |
| 12379 | return ira->codegen->builtin_types.entry_invalid; | |
| 12380 | ConstExprValue *mode_val = ir_resolve_const(ira, casted_value, UndefBad); | |
| 12381 | if (!mode_val) | |
| 12382 | return ira->codegen->builtin_types.entry_invalid; | |
| 12383 | 12402 | |
| 12384 | bool want_fast_math = (mode_val->data.x_enum.tag == FloatModeOptimized); | |
| 12403 | FloatMode float_mode_scalar; | |
| 12404 | if (!ir_resolve_float_mode(ira, float_mode_value, &float_mode_scalar)) | |
| 12405 | return ira->codegen->builtin_types.entry_invalid; | |
| 12385 | 12406 | |
| 12386 | 12407 | AstNode *source_node = instruction->base.source_node; |
| 12387 | 12408 | if (*fast_math_set_node_ptr) { |
| ... | ... | @@ -12391,7 +12412,7 @@ static TypeTableEntry *ir_analyze_instruction_set_float_mode(IrAnalyze *ira, |
| 12391 | 12412 | return ira->codegen->builtin_types.entry_invalid; |
| 12392 | 12413 | } |
| 12393 | 12414 | *fast_math_set_node_ptr = source_node; |
| 12394 | *fast_math_off_ptr = !want_fast_math; | |
| 12415 | *fast_math_off_ptr = (float_mode_scalar == FloatModeStrict); | |
| 12395 | 12416 | |
| 12396 | 12417 | ir_build_const_from(ira, &instruction->base); |
| 12397 | 12418 | return ira->codegen->builtin_types.entry_void; |
| ... | ... | @@ -12448,7 +12469,6 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 12448 | 12469 | case TypeTableEntryIdFn: |
| 12449 | 12470 | case TypeTableEntryIdNamespace: |
| 12450 | 12471 | case TypeTableEntryIdBoundFn: |
| 12451 | case TypeTableEntryIdEnumTag: | |
| 12452 | 12472 | { |
| 12453 | 12473 | type_ensure_zero_bits_known(ira->codegen, child_type); |
| 12454 | 12474 | TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type, |
| ... | ... | @@ -12557,7 +12577,6 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 12557 | 12577 | case TypeTableEntryIdFn: |
| 12558 | 12578 | case TypeTableEntryIdNamespace: |
| 12559 | 12579 | case TypeTableEntryIdBoundFn: |
| 12560 | case TypeTableEntryIdEnumTag: | |
| 12561 | 12580 | { |
| 12562 | 12581 | TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size); |
| 12563 | 12582 | ConstExprValue *out_val = ir_build_const_from(ira, &array_type_instruction->base); |
| ... | ... | @@ -12608,7 +12627,6 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 12608 | 12627 | case TypeTableEntryIdPureError: |
| 12609 | 12628 | case TypeTableEntryIdEnum: |
| 12610 | 12629 | case TypeTableEntryIdUnion: |
| 12611 | case TypeTableEntryIdEnumTag: | |
| 12612 | 12630 | case TypeTableEntryIdFn: |
| 12613 | 12631 | { |
| 12614 | 12632 | uint64_t size_in_bytes = type_size(ira->codegen, type_entry); |
| ... | ... | @@ -12761,17 +12779,22 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC |
| 12761 | 12779 | } |
| 12762 | 12780 | } |
| 12763 | 12781 | |
| 12764 | static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) { | |
| 12782 | static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) { | |
| 12765 | 12783 | if (type_is_invalid(value->value.type)) |
| 12766 | 12784 | return ira->codegen->invalid_instruction; |
| 12767 | 12785 | |
| 12768 | if (value->value.type->id != TypeTableEntryIdEnum) { | |
| 12786 | if (value->value.type->id == TypeTableEntryIdEnum) { | |
| 12787 | return value; | |
| 12788 | } | |
| 12789 | ||
| 12790 | if (value->value.type->id != TypeTableEntryIdUnion) { | |
| 12769 | 12791 | ir_add_error(ira, source_instr, |
| 12770 | buf_sprintf("expected enum type, found '%s'", buf_ptr(&value->value.type->name))); | |
| 12792 | buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value.type->name))); | |
| 12771 | 12793 | return ira->codegen->invalid_instruction; |
| 12772 | 12794 | } |
| 12773 | 12795 | |
| 12774 | TypeTableEntry *tag_type = value->value.type->data.enumeration.tag_type; | |
| 12796 | TypeTableEntry *tag_type = value->value.type->data.unionation.tag_type; | |
| 12797 | assert(tag_type->id == TypeTableEntryIdEnum); | |
| 12775 | 12798 | |
| 12776 | 12799 | if (instr_is_comptime(value)) { |
| 12777 | 12800 | ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); |
| ... | ... | @@ -12782,11 +12805,11 @@ static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_ |
| 12782 | 12805 | source_instr->scope, source_instr->source_node); |
| 12783 | 12806 | const_instruction->base.value.type = tag_type; |
| 12784 | 12807 | const_instruction->base.value.special = ConstValSpecialStatic; |
| 12785 | bigint_init_unsigned(&const_instruction->base.value.data.x_bigint, val->data.x_enum.tag); | |
| 12808 | bigint_init_bigint(&const_instruction->base.value.data.x_enum_tag, &val->data.x_union.tag); | |
| 12786 | 12809 | return &const_instruction->base; |
| 12787 | 12810 | } |
| 12788 | 12811 | |
| 12789 | IrInstruction *result = ir_build_enum_tag(&ira->new_irb, source_instr->scope, source_instr->source_node, value); | |
| 12812 | IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope, source_instr->source_node, value); | |
| 12790 | 12813 | result->value.type = tag_type; |
| 12791 | 12814 | return result; |
| 12792 | 12815 | } |
| ... | ... | @@ -12817,7 +12840,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira, |
| 12817 | 12840 | return ir_unreach_error(ira); |
| 12818 | 12841 | |
| 12819 | 12842 | if (case_value->value.type->id == TypeTableEntryIdEnum) { |
| 12820 | case_value = ir_analyze_enum_tag(ira, &switch_br_instruction->base, case_value); | |
| 12843 | case_value = ir_analyze_union_tag(ira, &switch_br_instruction->base, case_value); | |
| 12821 | 12844 | if (type_is_invalid(case_value->value.type)) |
| 12822 | 12845 | return ir_unreach_error(ira); |
| 12823 | 12846 | } |
| ... | ... | @@ -12864,7 +12887,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira, |
| 12864 | 12887 | continue; |
| 12865 | 12888 | |
| 12866 | 12889 | if (new_value->value.type->id == TypeTableEntryIdEnum) { |
| 12867 | new_value = ir_analyze_enum_tag(ira, &switch_br_instruction->base, new_value); | |
| 12890 | new_value = ir_analyze_union_tag(ira, &switch_br_instruction->base, new_value); | |
| 12868 | 12891 | if (type_is_invalid(new_value->value.type)) |
| 12869 | 12892 | continue; |
| 12870 | 12893 | } |
| ... | ... | @@ -12946,34 +12969,57 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 12946 | 12969 | |
| 12947 | 12970 | ir_build_load_ptr_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr); |
| 12948 | 12971 | return target_type; |
| 12949 | case TypeTableEntryIdEnum: | |
| 12972 | case TypeTableEntryIdUnion: { | |
| 12973 | AstNode *decl_node = target_type->data.unionation.decl_node; | |
| 12974 | if (!decl_node->data.container_decl.auto_enum && | |
| 12975 | decl_node->data.container_decl.init_arg_expr == nullptr) | |
| 12950 | 12976 | { |
| 12951 | TypeTableEntry *tag_type = target_type->data.enumeration.tag_type; | |
| 12952 | assert(tag_type != nullptr); | |
| 12953 | if (pointee_val) { | |
| 12954 | ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); | |
| 12955 | bigint_init_unsigned(&out_val->data.x_bigint, pointee_val->data.x_enum.tag); | |
| 12956 | return tag_type; | |
| 12957 | } | |
| 12958 | ||
| 12959 | IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, | |
| 12960 | switch_target_instruction->base.source_node, target_value_ptr); | |
| 12961 | enum_value->value.type = target_type; | |
| 12962 | ir_build_enum_tag_from(&ira->new_irb, &switch_target_instruction->base, enum_value); | |
| 12977 | ErrorMsg *msg = ir_add_error(ira, target_value_ptr, | |
| 12978 | buf_sprintf("switch on union which has no attached enum")); | |
| 12979 | add_error_note(ira->codegen, msg, decl_node, | |
| 12980 | buf_sprintf("consider 'union(enum)' here")); | |
| 12981 | return ira->codegen->builtin_types.entry_invalid; | |
| 12982 | } | |
| 12983 | TypeTableEntry *tag_type = target_type->data.unionation.tag_type; | |
| 12984 | assert(tag_type != nullptr); | |
| 12985 | if (pointee_val) { | |
| 12986 | ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); | |
| 12987 | bigint_init_bigint(&out_val->data.x_enum_tag, &pointee_val->data.x_union.tag); | |
| 12963 | 12988 | return tag_type; |
| 12964 | 12989 | } |
| 12990 | ||
| 12991 | IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, | |
| 12992 | switch_target_instruction->base.source_node, target_value_ptr); | |
| 12993 | union_value->value.type = target_type; | |
| 12994 | ||
| 12995 | IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope, | |
| 12996 | switch_target_instruction->base.source_node, union_value); | |
| 12997 | union_tag_inst->value.type = tag_type; | |
| 12998 | ir_link_new_instruction(union_tag_inst, &switch_target_instruction->base); | |
| 12999 | return tag_type; | |
| 13000 | } | |
| 13001 | case TypeTableEntryIdEnum: { | |
| 13002 | if (pointee_val) { | |
| 13003 | ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base); | |
| 13004 | bigint_init_bigint(&out_val->data.x_enum_tag, &pointee_val->data.x_enum_tag); | |
| 13005 | return target_type; | |
| 13006 | } | |
| 13007 | ||
| 13008 | IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope, | |
| 13009 | switch_target_instruction->base.source_node, target_value_ptr); | |
| 13010 | enum_value->value.type = target_type; | |
| 13011 | ir_link_new_instruction(enum_value, &switch_target_instruction->base); | |
| 13012 | return target_type; | |
| 13013 | } | |
| 12965 | 13014 | case TypeTableEntryIdErrorUnion: |
| 12966 | // see https://github.com/andrewrk/zig/issues/83 | |
| 13015 | // see https://github.com/andrewrk/zig/issues/632 | |
| 12967 | 13016 | zig_panic("TODO switch on error union"); |
| 12968 | case TypeTableEntryIdEnumTag: | |
| 12969 | zig_panic("TODO switch on enum tag type"); | |
| 12970 | 13017 | case TypeTableEntryIdUnreachable: |
| 12971 | 13018 | case TypeTableEntryIdArray: |
| 12972 | 13019 | case TypeTableEntryIdStruct: |
| 12973 | 13020 | case TypeTableEntryIdUndefLit: |
| 12974 | 13021 | case TypeTableEntryIdNullLit: |
| 12975 | 13022 | case TypeTableEntryIdMaybe: |
| 12976 | case TypeTableEntryIdUnion: | |
| 12977 | 13023 | case TypeTableEntryIdBlock: |
| 12978 | 13024 | case TypeTableEntryIdBoundFn: |
| 12979 | 13025 | case TypeTableEntryIdArgTuple: |
| ... | ... | @@ -12996,19 +13042,13 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr |
| 12996 | 13042 | |
| 12997 | 13043 | assert(target_value_ptr->value.type->id == TypeTableEntryIdPointer); |
| 12998 | 13044 | TypeTableEntry *target_type = target_value_ptr->value.type->data.pointer.child_type; |
| 12999 | if (target_type->id == TypeTableEntryIdEnum) { | |
| 13045 | if (target_type->id == TypeTableEntryIdUnion) { | |
| 13000 | 13046 | ConstExprValue *prong_val = ir_resolve_const(ira, prong_value, UndefBad); |
| 13001 | 13047 | if (!prong_val) |
| 13002 | 13048 | return ira->codegen->builtin_types.entry_invalid; |
| 13003 | 13049 | |
| 13004 | TypeEnumField *field; | |
| 13005 | if (prong_value->value.type->id == TypeTableEntryIdEnumTag) { | |
| 13006 | field = &target_type->data.enumeration.fields[bigint_as_unsigned(&prong_val->data.x_bigint)]; | |
| 13007 | } else if (prong_value->value.type->id == TypeTableEntryIdEnum) { | |
| 13008 | field = &target_type->data.enumeration.fields[prong_val->data.x_enum.tag]; | |
| 13009 | } else { | |
| 13010 | zig_unreachable(); | |
| 13011 | } | |
| 13050 | assert(prong_value->value.type->id == TypeTableEntryIdEnum); | |
| 13051 | TypeUnionField *field = find_union_field_by_tag(target_type, &prong_val->data.x_enum_tag); | |
| 13012 | 13052 | |
| 13013 | 13053 | if (instr_is_comptime(target_value_ptr)) { |
| 13014 | 13054 | ConstExprValue *target_val_ptr = ir_resolve_const(ira, target_value_ptr, UndefBad); |
| ... | ... | @@ -13019,11 +13059,11 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr |
| 13019 | 13059 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 13020 | 13060 | out_val->data.x_ptr.special = ConstPtrSpecialRef; |
| 13021 | 13061 | out_val->data.x_ptr.mut = target_val_ptr->data.x_ptr.mut; |
| 13022 | out_val->data.x_ptr.data.ref.pointee = pointee_val->data.x_enum.payload; | |
| 13062 | out_val->data.x_ptr.data.ref.pointee = pointee_val->data.x_union.payload; | |
| 13023 | 13063 | return get_pointer_to_type(ira->codegen, field->type_entry, target_val_ptr->type->data.pointer.is_const); |
| 13024 | 13064 | } |
| 13025 | 13065 | |
| 13026 | ir_build_enum_field_ptr_from(&ira->new_irb, &instruction->base, target_value_ptr, field); | |
| 13066 | ir_build_union_field_ptr_from(&ira->new_irb, &instruction->base, target_value_ptr, field); | |
| 13027 | 13067 | return get_pointer_to_type(ira->codegen, field->type_entry, |
| 13028 | 13068 | target_value_ptr->value.type->data.pointer.is_const); |
| 13029 | 13069 | } else { |
| ... | ... | @@ -13033,10 +13073,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr |
| 13033 | 13073 | } |
| 13034 | 13074 | } |
| 13035 | 13075 | |
| 13036 | static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira, IrInstructionEnumTag *enum_tag_instruction) { | |
| 13037 | IrInstruction *value = enum_tag_instruction->value->other; | |
| 13038 | IrInstruction *new_instruction = ir_analyze_enum_tag(ira, &enum_tag_instruction->base, value); | |
| 13039 | ir_link_new_instruction(new_instruction, &enum_tag_instruction->base); | |
| 13076 | static TypeTableEntry *ir_analyze_instruction_union_tag(IrAnalyze *ira, IrInstructionUnionTag *instruction) { | |
| 13077 | IrInstruction *value = instruction->value->other; | |
| 13078 | IrInstruction *new_instruction = ir_analyze_union_tag(ira, &instruction->base, value); | |
| 13079 | ir_link_new_instruction(new_instruction, &instruction->base); | |
| 13040 | 13080 | return new_instruction->value.type; |
| 13041 | 13081 | } |
| 13042 | 13082 | |
| ... | ... | @@ -13192,7 +13232,7 @@ static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, Ir |
| 13192 | 13232 | |
| 13193 | 13233 | ConstExprValue *out_val = ir_build_const_from(ira, instruction); |
| 13194 | 13234 | out_val->data.x_union.payload = field_val; |
| 13195 | out_val->data.x_union.tag = type_field->value; | |
| 13235 | out_val->data.x_union.tag = type_field->enum_field->value; | |
| 13196 | 13236 | |
| 13197 | 13237 | ConstParent *parent = get_const_val_parent(ira->codegen, field_val); |
| 13198 | 13238 | if (parent != nullptr) { |
| ... | ... | @@ -13439,46 +13479,9 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira |
| 13439 | 13479 | buf_ptr(&container_type->name))); |
| 13440 | 13480 | return ira->codegen->builtin_types.entry_invalid; |
| 13441 | 13481 | } |
| 13442 | } else if (container_type_value->value.type->id == TypeTableEntryIdEnumTag) { | |
| 13443 | if (elem_count != 1) { | |
| 13444 | ir_add_error(ira, &instruction->base, buf_sprintf("enum initialization requires exactly one element")); | |
| 13445 | return ira->codegen->builtin_types.entry_invalid; | |
| 13446 | } | |
| 13447 | ConstExprValue *tag_value = ir_resolve_const(ira, container_type_value, UndefBad); | |
| 13448 | if (!tag_value) | |
| 13449 | return ira->codegen->builtin_types.entry_invalid; | |
| 13450 | ||
| 13451 | TypeTableEntry *enum_type = container_type_value->value.type->data.enum_tag.enum_type; | |
| 13452 | ||
| 13453 | uint64_t tag_uint = bigint_as_unsigned(&tag_value->data.x_bigint); | |
| 13454 | TypeEnumField *field = &enum_type->data.enumeration.fields[tag_uint]; | |
| 13455 | TypeTableEntry *this_field_type = field->type_entry; | |
| 13456 | ||
| 13457 | IrInstruction *init_value = instruction->items[0]->other; | |
| 13458 | if (type_is_invalid(init_value->value.type)) | |
| 13459 | return ira->codegen->builtin_types.entry_invalid; | |
| 13460 | ||
| 13461 | IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, this_field_type); | |
| 13462 | if (casted_init_value == ira->codegen->invalid_instruction) | |
| 13463 | return ira->codegen->builtin_types.entry_invalid; | |
| 13464 | ||
| 13465 | if (instr_is_comptime(casted_init_value)) { | |
| 13466 | ConstExprValue *init_val = ir_resolve_const(ira, casted_init_value, UndefOk); | |
| 13467 | if (!init_val) | |
| 13468 | return ira->codegen->builtin_types.entry_invalid; | |
| 13469 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 13470 | out_val->data.x_enum.tag = tag_uint; | |
| 13471 | out_val->data.x_enum.payload = init_val; | |
| 13472 | return enum_type; | |
| 13473 | } | |
| 13474 | ||
| 13475 | IrInstruction *new_instruction = ir_build_init_enum_from(&ira->new_irb, &instruction->base, | |
| 13476 | enum_type, field, casted_init_value); | |
| 13477 | ir_add_alloca(ira, new_instruction, enum_type); | |
| 13478 | return enum_type; | |
| 13479 | 13482 | } else { |
| 13480 | 13483 | ir_add_error(ira, container_type_value, |
| 13481 | buf_sprintf("expected type, found '%s'", buf_ptr(&container_type_value->value.type->name))); | |
| 13484 | buf_sprintf("expected type, found '%s' value", buf_ptr(&container_type_value->value.type->name))); | |
| 13482 | 13485 | return ira->codegen->builtin_types.entry_invalid; |
| 13483 | 13486 | } |
| 13484 | 13487 | } |
| ... | ... | @@ -13521,8 +13524,8 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ |
| 13521 | 13524 | eval_min_max_value(ira->codegen, target_type, out_val, is_max); |
| 13522 | 13525 | return target_type; |
| 13523 | 13526 | } |
| 13524 | case TypeTableEntryIdEnumTag: | |
| 13525 | zig_panic("TODO min/max value for enum tag type"); | |
| 13527 | case TypeTableEntryIdEnum: | |
| 13528 | zig_panic("TODO min/max value for enum type"); | |
| 13526 | 13529 | case TypeTableEntryIdVar: |
| 13527 | 13530 | case TypeTableEntryIdMetaType: |
| 13528 | 13531 | case TypeTableEntryIdUnreachable: |
| ... | ... | @@ -13536,7 +13539,6 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ |
| 13536 | 13539 | case TypeTableEntryIdMaybe: |
| 13537 | 13540 | case TypeTableEntryIdErrorUnion: |
| 13538 | 13541 | case TypeTableEntryIdPureError: |
| 13539 | case TypeTableEntryIdEnum: | |
| 13540 | 13542 | case TypeTableEntryIdUnion: |
| 13541 | 13543 | case TypeTableEntryIdFn: |
| 13542 | 13544 | case TypeTableEntryIdNamespace: |
| ... | ... | @@ -13639,29 +13641,27 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc |
| 13639 | 13641 | return str_type; |
| 13640 | 13642 | } |
| 13641 | 13643 | |
| 13642 | static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructionEnumTagName *instruction) { | |
| 13644 | static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrInstructionTagName *instruction) { | |
| 13643 | 13645 | IrInstruction *target = instruction->target->other; |
| 13644 | 13646 | if (type_is_invalid(target->value.type)) |
| 13645 | 13647 | return ira->codegen->builtin_types.entry_invalid; |
| 13646 | 13648 | |
| 13647 | assert(target->value.type->id == TypeTableEntryIdEnumTag); | |
| 13649 | assert(target->value.type->id == TypeTableEntryIdEnum); | |
| 13648 | 13650 | |
| 13649 | 13651 | if (instr_is_comptime(target)) { |
| 13650 | TypeTableEntry *enum_type = target->value.type->data.enum_tag.enum_type; | |
| 13651 | uint64_t tag_value = bigint_as_unsigned(&target->value.data.x_bigint); | |
| 13652 | TypeEnumField *field = &enum_type->data.enumeration.fields[tag_value]; | |
| 13652 | TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint); | |
| 13653 | 13653 | ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name); |
| 13654 | 13654 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 13655 | 13655 | init_const_slice(ira->codegen, out_val, array_val, 0, buf_len(field->name), true); |
| 13656 | 13656 | return out_val->type; |
| 13657 | 13657 | } |
| 13658 | 13658 | |
| 13659 | if (!target->value.type->data.enum_tag.generate_name_table) { | |
| 13660 | target->value.type->data.enum_tag.generate_name_table = true; | |
| 13659 | if (!target->value.type->data.enumeration.generate_name_table) { | |
| 13660 | target->value.type->data.enumeration.generate_name_table = true; | |
| 13661 | 13661 | ira->codegen->name_table_enums.append(target->value.type); |
| 13662 | 13662 | } |
| 13663 | 13663 | |
| 13664 | IrInstruction *result = ir_build_enum_tag_name(&ira->new_irb, instruction->base.scope, | |
| 13664 | IrInstruction *result = ir_build_tag_name(&ira->new_irb, instruction->base.scope, | |
| 13665 | 13665 | instruction->base.source_node, target); |
| 13666 | 13666 | ir_link_new_instruction(result, &instruction->base); |
| 13667 | 13667 | TypeTableEntry *u8_ptr_type = get_pointer_to_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true); |
| ... | ... | @@ -13806,7 +13806,7 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira, |
| 13806 | 13806 | TypeTableEntry *result_type = var_value->data.x_type; |
| 13807 | 13807 | |
| 13808 | 13808 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 13809 | out_val->data.x_enum.tag = type_id_index(type_entry->id); | |
| 13809 | bigint_init_unsigned(&out_val->data.x_enum_tag, type_id_index(type_entry->id)); | |
| 13810 | 13810 | return result_type; |
| 13811 | 13811 | } |
| 13812 | 13812 | |
| ... | ... | @@ -13870,7 +13870,10 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc |
| 13870 | 13870 | |
| 13871 | 13871 | int err; |
| 13872 | 13872 | if ((err = parse_h_buf(child_import, &errors, &cimport_scope->buf, ira->codegen, node))) { |
| 13873 | zig_panic("unable to parse C file: %s\n", err_str(err)); | |
| 13873 | if (err != ErrorCCompileErrors) { | |
| 13874 | ir_add_error_node(ira, node, buf_sprintf("C import failed: %s", err_str(err))); | |
| 13875 | return ira->codegen->builtin_types.entry_invalid; | |
| 13876 | } | |
| 13874 | 13877 | } |
| 13875 | 13878 | |
| 13876 | 13879 | if (errors.length > 0) { |
| ... | ... | @@ -14632,14 +14635,14 @@ static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInst |
| 14632 | 14635 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 14633 | 14636 | out_val->data.x_type = field->type_entry; |
| 14634 | 14637 | return ira->codegen->builtin_types.entry_type; |
| 14635 | } else if (container_type->id == TypeTableEntryIdEnum) { | |
| 14636 | if (member_index >= container_type->data.enumeration.src_field_count) { | |
| 14638 | } else if (container_type->id == TypeTableEntryIdUnion) { | |
| 14639 | if (member_index >= container_type->data.unionation.src_field_count) { | |
| 14637 | 14640 | ir_add_error(ira, index_value, |
| 14638 | 14641 | buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members", |
| 14639 | member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count)); | |
| 14642 | member_index, buf_ptr(&container_type->name), container_type->data.unionation.src_field_count)); | |
| 14640 | 14643 | return ira->codegen->builtin_types.entry_invalid; |
| 14641 | 14644 | } |
| 14642 | TypeEnumField *field = &container_type->data.enumeration.fields[member_index]; | |
| 14645 | TypeUnionField *field = &container_type->data.unionation.fields[member_index]; | |
| 14643 | 14646 | |
| 14644 | 14647 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 14645 | 14648 | out_val->data.x_type = field->type_entry; |
| ... | ... | @@ -14683,6 +14686,18 @@ static TypeTableEntry *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInst |
| 14683 | 14686 | } |
| 14684 | 14687 | TypeEnumField *field = &container_type->data.enumeration.fields[member_index]; |
| 14685 | 14688 | |
| 14689 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 14690 | init_const_str_lit(ira->codegen, out_val, field->name); | |
| 14691 | return out_val->type; | |
| 14692 | } else if (container_type->id == TypeTableEntryIdUnion) { | |
| 14693 | if (member_index >= container_type->data.unionation.src_field_count) { | |
| 14694 | ir_add_error(ira, index_value, | |
| 14695 | buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members", | |
| 14696 | member_index, buf_ptr(&container_type->name), container_type->data.unionation.src_field_count)); | |
| 14697 | return ira->codegen->builtin_types.entry_invalid; | |
| 14698 | } | |
| 14699 | TypeUnionField *field = &container_type->data.unionation.fields[member_index]; | |
| 14700 | ||
| 14686 | 14701 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); |
| 14687 | 14702 | init_const_str_lit(ira->codegen, out_val, field->name); |
| 14688 | 14703 | return out_val->type; |
| ... | ... | @@ -14753,7 +14768,6 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc |
| 14753 | 14768 | case TypeTableEntryIdErrorUnion: |
| 14754 | 14769 | case TypeTableEntryIdPureError: |
| 14755 | 14770 | case TypeTableEntryIdEnum: |
| 14756 | case TypeTableEntryIdEnumTag: | |
| 14757 | 14771 | case TypeTableEntryIdUnion: |
| 14758 | 14772 | case TypeTableEntryIdFn: |
| 14759 | 14773 | { |
| ... | ... | @@ -15059,9 +15073,10 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira |
| 15059 | 15073 | if (type_is_invalid(switch_type)) |
| 15060 | 15074 | return ira->codegen->builtin_types.entry_invalid; |
| 15061 | 15075 | |
| 15062 | if (switch_type->id == TypeTableEntryIdEnumTag) { | |
| 15063 | TypeTableEntry *enum_type = switch_type->data.enum_tag.enum_type; | |
| 15064 | AstNode **field_prev_uses = allocate<AstNode *>(enum_type->data.enumeration.src_field_count); | |
| 15076 | if (switch_type->id == TypeTableEntryIdEnum) { | |
| 15077 | HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> field_prev_uses = {}; | |
| 15078 | field_prev_uses.init(switch_type->data.enumeration.src_field_count); | |
| 15079 | ||
| 15065 | 15080 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { |
| 15066 | 15081 | IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i]; |
| 15067 | 15082 | |
| ... | ... | @@ -15073,41 +15088,43 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira |
| 15073 | 15088 | if (type_is_invalid(end_value->value.type)) |
| 15074 | 15089 | return ira->codegen->builtin_types.entry_invalid; |
| 15075 | 15090 | |
| 15076 | size_t start_index; | |
| 15077 | size_t end_index; | |
| 15078 | if (start_value->value.type->id == TypeTableEntryIdEnumTag) { | |
| 15079 | start_index = bigint_as_unsigned(&start_value->value.data.x_bigint); | |
| 15080 | } else if (start_value->value.type->id == TypeTableEntryIdEnum) { | |
| 15081 | start_index = start_value->value.data.x_enum.tag; | |
| 15082 | } else { | |
| 15083 | zig_unreachable(); | |
| 15084 | } | |
| 15085 | if (end_value->value.type->id == TypeTableEntryIdEnumTag) { | |
| 15086 | end_index = bigint_as_unsigned(&end_value->value.data.x_bigint); | |
| 15087 | } else if (end_value->value.type->id == TypeTableEntryIdEnum) { | |
| 15088 | end_index = end_value->value.data.x_enum.tag; | |
| 15089 | } else { | |
| 15090 | zig_unreachable(); | |
| 15091 | } | |
| 15091 | assert(start_value->value.type->id == TypeTableEntryIdEnum); | |
| 15092 | BigInt start_index; | |
| 15093 | bigint_init_bigint(&start_index, &start_value->value.data.x_enum_tag); | |
| 15092 | 15094 | |
| 15093 | for (size_t field_index = start_index; field_index <= end_index; field_index += 1) { | |
| 15094 | AstNode *prev_node = field_prev_uses[field_index]; | |
| 15095 | if (prev_node != nullptr) { | |
| 15096 | TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_index]; | |
| 15095 | assert(end_value->value.type->id == TypeTableEntryIdEnum); | |
| 15096 | BigInt end_index; | |
| 15097 | bigint_init_bigint(&end_index, &end_value->value.data.x_enum_tag); | |
| 15098 | ||
| 15099 | BigInt field_index; | |
| 15100 | bigint_init_bigint(&field_index, &start_index); | |
| 15101 | for (;;) { | |
| 15102 | Cmp cmp = bigint_cmp(&field_index, &end_index); | |
| 15103 | if (cmp == CmpGT) { | |
| 15104 | break; | |
| 15105 | } | |
| 15106 | auto entry = field_prev_uses.put_unique(field_index, start_value->source_node); | |
| 15107 | if (entry) { | |
| 15108 | AstNode *prev_node = entry->value; | |
| 15109 | TypeEnumField *enum_field = find_enum_field_by_tag(switch_type, &field_index); | |
| 15110 | assert(enum_field != nullptr); | |
| 15097 | 15111 | ErrorMsg *msg = ir_add_error(ira, start_value, |
| 15098 | buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&enum_type->name), | |
| 15099 | buf_ptr(type_enum_field->name))); | |
| 15112 | buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name), | |
| 15113 | buf_ptr(enum_field->name))); | |
| 15100 | 15114 | add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value is here")); |
| 15101 | 15115 | } |
| 15102 | field_prev_uses[field_index] = start_value->source_node; | |
| 15116 | bigint_incr(&field_index); | |
| 15103 | 15117 | } |
| 15104 | 15118 | } |
| 15105 | 15119 | if (!instruction->have_else_prong) { |
| 15106 | for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) { | |
| 15107 | if (field_prev_uses[i] == nullptr) { | |
| 15120 | for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) { | |
| 15121 | TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i]; | |
| 15122 | ||
| 15123 | auto entry = field_prev_uses.maybe_get(enum_field->value); | |
| 15124 | if (!entry) { | |
| 15108 | 15125 | ir_add_error(ira, &instruction->base, |
| 15109 | buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&enum_type->name), | |
| 15110 | buf_ptr(enum_type->data.enumeration.fields[i].name))); | |
| 15126 | buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&switch_type->name), | |
| 15127 | buf_ptr(enum_field->name))); | |
| 15111 | 15128 | } |
| 15112 | 15129 | } |
| 15113 | 15130 | } |
| ... | ... | @@ -15402,8 +15419,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 15402 | 15419 | zig_panic("TODO buf_write_value_bytes pure error type"); |
| 15403 | 15420 | case TypeTableEntryIdEnum: |
| 15404 | 15421 | zig_panic("TODO buf_write_value_bytes enum type"); |
| 15405 | case TypeTableEntryIdEnumTag: | |
| 15406 | zig_panic("TODO buf_write_value_bytes enum tag type"); | |
| 15407 | 15422 | case TypeTableEntryIdFn: |
| 15408 | 15423 | zig_panic("TODO buf_write_value_bytes fn type"); |
| 15409 | 15424 | case TypeTableEntryIdUnion: |
| ... | ... | @@ -15462,8 +15477,6 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue |
| 15462 | 15477 | zig_panic("TODO buf_read_value_bytes pure error type"); |
| 15463 | 15478 | case TypeTableEntryIdEnum: |
| 15464 | 15479 | zig_panic("TODO buf_read_value_bytes enum type"); |
| 15465 | case TypeTableEntryIdEnumTag: | |
| 15466 | zig_panic("TODO buf_read_value_bytes enum tag type"); | |
| 15467 | 15480 | case TypeTableEntryIdFn: |
| 15468 | 15481 | zig_panic("TODO buf_read_value_bytes fn type"); |
| 15469 | 15482 | case TypeTableEntryIdUnion: |
| ... | ... | @@ -15828,6 +15841,45 @@ static TypeTableEntry *ir_analyze_instruction_arg_type(IrAnalyze *ira, IrInstruc |
| 15828 | 15841 | return ira->codegen->builtin_types.entry_type; |
| 15829 | 15842 | } |
| 15830 | 15843 | |
| 15844 | static TypeTableEntry *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstructionTagType *instruction) { | |
| 15845 | IrInstruction *target_inst = instruction->target->other; | |
| 15846 | TypeTableEntry *enum_type = ir_resolve_type(ira, target_inst); | |
| 15847 | if (type_is_invalid(enum_type)) | |
| 15848 | return ira->codegen->builtin_types.entry_invalid; | |
| 15849 | ||
| 15850 | if (enum_type->id == TypeTableEntryIdEnum) { | |
| 15851 | ensure_complete_type(ira->codegen, enum_type); | |
| 15852 | if (type_is_invalid(enum_type)) | |
| 15853 | return ira->codegen->builtin_types.entry_invalid; | |
| 15854 | ||
| 15855 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 15856 | out_val->data.x_type = enum_type->data.enumeration.tag_int_type; | |
| 15857 | return ira->codegen->builtin_types.entry_type; | |
| 15858 | } else if (enum_type->id == TypeTableEntryIdUnion) { | |
| 15859 | ensure_complete_type(ira->codegen, enum_type); | |
| 15860 | if (type_is_invalid(enum_type)) | |
| 15861 | return ira->codegen->builtin_types.entry_invalid; | |
| 15862 | ||
| 15863 | AstNode *decl_node = enum_type->data.unionation.decl_node; | |
| 15864 | if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) { | |
| 15865 | assert(enum_type->data.unionation.tag_type != nullptr); | |
| 15866 | ||
| 15867 | ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); | |
| 15868 | out_val->data.x_type = enum_type->data.unionation.tag_type; | |
| 15869 | return ira->codegen->builtin_types.entry_type; | |
| 15870 | } else { | |
| 15871 | ErrorMsg *msg = ir_add_error(ira, target_inst, buf_sprintf("union '%s' has no tag", | |
| 15872 | buf_ptr(&enum_type->name))); | |
| 15873 | add_error_note(ira->codegen, msg, decl_node, buf_sprintf("consider 'union(enum)' here")); | |
| 15874 | return ira->codegen->builtin_types.entry_invalid; | |
| 15875 | } | |
| 15876 | } else { | |
| 15877 | ir_add_error(ira, target_inst, buf_sprintf("expected enum or union, found '%s'", | |
| 15878 | buf_ptr(&enum_type->name))); | |
| 15879 | return ira->codegen->builtin_types.entry_invalid; | |
| 15880 | } | |
| 15881 | } | |
| 15882 | ||
| 15831 | 15883 | static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { |
| 15832 | 15884 | switch (instruction->id) { |
| 15833 | 15885 | case IrInstructionIdInvalid: |
| ... | ... | @@ -15838,9 +15890,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15838 | 15890 | case IrInstructionIdStructInit: |
| 15839 | 15891 | case IrInstructionIdUnionInit: |
| 15840 | 15892 | case IrInstructionIdStructFieldPtr: |
| 15841 | case IrInstructionIdEnumFieldPtr: | |
| 15842 | 15893 | case IrInstructionIdUnionFieldPtr: |
| 15843 | case IrInstructionIdInitEnum: | |
| 15844 | 15894 | case IrInstructionIdMaybeWrap: |
| 15845 | 15895 | case IrInstructionIdErrWrapCode: |
| 15846 | 15896 | case IrInstructionIdErrWrapPayload: |
| ... | ... | @@ -15912,8 +15962,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15912 | 15962 | return ir_analyze_instruction_switch_target(ira, (IrInstructionSwitchTarget *)instruction); |
| 15913 | 15963 | case IrInstructionIdSwitchVar: |
| 15914 | 15964 | return ir_analyze_instruction_switch_var(ira, (IrInstructionSwitchVar *)instruction); |
| 15915 | case IrInstructionIdEnumTag: | |
| 15916 | return ir_analyze_instruction_enum_tag(ira, (IrInstructionEnumTag *)instruction); | |
| 15965 | case IrInstructionIdUnionTag: | |
| 15966 | return ir_analyze_instruction_union_tag(ira, (IrInstructionUnionTag *)instruction); | |
| 15917 | 15967 | case IrInstructionIdImport: |
| 15918 | 15968 | return ir_analyze_instruction_import(ira, (IrInstructionImport *)instruction); |
| 15919 | 15969 | case IrInstructionIdArrayLen: |
| ... | ... | @@ -16006,8 +16056,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 16006 | 16056 | return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction); |
| 16007 | 16057 | case IrInstructionIdPtrToInt: |
| 16008 | 16058 | return ir_analyze_instruction_ptr_to_int(ira, (IrInstructionPtrToInt *)instruction); |
| 16009 | case IrInstructionIdEnumTagName: | |
| 16010 | return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionEnumTagName *)instruction); | |
| 16059 | case IrInstructionIdTagName: | |
| 16060 | return ir_analyze_instruction_enum_tag_name(ira, (IrInstructionTagName *)instruction); | |
| 16011 | 16061 | case IrInstructionIdFieldParentPtr: |
| 16012 | 16062 | return ir_analyze_instruction_field_parent_ptr(ira, (IrInstructionFieldParentPtr *)instruction); |
| 16013 | 16063 | case IrInstructionIdOffsetOf: |
| ... | ... | @@ -16026,6 +16076,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 16026 | 16076 | return ir_analyze_instruction_set_align_stack(ira, (IrInstructionSetAlignStack *)instruction); |
| 16027 | 16077 | case IrInstructionIdArgType: |
| 16028 | 16078 | return ir_analyze_instruction_arg_type(ira, (IrInstructionArgType *)instruction); |
| 16079 | case IrInstructionIdTagType: | |
| 16080 | return ir_analyze_instruction_tag_type(ira, (IrInstructionTagType *)instruction); | |
| 16029 | 16081 | } |
| 16030 | 16082 | zig_unreachable(); |
| 16031 | 16083 | } |
| ... | ... | @@ -16158,7 +16210,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 16158 | 16210 | case IrInstructionIdPtrTypeChild: |
| 16159 | 16211 | case IrInstructionIdArrayLen: |
| 16160 | 16212 | case IrInstructionIdStructFieldPtr: |
| 16161 | case IrInstructionIdEnumFieldPtr: | |
| 16162 | 16213 | case IrInstructionIdUnionFieldPtr: |
| 16163 | 16214 | case IrInstructionIdArrayType: |
| 16164 | 16215 | case IrInstructionIdSliceType: |
| ... | ... | @@ -16169,7 +16220,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 16169 | 16220 | case IrInstructionIdCtz: |
| 16170 | 16221 | case IrInstructionIdSwitchVar: |
| 16171 | 16222 | case IrInstructionIdSwitchTarget: |
| 16172 | case IrInstructionIdEnumTag: | |
| 16223 | case IrInstructionIdUnionTag: | |
| 16173 | 16224 | case IrInstructionIdRef: |
| 16174 | 16225 | case IrInstructionIdMinValue: |
| 16175 | 16226 | case IrInstructionIdMaxValue: |
| ... | ... | @@ -16191,7 +16242,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 16191 | 16242 | case IrInstructionIdErrWrapPayload: |
| 16192 | 16243 | case IrInstructionIdFnProto: |
| 16193 | 16244 | case IrInstructionIdTestComptime: |
| 16194 | case IrInstructionIdInitEnum: | |
| 16195 | 16245 | case IrInstructionIdPtrCast: |
| 16196 | 16246 | case IrInstructionIdBitCast: |
| 16197 | 16247 | case IrInstructionIdWidenOrShorten: |
| ... | ... | @@ -16204,13 +16254,14 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 16204 | 16254 | case IrInstructionIdDeclRef: |
| 16205 | 16255 | case IrInstructionIdErrName: |
| 16206 | 16256 | case IrInstructionIdTypeName: |
| 16207 | case IrInstructionIdEnumTagName: | |
| 16257 | case IrInstructionIdTagName: | |
| 16208 | 16258 | case IrInstructionIdFieldParentPtr: |
| 16209 | 16259 | case IrInstructionIdOffsetOf: |
| 16210 | 16260 | case IrInstructionIdTypeId: |
| 16211 | 16261 | case IrInstructionIdAlignCast: |
| 16212 | 16262 | case IrInstructionIdOpaqueType: |
| 16213 | 16263 | case IrInstructionIdArgType: |
| 16264 | case IrInstructionIdTagType: | |
| 16214 | 16265 | return false; |
| 16215 | 16266 | case IrInstructionIdAsm: |
| 16216 | 16267 | { |
src/ir_print.cpp+19-29| ... | ... | @@ -291,7 +291,7 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct |
| 291 | 291 | } |
| 292 | 292 | |
| 293 | 293 | static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) { |
| 294 | Buf *field_name = instruction->field->name; | |
| 294 | Buf *field_name = instruction->field->enum_field->name; | |
| 295 | 295 | |
| 296 | 296 | fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name)); |
| 297 | 297 | fprintf(irp->f, ".%s = ", buf_ptr(field_name)); |
| ... | ... | @@ -361,17 +361,10 @@ static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr |
| 361 | 361 | fprintf(irp->f, ")"); |
| 362 | 362 | } |
| 363 | 363 | |
| 364 | static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *instruction) { | |
| 365 | fprintf(irp->f, "@EnumFieldPtr(&"); | |
| 366 | ir_print_other_instruction(irp, instruction->enum_ptr); | |
| 367 | fprintf(irp->f, ".%s", buf_ptr(instruction->field->name)); | |
| 368 | fprintf(irp->f, ")"); | |
| 369 | } | |
| 370 | ||
| 371 | 364 | static void ir_print_union_field_ptr(IrPrint *irp, IrInstructionUnionFieldPtr *instruction) { |
| 372 | 365 | fprintf(irp->f, "@UnionFieldPtr(&"); |
| 373 | 366 | ir_print_other_instruction(irp, instruction->union_ptr); |
| 374 | fprintf(irp->f, ".%s", buf_ptr(instruction->field->name)); | |
| 367 | fprintf(irp->f, ".%s", buf_ptr(instruction->field->enum_field->name)); | |
| 375 | 368 | fprintf(irp->f, ")"); |
| 376 | 369 | } |
| 377 | 370 | |
| ... | ... | @@ -509,8 +502,8 @@ static void ir_print_switch_target(IrPrint *irp, IrInstructionSwitchTarget *inst |
| 509 | 502 | ir_print_other_instruction(irp, instruction->target_value_ptr); |
| 510 | 503 | } |
| 511 | 504 | |
| 512 | static void ir_print_enum_tag(IrPrint *irp, IrInstructionEnumTag *instruction) { | |
| 513 | fprintf(irp->f, "enumtag "); | |
| 505 | static void ir_print_union_tag(IrPrint *irp, IrInstructionUnionTag *instruction) { | |
| 506 | fprintf(irp->f, "uniontag "); | |
| 514 | 507 | ir_print_other_instruction(irp, instruction->value); |
| 515 | 508 | } |
| 516 | 509 | |
| ... | ... | @@ -799,12 +792,6 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst |
| 799 | 792 | fprintf(irp->f, ")"); |
| 800 | 793 | } |
| 801 | 794 | |
| 802 | static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction) { | |
| 803 | fprintf(irp->f, "%s.%s {", buf_ptr(&instruction->enum_type->name), buf_ptr(instruction->field->name)); | |
| 804 | ir_print_other_instruction(irp, instruction->init_value); | |
| 805 | fprintf(irp->f, "}"); | |
| 806 | } | |
| 807 | ||
| 808 | 795 | static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) { |
| 809 | 796 | fprintf(irp->f, "@ptrCast("); |
| 810 | 797 | if (instruction->dest_type) { |
| ... | ... | @@ -885,8 +872,8 @@ static void ir_print_type_name(IrPrint *irp, IrInstructionTypeName *instruction) |
| 885 | 872 | ir_print_other_instruction(irp, instruction->type_value); |
| 886 | 873 | } |
| 887 | 874 | |
| 888 | static void ir_print_enum_tag_name(IrPrint *irp, IrInstructionEnumTagName *instruction) { | |
| 889 | fprintf(irp->f, "enumtagname "); | |
| 875 | static void ir_print_tag_name(IrPrint *irp, IrInstructionTagName *instruction) { | |
| 876 | fprintf(irp->f, "tagname "); | |
| 890 | 877 | ir_print_other_instruction(irp, instruction->target); |
| 891 | 878 | } |
| 892 | 879 | |
| ... | ... | @@ -994,6 +981,12 @@ static void ir_print_arg_type(IrPrint *irp, IrInstructionArgType *instruction) { |
| 994 | 981 | fprintf(irp->f, ")"); |
| 995 | 982 | } |
| 996 | 983 | |
| 984 | static void ir_print_enum_tag_type(IrPrint *irp, IrInstructionTagType *instruction) { | |
| 985 | fprintf(irp->f, "@TagType("); | |
| 986 | ir_print_other_instruction(irp, instruction->target); | |
| 987 | fprintf(irp->f, ")"); | |
| 988 | } | |
| 989 | ||
| 997 | 990 | |
| 998 | 991 | static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 999 | 992 | ir_print_prefix(irp, instruction); |
| ... | ... | @@ -1072,9 +1065,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1072 | 1065 | case IrInstructionIdStructFieldPtr: |
| 1073 | 1066 | ir_print_struct_field_ptr(irp, (IrInstructionStructFieldPtr *)instruction); |
| 1074 | 1067 | break; |
| 1075 | case IrInstructionIdEnumFieldPtr: | |
| 1076 | ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction); | |
| 1077 | break; | |
| 1078 | 1068 | case IrInstructionIdUnionFieldPtr: |
| 1079 | 1069 | ir_print_union_field_ptr(irp, (IrInstructionUnionFieldPtr *)instruction); |
| 1080 | 1070 | break; |
| ... | ... | @@ -1117,8 +1107,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1117 | 1107 | case IrInstructionIdSwitchTarget: |
| 1118 | 1108 | ir_print_switch_target(irp, (IrInstructionSwitchTarget *)instruction); |
| 1119 | 1109 | break; |
| 1120 | case IrInstructionIdEnumTag: | |
| 1121 | ir_print_enum_tag(irp, (IrInstructionEnumTag *)instruction); | |
| 1110 | case IrInstructionIdUnionTag: | |
| 1111 | ir_print_union_tag(irp, (IrInstructionUnionTag *)instruction); | |
| 1122 | 1112 | break; |
| 1123 | 1113 | case IrInstructionIdImport: |
| 1124 | 1114 | ir_print_import(irp, (IrInstructionImport *)instruction); |
| ... | ... | @@ -1231,9 +1221,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1231 | 1221 | case IrInstructionIdTestComptime: |
| 1232 | 1222 | ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction); |
| 1233 | 1223 | break; |
| 1234 | case IrInstructionIdInitEnum: | |
| 1235 | ir_print_init_enum(irp, (IrInstructionInitEnum *)instruction); | |
| 1236 | break; | |
| 1237 | 1224 | case IrInstructionIdPtrCast: |
| 1238 | 1225 | ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction); |
| 1239 | 1226 | break; |
| ... | ... | @@ -1267,8 +1254,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1267 | 1254 | case IrInstructionIdTypeName: |
| 1268 | 1255 | ir_print_type_name(irp, (IrInstructionTypeName *)instruction); |
| 1269 | 1256 | break; |
| 1270 | case IrInstructionIdEnumTagName: | |
| 1271 | ir_print_enum_tag_name(irp, (IrInstructionEnumTagName *)instruction); | |
| 1257 | case IrInstructionIdTagName: | |
| 1258 | ir_print_tag_name(irp, (IrInstructionTagName *)instruction); | |
| 1272 | 1259 | break; |
| 1273 | 1260 | case IrInstructionIdCanImplicitCast: |
| 1274 | 1261 | ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction); |
| ... | ... | @@ -1312,6 +1299,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1312 | 1299 | case IrInstructionIdArgType: |
| 1313 | 1300 | ir_print_arg_type(irp, (IrInstructionArgType *)instruction); |
| 1314 | 1301 | break; |
| 1302 | case IrInstructionIdTagType: | |
| 1303 | ir_print_enum_tag_type(irp, (IrInstructionTagType *)instruction); | |
| 1304 | break; | |
| 1315 | 1305 | } |
| 1316 | 1306 | fprintf(irp->f, "\n"); |
| 1317 | 1307 | } |
src/os.cpp+5| ... | ... | @@ -931,6 +931,7 @@ int os_self_exe_path(Buf *out_path) { |
| 931 | 931 | #define VT_GREEN "\x1b[32;1m" |
| 932 | 932 | #define VT_CYAN "\x1b[36;1m" |
| 933 | 933 | #define VT_WHITE "\x1b[37;1m" |
| 934 | #define VT_BOLD "\x1b[0;1m" | |
| 934 | 935 | #define VT_RESET "\x1b[0m" |
| 935 | 936 | |
| 936 | 937 | static void set_color_posix(TermColor color) { |
| ... | ... | @@ -947,6 +948,9 @@ static void set_color_posix(TermColor color) { |
| 947 | 948 | case TermColorWhite: |
| 948 | 949 | fprintf(stderr, VT_WHITE); |
| 949 | 950 | break; |
| 951 | case TermColorBold: | |
| 952 | fprintf(stderr, VT_BOLD); | |
| 953 | break; | |
| 950 | 954 | case TermColorReset: |
| 951 | 955 | fprintf(stderr, VT_RESET); |
| 952 | 956 | break; |
| ... | ... | @@ -989,6 +993,7 @@ void os_stderr_set_color(TermColor color) { |
| 989 | 993 | SetConsoleTextAttribute(stderr_handle, FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY); |
| 990 | 994 | break; |
| 991 | 995 | case TermColorWhite: |
| 996 | case TermColorBold: | |
| 992 | 997 | SetConsoleTextAttribute(stderr_handle, |
| 993 | 998 | FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY); |
| 994 | 999 | break; |
src/os.hpp+1| ... | ... | @@ -21,6 +21,7 @@ enum TermColor { |
| 21 | 21 | TermColorGreen, |
| 22 | 22 | TermColorCyan, |
| 23 | 23 | TermColorWhite, |
| 24 | TermColorBold, | |
| 24 | 25 | TermColorReset, |
| 25 | 26 | }; |
| 26 | 27 |
src/parser.cpp+48-20| ... | ... | @@ -2377,9 +2377,11 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi |
| 2377 | 2377 | } |
| 2378 | 2378 | |
| 2379 | 2379 | /* |
| 2380 | ContainerDecl = option("extern" | "packed") ("struct" | "enum" | "union") "{" many(ContainerMember) "}" | |
| 2380 | ContainerDecl = option("extern" | "packed") | |
| 2381 | ("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression))) | |
| 2382 | "{" many(ContainerMember) "}" | |
| 2381 | 2383 | ContainerMember = (ContainerField | FnDef | GlobalVarDecl) |
| 2382 | ContainerField = Symbol option(":" Expression) "," | |
| 2384 | ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression "," | |
| 2383 | 2385 | */ |
| 2384 | 2386 | static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory) { |
| 2385 | 2387 | Token *first_token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -2415,6 +2417,28 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, |
| 2415 | 2417 | node->data.container_decl.layout = layout; |
| 2416 | 2418 | node->data.container_decl.kind = kind; |
| 2417 | 2419 | |
| 2420 | if (kind == ContainerKindUnion) { | |
| 2421 | Token *lparen_token = &pc->tokens->at(*token_index); | |
| 2422 | if (lparen_token->id == TokenIdLParen) { | |
| 2423 | Token *enum_token = &pc->tokens->at(*token_index + 1); | |
| 2424 | if (enum_token->id == TokenIdKeywordEnum) { | |
| 2425 | Token *paren_token = &pc->tokens->at(*token_index + 2); | |
| 2426 | if (paren_token->id == TokenIdLParen) { | |
| 2427 | node->data.container_decl.auto_enum = true; | |
| 2428 | *token_index += 2; | |
| 2429 | node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, true); | |
| 2430 | ast_eat_token(pc, token_index, TokenIdRParen); | |
| 2431 | } else if (paren_token->id == TokenIdRParen) { | |
| 2432 | node->data.container_decl.auto_enum = true; | |
| 2433 | *token_index += 3; | |
| 2434 | } | |
| 2435 | } | |
| 2436 | } | |
| 2437 | } | |
| 2438 | if (!node->data.container_decl.auto_enum) { | |
| 2439 | node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, false); | |
| 2440 | } | |
| 2441 | ||
| 2418 | 2442 | ast_eat_token(pc, token_index, TokenIdLBrace); |
| 2419 | 2443 | |
| 2420 | 2444 | for (;;) { |
| ... | ... | @@ -2452,31 +2476,33 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, |
| 2452 | 2476 | AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token); |
| 2453 | 2477 | *token_index += 1; |
| 2454 | 2478 | |
| 2479 | node->data.container_decl.fields.append(field_node); | |
| 2455 | 2480 | field_node->data.struct_field.visib_mod = visib_mod; |
| 2456 | 2481 | field_node->data.struct_field.name = token_buf(token); |
| 2457 | 2482 | |
| 2458 | Token *token = &pc->tokens->at(*token_index); | |
| 2459 | if (token->id == TokenIdComma || token->id == TokenIdRBrace) { | |
| 2460 | field_node->data.struct_field.type = ast_create_void_type_node(pc, token); | |
| 2483 | Token *colon_token = &pc->tokens->at(*token_index); | |
| 2484 | if (colon_token->id == TokenIdColon) { | |
| 2485 | *token_index += 1; | |
| 2486 | field_node->data.struct_field.type = ast_parse_prefix_op_expr(pc, token_index, true); | |
| 2487 | } | |
| 2488 | Token *eq_token = &pc->tokens->at(*token_index); | |
| 2489 | if (eq_token->id == TokenIdEq) { | |
| 2461 | 2490 | *token_index += 1; |
| 2462 | node->data.container_decl.fields.append(field_node); | |
| 2491 | field_node->data.struct_field.value = ast_parse_prefix_op_expr(pc, token_index, true); | |
| 2492 | } | |
| 2463 | 2493 | |
| 2464 | if (token->id == TokenIdRBrace) { | |
| 2465 | break; | |
| 2466 | } | |
| 2467 | } else { | |
| 2468 | ast_eat_token(pc, token_index, TokenIdColon); | |
| 2469 | field_node->data.struct_field.type = ast_parse_expression(pc, token_index, true); | |
| 2470 | node->data.container_decl.fields.append(field_node); | |
| 2494 | Token *next_token = &pc->tokens->at(*token_index); | |
| 2495 | if (next_token->id == TokenIdComma) { | |
| 2496 | *token_index += 1; | |
| 2497 | continue; | |
| 2498 | } | |
| 2471 | 2499 | |
| 2472 | Token *token = &pc->tokens->at(*token_index); | |
| 2473 | if (token->id == TokenIdRBrace) { | |
| 2474 | *token_index += 1; | |
| 2475 | break; | |
| 2476 | } else { | |
| 2477 | ast_eat_token(pc, token_index, TokenIdComma); | |
| 2478 | } | |
| 2500 | if (next_token->id == TokenIdRBrace) { | |
| 2501 | *token_index += 1; | |
| 2502 | break; | |
| 2479 | 2503 | } |
| 2504 | ||
| 2505 | ast_invalid_token_error(pc, next_token); | |
| 2480 | 2506 | } else { |
| 2481 | 2507 | ast_invalid_token_error(pc, token); |
| 2482 | 2508 | } |
| ... | ... | @@ -2804,9 +2830,11 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont |
| 2804 | 2830 | case NodeTypeContainerDecl: |
| 2805 | 2831 | visit_node_list(&node->data.container_decl.fields, visit, context); |
| 2806 | 2832 | visit_node_list(&node->data.container_decl.decls, visit, context); |
| 2833 | visit_field(&node->data.container_decl.init_arg_expr, visit, context); | |
| 2807 | 2834 | break; |
| 2808 | 2835 | case NodeTypeStructField: |
| 2809 | 2836 | visit_field(&node->data.struct_field.type, visit, context); |
| 2837 | visit_field(&node->data.struct_field.value, visit, context); | |
| 2810 | 2838 | break; |
| 2811 | 2839 | case NodeTypeContainerInitExpr: |
| 2812 | 2840 | visit_field(&node->data.container_init_expr.type, visit, context); |
src/translate_c.cpp+30-3| ... | ... | @@ -651,6 +651,14 @@ static bool c_is_unsigned_integer(Context *c, QualType qt) { |
| 651 | 651 | } |
| 652 | 652 | } |
| 653 | 653 | |
| 654 | static bool c_is_builtin_type(Context *c, QualType qt, BuiltinType::Kind kind) { | |
| 655 | const Type *c_type = qual_type_canon(qt); | |
| 656 | if (c_type->getTypeClass() != Type::Builtin) | |
| 657 | return false; | |
| 658 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 659 | return builtin_ty->getKind() == kind; | |
| 660 | } | |
| 661 | ||
| 654 | 662 | static bool c_is_float(Context *c, QualType qt) { |
| 655 | 663 | const Type *c_type = qt.getTypePtr(); |
| 656 | 664 | if (c_type->getTypeClass() != Type::Builtin) |
| ... | ... | @@ -978,11 +986,23 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou |
| 978 | 986 | const AttributedType *attributed_ty = static_cast<const AttributedType *>(ty); |
| 979 | 987 | return trans_qual_type(c, attributed_ty->getEquivalentType(), source_loc); |
| 980 | 988 | } |
| 989 | case Type::IncompleteArray: | |
| 990 | { | |
| 991 | const IncompleteArrayType *incomplete_array_ty = static_cast<const IncompleteArrayType *>(ty); | |
| 992 | QualType child_qt = incomplete_array_ty->getElementType(); | |
| 993 | AstNode *child_type_node = trans_qual_type(c, child_qt, source_loc); | |
| 994 | if (child_type_node == nullptr) { | |
| 995 | emit_warning(c, source_loc, "unresolved array element type"); | |
| 996 | return nullptr; | |
| 997 | } | |
| 998 | AstNode *pointer_node = trans_create_node_addr_of(c, child_qt.isConstQualified(), | |
| 999 | child_qt.isVolatileQualified(), child_type_node); | |
| 1000 | return pointer_node; | |
| 1001 | } | |
| 981 | 1002 | case Type::BlockPointer: |
| 982 | 1003 | case Type::LValueReference: |
| 983 | 1004 | case Type::RValueReference: |
| 984 | 1005 | case Type::MemberPointer: |
| 985 | case Type::IncompleteArray: | |
| 986 | 1006 | case Type::VariableArray: |
| 987 | 1007 | case Type::DependentSizedArray: |
| 988 | 1008 | case Type::DependentSizedExtVector: |
| ... | ... | @@ -3417,7 +3437,14 @@ static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { |
| 3417 | 3437 | AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); |
| 3418 | 3438 | enum_node->data.container_decl.kind = ContainerKindEnum; |
| 3419 | 3439 | enum_node->data.container_decl.layout = ContainerLayoutExtern; |
| 3420 | enum_node->data.container_decl.init_arg_expr = tag_int_type; | |
| 3440 | // TODO only emit this tag type if the enum tag type is not the default. | |
| 3441 | // I don't know what the default is, need to figure out how clang is deciding. | |
| 3442 | // it appears to at least be different across gcc/msvc | |
| 3443 | if (!c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::UInt) && | |
| 3444 | !c_is_builtin_type(c, enum_decl->getIntegerType(), BuiltinType::Int)) | |
| 3445 | { | |
| 3446 | enum_node->data.container_decl.init_arg_expr = tag_int_type; | |
| 3447 | } | |
| 3421 | 3448 | |
| 3422 | 3449 | enum_node->data.container_decl.fields.resize(field_count); |
| 3423 | 3450 | uint32_t i = 0; |
| ... | ... | @@ -4304,7 +4331,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch |
| 4304 | 4331 | } |
| 4305 | 4332 | } |
| 4306 | 4333 | |
| 4307 | return 0; | |
| 4334 | return ErrorCCompileErrors; | |
| 4308 | 4335 | } |
| 4309 | 4336 | |
| 4310 | 4337 | c->ctx = &ast_unit->getASTContext(); |
src/zig_llvm.cpp+1-1| ... | ... | @@ -793,7 +793,7 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_ |
| 793 | 793 | zig_unreachable(); |
| 794 | 794 | |
| 795 | 795 | case ZigLLVM_COFF: |
| 796 | return lld::coff::link(array_ref_args, false); | |
| 796 | return lld::coff::link(array_ref_args, false, diag); | |
| 797 | 797 | |
| 798 | 798 | case ZigLLVM_ELF: |
| 799 | 799 | return lld::elf::link(array_ref_args, false, diag); |
std/buffer.zig+6| ... | ... | @@ -4,6 +4,8 @@ const Allocator = mem.Allocator; |
| 4 | 4 | const assert = debug.assert; |
| 5 | 5 | const ArrayList = @import("array_list.zig").ArrayList; |
| 6 | 6 | |
| 7 | const fmt = @import("fmt/index.zig"); | |
| 8 | ||
| 7 | 9 | /// A buffer that allocates memory and maintains a null byte at the end. |
| 8 | 10 | pub const Buffer = struct { |
| 9 | 11 | list: ArrayList(u8), |
| ... | ... | @@ -96,6 +98,10 @@ pub const Buffer = struct { |
| 96 | 98 | mem.copy(u8, self.list.toSlice()[old_len..], m); |
| 97 | 99 | } |
| 98 | 100 | |
| 101 | pub fn appendFormat(self: &Buffer, comptime format: []const u8, args: ...) -> %void { | |
| 102 | return fmt.format(self, append, format, args); | |
| 103 | } | |
| 104 | ||
| 99 | 105 | pub fn appendByte(self: &Buffer, byte: u8) -> %void { |
| 100 | 106 | return self.appendByteNTimes(byte, 1); |
| 101 | 107 | } |
std/build.zig+21-21| ... | ... | @@ -69,8 +69,8 @@ pub const Builder = struct { |
| 69 | 69 | used: bool, |
| 70 | 70 | }; |
| 71 | 71 | |
| 72 | const UserValue = enum { | |
| 73 | Flag, | |
| 72 | const UserValue = union(enum) { | |
| 73 | Flag: void, | |
| 74 | 74 | Scalar: []const u8, |
| 75 | 75 | List: ArrayList([]const u8), |
| 76 | 76 | }; |
| ... | ... | @@ -450,7 +450,7 @@ pub const Builder = struct { |
| 450 | 450 | pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) -> bool { |
| 451 | 451 | if (%%self.user_input_options.put(name, UserInputOption { |
| 452 | 452 | .name = name, |
| 453 | .value = UserValue.Scalar { value }, | |
| 453 | .value = UserValue { .Scalar = value }, | |
| 454 | 454 | .used = false, |
| 455 | 455 | })) |*prev_value| { |
| 456 | 456 | // option already exists |
| ... | ... | @@ -462,7 +462,7 @@ pub const Builder = struct { |
| 462 | 462 | %%list.append(value); |
| 463 | 463 | _ = %%self.user_input_options.put(name, UserInputOption { |
| 464 | 464 | .name = name, |
| 465 | .value = UserValue.List { list }, | |
| 465 | .value = UserValue { .List = list }, | |
| 466 | 466 | .used = false, |
| 467 | 467 | }); |
| 468 | 468 | }, |
| ... | ... | @@ -471,7 +471,7 @@ pub const Builder = struct { |
| 471 | 471 | %%list.append(value); |
| 472 | 472 | _ = %%self.user_input_options.put(name, UserInputOption { |
| 473 | 473 | .name = name, |
| 474 | .value = UserValue.List { *list }, | |
| 474 | .value = UserValue { .List = *list }, | |
| 475 | 475 | .used = false, |
| 476 | 476 | }); |
| 477 | 477 | }, |
| ... | ... | @@ -487,7 +487,7 @@ pub const Builder = struct { |
| 487 | 487 | pub fn addUserInputFlag(self: &Builder, name: []const u8) -> bool { |
| 488 | 488 | if (%%self.user_input_options.put(name, UserInputOption { |
| 489 | 489 | .name = name, |
| 490 | .value = UserValue.Flag, | |
| 490 | .value = UserValue {.Flag = {} }, | |
| 491 | 491 | .used = false, |
| 492 | 492 | })) |*prev_value| { |
| 493 | 493 | switch (prev_value.value) { |
| ... | ... | @@ -685,8 +685,8 @@ const CrossTarget = struct { |
| 685 | 685 | environ: builtin.Environ, |
| 686 | 686 | }; |
| 687 | 687 | |
| 688 | const Target = enum { | |
| 689 | Native, | |
| 688 | const Target = union(enum) { | |
| 689 | Native: void, | |
| 690 | 690 | Cross: CrossTarget, |
| 691 | 691 | |
| 692 | 692 | pub fn oFileExt(self: &const Target) -> []const u8 { |
| ... | ... | @@ -844,7 +844,7 @@ pub const LibExeObjStep = struct { |
| 844 | 844 | .kind = kind, |
| 845 | 845 | .root_src = root_src, |
| 846 | 846 | .name = name, |
| 847 | .target = Target.Native, | |
| 847 | .target = Target { .Native = {} }, | |
| 848 | 848 | .linker_script = null, |
| 849 | 849 | .link_libs = BufSet.init(builder.allocator), |
| 850 | 850 | .frameworks = BufSet.init(builder.allocator), |
| ... | ... | @@ -879,7 +879,7 @@ pub const LibExeObjStep = struct { |
| 879 | 879 | .kind = kind, |
| 880 | 880 | .version = *version, |
| 881 | 881 | .static = static, |
| 882 | .target = Target.Native, | |
| 882 | .target = Target { .Native = {} }, | |
| 883 | 883 | .cflags = ArrayList([]const u8).init(builder.allocator), |
| 884 | 884 | .source_files = ArrayList([]const u8).init(builder.allocator), |
| 885 | 885 | .object_files = ArrayList([]const u8).init(builder.allocator), |
| ... | ... | @@ -948,8 +948,8 @@ pub const LibExeObjStep = struct { |
| 948 | 948 | pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os, |
| 949 | 949 | target_environ: builtin.Environ) |
| 950 | 950 | { |
| 951 | self.target = Target.Cross { | |
| 952 | CrossTarget { | |
| 951 | self.target = Target { | |
| 952 | .Cross = CrossTarget { | |
| 953 | 953 | .arch = target_arch, |
| 954 | 954 | .os = target_os, |
| 955 | 955 | .environ = target_environ, |
| ... | ... | @@ -1186,13 +1186,13 @@ pub const LibExeObjStep = struct { |
| 1186 | 1186 | Target.Native => {}, |
| 1187 | 1187 | Target.Cross => |cross_target| { |
| 1188 | 1188 | %%zig_args.append("--target-arch"); |
| 1189 | %%zig_args.append(@enumTagName(cross_target.arch)); | |
| 1189 | %%zig_args.append(@tagName(cross_target.arch)); | |
| 1190 | 1190 | |
| 1191 | 1191 | %%zig_args.append("--target-os"); |
| 1192 | %%zig_args.append(@enumTagName(cross_target.os)); | |
| 1192 | %%zig_args.append(@tagName(cross_target.os)); | |
| 1193 | 1193 | |
| 1194 | 1194 | %%zig_args.append("--target-environ"); |
| 1195 | %%zig_args.append(@enumTagName(cross_target.environ)); | |
| 1195 | %%zig_args.append(@tagName(cross_target.environ)); | |
| 1196 | 1196 | }, |
| 1197 | 1197 | } |
| 1198 | 1198 | |
| ... | ... | @@ -1553,7 +1553,7 @@ pub const TestStep = struct { |
| 1553 | 1553 | .name_prefix = "", |
| 1554 | 1554 | .filter = null, |
| 1555 | 1555 | .link_libs = BufSet.init(builder.allocator), |
| 1556 | .target = Target.Native, | |
| 1556 | .target = Target { .Native = {} }, | |
| 1557 | 1557 | .exec_cmd_args = null, |
| 1558 | 1558 | } |
| 1559 | 1559 | } |
| ... | ... | @@ -1581,8 +1581,8 @@ pub const TestStep = struct { |
| 1581 | 1581 | pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os, |
| 1582 | 1582 | target_environ: builtin.Environ) |
| 1583 | 1583 | { |
| 1584 | self.target = Target.Cross { | |
| 1585 | CrossTarget { | |
| 1584 | self.target = Target { | |
| 1585 | .Cross = CrossTarget { | |
| 1586 | 1586 | .arch = target_arch, |
| 1587 | 1587 | .os = target_os, |
| 1588 | 1588 | .environ = target_environ, |
| ... | ... | @@ -1620,13 +1620,13 @@ pub const TestStep = struct { |
| 1620 | 1620 | Target.Native => {}, |
| 1621 | 1621 | Target.Cross => |cross_target| { |
| 1622 | 1622 | %%zig_args.append("--target-arch"); |
| 1623 | %%zig_args.append(@enumTagName(cross_target.arch)); | |
| 1623 | %%zig_args.append(@tagName(cross_target.arch)); | |
| 1624 | 1624 | |
| 1625 | 1625 | %%zig_args.append("--target-os"); |
| 1626 | %%zig_args.append(@enumTagName(cross_target.os)); | |
| 1626 | %%zig_args.append(@tagName(cross_target.os)); | |
| 1627 | 1627 | |
| 1628 | 1628 | %%zig_args.append("--target-environ"); |
| 1629 | %%zig_args.append(@enumTagName(cross_target.environ)); | |
| 1629 | %%zig_args.append(@tagName(cross_target.environ)); | |
| 1630 | 1630 | }, |
| 1631 | 1631 | } |
| 1632 | 1632 |
std/debug.zig+22-24| ... | ... | @@ -280,7 +280,7 @@ const AbbrevAttr = struct { |
| 280 | 280 | form_id: u64, |
| 281 | 281 | }; |
| 282 | 282 | |
| 283 | const FormValue = enum { | |
| 283 | const FormValue = union(enum) { | |
| 284 | 284 | Address: u64, |
| 285 | 285 | Block: []u8, |
| 286 | 286 | Const: Constant, |
| ... | ... | @@ -303,7 +303,7 @@ const Constant = struct { |
| 303 | 303 | return error.InvalidDebugInfo; |
| 304 | 304 | if (self.signed) |
| 305 | 305 | return error.InvalidDebugInfo; |
| 306 | return mem.readInt(self.payload, u64, false); | |
| 306 | return mem.readInt(self.payload, u64, builtin.Endian.Little); | |
| 307 | 307 | } |
| 308 | 308 | }; |
| 309 | 309 | |
| ... | ... | @@ -475,16 +475,16 @@ fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usiz |
| 475 | 475 | |
| 476 | 476 | fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue { |
| 477 | 477 | const buf = %return readAllocBytes(allocator, in_stream, size); |
| 478 | return FormValue.Block { buf }; | |
| 478 | return FormValue { .Block = buf }; | |
| 479 | 479 | } |
| 480 | 480 | |
| 481 | 481 | fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue { |
| 482 | const block_len = %return in_stream.readVarInt(false, usize, size); | |
| 482 | const block_len = %return in_stream.readVarInt(builtin.Endian.Little, usize, size); | |
| 483 | 483 | return parseFormValueBlockLen(allocator, in_stream, block_len); |
| 484 | 484 | } |
| 485 | 485 | |
| 486 | 486 | fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue { |
| 487 | FormValue.Const { Constant { | |
| 487 | FormValue { .Const = Constant { | |
| 488 | 488 | .signed = signed, |
| 489 | 489 | .payload = %return readAllocBytes(allocator, in_stream, size), |
| 490 | 490 | }} |
| ... | ... | @@ -510,7 +510,7 @@ fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 { |
| 510 | 510 | |
| 511 | 511 | fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue { |
| 512 | 512 | const buf = %return readAllocBytes(allocator, in_stream, size); |
| 513 | return FormValue.Ref { buf }; | |
| 513 | return FormValue { .Ref = buf }; | |
| 514 | 514 | } |
| 515 | 515 | |
| 516 | 516 | 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 |
| 520 | 520 | |
| 521 | 521 | fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue { |
| 522 | 522 | return switch (form_id) { |
| 523 | DW.FORM_addr => FormValue.Address { %return parseFormValueTargetAddrSize(in_stream) }, | |
| 523 | DW.FORM_addr => FormValue { .Address = %return parseFormValueTargetAddrSize(in_stream) }, | |
| 524 | 524 | DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), |
| 525 | 525 | DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2), |
| 526 | 526 | DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4), |
| ... | ... | @@ -540,13 +540,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u |
| 540 | 540 | DW.FORM_exprloc => { |
| 541 | 541 | const size = %return readULeb128(in_stream); |
| 542 | 542 | const buf = %return readAllocBytes(allocator, in_stream, size); |
| 543 | return FormValue.ExprLoc { buf }; | |
| 544 | }, | |
| 545 | DW.FORM_flag => FormValue.Flag { (%return in_stream.readByte()) != 0 }, | |
| 546 | DW.FORM_flag_present => FormValue.Flag { true }, | |
| 547 | DW.FORM_sec_offset => FormValue.SecOffset { | |
| 548 | %return parseFormValueDwarfOffsetSize(in_stream, is_64) | |
| 543 | return FormValue { .ExprLoc = buf }; | |
| 549 | 544 | }, |
| 545 | DW.FORM_flag => FormValue { .Flag = (%return in_stream.readByte()) != 0 }, | |
| 546 | DW.FORM_flag_present => FormValue { .Flag = true }, | |
| 547 | DW.FORM_sec_offset => FormValue { .SecOffset = %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, | |
| 550 | 548 | |
| 551 | 549 | DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8), |
| 552 | 550 | DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16), |
| ... | ... | @@ -557,11 +555,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u |
| 557 | 555 | parseFormValueRefLen(allocator, in_stream, ref_len) |
| 558 | 556 | }, |
| 559 | 557 | |
| 560 | DW.FORM_ref_addr => FormValue.RefAddr { %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, | |
| 561 | DW.FORM_ref_sig8 => FormValue.RefSig8 { %return in_stream.readIntLe(u64) }, | |
| 558 | DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, | |
| 559 | DW.FORM_ref_sig8 => FormValue { .RefSig8 = %return in_stream.readIntLe(u64) }, | |
| 562 | 560 | |
| 563 | DW.FORM_string => FormValue.String { %return readStringRaw(allocator, in_stream) }, | |
| 564 | DW.FORM_strp => FormValue.StrPtr { %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, | |
| 561 | DW.FORM_string => FormValue { .String = %return readStringRaw(allocator, in_stream) }, | |
| 562 | DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) }, | |
| 565 | 563 | DW.FORM_indirect => { |
| 566 | 564 | const child_form_id = %return readULeb128(in_stream); |
| 567 | 565 | parseFormValue(allocator, in_stream, child_form_id, is_64) |
| ... | ... | @@ -671,10 +669,10 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe |
| 671 | 669 | continue; |
| 672 | 670 | } |
| 673 | 671 | |
| 674 | const version = %return in_stream.readInt(st.elf.is_big_endian, u16); | |
| 672 | const version = %return in_stream.readInt(st.elf.endian, u16); | |
| 675 | 673 | if (version != 2) return error.InvalidDebugInfo; |
| 676 | 674 | |
| 677 | const prologue_length = %return in_stream.readInt(st.elf.is_big_endian, u32); | |
| 675 | const prologue_length = %return in_stream.readInt(st.elf.endian, u32); | |
| 678 | 676 | const prog_start_offset = (%return in_file.getPos()) + prologue_length; |
| 679 | 677 | |
| 680 | 678 | const minimum_instruction_length = %return in_stream.readByte(); |
| ... | ... | @@ -741,7 +739,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe |
| 741 | 739 | return error.MissingDebugInfo; |
| 742 | 740 | }, |
| 743 | 741 | DW.LNE_set_address => { |
| 744 | const addr = %return in_stream.readInt(st.elf.is_big_endian, usize); | |
| 742 | const addr = %return in_stream.readInt(st.elf.endian, usize); | |
| 745 | 743 | prog.address = addr; |
| 746 | 744 | }, |
| 747 | 745 | DW.LNE_define_file => { |
| ... | ... | @@ -803,7 +801,7 @@ fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, targe |
| 803 | 801 | prog.address += inc_addr; |
| 804 | 802 | }, |
| 805 | 803 | DW.LNS_fixed_advance_pc => { |
| 806 | const arg = %return in_stream.readInt(st.elf.is_big_endian, u16); | |
| 804 | const arg = %return in_stream.readInt(st.elf.endian, u16); | |
| 807 | 805 | prog.address += arg; |
| 808 | 806 | }, |
| 809 | 807 | DW.LNS_set_prologue_end => { |
| ... | ... | @@ -841,13 +839,13 @@ fn scanAllCompileUnits(st: &ElfStackTrace) -> %void { |
| 841 | 839 | return; |
| 842 | 840 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); |
| 843 | 841 | |
| 844 | const version = %return in_stream.readInt(st.elf.is_big_endian, u16); | |
| 842 | const version = %return in_stream.readInt(st.elf.endian, u16); | |
| 845 | 843 | if (version < 2 or version > 5) return error.InvalidDebugInfo; |
| 846 | 844 | |
| 847 | 845 | const debug_abbrev_offset = if (is_64) { |
| 848 | %return in_stream.readInt(st.elf.is_big_endian, u64) | |
| 846 | %return in_stream.readInt(st.elf.endian, u64) | |
| 849 | 847 | } else { |
| 850 | %return in_stream.readInt(st.elf.is_big_endian, u32) | |
| 848 | %return in_stream.readInt(st.elf.endian, u32) | |
| 851 | 849 | }; |
| 852 | 850 | |
| 853 | 851 | const address_size = %return in_stream.readByte(); |
std/elf.zig+40-39| ... | ... | @@ -1,3 +1,4 @@ |
| 1 | const builtin = @import("builtin"); | |
| 1 | 2 | const std = @import("index.zig"); |
| 2 | 3 | const io = std.io; |
| 3 | 4 | const math = std.math; |
| ... | ... | @@ -67,7 +68,7 @@ pub const Elf = struct { |
| 67 | 68 | in_file: &io.File, |
| 68 | 69 | auto_close_stream: bool, |
| 69 | 70 | is_64: bool, |
| 70 | is_big_endian: bool, | |
| 71 | endian: builtin.Endian, | |
| 71 | 72 | file_type: FileType, |
| 72 | 73 | arch: Arch, |
| 73 | 74 | entry_addr: u64, |
| ... | ... | @@ -105,9 +106,9 @@ pub const Elf = struct { |
| 105 | 106 | else => return error.InvalidFormat, |
| 106 | 107 | }; |
| 107 | 108 | |
| 108 | elf.is_big_endian = switch (%return in.readByte()) { | |
| 109 | 1 => false, | |
| 110 | 2 => true, | |
| 109 | elf.endian = switch (%return in.readByte()) { | |
| 110 | 1 => builtin.Endian.Little, | |
| 111 | 2 => builtin.Endian.Big, | |
| 111 | 112 | else => return error.InvalidFormat, |
| 112 | 113 | }; |
| 113 | 114 | |
| ... | ... | @@ -117,7 +118,7 @@ pub const Elf = struct { |
| 117 | 118 | // skip over padding |
| 118 | 119 | %return elf.in_file.seekForward(9); |
| 119 | 120 | |
| 120 | elf.file_type = switch (%return in.readInt(elf.is_big_endian, u16)) { | |
| 121 | elf.file_type = switch (%return in.readInt(elf.endian, u16)) { | |
| 121 | 122 | 1 => FileType.Relocatable, |
| 122 | 123 | 2 => FileType.Executable, |
| 123 | 124 | 3 => FileType.Shared, |
| ... | ... | @@ -125,7 +126,7 @@ pub const Elf = struct { |
| 125 | 126 | else => return error.InvalidFormat, |
| 126 | 127 | }; |
| 127 | 128 | |
| 128 | elf.arch = switch (%return in.readInt(elf.is_big_endian, u16)) { | |
| 129 | elf.arch = switch (%return in.readInt(elf.endian, u16)) { | |
| 129 | 130 | 0x02 => Arch.Sparc, |
| 130 | 131 | 0x03 => Arch.x86, |
| 131 | 132 | 0x08 => Arch.Mips, |
| ... | ... | @@ -138,34 +139,34 @@ pub const Elf = struct { |
| 138 | 139 | else => return error.InvalidFormat, |
| 139 | 140 | }; |
| 140 | 141 | |
| 141 | const elf_version = %return in.readInt(elf.is_big_endian, u32); | |
| 142 | const elf_version = %return in.readInt(elf.endian, u32); | |
| 142 | 143 | if (elf_version != 1) return error.InvalidFormat; |
| 143 | 144 | |
| 144 | 145 | if (elf.is_64) { |
| 145 | elf.entry_addr = %return in.readInt(elf.is_big_endian, u64); | |
| 146 | elf.program_header_offset = %return in.readInt(elf.is_big_endian, u64); | |
| 147 | elf.section_header_offset = %return in.readInt(elf.is_big_endian, u64); | |
| 146 | elf.entry_addr = %return in.readInt(elf.endian, u64); | |
| 147 | elf.program_header_offset = %return in.readInt(elf.endian, u64); | |
| 148 | elf.section_header_offset = %return in.readInt(elf.endian, u64); | |
| 148 | 149 | } else { |
| 149 | elf.entry_addr = u64(%return in.readInt(elf.is_big_endian, u32)); | |
| 150 | elf.program_header_offset = u64(%return in.readInt(elf.is_big_endian, u32)); | |
| 151 | elf.section_header_offset = u64(%return in.readInt(elf.is_big_endian, u32)); | |
| 150 | elf.entry_addr = u64(%return in.readInt(elf.endian, u32)); | |
| 151 | elf.program_header_offset = u64(%return in.readInt(elf.endian, u32)); | |
| 152 | elf.section_header_offset = u64(%return in.readInt(elf.endian, u32)); | |
| 152 | 153 | } |
| 153 | 154 | |
| 154 | 155 | // skip over flags |
| 155 | 156 | %return elf.in_file.seekForward(4); |
| 156 | 157 | |
| 157 | const header_size = %return in.readInt(elf.is_big_endian, u16); | |
| 158 | const header_size = %return in.readInt(elf.endian, u16); | |
| 158 | 159 | if ((elf.is_64 and header_size != 64) or |
| 159 | 160 | (!elf.is_64 and header_size != 52)) |
| 160 | 161 | { |
| 161 | 162 | return error.InvalidFormat; |
| 162 | 163 | } |
| 163 | 164 | |
| 164 | const ph_entry_size = %return in.readInt(elf.is_big_endian, u16); | |
| 165 | const ph_entry_count = %return in.readInt(elf.is_big_endian, u16); | |
| 166 | const sh_entry_size = %return in.readInt(elf.is_big_endian, u16); | |
| 167 | const sh_entry_count = %return in.readInt(elf.is_big_endian, u16); | |
| 168 | elf.string_section_index = u64(%return in.readInt(elf.is_big_endian, u16)); | |
| 165 | const ph_entry_size = %return in.readInt(elf.endian, u16); | |
| 166 | const ph_entry_count = %return in.readInt(elf.endian, u16); | |
| 167 | const sh_entry_size = %return in.readInt(elf.endian, u16); | |
| 168 | const sh_entry_count = %return in.readInt(elf.endian, u16); | |
| 169 | elf.string_section_index = u64(%return in.readInt(elf.endian, u16)); | |
| 169 | 170 | |
| 170 | 171 | if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat; |
| 171 | 172 | |
| ... | ... | @@ -188,32 +189,32 @@ pub const Elf = struct { |
| 188 | 189 | if (sh_entry_size != 64) return error.InvalidFormat; |
| 189 | 190 | |
| 190 | 191 | for (elf.section_headers) |*section| { |
| 191 | section.name = %return in.readInt(elf.is_big_endian, u32); | |
| 192 | section.sh_type = %return in.readInt(elf.is_big_endian, u32); | |
| 193 | section.flags = %return in.readInt(elf.is_big_endian, u64); | |
| 194 | section.addr = %return in.readInt(elf.is_big_endian, u64); | |
| 195 | section.offset = %return in.readInt(elf.is_big_endian, u64); | |
| 196 | section.size = %return in.readInt(elf.is_big_endian, u64); | |
| 197 | section.link = %return in.readInt(elf.is_big_endian, u32); | |
| 198 | section.info = %return in.readInt(elf.is_big_endian, u32); | |
| 199 | section.addr_align = %return in.readInt(elf.is_big_endian, u64); | |
| 200 | section.ent_size = %return in.readInt(elf.is_big_endian, u64); | |
| 192 | section.name = %return in.readInt(elf.endian, u32); | |
| 193 | section.sh_type = %return in.readInt(elf.endian, u32); | |
| 194 | section.flags = %return in.readInt(elf.endian, u64); | |
| 195 | section.addr = %return in.readInt(elf.endian, u64); | |
| 196 | section.offset = %return in.readInt(elf.endian, u64); | |
| 197 | section.size = %return in.readInt(elf.endian, u64); | |
| 198 | section.link = %return in.readInt(elf.endian, u32); | |
| 199 | section.info = %return in.readInt(elf.endian, u32); | |
| 200 | section.addr_align = %return in.readInt(elf.endian, u64); | |
| 201 | section.ent_size = %return in.readInt(elf.endian, u64); | |
| 201 | 202 | } |
| 202 | 203 | } else { |
| 203 | 204 | if (sh_entry_size != 40) return error.InvalidFormat; |
| 204 | 205 | |
| 205 | 206 | for (elf.section_headers) |*section| { |
| 206 | 207 | // TODO (multiple occurences) allow implicit cast from %u32 -> %u64 ? |
| 207 | section.name = %return in.readInt(elf.is_big_endian, u32); | |
| 208 | section.sh_type = %return in.readInt(elf.is_big_endian, u32); | |
| 209 | section.flags = u64(%return in.readInt(elf.is_big_endian, u32)); | |
| 210 | section.addr = u64(%return in.readInt(elf.is_big_endian, u32)); | |
| 211 | section.offset = u64(%return in.readInt(elf.is_big_endian, u32)); | |
| 212 | section.size = u64(%return in.readInt(elf.is_big_endian, u32)); | |
| 213 | section.link = %return in.readInt(elf.is_big_endian, u32); | |
| 214 | section.info = %return in.readInt(elf.is_big_endian, u32); | |
| 215 | section.addr_align = u64(%return in.readInt(elf.is_big_endian, u32)); | |
| 216 | section.ent_size = u64(%return in.readInt(elf.is_big_endian, u32)); | |
| 208 | section.name = %return in.readInt(elf.endian, u32); | |
| 209 | section.sh_type = %return in.readInt(elf.endian, u32); | |
| 210 | section.flags = u64(%return in.readInt(elf.endian, u32)); | |
| 211 | section.addr = u64(%return in.readInt(elf.endian, u32)); | |
| 212 | section.offset = u64(%return in.readInt(elf.endian, u32)); | |
| 213 | section.size = u64(%return in.readInt(elf.endian, u32)); | |
| 214 | section.link = %return in.readInt(elf.endian, u32); | |
| 215 | section.info = %return in.readInt(elf.endian, u32); | |
| 216 | section.addr_align = u64(%return in.readInt(elf.endian, u32)); | |
| 217 | section.ent_size = u64(%return in.readInt(elf.endian, u32)); | |
| 217 | 218 | } |
| 218 | 219 | } |
| 219 | 220 |
std/endian.zig+2-2| ... | ... | @@ -9,8 +9,8 @@ pub fn swapIfBe(comptime T: type, x: T) -> T { |
| 9 | 9 | swapIf(true, T, x) |
| 10 | 10 | } |
| 11 | 11 | |
| 12 | pub fn swapIf(is_be: bool, comptime T: type, x: T) -> T { | |
| 13 | if (builtin.is_big_endian == is_be) swap(T, x) else x | |
| 12 | pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) -> T { | |
| 13 | if (builtin.endian == endian) swap(T, x) else x | |
| 14 | 14 | } |
| 15 | 15 | |
| 16 | 16 | pub fn swap(comptime T: type, x: T) -> T { |
std/io.zig+7-7| ... | ... | @@ -259,7 +259,7 @@ pub const File = struct { |
| 259 | 259 | if (err > 0) { |
| 260 | 260 | return switch (err) { |
| 261 | 261 | system.EBADF => error.BadFd, |
| 262 | system.ENOMEM => error.OutOfMemory, | |
| 262 | system.ENOMEM => error.SystemResources, | |
| 263 | 263 | else => os.unexpectedErrorPosix(err), |
| 264 | 264 | } |
| 265 | 265 | } |
| ... | ... | @@ -441,26 +441,26 @@ pub const InStream = struct { |
| 441 | 441 | } |
| 442 | 442 | |
| 443 | 443 | pub fn readIntLe(self: &InStream, comptime T: type) -> %T { |
| 444 | return self.readInt(false, T); | |
| 444 | return self.readInt(builtin.Endian.Little, T); | |
| 445 | 445 | } |
| 446 | 446 | |
| 447 | 447 | pub fn readIntBe(self: &InStream, comptime T: type) -> %T { |
| 448 | return self.readInt(true, T); | |
| 448 | return self.readInt(builtin.Endian.Big, T); | |
| 449 | 449 | } |
| 450 | 450 | |
| 451 | pub fn readInt(self: &InStream, is_be: bool, comptime T: type) -> %T { | |
| 451 | pub fn readInt(self: &InStream, endian: builtin.Endian, comptime T: type) -> %T { | |
| 452 | 452 | var bytes: [@sizeOf(T)]u8 = undefined; |
| 453 | 453 | %return self.readNoEof(bytes[0..]); |
| 454 | return mem.readInt(bytes, T, is_be); | |
| 454 | return mem.readInt(bytes, T, endian); | |
| 455 | 455 | } |
| 456 | 456 | |
| 457 | pub fn readVarInt(self: &InStream, is_be: bool, comptime T: type, size: usize) -> %T { | |
| 457 | pub fn readVarInt(self: &InStream, endian: builtin.Endian, comptime T: type, size: usize) -> %T { | |
| 458 | 458 | assert(size <= @sizeOf(T)); |
| 459 | 459 | assert(size <= 8); |
| 460 | 460 | var input_buf: [8]u8 = undefined; |
| 461 | 461 | const input_slice = input_buf[0..size]; |
| 462 | 462 | %return self.readNoEof(input_slice); |
| 463 | return mem.readInt(input_slice, T, is_be); | |
| 463 | return mem.readInt(input_slice, T, endian); | |
| 464 | 464 | } |
| 465 | 465 | |
| 466 | 466 |
std/mem.zig+79-32| ... | ... | @@ -1,6 +1,7 @@ |
| 1 | 1 | const debug = @import("debug.zig"); |
| 2 | 2 | const assert = debug.assert; |
| 3 | 3 | const math = @import("math/index.zig"); |
| 4 | const builtin = @import("builtin"); | |
| 4 | 5 | |
| 5 | 6 | pub const Cmp = math.Cmp; |
| 6 | 7 | |
| ... | ... | @@ -180,43 +181,78 @@ test "mem.indexOf" { |
| 180 | 181 | /// Reads an integer from memory with size equal to bytes.len. |
| 181 | 182 | /// T specifies the return type, which must be large enough to store |
| 182 | 183 | /// the result. |
| 183 | pub fn readInt(bytes: []const u8, comptime T: type, big_endian: bool) -> T { | |
| 184 | /// See also ::readIntBE or ::readIntLE. | |
| 185 | pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) -> T { | |
| 184 | 186 | if (T.bit_count == 8) { |
| 185 | 187 | return bytes[0]; |
| 186 | 188 | } |
| 187 | 189 | var result: T = 0; |
| 188 | if (big_endian) { | |
| 189 | for (bytes) |b| { | |
| 190 | result = (result << 8) | b; | |
| 191 | } | |
| 192 | } else { | |
| 193 | const ShiftType = math.Log2Int(T); | |
| 194 | for (bytes) |b, index| { | |
| 195 | result = result | (T(b) << ShiftType(index * 8)); | |
| 196 | } | |
| 190 | switch (endian) { | |
| 191 | builtin.Endian.Big => { | |
| 192 | for (bytes) |b| { | |
| 193 | result = (result << 8) | b; | |
| 194 | } | |
| 195 | }, | |
| 196 | builtin.Endian.Little => { | |
| 197 | const ShiftType = math.Log2Int(T); | |
| 198 | for (bytes) |b, index| { | |
| 199 | result = result | (T(b) << ShiftType(index * 8)); | |
| 200 | } | |
| 201 | }, | |
| 197 | 202 | } |
| 198 | 203 | return result; |
| 199 | 204 | } |
| 200 | 205 | |
| 206 | /// Reads a big-endian int of type T from bytes. | |
| 207 | /// bytes.len must be exactly @sizeOf(T). | |
| 208 | pub fn readIntBE(comptime T: type, bytes: []const u8) -> T { | |
| 209 | if (T.is_signed) { | |
| 210 | return @bitCast(T, readIntBE(@IntType(false, T.bit_count), bytes)); | |
| 211 | } | |
| 212 | assert(bytes.len == @sizeOf(T)); | |
| 213 | var result: T = 0; | |
| 214 | {comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) { | |
| 215 | result = (result << 8) | T(bytes[i]); | |
| 216 | }} | |
| 217 | return result; | |
| 218 | } | |
| 219 | ||
| 220 | /// Reads a little-endian int of type T from bytes. | |
| 221 | /// bytes.len must be exactly @sizeOf(T). | |
| 222 | pub fn readIntLE(comptime T: type, bytes: []const u8) -> T { | |
| 223 | if (T.is_signed) { | |
| 224 | return @bitCast(T, readIntLE(@IntType(false, T.bit_count), bytes)); | |
| 225 | } | |
| 226 | assert(bytes.len == @sizeOf(T)); | |
| 227 | var result: T = 0; | |
| 228 | {comptime var i = 0; inline while (i < @sizeOf(T)) : (i += 1) { | |
| 229 | result |= T(bytes[i]) << i * 8; | |
| 230 | }} | |
| 231 | return result; | |
| 232 | } | |
| 233 | ||
| 201 | 234 | /// Writes an integer to memory with size equal to bytes.len. Pads with zeroes |
| 202 | 235 | /// to fill the entire buffer provided. |
| 203 | 236 | /// value must be an integer. |
| 204 | pub fn writeInt(buf: []u8, value: var, big_endian: bool) { | |
| 237 | pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) { | |
| 205 | 238 | const uint = @IntType(false, @typeOf(value).bit_count); |
| 206 | 239 | var bits = @truncate(uint, value); |
| 207 | if (big_endian) { | |
| 208 | var index: usize = buf.len; | |
| 209 | while (index != 0) { | |
| 210 | index -= 1; | |
| 211 | ||
| 212 | buf[index] = @truncate(u8, bits); | |
| 213 | bits >>= 8; | |
| 214 | } | |
| 215 | } else { | |
| 216 | for (buf) |*b| { | |
| 217 | *b = @truncate(u8, bits); | |
| 218 | bits >>= 8; | |
| 219 | } | |
| 240 | switch (endian) { | |
| 241 | builtin.Endian.Big => { | |
| 242 | var index: usize = buf.len; | |
| 243 | while (index != 0) { | |
| 244 | index -= 1; | |
| 245 | ||
| 246 | buf[index] = @truncate(u8, bits); | |
| 247 | bits >>= 8; | |
| 248 | } | |
| 249 | }, | |
| 250 | builtin.Endian.Little => { | |
| 251 | for (buf) |*b| { | |
| 252 | *b = @truncate(u8, bits); | |
| 253 | bits >>= 8; | |
| 254 | } | |
| 255 | }, | |
| 220 | 256 | } |
| 221 | 257 | assert(bits == 0); |
| 222 | 258 | } |
| ... | ... | @@ -348,19 +384,30 @@ test "testReadInt" { |
| 348 | 384 | fn testReadIntImpl() { |
| 349 | 385 | { |
| 350 | 386 | const bytes = []u8{ 0x12, 0x34, 0x56, 0x78 }; |
| 351 | assert(readInt(bytes, u32, true) == 0x12345678); | |
| 352 | assert(readInt(bytes, u32, false) == 0x78563412); | |
| 387 | assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678); | |
| 388 | assert(readIntBE(u32, bytes) == 0x12345678); | |
| 389 | assert(readIntBE(i32, bytes) == 0x12345678); | |
| 390 | assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412); | |
| 391 | assert(readIntLE(u32, bytes) == 0x78563412); | |
| 392 | assert(readIntLE(i32, bytes) == 0x78563412); | |
| 353 | 393 | } |
| 354 | 394 | { |
| 355 | 395 | const buf = []u8{0x00, 0x00, 0x12, 0x34}; |
| 356 | const answer = readInt(buf, u64, true); | |
| 396 | const answer = readInt(buf, u64, builtin.Endian.Big); | |
| 357 | 397 | assert(answer == 0x00001234); |
| 358 | 398 | } |
| 359 | 399 | { |
| 360 | 400 | const buf = []u8{0x12, 0x34, 0x00, 0x00}; |
| 361 | const answer = readInt(buf, u64, false); | |
| 401 | const answer = readInt(buf, u64, builtin.Endian.Little); | |
| 362 | 402 | assert(answer == 0x00003412); |
| 363 | 403 | } |
| 404 | { | |
| 405 | const bytes = []u8{0xff, 0xfe}; | |
| 406 | assert(readIntBE(u16, bytes) == 0xfffe); | |
| 407 | assert(readIntBE(i16, bytes) == -0x0002); | |
| 408 | assert(readIntLE(u16, bytes) == 0xfeff); | |
| 409 | assert(readIntLE(i16, bytes) == -0x0101); | |
| 410 | } | |
| 364 | 411 | } |
| 365 | 412 | |
| 366 | 413 | test "testWriteInt" { |
| ... | ... | @@ -370,16 +417,16 @@ test "testWriteInt" { |
| 370 | 417 | fn testWriteIntImpl() { |
| 371 | 418 | var bytes: [4]u8 = undefined; |
| 372 | 419 | |
| 373 | writeInt(bytes[0..], u32(0x12345678), true); | |
| 420 | writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big); | |
| 374 | 421 | assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 })); |
| 375 | 422 | |
| 376 | writeInt(bytes[0..], u32(0x78563412), false); | |
| 423 | writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little); | |
| 377 | 424 | assert(eql(u8, bytes, []u8{ 0x12, 0x34, 0x56, 0x78 })); |
| 378 | 425 | |
| 379 | writeInt(bytes[0..], u16(0x1234), true); | |
| 426 | writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big); | |
| 380 | 427 | assert(eql(u8, bytes, []u8{ 0x00, 0x00, 0x12, 0x34 })); |
| 381 | 428 | |
| 382 | writeInt(bytes[0..], u16(0x1234), false); | |
| 429 | writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little); | |
| 383 | 430 | assert(eql(u8, bytes, []u8{ 0x34, 0x12, 0x00, 0x00 })); |
| 384 | 431 | } |
| 385 | 432 |
std/os/child_process.zig+9-9| ... | ... | @@ -58,7 +58,7 @@ pub const ChildProcess = struct { |
| 58 | 58 | err_pipe: if (is_windows) void else [2]i32, |
| 59 | 59 | llnode: if (is_windows) void else LinkedList(&ChildProcess).Node, |
| 60 | 60 | |
| 61 | pub const Term = enum { | |
| 61 | pub const Term = union(enum) { | |
| 62 | 62 | Exited: i32, |
| 63 | 63 | Signal: i32, |
| 64 | 64 | Stopped: i32, |
| ... | ... | @@ -213,9 +213,9 @@ pub const ChildProcess = struct { |
| 213 | 213 | self.term = (%Term)({ |
| 214 | 214 | var exit_code: windows.DWORD = undefined; |
| 215 | 215 | if (windows.GetExitCodeProcess(self.handle, &exit_code) == 0) { |
| 216 | Term.Unknown{0} | |
| 216 | Term { .Unknown = 0 } | |
| 217 | 217 | } else { |
| 218 | Term.Exited {@bitCast(i32, exit_code)} | |
| 218 | Term { .Exited = @bitCast(i32, exit_code)} | |
| 219 | 219 | } |
| 220 | 220 | }); |
| 221 | 221 | |
| ... | ... | @@ -281,13 +281,13 @@ pub const ChildProcess = struct { |
| 281 | 281 | |
| 282 | 282 | fn statusToTerm(status: i32) -> Term { |
| 283 | 283 | return if (posix.WIFEXITED(status)) { |
| 284 | Term.Exited { posix.WEXITSTATUS(status) } | |
| 284 | Term { .Exited = posix.WEXITSTATUS(status) } | |
| 285 | 285 | } else if (posix.WIFSIGNALED(status)) { |
| 286 | Term.Signal { posix.WTERMSIG(status) } | |
| 286 | Term { .Signal = posix.WTERMSIG(status) } | |
| 287 | 287 | } else if (posix.WIFSTOPPED(status)) { |
| 288 | Term.Stopped { posix.WSTOPSIG(status) } | |
| 288 | Term { .Stopped = posix.WSTOPSIG(status) } | |
| 289 | 289 | } else { |
| 290 | Term.Unknown { status } | |
| 290 | Term { .Unknown = status } | |
| 291 | 291 | }; |
| 292 | 292 | } |
| 293 | 293 | |
| ... | ... | @@ -722,14 +722,14 @@ const ErrInt = @IntType(false, @sizeOf(error) * 8); |
| 722 | 722 | |
| 723 | 723 | fn writeIntFd(fd: i32, value: ErrInt) -> %void { |
| 724 | 724 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; |
| 725 | mem.writeInt(bytes[0..], value, true); | |
| 725 | mem.writeInt(bytes[0..], value, builtin.endian); | |
| 726 | 726 | os.posixWrite(fd, bytes[0..]) %% return error.SystemResources; |
| 727 | 727 | } |
| 728 | 728 | |
| 729 | 729 | fn readIntFd(fd: i32) -> %ErrInt { |
| 730 | 730 | var bytes: [@sizeOf(ErrInt)]u8 = undefined; |
| 731 | 731 | os.posixRead(fd, bytes[0..]) %% return error.SystemResources; |
| 732 | return mem.readInt(bytes[0..], ErrInt, true); | |
| 732 | return mem.readInt(bytes[0..], ErrInt, builtin.endian); | |
| 733 | 733 | } |
| 734 | 734 | |
| 735 | 735 | extern fn sigchld_handler(_: i32) { |
std/os/index.zig+3-2| ... | ... | @@ -939,6 +939,7 @@ start_over: |
| 939 | 939 | } |
| 940 | 940 | |
| 941 | 941 | pub const Dir = struct { |
| 942 | // See man getdents | |
| 942 | 943 | fd: i32, |
| 943 | 944 | allocator: &Allocator, |
| 944 | 945 | buf: []u8, |
| ... | ... | @@ -981,7 +982,7 @@ pub const Dir = struct { |
| 981 | 982 | |
| 982 | 983 | pub fn close(self: &Dir) { |
| 983 | 984 | self.allocator.free(self.buf); |
| 984 | close(self.fd); | |
| 985 | os.close(self.fd); | |
| 985 | 986 | } |
| 986 | 987 | |
| 987 | 988 | /// Memory such as file names referenced in this returned entry becomes invalid |
| ... | ... | @@ -1013,7 +1014,7 @@ pub const Dir = struct { |
| 1013 | 1014 | break; |
| 1014 | 1015 | } |
| 1015 | 1016 | } |
| 1016 | const linux_entry = @ptrCast(&LinuxEntry, &self.buf[self.index]); | |
| 1017 | const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]); | |
| 1017 | 1018 | const next_index = self.index + linux_entry.d_reclen; |
| 1018 | 1019 | self.index = next_index; |
| 1019 | 1020 |
std/os/path.zig+1-1| ... | ... | @@ -1016,7 +1016,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 { |
| 1016 | 1016 | |
| 1017 | 1017 | return os.readLink(allocator, proc_path); |
| 1018 | 1018 | }, |
| 1019 | else => @compileError("TODO implement os.path.real for " ++ @enumTagName(builtin.os)), | |
| 1019 | else => @compileError("TODO implement os.path.real for " ++ @tagName(builtin.os)), | |
| 1020 | 1020 | } |
| 1021 | 1021 | } |
| 1022 | 1022 |
std/rand.zig+3-3| ... | ... | @@ -50,12 +50,12 @@ pub const Rand = struct { |
| 50 | 50 | pub fn fillBytes(r: &Rand, buf: []u8) { |
| 51 | 51 | var bytes_left = buf.len; |
| 52 | 52 | while (bytes_left >= @sizeOf(usize)) { |
| 53 | mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), false); | |
| 53 | mem.writeInt(buf[buf.len - bytes_left..], r.rng.get(), builtin.Endian.Little); | |
| 54 | 54 | bytes_left -= @sizeOf(usize); |
| 55 | 55 | } |
| 56 | 56 | if (bytes_left > 0) { |
| 57 | 57 | var rand_val_array: [@sizeOf(usize)]u8 = undefined; |
| 58 | mem.writeInt(rand_val_array[0..], r.rng.get(), false); | |
| 58 | mem.writeInt(rand_val_array[0..], r.rng.get(), builtin.Endian.Little); | |
| 59 | 59 | while (bytes_left > 0) { |
| 60 | 60 | buf[buf.len - bytes_left] = rand_val_array[@sizeOf(usize) - bytes_left]; |
| 61 | 61 | bytes_left -= 1; |
| ... | ... | @@ -98,7 +98,7 @@ pub const Rand = struct { |
| 98 | 98 | |
| 99 | 99 | while (true) { |
| 100 | 100 | r.fillBytes(rand_val_array[0..]); |
| 101 | const rand_val = mem.readInt(rand_val_array, T, false); | |
| 101 | const rand_val = mem.readInt(rand_val_array, T, builtin.Endian.Little); | |
| 102 | 102 | if (rand_val < upper_bound) { |
| 103 | 103 | return start + (rand_val % total_range); |
| 104 | 104 | } |
std/sort.zig+70| ... | ... | @@ -4,6 +4,19 @@ const math = @import("math/index.zig"); |
| 4 | 4 | |
| 5 | 5 | pub const Cmp = math.Cmp; |
| 6 | 6 | |
| 7 | /// Stable sort using O(1) space. Currently implemented as insertion sort. | |
| 8 | pub fn sort_stable(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) { | |
| 9 | {var i: usize = 1; while (i < array.len) : (i += 1) { | |
| 10 | const x = array[i]; | |
| 11 | var j: usize = i; | |
| 12 | while (j > 0 and cmp(array[j - 1], x) == Cmp.Greater) : (j -= 1) { | |
| 13 | array[j] = array[j - 1]; | |
| 14 | } | |
| 15 | array[j] = x; | |
| 16 | }} | |
| 17 | } | |
| 18 | ||
| 19 | /// Unstable sort using O(n) stack space. Currently implemented as quicksort. | |
| 7 | 20 | pub fn sort(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) { |
| 8 | 21 | if (array.len > 0) { |
| 9 | 22 | quicksort(T, array, 0, array.len - 1, cmp); |
| ... | ... | @@ -58,6 +71,63 @@ fn reverse(was: Cmp) -> Cmp { |
| 58 | 71 | // --------------------------------------- |
| 59 | 72 | // tests |
| 60 | 73 | |
| 74 | test "stable sort" { | |
| 75 | testStableSort(); | |
| 76 | // TODO: uncomment this after https://github.com/zig-lang/zig/issues/639 | |
| 77 | //comptime testStableSort(); | |
| 78 | } | |
| 79 | fn testStableSort() { | |
| 80 | var expected = []IdAndValue { | |
| 81 | IdAndValue{.id = 0, .value = 0}, | |
| 82 | IdAndValue{.id = 1, .value = 0}, | |
| 83 | IdAndValue{.id = 2, .value = 0}, | |
| 84 | IdAndValue{.id = 0, .value = 1}, | |
| 85 | IdAndValue{.id = 1, .value = 1}, | |
| 86 | IdAndValue{.id = 2, .value = 1}, | |
| 87 | IdAndValue{.id = 0, .value = 2}, | |
| 88 | IdAndValue{.id = 1, .value = 2}, | |
| 89 | IdAndValue{.id = 2, .value = 2}, | |
| 90 | }; | |
| 91 | var cases = [][9]IdAndValue { | |
| 92 | []IdAndValue { | |
| 93 | IdAndValue{.id = 0, .value = 0}, | |
| 94 | IdAndValue{.id = 0, .value = 1}, | |
| 95 | IdAndValue{.id = 0, .value = 2}, | |
| 96 | IdAndValue{.id = 1, .value = 0}, | |
| 97 | IdAndValue{.id = 1, .value = 1}, | |
| 98 | IdAndValue{.id = 1, .value = 2}, | |
| 99 | IdAndValue{.id = 2, .value = 0}, | |
| 100 | IdAndValue{.id = 2, .value = 1}, | |
| 101 | IdAndValue{.id = 2, .value = 2}, | |
| 102 | }, | |
| 103 | []IdAndValue { | |
| 104 | IdAndValue{.id = 0, .value = 2}, | |
| 105 | IdAndValue{.id = 0, .value = 1}, | |
| 106 | IdAndValue{.id = 0, .value = 0}, | |
| 107 | IdAndValue{.id = 1, .value = 2}, | |
| 108 | IdAndValue{.id = 1, .value = 1}, | |
| 109 | IdAndValue{.id = 1, .value = 0}, | |
| 110 | IdAndValue{.id = 2, .value = 2}, | |
| 111 | IdAndValue{.id = 2, .value = 1}, | |
| 112 | IdAndValue{.id = 2, .value = 0}, | |
| 113 | }, | |
| 114 | }; | |
| 115 | for (cases) |*case| { | |
| 116 | sort_stable(IdAndValue, (*case)[0..], cmpByValue); | |
| 117 | for (*case) |item, i| { | |
| 118 | assert(item.id == expected[i].id); | |
| 119 | assert(item.value == expected[i].value); | |
| 120 | } | |
| 121 | } | |
| 122 | } | |
| 123 | const IdAndValue = struct { | |
| 124 | id: i32, | |
| 125 | value: i32, | |
| 126 | }; | |
| 127 | fn cmpByValue(a: &const IdAndValue, b: &const IdAndValue) -> Cmp { | |
| 128 | return i32asc(a.value, b.value); | |
| 129 | } | |
| 130 | ||
| 61 | 131 | test "testSort" { |
| 62 | 132 | const u8cases = [][]const []const u8 { |
| 63 | 133 | [][]const u8{"", ""}, |
std/special/compiler_rt/udivmod.zig+1-1| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | const builtin = @import("builtin"); |
| 2 | 2 | const is_test = builtin.is_test; |
| 3 | 3 | |
| 4 | const low = if (builtin.is_big_endian) 1 else 0; | |
| 4 | const low = switch (builtin.endian) { builtin.Endian.Big => 1, builtin.Endian.Little => 0 }; | |
| 5 | 5 | const high = 1 - low; |
| 6 | 6 | |
| 7 | 7 | pub fn udivmod(comptime DoubleInt: type, a: DoubleInt, b: DoubleInt, maybe_rem: ?&DoubleInt) -> DoubleInt { |
test/cases/bugs/394.zig+2-2| ... | ... | @@ -1,9 +1,9 @@ |
| 1 | const E = enum { A: [9]u8, B: u64, }; | |
| 1 | const E = union(enum) { A: [9]u8, B: u64, }; | |
| 2 | 2 | const S = struct { x: u8, y: E, }; |
| 3 | 3 | |
| 4 | 4 | const assert = @import("std").debug.assert; |
| 5 | 5 | |
| 6 | 6 | test "bug 394 fixed" { |
| 7 | const x = S { .x = 3, .y = E.B {1} }; | |
| 7 | const x = S { .x = 3, .y = E {.B = 1 } }; | |
| 8 | 8 | assert(x.x == 3); |
| 9 | 9 | } |
test/cases/enum.zig+171-17| ... | ... | @@ -2,8 +2,8 @@ const assert = @import("std").debug.assert; |
| 2 | 2 | const mem = @import("std").mem; |
| 3 | 3 | |
| 4 | 4 | test "enum type" { |
| 5 | const foo1 = Foo.One {13}; | |
| 6 | const foo2 = Foo.Two { Point { .x = 1234, .y = 5678, }}; | |
| 5 | const foo1 = Foo{ .One = 13}; | |
| 6 | const foo2 = Foo{. Two = Point { .x = 1234, .y = 5678, }}; | |
| 7 | 7 | const bar = Bar.B; |
| 8 | 8 | |
| 9 | 9 | assert(bar == Bar.B); |
| ... | ... | @@ -24,12 +24,12 @@ const Point = struct { |
| 24 | 24 | x: u64, |
| 25 | 25 | y: u64, |
| 26 | 26 | }; |
| 27 | const Foo = enum { | |
| 27 | const Foo = union(enum) { | |
| 28 | 28 | One: i32, |
| 29 | 29 | Two: Point, |
| 30 | 30 | Three: void, |
| 31 | 31 | }; |
| 32 | const FooNoVoid = enum { | |
| 32 | const FooNoVoid = union(enum) { | |
| 33 | 33 | One: i32, |
| 34 | 34 | Two: Point, |
| 35 | 35 | }; |
| ... | ... | @@ -41,13 +41,13 @@ const Bar = enum { |
| 41 | 41 | }; |
| 42 | 42 | |
| 43 | 43 | fn returnAnInt(x: i32) -> Foo { |
| 44 | Foo.One { x } | |
| 44 | Foo { .One = x } | |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | 47 | |
| 48 | 48 | test "constant enum with payload" { |
| 49 | var empty = AnEnumWithPayload.Empty; | |
| 50 | var full = AnEnumWithPayload.Full {13}; | |
| 49 | var empty = AnEnumWithPayload {.Empty = {}}; | |
| 50 | var full = AnEnumWithPayload {.Full = 13}; | |
| 51 | 51 | shouldBeEmpty(empty); |
| 52 | 52 | shouldBeNotEmpty(full); |
| 53 | 53 | } |
| ... | ... | @@ -66,8 +66,8 @@ fn shouldBeNotEmpty(x: &const AnEnumWithPayload) { |
| 66 | 66 | } |
| 67 | 67 | } |
| 68 | 68 | |
| 69 | const AnEnumWithPayload = enum { | |
| 70 | Empty, | |
| 69 | const AnEnumWithPayload = union(enum) { | |
| 70 | Empty: void, | |
| 71 | 71 | Full: i32, |
| 72 | 72 | }; |
| 73 | 73 | |
| ... | ... | @@ -89,8 +89,8 @@ test "enum to int" { |
| 89 | 89 | shouldEqual(Number.Four, 4); |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | fn shouldEqual(n: Number, expected: usize) { | |
| 93 | assert(usize(n) == expected); | |
| 92 | fn shouldEqual(n: Number, expected: u3) { | |
| 93 | assert(u3(n) == expected); | |
| 94 | 94 | } |
| 95 | 95 | |
| 96 | 96 | |
| ... | ... | @@ -98,7 +98,7 @@ test "int to enum" { |
| 98 | 98 | testIntToEnumEval(3); |
| 99 | 99 | } |
| 100 | 100 | fn testIntToEnumEval(x: i32) { |
| 101 | assert(IntToEnumNumber(x) == IntToEnumNumber.Three); | |
| 101 | assert(IntToEnumNumber(u3(x)) == IntToEnumNumber.Three); | |
| 102 | 102 | } |
| 103 | 103 | const IntToEnumNumber = enum { |
| 104 | 104 | Zero, |
| ... | ... | @@ -109,13 +109,13 @@ const IntToEnumNumber = enum { |
| 109 | 109 | }; |
| 110 | 110 | |
| 111 | 111 | |
| 112 | test "@enumTagName" { | |
| 112 | test "@tagName" { | |
| 113 | 113 | assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); |
| 114 | 114 | comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three")); |
| 115 | 115 | } |
| 116 | 116 | |
| 117 | 117 | fn testEnumTagNameBare(n: BareNumber) -> []const u8 { |
| 118 | return @enumTagName(n); | |
| 118 | return @tagName(n); | |
| 119 | 119 | } |
| 120 | 120 | |
| 121 | 121 | const BareNumber = enum { |
| ... | ... | @@ -132,12 +132,11 @@ test "enum alignment" { |
| 132 | 132 | } |
| 133 | 133 | } |
| 134 | 134 | |
| 135 | const AlignTestEnum = enum { | |
| 135 | const AlignTestEnum = union(enum) { | |
| 136 | 136 | A: [9]u8, |
| 137 | 137 | B: u64, |
| 138 | 138 | }; |
| 139 | 139 | |
| 140 | const ValueCount0 = enum {}; | |
| 141 | 140 | const ValueCount1 = enum { I0 }; |
| 142 | 141 | const ValueCount2 = enum { I0, I1 }; |
| 143 | 142 | const ValueCount256 = enum { |
| ... | ... | @@ -183,10 +182,165 @@ const ValueCount257 = enum { |
| 183 | 182 | |
| 184 | 183 | test "enum sizes" { |
| 185 | 184 | comptime { |
| 186 | assert(@sizeOf(ValueCount0) == 0); | |
| 187 | 185 | assert(@sizeOf(ValueCount1) == 0); |
| 188 | 186 | assert(@sizeOf(ValueCount2) == 1); |
| 189 | 187 | assert(@sizeOf(ValueCount256) == 1); |
| 190 | 188 | assert(@sizeOf(ValueCount257) == 2); |
| 191 | 189 | } |
| 192 | 190 | } |
| 191 | ||
| 192 | const Small2 = enum (u2) { | |
| 193 | One, | |
| 194 | Two, | |
| 195 | }; | |
| 196 | const Small = enum (u2) { | |
| 197 | One, | |
| 198 | Two, | |
| 199 | Three, | |
| 200 | Four, | |
| 201 | }; | |
| 202 | ||
| 203 | test "set enum tag type" { | |
| 204 | { | |
| 205 | var x = Small.One; | |
| 206 | x = Small.Two; | |
| 207 | comptime assert(@TagType(Small) == u2); | |
| 208 | } | |
| 209 | { | |
| 210 | var x = Small2.One; | |
| 211 | x = Small2.Two; | |
| 212 | comptime assert(@TagType(Small2) == u2); | |
| 213 | } | |
| 214 | } | |
| 215 | ||
| 216 | ||
| 217 | const A = enum (u3) { | |
| 218 | One, | |
| 219 | Two, | |
| 220 | Three, | |
| 221 | Four, | |
| 222 | One2, | |
| 223 | Two2, | |
| 224 | Three2, | |
| 225 | Four2, | |
| 226 | }; | |
| 227 | ||
| 228 | const B = enum (u3) { | |
| 229 | One3, | |
| 230 | Two3, | |
| 231 | Three3, | |
| 232 | Four3, | |
| 233 | One23, | |
| 234 | Two23, | |
| 235 | Three23, | |
| 236 | Four23, | |
| 237 | }; | |
| 238 | ||
| 239 | const C = enum (u2) { | |
| 240 | One4, | |
| 241 | Two4, | |
| 242 | Three4, | |
| 243 | Four4, | |
| 244 | }; | |
| 245 | ||
| 246 | const BitFieldOfEnums = packed struct { | |
| 247 | a: A, | |
| 248 | b: B, | |
| 249 | c: C, | |
| 250 | }; | |
| 251 | ||
| 252 | const bit_field_1 = BitFieldOfEnums { | |
| 253 | .a = A.Two, | |
| 254 | .b = B.Three3, | |
| 255 | .c = C.Four4, | |
| 256 | }; | |
| 257 | ||
| 258 | test "bit field access with enum fields" { | |
| 259 | var data = bit_field_1; | |
| 260 | assert(getA(&data) == A.Two); | |
| 261 | assert(getB(&data) == B.Three3); | |
| 262 | assert(getC(&data) == C.Four4); | |
| 263 | comptime assert(@sizeOf(BitFieldOfEnums) == 1); | |
| 264 | ||
| 265 | data.b = B.Four3; | |
| 266 | assert(data.b == B.Four3); | |
| 267 | ||
| 268 | data.a = A.Three; | |
| 269 | assert(data.a == A.Three); | |
| 270 | assert(data.b == B.Four3); | |
| 271 | } | |
| 272 | ||
| 273 | fn getA(data: &const BitFieldOfEnums) -> A { | |
| 274 | return data.a; | |
| 275 | } | |
| 276 | ||
| 277 | fn getB(data: &const BitFieldOfEnums) -> B { | |
| 278 | return data.b; | |
| 279 | } | |
| 280 | ||
| 281 | fn getC(data: &const BitFieldOfEnums) -> C { | |
| 282 | return data.c; | |
| 283 | } | |
| 284 | ||
| 285 | test "casting enum to its tag type" { | |
| 286 | testCastEnumToTagType(Small2.Two); | |
| 287 | comptime testCastEnumToTagType(Small2.Two); | |
| 288 | } | |
| 289 | ||
| 290 | fn testCastEnumToTagType(value: Small2) { | |
| 291 | assert(u2(value) == 1); | |
| 292 | } | |
| 293 | ||
| 294 | const MultipleChoice = enum(u32) { | |
| 295 | A = 20, | |
| 296 | B = 40, | |
| 297 | C = 60, | |
| 298 | D = 1000, | |
| 299 | }; | |
| 300 | ||
| 301 | test "enum with specified tag values" { | |
| 302 | testEnumWithSpecifiedTagValues(MultipleChoice.C); | |
| 303 | comptime testEnumWithSpecifiedTagValues(MultipleChoice.C); | |
| 304 | } | |
| 305 | ||
| 306 | fn testEnumWithSpecifiedTagValues(x: MultipleChoice) { | |
| 307 | assert(u32(x) == 60); | |
| 308 | assert(1234 == switch (x) { | |
| 309 | MultipleChoice.A => 1, | |
| 310 | MultipleChoice.B => 2, | |
| 311 | MultipleChoice.C => u32(1234), | |
| 312 | MultipleChoice.D => 4, | |
| 313 | }); | |
| 314 | } | |
| 315 | ||
| 316 | const MultipleChoice2 = enum(u32) { | |
| 317 | Unspecified1, | |
| 318 | A = 20, | |
| 319 | Unspecified2, | |
| 320 | B = 40, | |
| 321 | Unspecified3, | |
| 322 | C = 60, | |
| 323 | Unspecified4, | |
| 324 | D = 1000, | |
| 325 | Unspecified5, | |
| 326 | }; | |
| 327 | ||
| 328 | test "enum with specified and unspecified tag values" { | |
| 329 | testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | |
| 330 | comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D); | |
| 331 | } | |
| 332 | ||
| 333 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) { | |
| 334 | assert(u32(x) == 1000); | |
| 335 | assert(1234 == switch (x) { | |
| 336 | MultipleChoice2.A => 1, | |
| 337 | MultipleChoice2.B => 2, | |
| 338 | MultipleChoice2.C => 3, | |
| 339 | MultipleChoice2.D => u32(1234), | |
| 340 | MultipleChoice2.Unspecified1 => 5, | |
| 341 | MultipleChoice2.Unspecified2 => 6, | |
| 342 | MultipleChoice2.Unspecified3 => 7, | |
| 343 | MultipleChoice2.Unspecified4 => 8, | |
| 344 | MultipleChoice2.Unspecified5 => 9, | |
| 345 | }); | |
| 346 | } |
test/cases/enum_with_members.zig+3-3| ... | ... | @@ -2,7 +2,7 @@ const assert = @import("std").debug.assert; |
| 2 | 2 | const mem = @import("std").mem; |
| 3 | 3 | const fmt = @import("std").fmt; |
| 4 | 4 | |
| 5 | const ET = enum { | |
| 5 | const ET = union(enum) { | |
| 6 | 6 | SINT: i32, |
| 7 | 7 | UINT: u32, |
| 8 | 8 | |
| ... | ... | @@ -15,8 +15,8 @@ const ET = enum { |
| 15 | 15 | }; |
| 16 | 16 | |
| 17 | 17 | test "enum with members" { |
| 18 | const a = ET.SINT { -42 }; | |
| 19 | const b = ET.UINT { 42 }; | |
| 18 | const a = ET { .SINT = -42 }; | |
| 19 | const b = ET { .UINT = 42 }; | |
| 20 | 20 | var buf: [20]u8 = undefined; |
| 21 | 21 | |
| 22 | 22 | assert(%%a.print(buf[0..]) == 3); |
test/cases/misc.zig+9-7| ... | ... | @@ -324,8 +324,8 @@ test "constant enum initialization with differing sizes" { |
| 324 | 324 | test3_1(test3_foo); |
| 325 | 325 | test3_2(test3_bar); |
| 326 | 326 | } |
| 327 | const Test3Foo = enum { | |
| 328 | One, | |
| 327 | const Test3Foo = union(enum) { | |
| 328 | One: void, | |
| 329 | 329 | Two: f32, |
| 330 | 330 | Three: Test3Point, |
| 331 | 331 | }; |
| ... | ... | @@ -333,8 +333,8 @@ const Test3Point = struct { |
| 333 | 333 | x: i32, |
| 334 | 334 | y: i32, |
| 335 | 335 | }; |
| 336 | const test3_foo = Test3Foo.Three{Test3Point {.x = 3, .y = 4}}; | |
| 337 | const test3_bar = Test3Foo.Two{13}; | |
| 336 | const test3_foo = Test3Foo { .Three = Test3Point {.x = 3, .y = 4}}; | |
| 337 | const test3_bar = Test3Foo { .Two = 13}; | |
| 338 | 338 | fn test3_1(f: &const Test3Foo) { |
| 339 | 339 | switch (*f) { |
| 340 | 340 | Test3Foo.Three => |pt| { |
| ... | ... | @@ -449,7 +449,8 @@ fn testArray2DConstDoublePtr(ptr: &const f32) { |
| 449 | 449 | const Tid = builtin.TypeId; |
| 450 | 450 | const AStruct = struct { x: i32, }; |
| 451 | 451 | const AnEnum = enum { One, Two, }; |
| 452 | const AnEnumWithPayload = enum { One: i32, Two, }; | |
| 452 | const AUnionEnum = union(enum) { One: i32, Two: void, }; | |
| 453 | const AUnion = union { One: void, Two: void }; | |
| 453 | 454 | |
| 454 | 455 | test "@typeId" { |
| 455 | 456 | comptime { |
| ... | ... | @@ -474,8 +475,9 @@ test "@typeId" { |
| 474 | 475 | assert(@typeId(%i32) == Tid.ErrorUnion); |
| 475 | 476 | assert(@typeId(error) == Tid.Error); |
| 476 | 477 | assert(@typeId(AnEnum) == Tid.Enum); |
| 477 | assert(@typeId(@typeOf(AnEnumWithPayload.One)) == Tid.EnumTag); | |
| 478 | // TODO union | |
| 478 | assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum); | |
| 479 | assert(@typeId(AUnionEnum) == Tid.Union); | |
| 480 | assert(@typeId(AUnion) == Tid.Union); | |
| 479 | 481 | assert(@typeId(fn()) == Tid.Fn); |
| 480 | 482 | assert(@typeId(@typeOf(builtin)) == Tid.Namespace); |
| 481 | 483 | assert(@typeId(@typeOf({this})) == Tid.Block); |
test/cases/reflection.zig+2-2| ... | ... | @@ -62,8 +62,8 @@ const Foo = struct { |
| 62 | 62 | three: void, |
| 63 | 63 | }; |
| 64 | 64 | |
| 65 | const Bar = enum { | |
| 66 | One, | |
| 65 | const Bar = union(enum) { | |
| 66 | One: void, | |
| 67 | 67 | Two: i32, |
| 68 | 68 | Three: bool, |
| 69 | 69 | Four: f64, |
test/cases/switch.zig+19-8| ... | ... | @@ -83,14 +83,14 @@ const SwitchStatmentFoo = enum { |
| 83 | 83 | |
| 84 | 84 | |
| 85 | 85 | test "switch prong with variable" { |
| 86 | switchProngWithVarFn(SwitchProngWithVarEnum.One {13}); | |
| 87 | switchProngWithVarFn(SwitchProngWithVarEnum.Two {13.0}); | |
| 88 | switchProngWithVarFn(SwitchProngWithVarEnum.Meh); | |
| 86 | switchProngWithVarFn(SwitchProngWithVarEnum { .One = 13}); | |
| 87 | switchProngWithVarFn(SwitchProngWithVarEnum { .Two = 13.0}); | |
| 88 | switchProngWithVarFn(SwitchProngWithVarEnum { .Meh = {}}); | |
| 89 | 89 | } |
| 90 | const SwitchProngWithVarEnum = enum { | |
| 90 | const SwitchProngWithVarEnum = union(enum) { | |
| 91 | 91 | One: i32, |
| 92 | 92 | Two: f32, |
| 93 | Meh, | |
| 93 | Meh: void, | |
| 94 | 94 | }; |
| 95 | 95 | fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) { |
| 96 | 96 | switch(*a) { |
| ... | ... | @@ -112,7 +112,7 @@ test "switch on enum using pointer capture" { |
| 112 | 112 | } |
| 113 | 113 | |
| 114 | 114 | fn testSwitchEnumPtrCapture() { |
| 115 | var value = SwitchProngWithVarEnum.One { 1234 }; | |
| 115 | var value = SwitchProngWithVarEnum { .One = 1234 }; | |
| 116 | 116 | switch (value) { |
| 117 | 117 | SwitchProngWithVarEnum.One => |*x| *x += 1, |
| 118 | 118 | else => unreachable, |
| ... | ... | @@ -136,13 +136,13 @@ fn returnsFive() -> i32 { |
| 136 | 136 | } |
| 137 | 137 | |
| 138 | 138 | |
| 139 | const Number = enum { | |
| 139 | const Number = union(enum) { | |
| 140 | 140 | One: u64, |
| 141 | 141 | Two: u8, |
| 142 | 142 | Three: f32, |
| 143 | 143 | }; |
| 144 | 144 | |
| 145 | const number = Number.Three { 1.23 }; | |
| 145 | const number = Number { .Three = 1.23 }; | |
| 146 | 146 | |
| 147 | 147 | fn returnsFalse() -> bool { |
| 148 | 148 | switch (number) { |
| ... | ... | @@ -224,3 +224,14 @@ fn switchWithUnreachable(x: i32) -> i32 { |
| 224 | 224 | } |
| 225 | 225 | return 10; |
| 226 | 226 | } |
| 227 | ||
| 228 | fn return_a_number() -> %i32 { | |
| 229 | return 1; | |
| 230 | } | |
| 231 | ||
| 232 | test "capture value of switch with all unreachable prongs" { | |
| 233 | const x = return_a_number() %% |err| switch (err) { | |
| 234 | else => unreachable, | |
| 235 | }; | |
| 236 | assert(x == 1); | |
| 237 | } |
test/cases/switch_prong_err_enum.zig+2-2| ... | ... | @@ -9,14 +9,14 @@ fn readOnce() -> %u64 { |
| 9 | 9 | |
| 10 | 10 | error InvalidDebugInfo; |
| 11 | 11 | |
| 12 | const FormValue = enum { | |
| 12 | const FormValue = union(enum) { | |
| 13 | 13 | Address: u64, |
| 14 | 14 | Other: bool, |
| 15 | 15 | }; |
| 16 | 16 | |
| 17 | 17 | fn doThing(form_id: u64) -> %FormValue { |
| 18 | 18 | return switch (form_id) { |
| 19 | 17 => FormValue.Address { %return readOnce() }, | |
| 19 | 17 => FormValue { .Address = %return readOnce() }, | |
| 20 | 20 | else => error.InvalidDebugInfo, |
| 21 | 21 | } |
| 22 | 22 | } |
test/cases/switch_prong_implicit_cast.zig+4-4| ... | ... | @@ -1,7 +1,7 @@ |
| 1 | 1 | const assert = @import("std").debug.assert; |
| 2 | 2 | |
| 3 | const FormValue = enum { | |
| 4 | One, | |
| 3 | const FormValue = union(enum) { | |
| 4 | One: void, | |
| 5 | 5 | Two: bool, |
| 6 | 6 | }; |
| 7 | 7 | |
| ... | ... | @@ -9,8 +9,8 @@ error Whatever; |
| 9 | 9 | |
| 10 | 10 | fn foo(id: u64) -> %FormValue { |
| 11 | 11 | switch (id) { |
| 12 | 2 => FormValue.Two { true }, | |
| 13 | 1 => FormValue.One, | |
| 12 | 2 => FormValue { .Two = true }, | |
| 13 | 1 => FormValue { .One = {} }, | |
| 14 | 14 | else => return error.Whatever, |
| 15 | 15 | } |
| 16 | 16 | } |
test/cases/union.zig+118-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | const assert = @import("std").debug.assert; |
| 2 | 2 | |
| 3 | const Value = enum { | |
| 3 | const Value = union(enum) { | |
| 4 | 4 | Int: u64, |
| 5 | 5 | Array: [9]u8, |
| 6 | 6 | }; |
| ... | ... | @@ -10,8 +10,8 @@ const Agg = struct { |
| 10 | 10 | val2: Value, |
| 11 | 11 | }; |
| 12 | 12 | |
| 13 | const v1 = Value.Int { 1234 }; | |
| 14 | const v2 = Value.Array { []u8{3} ** 9 }; | |
| 13 | const v1 = Value { .Int = 1234 }; | |
| 14 | const v2 = Value { .Array = []u8{3} ** 9 }; | |
| 15 | 15 | |
| 16 | 16 | const err = (%Agg)(Agg { |
| 17 | 17 | .val1 = v1, |
| ... | ... | @@ -75,3 +75,118 @@ test "basic extern unions" { |
| 75 | 75 | assert(foo.float == 12.34); |
| 76 | 76 | } |
| 77 | 77 | |
| 78 | ||
| 79 | const Letter = enum { | |
| 80 | A, | |
| 81 | B, | |
| 82 | C, | |
| 83 | }; | |
| 84 | const Payload = union(Letter) { | |
| 85 | A: i32, | |
| 86 | B: f64, | |
| 87 | C: bool, | |
| 88 | }; | |
| 89 | ||
| 90 | test "union with specified enum tag" { | |
| 91 | doTest(); | |
| 92 | comptime doTest(); | |
| 93 | } | |
| 94 | ||
| 95 | fn doTest() { | |
| 96 | assert(bar(Payload {.A = 1234}) == -10); | |
| 97 | } | |
| 98 | ||
| 99 | fn bar(value: &const Payload) -> i32 { | |
| 100 | assert(Letter(*value) == Letter.A); | |
| 101 | return switch (*value) { | |
| 102 | Payload.A => |x| return x - 1244, | |
| 103 | Payload.B => |x| if (x == 12.34) i32(20) else 21, | |
| 104 | Payload.C => |x| if (x) i32(30) else 31, | |
| 105 | }; | |
| 106 | } | |
| 107 | ||
| 108 | const MultipleChoice = union(enum(u32)) { | |
| 109 | A = 20, | |
| 110 | B = 40, | |
| 111 | C = 60, | |
| 112 | D = 1000, | |
| 113 | }; | |
| 114 | test "simple union(enum(u32))" { | |
| 115 | var x = MultipleChoice.C; | |
| 116 | assert(x == MultipleChoice.C); | |
| 117 | assert(u32(@TagType(MultipleChoice)(x)) == 60); | |
| 118 | } | |
| 119 | ||
| 120 | const MultipleChoice2 = union(enum(u32)) { | |
| 121 | Unspecified1: i32, | |
| 122 | A: f32 = 20, | |
| 123 | Unspecified2: void, | |
| 124 | B: bool = 40, | |
| 125 | Unspecified3: i32, | |
| 126 | C: i8 = 60, | |
| 127 | Unspecified4: void, | |
| 128 | D: void = 1000, | |
| 129 | Unspecified5: i32, | |
| 130 | }; | |
| 131 | ||
| 132 | test "union(enum(u32)) with specified and unspecified tag values" { | |
| 133 | comptime assert(@TagType(@TagType(MultipleChoice2)) == u32); | |
| 134 | testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 {.C = 123}); | |
| 135 | comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2 { .C = 123} ); | |
| 136 | } | |
| 137 | ||
| 138 | fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) { | |
| 139 | assert(u32(@TagType(MultipleChoice2)(*x)) == 60); | |
| 140 | assert(1123 == switch (*x) { | |
| 141 | MultipleChoice2.A => 1, | |
| 142 | MultipleChoice2.B => 2, | |
| 143 | MultipleChoice2.C => |v| i32(1000) + v, | |
| 144 | MultipleChoice2.D => 4, | |
| 145 | MultipleChoice2.Unspecified1 => 5, | |
| 146 | MultipleChoice2.Unspecified2 => 6, | |
| 147 | MultipleChoice2.Unspecified3 => 7, | |
| 148 | MultipleChoice2.Unspecified4 => 8, | |
| 149 | MultipleChoice2.Unspecified5 => 9, | |
| 150 | }); | |
| 151 | } | |
| 152 | ||
| 153 | ||
| 154 | const ExternPtrOrInt = extern union { | |
| 155 | ptr: &u8, | |
| 156 | int: u64 | |
| 157 | }; | |
| 158 | test "extern union size" { | |
| 159 | comptime assert(@sizeOf(ExternPtrOrInt) == 8); | |
| 160 | } | |
| 161 | ||
| 162 | const PackedPtrOrInt = packed union { | |
| 163 | ptr: &u8, | |
| 164 | int: u64 | |
| 165 | }; | |
| 166 | test "extern union size" { | |
| 167 | comptime assert(@sizeOf(PackedPtrOrInt) == 8); | |
| 168 | } | |
| 169 | ||
| 170 | const ZeroBits = union { | |
| 171 | OnlyField: void, | |
| 172 | }; | |
| 173 | test "union with only 1 field which is void should be zero bits" { | |
| 174 | comptime assert(@sizeOf(ZeroBits) == 0); | |
| 175 | } | |
| 176 | ||
| 177 | const TheTag = enum {A, B, C}; | |
| 178 | const TheUnion = union(TheTag) { A: i32, B: i32, C: i32 }; | |
| 179 | test "union field access gives the enum values" { | |
| 180 | assert(TheUnion.A == TheTag.A); | |
| 181 | assert(TheUnion.B == TheTag.B); | |
| 182 | assert(TheUnion.C == TheTag.C); | |
| 183 | } | |
| 184 | ||
| 185 | test "cast union to tag type of union" { | |
| 186 | testCastUnionToTagType(TheUnion {.B = 1234}); | |
| 187 | comptime testCastUnionToTagType(TheUnion {.B = 1234}); | |
| 188 | } | |
| 189 | ||
| 190 | fn testCastUnionToTagType(x: &const TheUnion) { | |
| 191 | assert(TheTag(*x) == TheTag.B); | |
| 192 | } |
test/compile_errors.zig+336-14| ... | ... | @@ -930,8 +930,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 930 | 930 | \\fn bad_eql_1(a: []u8, b: []u8) -> bool { |
| 931 | 931 | \\ a == b |
| 932 | 932 | \\} |
| 933 | \\const EnumWithData = enum { | |
| 934 | \\ One, | |
| 933 | \\const EnumWithData = union(enum) { | |
| 934 | \\ One: void, | |
| 935 | 935 | \\ Two: i32, |
| 936 | 936 | \\}; |
| 937 | 937 | \\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool { |
| ... | ... | @@ -1145,19 +1145,19 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 1145 | 1145 | \\const JasonHM = u8; |
| 1146 | 1146 | \\const JasonList = &JsonNode; |
| 1147 | 1147 | \\ |
| 1148 | \\const JsonOA = enum { | |
| 1148 | \\const JsonOA = union(enum) { | |
| 1149 | 1149 | \\ JSONArray: JsonList, |
| 1150 | 1150 | \\ JSONObject: JasonHM, |
| 1151 | 1151 | \\}; |
| 1152 | 1152 | \\ |
| 1153 | \\const JsonType = enum { | |
| 1153 | \\const JsonType = union(enum) { | |
| 1154 | 1154 | \\ JSONNull: void, |
| 1155 | 1155 | \\ JSONInteger: isize, |
| 1156 | 1156 | \\ JSONDouble: f64, |
| 1157 | 1157 | \\ JSONBool: bool, |
| 1158 | 1158 | \\ JSONString: []u8, |
| 1159 | \\ JSONArray, | |
| 1160 | \\ JSONObject, | |
| 1159 | \\ JSONArray: void, | |
| 1160 | \\ JSONObject: void, | |
| 1161 | 1161 | \\}; |
| 1162 | 1162 | \\ |
| 1163 | 1163 | \\pub const JsonNode = struct { |
| ... | ... | @@ -2138,7 +2138,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2138 | 2138 | \\ |
| 2139 | 2139 | \\const MdText = ArrayList(u8); |
| 2140 | 2140 | \\ |
| 2141 | \\const MdNode = enum { | |
| 2141 | \\const MdNode = union(enum) { | |
| 2142 | 2142 | \\ Header: struct { |
| 2143 | 2143 | \\ text: MdText, |
| 2144 | 2144 | \\ weight: HeaderValue, |
| ... | ... | @@ -2297,6 +2297,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2297 | 2297 | , |
| 2298 | 2298 | ".tmp_source.zig:2:21: error: type 'i32' does not support @memberType"); |
| 2299 | 2299 | |
| 2300 | cases.add("@memberType on enum", | |
| 2301 | \\comptime { | |
| 2302 | \\ _ = @memberType(Foo, 0); | |
| 2303 | \\} | |
| 2304 | \\const Foo = enum {A,}; | |
| 2305 | , | |
| 2306 | ".tmp_source.zig:2:21: error: type 'Foo' does not support @memberType"); | |
| 2307 | ||
| 2300 | 2308 | cases.add("@memberType struct out of bounds", |
| 2301 | 2309 | \\comptime { |
| 2302 | 2310 | \\ _ = @memberType(Foo, 0); |
| ... | ... | @@ -2305,13 +2313,13 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2305 | 2313 | , |
| 2306 | 2314 | ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members"); |
| 2307 | 2315 | |
| 2308 | cases.add("@memberType enum out of bounds", | |
| 2316 | cases.add("@memberType union out of bounds", | |
| 2309 | 2317 | \\comptime { |
| 2310 | \\ _ = @memberType(Foo, 0); | |
| 2318 | \\ _ = @memberType(Foo, 1); | |
| 2311 | 2319 | \\} |
| 2312 | \\const Foo = enum {}; | |
| 2320 | \\const Foo = union {A: void,}; | |
| 2313 | 2321 | , |
| 2314 | ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members"); | |
| 2322 | ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members"); | |
| 2315 | 2323 | |
| 2316 | 2324 | cases.add("@memberName on unsupported type", |
| 2317 | 2325 | \\comptime { |
| ... | ... | @@ -2330,11 +2338,19 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2330 | 2338 | |
| 2331 | 2339 | cases.add("@memberName enum out of bounds", |
| 2332 | 2340 | \\comptime { |
| 2333 | \\ _ = @memberName(Foo, 0); | |
| 2341 | \\ _ = @memberName(Foo, 1); | |
| 2334 | 2342 | \\} |
| 2335 | \\const Foo = enum {}; | |
| 2343 | \\const Foo = enum {A,}; | |
| 2336 | 2344 | , |
| 2337 | ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members"); | |
| 2345 | ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members"); | |
| 2346 | ||
| 2347 | cases.add("@memberName union out of bounds", | |
| 2348 | \\comptime { | |
| 2349 | \\ _ = @memberName(Foo, 1); | |
| 2350 | \\} | |
| 2351 | \\const Foo = union {A:i32,}; | |
| 2352 | , | |
| 2353 | ".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members"); | |
| 2338 | 2354 | |
| 2339 | 2355 | cases.add("calling var args extern function, passing array instead of pointer", |
| 2340 | 2356 | \\export fn entry() { |
| ... | ... | @@ -2362,4 +2378,310 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 2362 | 2378 | ".tmp_source.zig:4:25: error: aoeu", |
| 2363 | 2379 | ".tmp_source.zig:1:36: note: called from here", |
| 2364 | 2380 | ".tmp_source.zig:12:20: note: referenced here"); |
| 2381 | ||
| 2382 | cases.add("specify enum tag type that is too small", | |
| 2383 | \\const Small = enum (u2) { | |
| 2384 | \\ One, | |
| 2385 | \\ Two, | |
| 2386 | \\ Three, | |
| 2387 | \\ Four, | |
| 2388 | \\ Five, | |
| 2389 | \\}; | |
| 2390 | \\ | |
| 2391 | \\export fn entry() { | |
| 2392 | \\ var x = Small.One; | |
| 2393 | \\} | |
| 2394 | , | |
| 2395 | ".tmp_source.zig:1:20: error: 'u2' too small to hold all bits; must be at least 'u3'"); | |
| 2396 | ||
| 2397 | cases.add("specify non-integer enum tag type", | |
| 2398 | \\const Small = enum (f32) { | |
| 2399 | \\ One, | |
| 2400 | \\ Two, | |
| 2401 | \\ Three, | |
| 2402 | \\}; | |
| 2403 | \\ | |
| 2404 | \\export fn entry() { | |
| 2405 | \\ var x = Small.One; | |
| 2406 | \\} | |
| 2407 | , | |
| 2408 | ".tmp_source.zig:1:20: error: expected integer, found 'f32'"); | |
| 2409 | ||
| 2410 | cases.add("implicitly casting enum to tag type", | |
| 2411 | \\const Small = enum(u2) { | |
| 2412 | \\ One, | |
| 2413 | \\ Two, | |
| 2414 | \\ Three, | |
| 2415 | \\ Four, | |
| 2416 | \\}; | |
| 2417 | \\ | |
| 2418 | \\export fn entry() { | |
| 2419 | \\ var x: u2 = Small.Two; | |
| 2420 | \\} | |
| 2421 | , | |
| 2422 | ".tmp_source.zig:9:22: error: expected type 'u2', found 'Small'"); | |
| 2423 | ||
| 2424 | cases.add("explicitly casting enum to non tag type", | |
| 2425 | \\const Small = enum(u2) { | |
| 2426 | \\ One, | |
| 2427 | \\ Two, | |
| 2428 | \\ Three, | |
| 2429 | \\ Four, | |
| 2430 | \\}; | |
| 2431 | \\ | |
| 2432 | \\export fn entry() { | |
| 2433 | \\ var x = u3(Small.Two); | |
| 2434 | \\} | |
| 2435 | , | |
| 2436 | ".tmp_source.zig:9:15: error: enum to integer cast to 'u3' instead of its tag type, 'u2'"); | |
| 2437 | ||
| 2438 | cases.add("explicitly casting non tag type to enum", | |
| 2439 | \\const Small = enum(u2) { | |
| 2440 | \\ One, | |
| 2441 | \\ Two, | |
| 2442 | \\ Three, | |
| 2443 | \\ Four, | |
| 2444 | \\}; | |
| 2445 | \\ | |
| 2446 | \\export fn entry() { | |
| 2447 | \\ var y = u3(3); | |
| 2448 | \\ var x = Small(y); | |
| 2449 | \\} | |
| 2450 | , | |
| 2451 | ".tmp_source.zig:10:18: error: integer to enum cast from 'u3' instead of its tag type, 'u2'"); | |
| 2452 | ||
| 2453 | cases.add("non unsigned integer enum tag type", | |
| 2454 | \\const Small = enum(i2) { | |
| 2455 | \\ One, | |
| 2456 | \\ Two, | |
| 2457 | \\ Three, | |
| 2458 | \\ Four, | |
| 2459 | \\}; | |
| 2460 | \\ | |
| 2461 | \\export fn entry() { | |
| 2462 | \\ var y = Small.Two; | |
| 2463 | \\} | |
| 2464 | , | |
| 2465 | ".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'"); | |
| 2466 | ||
| 2467 | cases.add("struct fields with value assignments", | |
| 2468 | \\const MultipleChoice = struct { | |
| 2469 | \\ A: i32 = 20, | |
| 2470 | \\}; | |
| 2471 | \\export fn entry() { | |
| 2472 | \\ var x: MultipleChoice = undefined; | |
| 2473 | \\} | |
| 2474 | , | |
| 2475 | ".tmp_source.zig:2:14: error: enums, not structs, support field assignment"); | |
| 2476 | ||
| 2477 | cases.add("union fields with value assignments", | |
| 2478 | \\const MultipleChoice = union { | |
| 2479 | \\ A: i32 = 20, | |
| 2480 | \\}; | |
| 2481 | \\export fn entry() { | |
| 2482 | \\ var x: MultipleChoice = undefined; | |
| 2483 | \\} | |
| 2484 | , | |
| 2485 | ".tmp_source.zig:2:14: error: non-enum union field assignment", | |
| 2486 | ".tmp_source.zig:1:24: note: consider 'union(enum)' here"); | |
| 2487 | ||
| 2488 | cases.add("enum with 0 fields", | |
| 2489 | \\const Foo = enum {}; | |
| 2490 | \\export fn entry() -> usize { | |
| 2491 | \\ return @sizeOf(Foo); | |
| 2492 | \\} | |
| 2493 | , | |
| 2494 | ".tmp_source.zig:1:13: error: enums must have 1 or more fields"); | |
| 2495 | ||
| 2496 | cases.add("union with 0 fields", | |
| 2497 | \\const Foo = union {}; | |
| 2498 | \\export fn entry() -> usize { | |
| 2499 | \\ return @sizeOf(Foo); | |
| 2500 | \\} | |
| 2501 | , | |
| 2502 | ".tmp_source.zig:1:13: error: unions must have 1 or more fields"); | |
| 2503 | ||
| 2504 | cases.add("enum value already taken", | |
| 2505 | \\const MultipleChoice = enum(u32) { | |
| 2506 | \\ A = 20, | |
| 2507 | \\ B = 40, | |
| 2508 | \\ C = 60, | |
| 2509 | \\ D = 1000, | |
| 2510 | \\ E = 60, | |
| 2511 | \\}; | |
| 2512 | \\export fn entry() { | |
| 2513 | \\ var x = MultipleChoice.C; | |
| 2514 | \\} | |
| 2515 | , | |
| 2516 | ".tmp_source.zig:6:9: error: enum tag value 60 already taken", | |
| 2517 | ".tmp_source.zig:4:9: note: other occurrence here"); | |
| 2518 | ||
| 2519 | cases.add("union with specified enum omits field", | |
| 2520 | \\const Letter = enum { | |
| 2521 | \\ A, | |
| 2522 | \\ B, | |
| 2523 | \\ C, | |
| 2524 | \\}; | |
| 2525 | \\const Payload = union(Letter) { | |
| 2526 | \\ A: i32, | |
| 2527 | \\ B: f64, | |
| 2528 | \\}; | |
| 2529 | \\export fn entry() -> usize { | |
| 2530 | \\ return @sizeOf(Payload); | |
| 2531 | \\} | |
| 2532 | , | |
| 2533 | ".tmp_source.zig:6:17: error: enum field missing: 'C'", | |
| 2534 | ".tmp_source.zig:4:5: note: declared here"); | |
| 2535 | ||
| 2536 | cases.add("@TagType when union has no attached enum", | |
| 2537 | \\const Foo = union { | |
| 2538 | \\ A: i32, | |
| 2539 | \\}; | |
| 2540 | \\export fn entry() { | |
| 2541 | \\ const x = @TagType(Foo); | |
| 2542 | \\} | |
| 2543 | , | |
| 2544 | ".tmp_source.zig:5:24: error: union 'Foo' has no tag", | |
| 2545 | ".tmp_source.zig:1:13: note: consider 'union(enum)' here"); | |
| 2546 | ||
| 2547 | cases.add("non-integer tag type to automatic union enum", | |
| 2548 | \\const Foo = union(enum(f32)) { | |
| 2549 | \\ A: i32, | |
| 2550 | \\}; | |
| 2551 | \\export fn entry() { | |
| 2552 | \\ const x = @TagType(Foo); | |
| 2553 | \\} | |
| 2554 | , | |
| 2555 | ".tmp_source.zig:1:23: error: expected integer tag type, found 'f32'"); | |
| 2556 | ||
| 2557 | cases.add("non-enum tag type passed to union", | |
| 2558 | \\const Foo = union(u32) { | |
| 2559 | \\ A: i32, | |
| 2560 | \\}; | |
| 2561 | \\export fn entry() { | |
| 2562 | \\ const x = @TagType(Foo); | |
| 2563 | \\} | |
| 2564 | , | |
| 2565 | ".tmp_source.zig:1:18: error: expected enum tag type, found 'u32'"); | |
| 2566 | ||
| 2567 | cases.add("union auto-enum value already taken", | |
| 2568 | \\const MultipleChoice = union(enum(u32)) { | |
| 2569 | \\ A = 20, | |
| 2570 | \\ B = 40, | |
| 2571 | \\ C = 60, | |
| 2572 | \\ D = 1000, | |
| 2573 | \\ E = 60, | |
| 2574 | \\}; | |
| 2575 | \\export fn entry() { | |
| 2576 | \\ var x = MultipleChoice { .C = {} }; | |
| 2577 | \\} | |
| 2578 | , | |
| 2579 | ".tmp_source.zig:6:9: error: enum tag value 60 already taken", | |
| 2580 | ".tmp_source.zig:4:9: note: other occurrence here"); | |
| 2581 | ||
| 2582 | cases.add("union enum field does not match enum", | |
| 2583 | \\const Letter = enum { | |
| 2584 | \\ A, | |
| 2585 | \\ B, | |
| 2586 | \\ C, | |
| 2587 | \\}; | |
| 2588 | \\const Payload = union(Letter) { | |
| 2589 | \\ A: i32, | |
| 2590 | \\ B: f64, | |
| 2591 | \\ C: bool, | |
| 2592 | \\ D: bool, | |
| 2593 | \\}; | |
| 2594 | \\export fn entry() { | |
| 2595 | \\ var a = Payload {.A = 1234}; | |
| 2596 | \\} | |
| 2597 | , | |
| 2598 | ".tmp_source.zig:10:5: error: enum field not found: 'D'", | |
| 2599 | ".tmp_source.zig:1:16: note: enum declared here"); | |
| 2600 | ||
| 2601 | cases.add("field type supplied in an enum", | |
| 2602 | \\const Letter = enum { | |
| 2603 | \\ A: void, | |
| 2604 | \\ B, | |
| 2605 | \\ C, | |
| 2606 | \\}; | |
| 2607 | \\export fn entry() { | |
| 2608 | \\ var b = Letter.B; | |
| 2609 | \\} | |
| 2610 | , | |
| 2611 | ".tmp_source.zig:2:8: error: structs and unions, not enums, support field types", | |
| 2612 | ".tmp_source.zig:1:16: note: consider 'union(enum)' here"); | |
| 2613 | ||
| 2614 | cases.add("struct field missing type", | |
| 2615 | \\const Letter = struct { | |
| 2616 | \\ A, | |
| 2617 | \\}; | |
| 2618 | \\export fn entry() { | |
| 2619 | \\ var a = Letter { .A = {} }; | |
| 2620 | \\} | |
| 2621 | , | |
| 2622 | ".tmp_source.zig:2:5: error: struct field missing type"); | |
| 2623 | ||
| 2624 | cases.add("extern union field missing type", | |
| 2625 | \\const Letter = extern union { | |
| 2626 | \\ A, | |
| 2627 | \\}; | |
| 2628 | \\export fn entry() { | |
| 2629 | \\ var a = Letter { .A = {} }; | |
| 2630 | \\} | |
| 2631 | , | |
| 2632 | ".tmp_source.zig:2:5: error: union field missing type"); | |
| 2633 | ||
| 2634 | cases.add("extern union given enum tag type", | |
| 2635 | \\const Letter = enum { | |
| 2636 | \\ A, | |
| 2637 | \\ B, | |
| 2638 | \\ C, | |
| 2639 | \\}; | |
| 2640 | \\const Payload = extern union(Letter) { | |
| 2641 | \\ A: i32, | |
| 2642 | \\ B: f64, | |
| 2643 | \\ C: bool, | |
| 2644 | \\}; | |
| 2645 | \\export fn entry() { | |
| 2646 | \\ var a = Payload { .A = { 1234 } }; | |
| 2647 | \\} | |
| 2648 | , | |
| 2649 | ".tmp_source.zig:6:29: error: extern union does not support enum tag type"); | |
| 2650 | ||
| 2651 | cases.add("packed union given enum tag type", | |
| 2652 | \\const Letter = enum { | |
| 2653 | \\ A, | |
| 2654 | \\ B, | |
| 2655 | \\ C, | |
| 2656 | \\}; | |
| 2657 | \\const Payload = packed union(Letter) { | |
| 2658 | \\ A: i32, | |
| 2659 | \\ B: f64, | |
| 2660 | \\ C: bool, | |
| 2661 | \\}; | |
| 2662 | \\export fn entry() { | |
| 2663 | \\ var a = Payload { .A = { 1234 } }; | |
| 2664 | \\} | |
| 2665 | , | |
| 2666 | ".tmp_source.zig:6:29: error: packed union does not support enum tag type"); | |
| 2667 | ||
| 2668 | cases.add("switch on union with no attached enum", | |
| 2669 | \\const Payload = union { | |
| 2670 | \\ A: i32, | |
| 2671 | \\ B: f64, | |
| 2672 | \\ C: bool, | |
| 2673 | \\}; | |
| 2674 | \\export fn entry() { | |
| 2675 | \\ const a = Payload { .A = { 1234 } }; | |
| 2676 | \\ foo(a); | |
| 2677 | \\} | |
| 2678 | \\fn foo(a: &const Payload) { | |
| 2679 | \\ switch (*a) { | |
| 2680 | \\ Payload.A => {}, | |
| 2681 | \\ else => unreachable, | |
| 2682 | \\ } | |
| 2683 | \\} | |
| 2684 | , | |
| 2685 | ".tmp_source.zig:11:13: error: switch on union which has no attached enum", | |
| 2686 | ".tmp_source.zig:1:17: note: consider 'union(enum)' here"); | |
| 2365 | 2687 | } |
test/tests.zig+5-5| ... | ... | @@ -150,8 +150,8 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons |
| 150 | 150 | continue; |
| 151 | 151 | } |
| 152 | 152 | const these_tests = b.addTest(root_src); |
| 153 | these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @enumTagName(test_target.os), | |
| 154 | @enumTagName(test_target.arch), @enumTagName(mode), if (link_libc) "c" else "bare")); | |
| 153 | these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os), | |
| 154 | @tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare")); | |
| 155 | 155 | these_tests.setFilter(test_filter); |
| 156 | 156 | these_tests.setBuildMode(mode); |
| 157 | 157 | if (!is_native) { |
| ... | ... | @@ -428,7 +428,7 @@ pub const CompareOutputContext = struct { |
| 428 | 428 | Special.None => { |
| 429 | 429 | for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| { |
| 430 | 430 | const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "{} {} ({})", |
| 431 | "compare-output", case.name, @enumTagName(mode)); | |
| 431 | "compare-output", case.name, @tagName(mode)); | |
| 432 | 432 | if (self.test_filter) |filter| { |
| 433 | 433 | if (mem.indexOf(u8, annotated_case_name, filter) == null) |
| 434 | 434 | continue; |
| ... | ... | @@ -682,7 +682,7 @@ pub const CompileErrorContext = struct { |
| 682 | 682 | |
| 683 | 683 | for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| { |
| 684 | 684 | const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "compile-error {} ({})", |
| 685 | case.name, @enumTagName(mode)); | |
| 685 | case.name, @tagName(mode)); | |
| 686 | 686 | if (self.test_filter) |filter| { |
| 687 | 687 | if (mem.indexOf(u8, annotated_case_name, filter) == null) |
| 688 | 688 | continue; |
| ... | ... | @@ -750,7 +750,7 @@ pub const BuildExamplesContext = struct { |
| 750 | 750 | |
| 751 | 751 | for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| { |
| 752 | 752 | const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "build {} ({})", |
| 753 | root_src, @enumTagName(mode)); | |
| 753 | root_src, @tagName(mode)); | |
| 754 | 754 | if (self.test_filter) |filter| { |
| 755 | 755 | if (mem.indexOf(u8, annotated_case_name, filter) == null) |
| 756 | 756 | continue; |
test/translate_c.zig+10| ... | ... | @@ -1178,4 +1178,14 @@ pub fn addCases(cases: &tests.TranslateCContext) { |
| 1178 | 1178 | , |
| 1179 | 1179 | \\pub var v0: ?&const u8 = c"0.0.0"; |
| 1180 | 1180 | ); |
| 1181 | ||
| 1182 | cases.add("static incomplete array inside function", | |
| 1183 | \\void foo(void) { | |
| 1184 | \\ static const char v2[] = "2.2.2"; | |
| 1185 | \\} | |
| 1186 | , | |
| 1187 | \\pub fn foo() { | |
| 1188 | \\ const v2: &const u8 = c"2.2.2"; | |
| 1189 | \\} | |
| 1190 | ); | |
| 1181 | 1191 | } |