mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Merge llvm-project main llvmorg-17-init-19304-gd0b54bb50e51
This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp to llvm-project main llvmorg-17-init-19304-gd0b54bb50e51, the last commit before the upstream release/17.x branch was created. PR: 273753 MFC after: 1 month (cherry picked from commit 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
This commit is contained in:
parent
2f3b605b2e
commit
fe013be447
6358 changed files with 415762 additions and 227707 deletions
|
|
@ -2498,6 +2498,7 @@ _gensnmptree= usr.sbin/bsnmpd/gensnmptree
|
|||
${MK_LLDB} != "no" || ${MK_LLVM_BINUTILS} != "no"
|
||||
_clang_tblgen= \
|
||||
lib/clang/libllvmminimal \
|
||||
usr.bin/clang/llvm-min-tblgen \
|
||||
usr.bin/clang/llvm-tblgen
|
||||
.if ${MK_CLANG_BOOTSTRAP} != "no" || ${MK_CLANG} != "no" || \
|
||||
${MK_LLDB} != "no"
|
||||
|
|
@ -2508,8 +2509,10 @@ _clang_tblgen+= usr.bin/clang/clang-tblgen
|
|||
_clang_tblgen+= usr.bin/clang/lldb-tblgen
|
||||
.endif
|
||||
${_bt}-usr.bin/clang/clang-tblgen: ${_bt}-lib/clang/libllvmminimal
|
||||
${_bt}-usr.bin/clang/llvm-tblgen: ${_bt}-lib/clang/libllvmminimal
|
||||
${_bt}-usr.bin/clang/lldb-tblgen: ${_bt}-lib/clang/libllvmminimal
|
||||
${_bt}-usr.bin/clang/llvm-min-tblgen: ${_bt}-lib/clang/libllvmminimal
|
||||
${_bt}-usr.bin/clang/llvm-tblgen: ${_bt}-lib/clang/libllvmminimal
|
||||
${_bt}-usr.bin/clang/llvm-tblgen: ${_bt}-usr.bin/clang/llvm-min-tblgen
|
||||
.endif
|
||||
|
||||
# C.UTF-8 is always built in share/ctypes and we need localedef for that.
|
||||
|
|
|
|||
|
|
@ -51,6 +51,408 @@
|
|||
# xargs -n1 | sort | uniq -d;
|
||||
# done
|
||||
|
||||
# 20240107: new clang import which bumps version from 16 to 17
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_builtin_vars.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_cmath.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_complex_builtins.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_device_functions.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_intrinsics.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_libdevice_declares.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_math.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_math_forward_declares.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_runtime_wrapper.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_cuda_texture_intrinsics.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_hip_cmath.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_hip_libdevice_declares.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_hip_math.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_hip_runtime_wrapper.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__clang_hip_stdlib.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__stddef_max_align_t.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__wmmintrin_aes.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/__wmmintrin_pclmul.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/adxintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/altivec.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ammintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/amxfp16intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/amxintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/arm64intr.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/arm_acle.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/arm_bf16.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/arm_cde.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/arm_cmse.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/arm_fp16.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/arm_mve.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/arm_neon.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/arm_neon_sve_bridge.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/arm_sve.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/armintr.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx2intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512bf16intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512bitalgintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512bwintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512cdintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512dqintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512erintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512fintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512fp16intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512ifmaintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512ifmavlintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512pfintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vbmi2intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vbmiintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vbmivlintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vlbf16intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vlbitalgintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vlbwintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vlcdintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vldqintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vlfp16intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vlintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vlvbmi2intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vlvnniintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vlvp2intersectintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vnniintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vp2intersectintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vpopcntdqintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avx512vpopcntdqvlintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avxifmaintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avxintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avxneconvertintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avxvnniint8intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/avxvnniintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/bmi2intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/bmiintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/builtins.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/cet.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/cetintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/cldemoteintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/clflushoptintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/clwbintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/clzerointrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/cmpccxaddintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/cpuid.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/crc32intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/cuda_wrappers/algorithm
|
||||
OLD_FILES+=usr/lib/clang/16/include/cuda_wrappers/cmath
|
||||
OLD_FILES+=usr/lib/clang/16/include/cuda_wrappers/complex
|
||||
OLD_FILES+=usr/lib/clang/16/include/cuda_wrappers/new
|
||||
OLD_DIRS+=usr/lib/clang/16/include/cuda_wrappers
|
||||
OLD_FILES+=usr/lib/clang/16/include/emmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/enqcmdintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/f16cintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/float.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/fma4intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/fmaintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/fuzzer/FuzzedDataProvider.h
|
||||
OLD_DIRS+=usr/lib/clang/16/include/fuzzer
|
||||
OLD_FILES+=usr/lib/clang/16/include/fxsrintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/gfniintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/hexagon_circ_brev_intrinsics.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/hexagon_protos.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/hexagon_types.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/hlsl/hlsl_basic_types.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/hlsl/hlsl_intrinsics.h
|
||||
OLD_DIRS+=usr/lib/clang/16/include/hlsl
|
||||
OLD_FILES+=usr/lib/clang/16/include/hlsl.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/hresetintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/htmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/htmxlintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/hvx_hexagon_protos.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ia32intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/immintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/inttypes.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/invpcidintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/iso646.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/keylockerintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/larchintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/limits.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/lwpintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/lzcntintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/mm3dnow.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/mm_malloc.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/mmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/module.modulemap
|
||||
OLD_FILES+=usr/lib/clang/16/include/movdirintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/msa.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/mwaitxintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/nmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/omp-tools.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/omp.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ompt.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/opencl-c-base.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/opencl-c.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/__clang_openmp_device_functions.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/cmath
|
||||
OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/complex
|
||||
OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/complex.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/complex_cmath.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/math.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/openmp_wrappers/new
|
||||
OLD_DIRS+=usr/lib/clang/16/include/openmp_wrappers
|
||||
OLD_FILES+=usr/lib/clang/16/include/orc_rt/c_api.h
|
||||
OLD_DIRS+=usr/lib/clang/16/include/orc_rt
|
||||
OLD_FILES+=usr/lib/clang/16/include/pconfigintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/pkuintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/pmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/popcntintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/bmi2intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/bmiintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/emmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/immintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/mm_malloc.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/mmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/pmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/smmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/tmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/x86gprintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/x86intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/ppc_wrappers/xmmintrin.h
|
||||
OLD_DIRS+=usr/lib/clang/16/include/ppc_wrappers
|
||||
OLD_FILES+=usr/lib/clang/16/include/prfchiintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/prfchwintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/profile/InstrProfData.inc
|
||||
OLD_FILES+=usr/lib/clang/16/include/profile/MemProfData.inc
|
||||
OLD_DIRS+=usr/lib/clang/16/include/profile
|
||||
OLD_FILES+=usr/lib/clang/16/include/ptwriteintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/raointintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/rdpruintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/rdseedintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/riscv_vector.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/rtmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/s390intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/allocator_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/asan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/common_interface_defs.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/coverage_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/dfsan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/hwasan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/linux_syscall_hooks.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/lsan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/memprof_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/msan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/netbsd_syscall_hooks.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/scudo_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/tsan_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/tsan_interface_atomic.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sanitizer/ubsan_interface.h
|
||||
OLD_DIRS+=usr/lib/clang/16/include/sanitizer
|
||||
OLD_FILES+=usr/lib/clang/16/include/serializeintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/sgxintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/shaintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/smmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/stdalign.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/stdarg.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/stdatomic.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/stdbool.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/stddef.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/stdint.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/stdnoreturn.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/tbmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/tgmath.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/tmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/tsxldtrkintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/uintrintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/unwind.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/vadefs.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/vaesintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/varargs.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/vecintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/velintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/velintrin_approx.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/velintrin_gen.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/vpclmulqdqintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/waitpkgintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/wasm_simd128.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/wbnoinvdintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/wmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/x86gprintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/x86intrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/xmmintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/xopintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/xray/xray_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/xray/xray_log_interface.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/xray/xray_records.h
|
||||
OLD_DIRS+=usr/lib/clang/16/include/xray
|
||||
OLD_FILES+=usr/lib/clang/16/include/xsavecintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/xsaveintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/xsaveoptintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/xsavesintrin.h
|
||||
OLD_FILES+=usr/lib/clang/16/include/xtestintrin.h
|
||||
OLD_DIRS+=usr/lib/clang/16/include
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-aarch64.so
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-arm.so
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-armhf.so
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-i386.so
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-powerpc64.so
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-powerpc64le.so
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-riscv64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-riscv64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-riscv64.so
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan-x86_64.so
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-riscv64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_static-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_static-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_static-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.asan_static-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi_diag-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi_diag-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi_diag-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.dd-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.dd-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.fuzzer-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.fuzzer-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan_cxx-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan_cxx-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-powerpc.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-riscv64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.profile-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.safestack-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.safestack-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.safestack-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-riscv64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-riscv64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.stats_client-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan_cxx-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan_cxx-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-riscv64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-riscv64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-riscv64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-basic-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-basic-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-basic-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-basic-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-basic-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-fdr-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-fdr-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-fdr-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-profiling-arm.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-profiling-armhf.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-profiling-powerpc64le.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
|
||||
OLD_FILES+=usr/lib/clang/16/lib/freebsd/libclang_rt.xray-x86_64.a
|
||||
OLD_DIRS+=usr/lib/clang/16/lib/freebsd
|
||||
OLD_DIRS+=usr/lib/clang/16/lib
|
||||
OLD_FILES+=usr/lib/clang/16/share/asan_ignorelist.txt
|
||||
OLD_FILES+=usr/lib/clang/16/share/cfi_ignorelist.txt
|
||||
OLD_FILES+=usr/lib/clang/16/share/msan_ignorelist.txt
|
||||
OLD_DIRS+=usr/lib/clang/16/share
|
||||
OLD_DIRS+=usr/lib/clang/16
|
||||
|
||||
# 20240107: new libc++ import which bumps version from 16 to 17
|
||||
OLD_FILES+=usr/include/c++/v1/__bsd_locale_defaults.h
|
||||
OLD_FILES+=usr/include/c++/v1/__bsd_locale_fallbacks.h
|
||||
OLD_FILES+=usr/include/c++/v1/__debug
|
||||
OLD_FILES+=usr/include/c++/v1/__errc
|
||||
OLD_FILES+=usr/include/c++/v1/__functional/unwrap_ref.h
|
||||
OLD_FILES+=usr/include/c++/v1/__mutex_base
|
||||
OLD_FILES+=usr/include/c++/v1/__ranges/copyable_box.h
|
||||
OLD_FILES+=usr/include/c++/v1/__std_stream
|
||||
OLD_FILES+=usr/include/c++/v1/__tuple_dir/apply_cv.h
|
||||
OLD_FILES+=usr/include/c++/v1/__tuple_dir/make_tuple_types.h
|
||||
OLD_FILES+=usr/include/c++/v1/__tuple_dir/pair_like.h
|
||||
OLD_FILES+=usr/include/c++/v1/__tuple_dir/sfinae_helpers.h
|
||||
OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_element.h
|
||||
OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_indices.h
|
||||
OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_like.h
|
||||
OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_like_ext.h
|
||||
OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_size.h
|
||||
OLD_FILES+=usr/include/c++/v1/__tuple_dir/tuple_types.h
|
||||
OLD_DIRS+=usr/include/c++/v1/__tuple_dir
|
||||
OLD_FILES+=usr/include/c++/v1/experimental/algorithm
|
||||
OLD_FILES+=usr/include/c++/v1/experimental/coroutine
|
||||
OLD_FILES+=usr/include/c++/v1/experimental/functional
|
||||
|
||||
# 20231006: rename tcp6_v4unmapped_bind_test
|
||||
OLD_FILES+=usr/tests/sys/netinet/tcp6_v4unmapped_bind_test
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
.arcconfig
|
||||
.arclint
|
||||
.ci/
|
||||
.clang-format
|
||||
.clang-tidy
|
||||
.git-blame-ignore-revs
|
||||
|
|
@ -11,14 +12,12 @@ LICENSE.TXT
|
|||
README.md
|
||||
SECURITY.md
|
||||
bolt/
|
||||
clang-tools-extra/
|
||||
clang/.clang-format
|
||||
clang/.clang-tidy
|
||||
clang/.gitignore
|
||||
clang/CMakeLists.txt
|
||||
clang/CodeOwners.rst
|
||||
clang/INSTALL.txt
|
||||
clang/ModuleInfo.txt
|
||||
clang/NOTES.txt
|
||||
clang/README.txt
|
||||
clang/bindings/
|
||||
|
|
@ -102,7 +101,6 @@ clang/tools/c-index-test/
|
|||
clang/tools/clang-check/
|
||||
clang/tools/clang-diff/
|
||||
clang/tools/clang-extdef-mapping/
|
||||
clang/tools/clang-format-vs/
|
||||
clang/tools/clang-format/.clang-format
|
||||
clang/tools/clang-format/CMakeLists.txt
|
||||
clang/tools/clang-format/clang-format-bbedit.applescript
|
||||
|
|
@ -113,6 +111,7 @@ clang/tools/clang-format/clang-format.el
|
|||
clang/tools/clang-format/clang-format.py
|
||||
clang/tools/clang-format/fuzzer/
|
||||
clang/tools/clang-format/git-clang-format
|
||||
clang/tools/clang-format-vs/
|
||||
clang/tools/clang-fuzzer/
|
||||
clang/tools/clang-import-test/
|
||||
clang/tools/clang-linker-wrapper/
|
||||
|
|
@ -130,8 +129,8 @@ clang/tools/driver/Info.plist.in
|
|||
clang/tools/include-mapping/
|
||||
clang/tools/libclang/
|
||||
clang/tools/nvptx-arch/CMakeLists.txt
|
||||
clang/tools/scan-build-py/
|
||||
clang/tools/scan-build/
|
||||
clang/tools/scan-build-py/
|
||||
clang/tools/scan-view/
|
||||
clang/unittests/
|
||||
clang/utils/ABITest/
|
||||
|
|
@ -148,7 +147,9 @@ clang/utils/VtableTest/
|
|||
clang/utils/analyzer/
|
||||
clang/utils/bash-autocomplete.sh
|
||||
clang/utils/builtin-defines.c
|
||||
clang/utils/bundle_resources.py
|
||||
clang/utils/check_cfc/
|
||||
clang/utils/ci/
|
||||
clang/utils/clangdiag.py
|
||||
clang/utils/convert_arm_neon.py
|
||||
clang/utils/creduce-clang-crash.py
|
||||
|
|
@ -161,6 +162,7 @@ clang/utils/perf-training/
|
|||
clang/utils/token-delta.py
|
||||
clang/utils/valgrind/
|
||||
clang/www/
|
||||
clang-tools-extra/
|
||||
cmake/
|
||||
compiler-rt/.gitignore
|
||||
compiler-rt/CMakeLists.txt
|
||||
|
|
@ -173,11 +175,11 @@ compiler-rt/lib/asan/.clang-format
|
|||
compiler-rt/lib/asan/CMakeLists.txt
|
||||
compiler-rt/lib/asan/scripts/
|
||||
compiler-rt/lib/asan/tests/
|
||||
compiler-rt/lib/asan_abi/CMakeLists.txt
|
||||
compiler-rt/lib/builtins/CMakeLists.txt
|
||||
compiler-rt/lib/builtins/Darwin-excludes/
|
||||
compiler-rt/lib/builtins/macho_embedded/
|
||||
compiler-rt/lib/cfi/CMakeLists.txt
|
||||
compiler-rt/lib/crt/CMakeLists.txt
|
||||
compiler-rt/lib/dfsan/.clang-format
|
||||
compiler-rt/lib/dfsan/CMakeLists.txt
|
||||
compiler-rt/lib/dfsan/scripts/
|
||||
|
|
@ -258,8 +260,9 @@ libcxx/include/CMakeLists.txt
|
|||
libcxx/include/__config_site.in
|
||||
libcxx/include/__support/
|
||||
libcxx/lib/
|
||||
libcxx/modules/CMakeLists.txt
|
||||
libcxx/modules/CMakeLists.txt.in
|
||||
libcxx/src/CMakeLists.txt
|
||||
libcxx/src/support/solaris/
|
||||
libcxx/src/support/win32/
|
||||
libcxx/test/
|
||||
libcxx/utils/
|
||||
|
|
@ -281,6 +284,7 @@ lld/cmake/
|
|||
lld/docs/CMakeLists.txt
|
||||
lld/test/
|
||||
lld/tools/lld/CMakeLists.txt
|
||||
lld/unittests/
|
||||
lld/utils/
|
||||
lld/wasm/
|
||||
lldb/.clang-format
|
||||
|
|
@ -334,6 +338,7 @@ lldb/source/Plugins/ABI/ARC/CMakeLists.txt
|
|||
lldb/source/Plugins/ABI/ARM/CMakeLists.txt
|
||||
lldb/source/Plugins/ABI/CMakeLists.txt
|
||||
lldb/source/Plugins/ABI/Hexagon/CMakeLists.txt
|
||||
lldb/source/Plugins/ABI/MSP430/CMakeLists.txt
|
||||
lldb/source/Plugins/ABI/Mips/CMakeLists.txt
|
||||
lldb/source/Plugins/ABI/PowerPC/CMakeLists.txt
|
||||
lldb/source/Plugins/ABI/SystemZ/CMakeLists.txt
|
||||
|
|
@ -381,8 +386,7 @@ lldb/source/Plugins/LanguageRuntime/CPlusPlus/CMakeLists.txt
|
|||
lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/CMakeLists.txt
|
||||
lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/CMakeLists.txt
|
||||
lldb/source/Plugins/LanguageRuntime/ObjC/CMakeLists.txt
|
||||
lldb/source/Plugins/LanguageRuntime/RenderScript/CMakeLists.txt
|
||||
lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt
|
||||
lldb/source/Plugins/LanguageRuntime/ObjC/GNUstepObjCRuntime/CMakeLists.txt
|
||||
lldb/source/Plugins/MemoryHistory/CMakeLists.txt
|
||||
lldb/source/Plugins/MemoryHistory/asan/CMakeLists.txt
|
||||
lldb/source/Plugins/ObjectContainer/BSD-Archive/CMakeLists.txt
|
||||
|
|
@ -391,12 +395,14 @@ lldb/source/Plugins/ObjectContainer/Mach-O-Fileset/CMakeLists.txt
|
|||
lldb/source/Plugins/ObjectContainer/Universal-Mach-O/
|
||||
lldb/source/Plugins/ObjectFile/Breakpad/CMakeLists.txt
|
||||
lldb/source/Plugins/ObjectFile/CMakeLists.txt
|
||||
lldb/source/Plugins/ObjectFile/COFF/CMakeLists.txt
|
||||
lldb/source/Plugins/ObjectFile/ELF/CMakeLists.txt
|
||||
lldb/source/Plugins/ObjectFile/JIT/CMakeLists.txt
|
||||
lldb/source/Plugins/ObjectFile/JSON/CMakeLists.txt
|
||||
lldb/source/Plugins/ObjectFile/Mach-O/
|
||||
lldb/source/Plugins/ObjectFile/Minidump/CMakeLists.txt
|
||||
lldb/source/Plugins/ObjectFile/PDB/CMakeLists.txt
|
||||
lldb/source/Plugins/ObjectFile/PECOFF/
|
||||
lldb/source/Plugins/ObjectFile/Placeholder/CMakeLists.txt
|
||||
lldb/source/Plugins/ObjectFile/wasm/CMakeLists.txt
|
||||
lldb/source/Plugins/OperatingSystem/CMakeLists.txt
|
||||
lldb/source/Plugins/OperatingSystem/Python/CMakeLists.txt
|
||||
|
|
@ -427,6 +433,7 @@ lldb/source/Plugins/Process/minidump/CMakeLists.txt
|
|||
lldb/source/Plugins/Process/scripted/CMakeLists.txt
|
||||
lldb/source/Plugins/REPL/CMakeLists.txt
|
||||
lldb/source/Plugins/REPL/Clang/CMakeLists.txt
|
||||
lldb/source/Plugins/RegisterTypeBuilder/CMakeLists.txt
|
||||
lldb/source/Plugins/ScriptInterpreter/CMakeLists.txt
|
||||
lldb/source/Plugins/ScriptInterpreter/Lua/CMakeLists.txt
|
||||
lldb/source/Plugins/ScriptInterpreter/None/CMakeLists.txt
|
||||
|
|
@ -435,7 +442,9 @@ lldb/source/Plugins/StructuredData/CMakeLists.txt
|
|||
lldb/source/Plugins/StructuredData/DarwinLog/CMakeLists.txt
|
||||
lldb/source/Plugins/SymbolFile/Breakpad/CMakeLists.txt
|
||||
lldb/source/Plugins/SymbolFile/CMakeLists.txt
|
||||
lldb/source/Plugins/SymbolFile/CTF/CMakeLists.txt
|
||||
lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt
|
||||
lldb/source/Plugins/SymbolFile/JSON/CMakeLists.txt
|
||||
lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt
|
||||
lldb/source/Plugins/SymbolFile/PDB/CMakeLists.txt
|
||||
lldb/source/Plugins/SymbolFile/Symtab/CMakeLists.txt
|
||||
|
|
@ -483,7 +492,6 @@ lldb/utils/lit-cpuid/
|
|||
lldb/utils/lldb-dotest/
|
||||
lldb/utils/lldb-repro/
|
||||
lldb/utils/lui/
|
||||
llvm-libgcc/
|
||||
llvm/.clang-format
|
||||
llvm/.clang-tidy
|
||||
llvm/.gitattributes
|
||||
|
|
@ -499,7 +507,9 @@ llvm/cmake/
|
|||
llvm/configure
|
||||
llvm/docs/
|
||||
llvm/examples/
|
||||
llvm/include/CMakeLists.txt
|
||||
llvm/include/llvm/CMakeLists.txt
|
||||
llvm/include/llvm/CodeGen/CMakeLists.txt
|
||||
llvm/include/llvm/Config/
|
||||
llvm/include/llvm/Frontend/CMakeLists.txt
|
||||
llvm/include/llvm/Frontend/OpenACC/CMakeLists.txt
|
||||
|
|
@ -509,7 +519,6 @@ llvm/include/llvm/Support/CMakeLists.txt
|
|||
llvm/include/llvm/Support/LICENSE.TXT
|
||||
llvm/include/llvm/TargetParser/CMakeLists.txt
|
||||
llvm/lib/Analysis/CMakeLists.txt
|
||||
llvm/lib/Analysis/README.txt
|
||||
llvm/lib/Analysis/models/
|
||||
llvm/lib/AsmParser/CMakeLists.txt
|
||||
llvm/lib/BinaryFormat/CMakeLists.txt
|
||||
|
|
@ -528,6 +537,7 @@ llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt
|
|||
llvm/lib/DWARFLinker/CMakeLists.txt
|
||||
llvm/lib/DWARFLinkerParallel/CMakeLists.txt
|
||||
llvm/lib/DWP/CMakeLists.txt
|
||||
llvm/lib/DebugInfo/BTF/CMakeLists.txt
|
||||
llvm/lib/DebugInfo/CMakeLists.txt
|
||||
llvm/lib/DebugInfo/CodeView/CMakeLists.txt
|
||||
llvm/lib/DebugInfo/DWARF/CMakeLists.txt
|
||||
|
|
@ -749,8 +759,8 @@ llvm/resources/
|
|||
llvm/runtimes/
|
||||
llvm/test/
|
||||
llvm/tools/CMakeLists.txt
|
||||
llvm/tools/bugpoint-passes/
|
||||
llvm/tools/bugpoint/CMakeLists.txt
|
||||
llvm/tools/bugpoint-passes/
|
||||
llvm/tools/dsymutil/
|
||||
llvm/tools/dxil-dis/
|
||||
llvm/tools/gold/
|
||||
|
|
@ -758,8 +768,8 @@ llvm/tools/llc/CMakeLists.txt
|
|||
llvm/tools/lli/CMakeLists.txt
|
||||
llvm/tools/lli/ChildTarget/CMakeLists.txt
|
||||
llvm/tools/llvm-ar/CMakeLists.txt
|
||||
llvm/tools/llvm-as-fuzzer/
|
||||
llvm/tools/llvm-as/CMakeLists.txt
|
||||
llvm/tools/llvm-as-fuzzer/
|
||||
llvm/tools/llvm-bcanalyzer/CMakeLists.txt
|
||||
llvm/tools/llvm-c-test/
|
||||
llvm/tools/llvm-cat/
|
||||
|
|
@ -771,12 +781,12 @@ llvm/tools/llvm-cxxdump/CMakeLists.txt
|
|||
llvm/tools/llvm-cxxfilt/CMakeLists.txt
|
||||
llvm/tools/llvm-cxxmap/CMakeLists.txt
|
||||
llvm/tools/llvm-debuginfo-analyzer/CMakeLists.txt
|
||||
llvm/tools/llvm-debuginfod-find/
|
||||
llvm/tools/llvm-debuginfod/
|
||||
llvm/tools/llvm-debuginfod-find/
|
||||
llvm/tools/llvm-diff/CMakeLists.txt
|
||||
llvm/tools/llvm-diff/lib/CMakeLists.txt
|
||||
llvm/tools/llvm-dis-fuzzer/
|
||||
llvm/tools/llvm-dis/CMakeLists.txt
|
||||
llvm/tools/llvm-dis-fuzzer/
|
||||
llvm/tools/llvm-dlang-demangle-fuzzer/
|
||||
llvm/tools/llvm-driver/
|
||||
llvm/tools/llvm-dwarfdump/CMakeLists.txt
|
||||
|
|
@ -796,9 +806,9 @@ llvm/tools/llvm-link/CMakeLists.txt
|
|||
llvm/tools/llvm-lipo/
|
||||
llvm/tools/llvm-lto/CMakeLists.txt
|
||||
llvm/tools/llvm-lto2/CMakeLists.txt
|
||||
llvm/tools/llvm-mc/CMakeLists.txt
|
||||
llvm/tools/llvm-mc-assemble-fuzzer/
|
||||
llvm/tools/llvm-mc-disassemble-fuzzer/
|
||||
llvm/tools/llvm-mc/CMakeLists.txt
|
||||
llvm/tools/llvm-mca/CMakeLists.txt
|
||||
llvm/tools/llvm-microsoft-demangle-fuzzer/
|
||||
llvm/tools/llvm-ml/
|
||||
|
|
@ -835,8 +845,8 @@ llvm/tools/llvm-yaml-numeric-parser-fuzzer/
|
|||
llvm/tools/llvm-yaml-parser-fuzzer/
|
||||
llvm/tools/lto/
|
||||
llvm/tools/obj2yaml/
|
||||
llvm/tools/opt-viewer/
|
||||
llvm/tools/opt/CMakeLists.txt
|
||||
llvm/tools/opt-viewer/
|
||||
llvm/tools/remarks-shlib/
|
||||
llvm/tools/sancov/
|
||||
llvm/tools/sanstats/
|
||||
|
|
@ -899,7 +909,6 @@ llvm/utils/kate/
|
|||
llvm/utils/lint/
|
||||
llvm/utils/lit/
|
||||
llvm/utils/lldbDataFormatters.py
|
||||
llvm/utils/llvm-compilers-check
|
||||
llvm/utils/llvm-gisel-cov.py
|
||||
llvm/utils/llvm-lit/
|
||||
llvm/utils/llvm-locstats/
|
||||
|
|
@ -945,6 +954,7 @@ llvm/utils/vim/
|
|||
llvm/utils/vscode/
|
||||
llvm/utils/wciia.py
|
||||
llvm/utils/yaml-bench/
|
||||
llvm-libgcc/
|
||||
mlir/
|
||||
openmp/.gitignore
|
||||
openmp/CMakeLists.txt
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
* compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
|
||||
*/
|
||||
#define CINDEX_VERSION_MAJOR 0
|
||||
#define CINDEX_VERSION_MINOR 63
|
||||
#define CINDEX_VERSION_MINOR 64
|
||||
|
||||
#define CINDEX_VERSION_ENCODE(major, minor) (((major)*10000) + ((minor)*1))
|
||||
|
||||
|
|
@ -48,6 +48,10 @@
|
|||
#define CINDEX_VERSION_STRING \
|
||||
CINDEX_VERSION_STRINGIZE(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR)
|
||||
|
||||
#ifndef __has_feature
|
||||
#define __has_feature(feature) 0
|
||||
#endif
|
||||
|
||||
LLVM_CLANG_C_EXTERN_C_BEGIN
|
||||
|
||||
/** \defgroup CINDEX libclang: C Interface to Clang
|
||||
|
|
@ -275,6 +279,22 @@ CINDEX_LINKAGE CXIndex clang_createIndex(int excludeDeclarationsFromPCH,
|
|||
*/
|
||||
CINDEX_LINKAGE void clang_disposeIndex(CXIndex index);
|
||||
|
||||
typedef enum {
|
||||
/**
|
||||
* Use the default value of an option that may depend on the process
|
||||
* environment.
|
||||
*/
|
||||
CXChoice_Default = 0,
|
||||
/**
|
||||
* Enable the option.
|
||||
*/
|
||||
CXChoice_Enabled = 1,
|
||||
/**
|
||||
* Disable the option.
|
||||
*/
|
||||
CXChoice_Disabled = 2
|
||||
} CXChoice;
|
||||
|
||||
typedef enum {
|
||||
/**
|
||||
* Used to indicate that no special CXIndex options are needed.
|
||||
|
|
@ -309,9 +329,131 @@ typedef enum {
|
|||
|
||||
} CXGlobalOptFlags;
|
||||
|
||||
/**
|
||||
* Index initialization options.
|
||||
*
|
||||
* 0 is the default value of each member of this struct except for Size.
|
||||
* Initialize the struct in one of the following three ways to avoid adapting
|
||||
* code each time a new member is added to it:
|
||||
* \code
|
||||
* CXIndexOptions Opts;
|
||||
* memset(&Opts, 0, sizeof(Opts));
|
||||
* Opts.Size = sizeof(CXIndexOptions);
|
||||
* \endcode
|
||||
* or explicitly initialize the first data member and zero-initialize the rest:
|
||||
* \code
|
||||
* CXIndexOptions Opts = { sizeof(CXIndexOptions) };
|
||||
* \endcode
|
||||
* or to prevent the -Wmissing-field-initializers warning for the above version:
|
||||
* \code
|
||||
* CXIndexOptions Opts{};
|
||||
* Opts.Size = sizeof(CXIndexOptions);
|
||||
* \endcode
|
||||
*/
|
||||
typedef struct CXIndexOptions {
|
||||
/**
|
||||
* The size of struct CXIndexOptions used for option versioning.
|
||||
*
|
||||
* Always initialize this member to sizeof(CXIndexOptions), or assign
|
||||
* sizeof(CXIndexOptions) to it right after creating a CXIndexOptions object.
|
||||
*/
|
||||
unsigned Size;
|
||||
/**
|
||||
* A CXChoice enumerator that specifies the indexing priority policy.
|
||||
* \sa CXGlobalOpt_ThreadBackgroundPriorityForIndexing
|
||||
*/
|
||||
unsigned char ThreadBackgroundPriorityForIndexing;
|
||||
/**
|
||||
* A CXChoice enumerator that specifies the editing priority policy.
|
||||
* \sa CXGlobalOpt_ThreadBackgroundPriorityForEditing
|
||||
*/
|
||||
unsigned char ThreadBackgroundPriorityForEditing;
|
||||
/**
|
||||
* \see clang_createIndex()
|
||||
*/
|
||||
unsigned ExcludeDeclarationsFromPCH : 1;
|
||||
/**
|
||||
* \see clang_createIndex()
|
||||
*/
|
||||
unsigned DisplayDiagnostics : 1;
|
||||
/**
|
||||
* Store PCH in memory. If zero, PCH are stored in temporary files.
|
||||
*/
|
||||
unsigned StorePreamblesInMemory : 1;
|
||||
unsigned /*Reserved*/ : 13;
|
||||
|
||||
/**
|
||||
* The path to a directory, in which to store temporary PCH files. If null or
|
||||
* empty, the default system temporary directory is used. These PCH files are
|
||||
* deleted on clean exit but stay on disk if the program crashes or is killed.
|
||||
*
|
||||
* This option is ignored if \a StorePreamblesInMemory is non-zero.
|
||||
*
|
||||
* Libclang does not create the directory at the specified path in the file
|
||||
* system. Therefore it must exist, or storing PCH files will fail.
|
||||
*/
|
||||
const char *PreambleStoragePath;
|
||||
/**
|
||||
* Specifies a path which will contain log files for certain libclang
|
||||
* invocations. A null value implies that libclang invocations are not logged.
|
||||
*/
|
||||
const char *InvocationEmissionPath;
|
||||
} CXIndexOptions;
|
||||
|
||||
/**
|
||||
* Provides a shared context for creating translation units.
|
||||
*
|
||||
* Call this function instead of clang_createIndex() if you need to configure
|
||||
* the additional options in CXIndexOptions.
|
||||
*
|
||||
* \returns The created index or null in case of error, such as an unsupported
|
||||
* value of options->Size.
|
||||
*
|
||||
* For example:
|
||||
* \code
|
||||
* CXIndex createIndex(const char *ApplicationTemporaryPath) {
|
||||
* const int ExcludeDeclarationsFromPCH = 1;
|
||||
* const int DisplayDiagnostics = 1;
|
||||
* CXIndex Idx;
|
||||
* #if CINDEX_VERSION_MINOR >= 64
|
||||
* CXIndexOptions Opts;
|
||||
* memset(&Opts, 0, sizeof(Opts));
|
||||
* Opts.Size = sizeof(CXIndexOptions);
|
||||
* Opts.ThreadBackgroundPriorityForIndexing = 1;
|
||||
* Opts.ExcludeDeclarationsFromPCH = ExcludeDeclarationsFromPCH;
|
||||
* Opts.DisplayDiagnostics = DisplayDiagnostics;
|
||||
* Opts.PreambleStoragePath = ApplicationTemporaryPath;
|
||||
* Idx = clang_createIndexWithOptions(&Opts);
|
||||
* if (Idx)
|
||||
* return Idx;
|
||||
* fprintf(stderr,
|
||||
* "clang_createIndexWithOptions() failed. "
|
||||
* "CINDEX_VERSION_MINOR = %d, sizeof(CXIndexOptions) = %u\n",
|
||||
* CINDEX_VERSION_MINOR, Opts.Size);
|
||||
* #else
|
||||
* (void)ApplicationTemporaryPath;
|
||||
* #endif
|
||||
* Idx = clang_createIndex(ExcludeDeclarationsFromPCH, DisplayDiagnostics);
|
||||
* clang_CXIndex_setGlobalOptions(
|
||||
* Idx, clang_CXIndex_getGlobalOptions(Idx) |
|
||||
* CXGlobalOpt_ThreadBackgroundPriorityForIndexing);
|
||||
* return Idx;
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* \sa clang_createIndex()
|
||||
*/
|
||||
CINDEX_LINKAGE CXIndex
|
||||
clang_createIndexWithOptions(const CXIndexOptions *options);
|
||||
|
||||
/**
|
||||
* Sets general options associated with a CXIndex.
|
||||
*
|
||||
* This function is DEPRECATED. Set
|
||||
* CXIndexOptions::ThreadBackgroundPriorityForIndexing and/or
|
||||
* CXIndexOptions::ThreadBackgroundPriorityForEditing and call
|
||||
* clang_createIndexWithOptions() instead.
|
||||
*
|
||||
* For example:
|
||||
* \code
|
||||
* CXIndex idx = ...;
|
||||
|
|
@ -327,6 +469,9 @@ CINDEX_LINKAGE void clang_CXIndex_setGlobalOptions(CXIndex, unsigned options);
|
|||
/**
|
||||
* Gets the general options associated with a CXIndex.
|
||||
*
|
||||
* This function allows to obtain the final option values used by libclang after
|
||||
* specifying the option policies via CXChoice enumerators.
|
||||
*
|
||||
* \returns A bitmask of options, a bitwise OR of CXGlobalOpt_XXX flags that
|
||||
* are associated with the given CXIndex object.
|
||||
*/
|
||||
|
|
@ -335,6 +480,9 @@ CINDEX_LINKAGE unsigned clang_CXIndex_getGlobalOptions(CXIndex);
|
|||
/**
|
||||
* Sets the invocation emission path option in a CXIndex.
|
||||
*
|
||||
* This function is DEPRECATED. Set CXIndexOptions::InvocationEmissionPath and
|
||||
* call clang_createIndexWithOptions() instead.
|
||||
*
|
||||
* The invocation emission path specifies a path which will contain log
|
||||
* files for certain libclang invocations. A null value (default) implies that
|
||||
* libclang invocations are not logged..
|
||||
|
|
@ -2787,10 +2935,15 @@ enum CXTypeKind {
|
|||
CXType_OCLIntelSubgroupAVCImeResult = 169,
|
||||
CXType_OCLIntelSubgroupAVCRefResult = 170,
|
||||
CXType_OCLIntelSubgroupAVCSicResult = 171,
|
||||
CXType_OCLIntelSubgroupAVCImeResultSingleReferenceStreamout = 172,
|
||||
CXType_OCLIntelSubgroupAVCImeResultDualReferenceStreamout = 173,
|
||||
CXType_OCLIntelSubgroupAVCImeSingleReferenceStreamin = 174,
|
||||
CXType_OCLIntelSubgroupAVCImeDualReferenceStreamin = 175,
|
||||
|
||||
/* Old aliases for AVC OpenCL extension types. */
|
||||
CXType_OCLIntelSubgroupAVCImeResultSingleRefStreamout = 172,
|
||||
CXType_OCLIntelSubgroupAVCImeResultDualRefStreamout = 173,
|
||||
CXType_OCLIntelSubgroupAVCImeSingleRefStreamin = 174,
|
||||
|
||||
CXType_OCLIntelSubgroupAVCImeDualRefStreamin = 175,
|
||||
|
||||
CXType_ExtVector = 176,
|
||||
|
|
@ -2888,9 +3041,25 @@ CINDEX_LINKAGE unsigned long long
|
|||
clang_getEnumConstantDeclUnsignedValue(CXCursor C);
|
||||
|
||||
/**
|
||||
* Retrieve the bit width of a bit field declaration as an integer.
|
||||
* Returns non-zero if the cursor specifies a Record member that is a bit-field.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_Cursor_isBitField(CXCursor C);
|
||||
|
||||
/**
|
||||
* Retrieve the bit width of a bit-field declaration as an integer.
|
||||
*
|
||||
* If a cursor that is not a bit field declaration is passed in, -1 is returned.
|
||||
* If the cursor does not reference a bit-field, or if the bit-field's width
|
||||
* expression cannot be evaluated, -1 is returned.
|
||||
*
|
||||
* For example:
|
||||
* \code
|
||||
* if (clang_Cursor_isBitField(Cursor)) {
|
||||
* int Width = clang_getFieldDeclBitWidth(Cursor);
|
||||
* if (Width != -1) {
|
||||
* // The bit-field width is not value-dependent.
|
||||
* }
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
CINDEX_LINKAGE int clang_getFieldDeclBitWidth(CXCursor C);
|
||||
|
||||
|
|
@ -3519,12 +3688,6 @@ CINDEX_LINKAGE CXType clang_Type_getTemplateArgumentAsType(CXType T,
|
|||
*/
|
||||
CINDEX_LINKAGE enum CXRefQualifierKind clang_Type_getCXXRefQualifier(CXType T);
|
||||
|
||||
/**
|
||||
* Returns non-zero if the cursor specifies a Record member that is a
|
||||
* bitfield.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_Cursor_isBitField(CXCursor C);
|
||||
|
||||
/**
|
||||
* Returns 1 if the base class specified by the cursor with kind
|
||||
* CX_CXXBaseSpecifier is virtual.
|
||||
|
|
@ -3697,8 +3860,6 @@ typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor,
|
|||
CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent,
|
||||
CXCursorVisitor visitor,
|
||||
CXClientData client_data);
|
||||
#ifdef __has_feature
|
||||
#if __has_feature(blocks)
|
||||
/**
|
||||
* Visitor invoked for each cursor found by a traversal.
|
||||
*
|
||||
|
|
@ -3709,8 +3870,12 @@ CINDEX_LINKAGE unsigned clang_visitChildren(CXCursor parent,
|
|||
* The visitor should return one of the \c CXChildVisitResult values
|
||||
* to direct clang_visitChildrenWithBlock().
|
||||
*/
|
||||
#if __has_feature(blocks)
|
||||
typedef enum CXChildVisitResult (^CXCursorVisitorBlock)(CXCursor cursor,
|
||||
CXCursor parent);
|
||||
#else
|
||||
typedef struct _CXChildVisitResult *CXCursorVisitorBlock;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Visits the children of a cursor using the specified block. Behaves
|
||||
|
|
@ -3718,8 +3883,6 @@ typedef enum CXChildVisitResult (^CXCursorVisitorBlock)(CXCursor cursor,
|
|||
*/
|
||||
CINDEX_LINKAGE unsigned
|
||||
clang_visitChildrenWithBlock(CXCursor parent, CXCursorVisitorBlock block);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
|
@ -4343,6 +4506,51 @@ CINDEX_LINKAGE unsigned clang_CXXMethod_isCopyAssignmentOperator(CXCursor C);
|
|||
*/
|
||||
CINDEX_LINKAGE unsigned clang_CXXMethod_isMoveAssignmentOperator(CXCursor C);
|
||||
|
||||
/**
|
||||
* Determines if a C++ constructor or conversion function was declared
|
||||
* explicit, returning 1 if such is the case and 0 otherwise.
|
||||
*
|
||||
* Constructors or conversion functions are declared explicit through
|
||||
* the use of the explicit specifier.
|
||||
*
|
||||
* For example, the following constructor and conversion function are
|
||||
* not explicit as they lack the explicit specifier:
|
||||
*
|
||||
* class Foo {
|
||||
* Foo();
|
||||
* operator int();
|
||||
* };
|
||||
*
|
||||
* While the following constructor and conversion function are
|
||||
* explicit as they are declared with the explicit specifier.
|
||||
*
|
||||
* class Foo {
|
||||
* explicit Foo();
|
||||
* explicit operator int();
|
||||
* };
|
||||
*
|
||||
* This function will return 0 when given a cursor pointing to one of
|
||||
* the former declarations and it will return 1 for a cursor pointing
|
||||
* to the latter declarations.
|
||||
*
|
||||
* The explicit specifier allows the user to specify a
|
||||
* conditional compile-time expression whose value decides
|
||||
* whether the marked element is explicit or not.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* constexpr bool foo(int i) { return i % 2 == 0; }
|
||||
*
|
||||
* class Foo {
|
||||
* explicit(foo(1)) Foo();
|
||||
* explicit(foo(2)) operator int();
|
||||
* }
|
||||
*
|
||||
* This function will return 0 for the constructor and 1 for
|
||||
* the conversion function.
|
||||
*/
|
||||
CINDEX_LINKAGE unsigned clang_CXXMethod_isExplicit(CXCursor C);
|
||||
|
||||
/**
|
||||
* Determine if a C++ record is abstract, i.e. whether a class or struct
|
||||
* has a pure virtual member function.
|
||||
|
|
@ -5675,11 +5883,12 @@ CINDEX_LINKAGE CXResult clang_findReferencesInFile(
|
|||
CINDEX_LINKAGE CXResult clang_findIncludesInFile(
|
||||
CXTranslationUnit TU, CXFile file, CXCursorAndRangeVisitor visitor);
|
||||
|
||||
#ifdef __has_feature
|
||||
#if __has_feature(blocks)
|
||||
|
||||
typedef enum CXVisitorResult (^CXCursorAndRangeVisitorBlock)(CXCursor,
|
||||
CXSourceRange);
|
||||
#else
|
||||
typedef struct _CXCursorAndRangeVisitorBlock *CXCursorAndRangeVisitorBlock;
|
||||
#endif
|
||||
|
||||
CINDEX_LINKAGE
|
||||
CXResult clang_findReferencesInFileWithBlock(CXCursor, CXFile,
|
||||
|
|
@ -5689,9 +5898,6 @@ CINDEX_LINKAGE
|
|||
CXResult clang_findIncludesInFileWithBlock(CXTranslationUnit, CXFile,
|
||||
CXCursorAndRangeVisitorBlock);
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The client's data object that is associated with a CXFile.
|
||||
*/
|
||||
|
|
@ -6304,6 +6510,144 @@ typedef enum CXVisitorResult (*CXFieldVisitor)(CXCursor C,
|
|||
CINDEX_LINKAGE unsigned clang_Type_visitFields(CXType T, CXFieldVisitor visitor,
|
||||
CXClientData client_data);
|
||||
|
||||
/**
|
||||
* Describes the kind of binary operators.
|
||||
*/
|
||||
enum CXBinaryOperatorKind {
|
||||
/** This value describes cursors which are not binary operators. */
|
||||
CXBinaryOperator_Invalid,
|
||||
/** C++ Pointer - to - member operator. */
|
||||
CXBinaryOperator_PtrMemD,
|
||||
/** C++ Pointer - to - member operator. */
|
||||
CXBinaryOperator_PtrMemI,
|
||||
/** Multiplication operator. */
|
||||
CXBinaryOperator_Mul,
|
||||
/** Division operator. */
|
||||
CXBinaryOperator_Div,
|
||||
/** Remainder operator. */
|
||||
CXBinaryOperator_Rem,
|
||||
/** Addition operator. */
|
||||
CXBinaryOperator_Add,
|
||||
/** Subtraction operator. */
|
||||
CXBinaryOperator_Sub,
|
||||
/** Bitwise shift left operator. */
|
||||
CXBinaryOperator_Shl,
|
||||
/** Bitwise shift right operator. */
|
||||
CXBinaryOperator_Shr,
|
||||
/** C++ three-way comparison (spaceship) operator. */
|
||||
CXBinaryOperator_Cmp,
|
||||
/** Less than operator. */
|
||||
CXBinaryOperator_LT,
|
||||
/** Greater than operator. */
|
||||
CXBinaryOperator_GT,
|
||||
/** Less or equal operator. */
|
||||
CXBinaryOperator_LE,
|
||||
/** Greater or equal operator. */
|
||||
CXBinaryOperator_GE,
|
||||
/** Equal operator. */
|
||||
CXBinaryOperator_EQ,
|
||||
/** Not equal operator. */
|
||||
CXBinaryOperator_NE,
|
||||
/** Bitwise AND operator. */
|
||||
CXBinaryOperator_And,
|
||||
/** Bitwise XOR operator. */
|
||||
CXBinaryOperator_Xor,
|
||||
/** Bitwise OR operator. */
|
||||
CXBinaryOperator_Or,
|
||||
/** Logical AND operator. */
|
||||
CXBinaryOperator_LAnd,
|
||||
/** Logical OR operator. */
|
||||
CXBinaryOperator_LOr,
|
||||
/** Assignment operator. */
|
||||
CXBinaryOperator_Assign,
|
||||
/** Multiplication assignment operator. */
|
||||
CXBinaryOperator_MulAssign,
|
||||
/** Division assignment operator. */
|
||||
CXBinaryOperator_DivAssign,
|
||||
/** Remainder assignment operator. */
|
||||
CXBinaryOperator_RemAssign,
|
||||
/** Addition assignment operator. */
|
||||
CXBinaryOperator_AddAssign,
|
||||
/** Subtraction assignment operator. */
|
||||
CXBinaryOperator_SubAssign,
|
||||
/** Bitwise shift left assignment operator. */
|
||||
CXBinaryOperator_ShlAssign,
|
||||
/** Bitwise shift right assignment operator. */
|
||||
CXBinaryOperator_ShrAssign,
|
||||
/** Bitwise AND assignment operator. */
|
||||
CXBinaryOperator_AndAssign,
|
||||
/** Bitwise XOR assignment operator. */
|
||||
CXBinaryOperator_XorAssign,
|
||||
/** Bitwise OR assignment operator. */
|
||||
CXBinaryOperator_OrAssign,
|
||||
/** Comma operator. */
|
||||
CXBinaryOperator_Comma
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the spelling of a given CXBinaryOperatorKind.
|
||||
*/
|
||||
CINDEX_LINKAGE CXString
|
||||
clang_getBinaryOperatorKindSpelling(enum CXBinaryOperatorKind kind);
|
||||
|
||||
/**
|
||||
* Retrieve the binary operator kind of this cursor.
|
||||
*
|
||||
* If this cursor is not a binary operator then returns Invalid.
|
||||
*/
|
||||
CINDEX_LINKAGE enum CXBinaryOperatorKind
|
||||
clang_getCursorBinaryOperatorKind(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* Describes the kind of unary operators.
|
||||
*/
|
||||
enum CXUnaryOperatorKind {
|
||||
/** This value describes cursors which are not unary operators. */
|
||||
CXUnaryOperator_Invalid,
|
||||
/** Postfix increment operator. */
|
||||
CXUnaryOperator_PostInc,
|
||||
/** Postfix decrement operator. */
|
||||
CXUnaryOperator_PostDec,
|
||||
/** Prefix increment operator. */
|
||||
CXUnaryOperator_PreInc,
|
||||
/** Prefix decrement operator. */
|
||||
CXUnaryOperator_PreDec,
|
||||
/** Address of operator. */
|
||||
CXUnaryOperator_AddrOf,
|
||||
/** Dereference operator. */
|
||||
CXUnaryOperator_Deref,
|
||||
/** Plus operator. */
|
||||
CXUnaryOperator_Plus,
|
||||
/** Minus operator. */
|
||||
CXUnaryOperator_Minus,
|
||||
/** Not operator. */
|
||||
CXUnaryOperator_Not,
|
||||
/** LNot operator. */
|
||||
CXUnaryOperator_LNot,
|
||||
/** "__real expr" operator. */
|
||||
CXUnaryOperator_Real,
|
||||
/** "__imag expr" operator. */
|
||||
CXUnaryOperator_Imag,
|
||||
/** __extension__ marker operator. */
|
||||
CXUnaryOperator_Extension,
|
||||
/** C++ co_await operator. */
|
||||
CXUnaryOperator_Coawait
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the spelling of a given CXUnaryOperatorKind.
|
||||
*/
|
||||
CINDEX_LINKAGE CXString
|
||||
clang_getUnaryOperatorKindSpelling(enum CXUnaryOperatorKind kind);
|
||||
|
||||
/**
|
||||
* Retrieve the unary operator kind of this cursor.
|
||||
*
|
||||
* If this cursor is not a unary operator then returns Invalid.
|
||||
*/
|
||||
CINDEX_LINKAGE enum CXUnaryOperatorKind
|
||||
clang_getCursorUnaryOperatorKind(CXCursor cursor);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
module Clang_C {
|
||||
umbrella "."
|
||||
module * { export * }
|
||||
}
|
||||
|
|
@ -267,9 +267,9 @@ private:
|
|||
};
|
||||
struct LV;
|
||||
struct Vec {
|
||||
APValue *Elts;
|
||||
unsigned NumElts;
|
||||
Vec() : Elts(nullptr), NumElts(0) {}
|
||||
APValue *Elts = nullptr;
|
||||
unsigned NumElts = 0;
|
||||
Vec() = default;
|
||||
~Vec() { delete[] Elts; }
|
||||
};
|
||||
struct Arr {
|
||||
|
|
|
|||
|
|
@ -33,12 +33,12 @@ namespace clang {
|
|||
class ASTConsumer {
|
||||
/// Whether this AST consumer also requires information about
|
||||
/// semantic analysis.
|
||||
bool SemaConsumer;
|
||||
bool SemaConsumer = false;
|
||||
|
||||
friend class SemaConsumer;
|
||||
|
||||
public:
|
||||
ASTConsumer() : SemaConsumer(false) { }
|
||||
ASTConsumer() = default;
|
||||
|
||||
virtual ~ASTConsumer() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -447,8 +447,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
};
|
||||
llvm::DenseMap<Module*, PerModuleInitializers*> ModuleInitializers;
|
||||
|
||||
/// For module code-gen cases, this is the top-level module we are building.
|
||||
Module *TopLevelModule = nullptr;
|
||||
/// This is the top-level (C++20) Named module we are building.
|
||||
Module *CurrentCXXNamedModule = nullptr;
|
||||
|
||||
static constexpr unsigned ConstantArrayTypesLog2InitSize = 8;
|
||||
static constexpr unsigned GeneralTypesLog2InitSize = 9;
|
||||
|
|
@ -1051,10 +1051,10 @@ public:
|
|||
ArrayRef<Decl*> getModuleInitializers(Module *M);
|
||||
|
||||
/// Set the (C++20) module we are building.
|
||||
void setModuleForCodeGen(Module *M) { TopLevelModule = M; }
|
||||
void setCurrentNamedModule(Module *M);
|
||||
|
||||
/// Get module under construction, nullptr if this is not a C++20 module.
|
||||
Module *getModuleForCodeGen() const { return TopLevelModule; }
|
||||
Module *getCurrentNamedModule() const { return CurrentCXXNamedModule; }
|
||||
|
||||
TranslationUnitDecl *getTranslationUnitDecl() const {
|
||||
return TUDecl->getMostRecentDecl();
|
||||
|
|
@ -1126,6 +1126,8 @@ public:
|
|||
#define RVV_TYPE(Name, Id, SingletonId) \
|
||||
CanQualType SingletonId;
|
||||
#include "clang/Basic/RISCVVTypes.def"
|
||||
#define WASM_TYPE(Name, Id, SingletonId) CanQualType SingletonId;
|
||||
#include "clang/Basic/WebAssemblyReferenceTypes.def"
|
||||
|
||||
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
|
||||
mutable QualType AutoDeductTy; // Deduction against 'auto'.
|
||||
|
|
@ -1470,9 +1472,15 @@ public:
|
|||
|
||||
/// Return the unique reference to a scalable vector type of the specified
|
||||
/// element type and scalable number of elements.
|
||||
/// For RISC-V, number of fields is also provided when it fetching for
|
||||
/// tuple type.
|
||||
///
|
||||
/// \pre \p EltTy must be a built-in type.
|
||||
QualType getScalableVectorType(QualType EltTy, unsigned NumElts) const;
|
||||
QualType getScalableVectorType(QualType EltTy, unsigned NumElts,
|
||||
unsigned NumFields = 1) const;
|
||||
|
||||
/// Return a WebAssembly externref type.
|
||||
QualType getWebAssemblyExternrefType() const;
|
||||
|
||||
/// Return the unique reference to a vector type of the specified
|
||||
/// element type and size.
|
||||
|
|
@ -1710,6 +1718,10 @@ public:
|
|||
/// C++11 deduction pattern for 'auto &&' type.
|
||||
QualType getAutoRRefDeductType() const;
|
||||
|
||||
/// Remove any type constraints from a template parameter type, for
|
||||
/// equivalence comparison of template parameters.
|
||||
QualType getUnconstrainedType(QualType T) const;
|
||||
|
||||
/// C++17 deduced class template specialization type.
|
||||
QualType getDeducedTemplateSpecializationType(TemplateName Template,
|
||||
QualType DeducedType,
|
||||
|
|
@ -2243,6 +2255,17 @@ public:
|
|||
/// false otherwise.
|
||||
bool areLaxCompatibleSveTypes(QualType FirstType, QualType SecondType);
|
||||
|
||||
/// Return true if the given types are an RISC-V vector builtin type and a
|
||||
/// VectorType that is a fixed-length representation of the RISC-V vector
|
||||
/// builtin type for a specific vector-length.
|
||||
bool areCompatibleRVVTypes(QualType FirstType, QualType SecondType);
|
||||
|
||||
/// Return true if the given vector types are lax-compatible RISC-V vector
|
||||
/// types as defined by -flax-vector-conversions=, which permits implicit
|
||||
/// conversions between vectors with different number of elements and/or
|
||||
/// incompatible element types, false otherwise.
|
||||
bool areLaxCompatibleRVVTypes(QualType FirstType, QualType SecondType);
|
||||
|
||||
/// Return true if the type has been explicitly qualified with ObjC ownership.
|
||||
/// A type may be implicitly qualified with ownership under ObjC ARC, and in
|
||||
/// some cases the compiler treats these differently.
|
||||
|
|
@ -2482,7 +2505,9 @@ public:
|
|||
|
||||
/// Return true if the specified type has unique object representations
|
||||
/// according to (C++17 [meta.unary.prop]p9)
|
||||
bool hasUniqueObjectRepresentations(QualType Ty) const;
|
||||
bool
|
||||
hasUniqueObjectRepresentations(QualType Ty,
|
||||
bool CheckIfTriviallyCopyable = true) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Type Operators
|
||||
|
|
@ -2647,11 +2672,6 @@ public:
|
|||
/// template.
|
||||
bool hasSameTemplateName(const TemplateName &X, const TemplateName &Y) const;
|
||||
|
||||
/// Determine whether two Friend functions are different because constraints
|
||||
/// that refer to an enclosing template, according to [temp.friend] p9.
|
||||
bool FriendsDifferByConstraints(const FunctionDecl *X,
|
||||
const FunctionDecl *Y) const;
|
||||
|
||||
/// Determine whether the two declarations refer to the same entity.
|
||||
bool isSameEntity(const NamedDecl *X, const NamedDecl *Y) const;
|
||||
|
||||
|
|
@ -3042,7 +3062,7 @@ public:
|
|||
}
|
||||
|
||||
GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD) const;
|
||||
GVALinkage GetGVALinkageForVariable(const VarDecl *VD);
|
||||
GVALinkage GetGVALinkageForVariable(const VarDecl *VD) const;
|
||||
|
||||
/// Determines if the decl can be CodeGen'ed or deserialized from PCH
|
||||
/// lazily, only when used; this is only relevant for function or file scoped
|
||||
|
|
@ -3193,7 +3213,6 @@ private:
|
|||
|
||||
public:
|
||||
ObjCEncOptions() : Bits(0) {}
|
||||
ObjCEncOptions(const ObjCEncOptions &RHS) : Bits(RHS.Bits) {}
|
||||
|
||||
#define OPT_LIST(V) \
|
||||
V(ExpandPointedToStructures, 0) \
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@ namespace clang {
|
|||
ArrayRef<intptr_t> QualTypeVals);
|
||||
|
||||
/// Returns a desugared version of the QualType, and marks ShouldAKA as true
|
||||
/// whenever we remove significant sugar from the type.
|
||||
/// whenever we remove significant sugar from the type. Make sure ShouldAKA
|
||||
/// is initialized before passing it in.
|
||||
QualType desugarForDiagnostic(ASTContext &Context, QualType QT,
|
||||
bool &ShouldAKA);
|
||||
} // end namespace clang
|
||||
|
|
|
|||
|
|
@ -258,6 +258,7 @@ class TypeSourceInfo;
|
|||
FoundDeclsTy findDeclsInToCtx(DeclContext *DC, DeclarationName Name);
|
||||
|
||||
void AddToLookupTable(Decl *ToD);
|
||||
llvm::Error ImportAttrs(Decl *ToD, Decl *FromD);
|
||||
|
||||
protected:
|
||||
/// Can be overwritten by subclasses to implement their own import logic.
|
||||
|
|
|
|||
|
|
@ -104,7 +104,8 @@ public:
|
|||
Visit(Comment, Comment);
|
||||
|
||||
// Decls within functions are visited by the body.
|
||||
if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D)) {
|
||||
if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) &&
|
||||
!isa<BlockDecl>(*D)) {
|
||||
if (Traversal != TK_AsIs) {
|
||||
if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
|
||||
auto SK = CTSD->getSpecializationKind();
|
||||
|
|
@ -384,7 +385,8 @@ public:
|
|||
}
|
||||
void VisitAttributedType(const AttributedType *T) {
|
||||
// FIXME: AttrKind
|
||||
Visit(T->getModifiedType());
|
||||
if (T->getModifiedType() != T->getEquivalentType())
|
||||
Visit(T->getModifiedType());
|
||||
}
|
||||
void VisitBTFTagAttributedType(const BTFTagAttributedType *T) {
|
||||
Visit(T->getWrappedType());
|
||||
|
|
@ -731,8 +733,11 @@ public:
|
|||
}
|
||||
|
||||
void VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
|
||||
Visit(E->getControllingExpr());
|
||||
Visit(E->getControllingExpr()->getType()); // FIXME: remove
|
||||
if (E->isExprPredicate()) {
|
||||
Visit(E->getControllingExpr());
|
||||
Visit(E->getControllingExpr()->getType()); // FIXME: remove
|
||||
} else
|
||||
Visit(E->getControllingType()->getType());
|
||||
|
||||
for (const auto Assoc : E->associations()) {
|
||||
Visit(Assoc);
|
||||
|
|
|
|||
|
|
@ -77,10 +77,13 @@ public:
|
|||
/// Returns \c true only for the default \c ASTNodeKind()
|
||||
constexpr bool isNone() const { return KindId == NKI_None; }
|
||||
|
||||
/// Returns \c true if \c this is a base kind of (or same as) \c Other.
|
||||
bool isBaseOf(ASTNodeKind Other) const;
|
||||
|
||||
/// Returns \c true if \c this is a base kind of (or same as) \c Other.
|
||||
/// \param Distance If non-null, used to return the distance between \c this
|
||||
/// and \c Other in the class hierarchy.
|
||||
bool isBaseOf(ASTNodeKind Other, unsigned *Distance = nullptr) const;
|
||||
bool isBaseOf(ASTNodeKind Other, unsigned *Distance) const;
|
||||
|
||||
/// String representation of the kind.
|
||||
StringRef asStringRef() const;
|
||||
|
|
@ -166,6 +169,10 @@ private:
|
|||
/// Use getFromNodeKind<T>() to construct the kind.
|
||||
constexpr ASTNodeKind(NodeKindId KindId) : KindId(KindId) {}
|
||||
|
||||
/// Returns \c true if \c Base is a base kind of (or same as) \c
|
||||
/// Derived.
|
||||
static bool isBaseOf(NodeKindId Base, NodeKindId Derived);
|
||||
|
||||
/// Returns \c true if \c Base is a base kind of (or same as) \c
|
||||
/// Derived.
|
||||
/// \param Distance If non-null, used to return the distance between \c Base
|
||||
|
|
|
|||
|
|
@ -315,7 +315,7 @@ public:
|
|||
/// virtual function; in abstract classes, the final overrider for at
|
||||
/// least one virtual function is a pure virtual function. Due to
|
||||
/// multiple, virtual inheritance, it is possible for a class to have
|
||||
/// more than one final overrider. Athough this is an error (per C++
|
||||
/// more than one final overrider. Although this is an error (per C++
|
||||
/// [class.virtual]p2), it is not considered an error here: the final
|
||||
/// overrider map can represent multiple final overriders for a
|
||||
/// method, and it is up to the client to determine whether they are
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ private:
|
|||
void checkContainerDecl(const BlockCommandComment *Comment);
|
||||
|
||||
/// Resolve parameter names to parameter indexes in function declaration.
|
||||
/// Emit diagnostics about unknown parametrs.
|
||||
/// Emit diagnostics about unknown parameters.
|
||||
void resolveParamCommandIndexes(const FullComment *FC);
|
||||
|
||||
/// \returns \c true if the declaration that this comment is attached to
|
||||
|
|
|
|||
|
|
@ -39,9 +39,8 @@ class NamespaceDecl;
|
|||
/// An enumeration representing the different comparison categories
|
||||
/// types.
|
||||
///
|
||||
/// C++2a [cmp.categories.pre] The types weak_equality, strong_equality,
|
||||
/// partial_ordering, weak_ordering, and strong_ordering are collectively
|
||||
/// termed the comparison category types.
|
||||
/// C++20 [cmp.categories.pre] The types partial_ordering, weak_ordering, and
|
||||
/// strong_ordering are collectively termed the comparison category types.
|
||||
enum class ComparisonCategoryType : unsigned char {
|
||||
PartialOrdering,
|
||||
WeakOrdering,
|
||||
|
|
|
|||
|
|
@ -395,9 +395,7 @@ public:
|
|||
|
||||
/// Get the linkage from a semantic point of view. Entities in
|
||||
/// anonymous namespaces are external (in c++98).
|
||||
Linkage getFormalLinkage() const {
|
||||
return clang::getFormalLinkage(getLinkageInternal());
|
||||
}
|
||||
Linkage getFormalLinkage() const;
|
||||
|
||||
/// True if this decl has external linkage.
|
||||
bool hasExternalFormalLinkage() const {
|
||||
|
|
@ -902,7 +900,7 @@ struct EvaluatedStmt {
|
|||
bool HasICEInit : 1;
|
||||
bool CheckedForICEInit : 1;
|
||||
|
||||
Stmt *Value;
|
||||
LazyDeclStmtPtr Value;
|
||||
APValue Evaluated;
|
||||
|
||||
EvaluatedStmt()
|
||||
|
|
@ -1360,12 +1358,15 @@ public:
|
|||
EvaluatedStmt *getEvaluatedStmt() const;
|
||||
|
||||
/// Attempt to evaluate the value of the initializer attached to this
|
||||
/// declaration, and produce notes explaining why it cannot be evaluated or is
|
||||
/// not a constant expression. Returns a pointer to the value if evaluation
|
||||
/// succeeded, 0 otherwise.
|
||||
/// declaration, and produce notes explaining why it cannot be evaluated.
|
||||
/// Returns a pointer to the value if evaluation succeeded, 0 otherwise.
|
||||
APValue *evaluateValue() const;
|
||||
APValue *evaluateValue(SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
|
||||
|
||||
private:
|
||||
APValue *evaluateValueImpl(SmallVectorImpl<PartialDiagnosticAt> &Notes,
|
||||
bool IsConstantInitialization) const;
|
||||
|
||||
public:
|
||||
/// Return the already-evaluated value of this variable's
|
||||
/// initializer, or NULL if the value is not yet known. Returns pointer
|
||||
/// to untyped APValue if the value could not be evaluated.
|
||||
|
|
@ -2167,7 +2168,7 @@ public:
|
|||
/// declaration to the declaration that is a definition (if there is one).
|
||||
///
|
||||
/// \param CheckForPendingFriendDefinition If \c true, also check for friend
|
||||
/// declarations that were instantiataed from function definitions.
|
||||
/// declarations that were instantiated from function definitions.
|
||||
/// Such a declaration behaves as if it is a definition for the
|
||||
/// purpose of redefinition checking, but isn't actually a "real"
|
||||
/// definition until its body is instantiated.
|
||||
|
|
@ -2377,6 +2378,21 @@ public:
|
|||
return getConstexprKind() == ConstexprSpecKind::Consteval;
|
||||
}
|
||||
|
||||
void setBodyContainsImmediateEscalatingExpressions(bool Set) {
|
||||
FunctionDeclBits.BodyContainsImmediateEscalatingExpression = Set;
|
||||
}
|
||||
|
||||
bool BodyContainsImmediateEscalatingExpressions() const {
|
||||
return FunctionDeclBits.BodyContainsImmediateEscalatingExpression;
|
||||
}
|
||||
|
||||
bool isImmediateEscalating() const;
|
||||
|
||||
// The function is a C++ immediate function.
|
||||
// This can be either a consteval function, or an immediate escalating
|
||||
// function containing an immediate escalating expression.
|
||||
bool isImmediateFunction() const;
|
||||
|
||||
/// Whether the instantiation of this function is pending.
|
||||
/// This bit is set when the decision to instantiate this function is made
|
||||
/// and unset if and when the function body is created. That leaves out
|
||||
|
|
@ -2536,6 +2552,10 @@ public:
|
|||
->FunctionDeclBits.FriendConstraintRefersToEnclosingTemplate;
|
||||
}
|
||||
|
||||
/// Determine whether a function is a friend function that cannot be
|
||||
/// redeclared outside of its class, per C++ [temp.friend]p9.
|
||||
bool isMemberLikeConstrainedFriend() const;
|
||||
|
||||
/// Gets the kind of multiversioning attribute this declaration has. Note that
|
||||
/// this can return a value even if the function is not multiversion, such as
|
||||
/// the case of 'target'.
|
||||
|
|
@ -2938,11 +2958,7 @@ public:
|
|||
|
||||
/// Represents a member of a struct/union/class.
|
||||
class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
|
||||
unsigned BitField : 1;
|
||||
unsigned Mutable : 1;
|
||||
mutable unsigned CachedFieldIndex : 30;
|
||||
|
||||
/// The kinds of value we can store in InitializerOrBitWidth.
|
||||
/// The kinds of value we can store in StorageKind.
|
||||
///
|
||||
/// Note that this is compatible with InClassInitStyle except for
|
||||
/// ISK_CapturedVLAType.
|
||||
|
|
@ -2965,10 +2981,15 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
|
|||
ISK_CapturedVLAType,
|
||||
};
|
||||
|
||||
unsigned BitField : 1;
|
||||
unsigned Mutable : 1;
|
||||
unsigned StorageKind : 2;
|
||||
mutable unsigned CachedFieldIndex : 28;
|
||||
|
||||
/// If this is a bitfield with a default member initializer, this
|
||||
/// structure is used to represent the two expressions.
|
||||
struct InitAndBitWidth {
|
||||
Expr *Init;
|
||||
struct InitAndBitWidthStorage {
|
||||
LazyDeclStmtPtr Init;
|
||||
Expr *BitWidth;
|
||||
};
|
||||
|
||||
|
|
@ -2981,16 +3002,25 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
|
|||
/// and attached.
|
||||
// FIXME: Tail-allocate this to reduce the size of FieldDecl in the
|
||||
// overwhelmingly common case that we have none of these things.
|
||||
llvm::PointerIntPair<void *, 2, InitStorageKind> InitStorage;
|
||||
union {
|
||||
// Active member if ISK is not ISK_CapturedVLAType and BitField is false.
|
||||
LazyDeclStmtPtr Init;
|
||||
// Active member if ISK is ISK_NoInit and BitField is true.
|
||||
Expr *BitWidth;
|
||||
// Active member if ISK is ISK_InClass*Init and BitField is true.
|
||||
InitAndBitWidthStorage *InitAndBitWidth;
|
||||
// Active member if ISK is ISK_CapturedVLAType.
|
||||
const VariableArrayType *CapturedVLAType;
|
||||
};
|
||||
|
||||
protected:
|
||||
FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id,
|
||||
QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
|
||||
SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
|
||||
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
|
||||
InClassInitStyle InitStyle)
|
||||
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc),
|
||||
BitField(false), Mutable(Mutable), CachedFieldIndex(0),
|
||||
InitStorage(nullptr, (InitStorageKind) InitStyle) {
|
||||
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), BitField(false),
|
||||
Mutable(Mutable), StorageKind((InitStorageKind)InitStyle),
|
||||
CachedFieldIndex(0), Init() {
|
||||
if (BW)
|
||||
setBitWidth(BW);
|
||||
}
|
||||
|
|
@ -3029,10 +3059,7 @@ public:
|
|||
Expr *getBitWidth() const {
|
||||
if (!BitField)
|
||||
return nullptr;
|
||||
void *Ptr = InitStorage.getPointer();
|
||||
if (getInClassInitStyle())
|
||||
return static_cast<InitAndBitWidth*>(Ptr)->BitWidth;
|
||||
return static_cast<Expr*>(Ptr);
|
||||
return hasInClassInitializer() ? InitAndBitWidth->BitWidth : BitWidth;
|
||||
}
|
||||
|
||||
unsigned getBitWidthValue(const ASTContext &Ctx) const;
|
||||
|
|
@ -3043,11 +3070,11 @@ public:
|
|||
assert(!hasCapturedVLAType() && !BitField &&
|
||||
"bit width or captured type already set");
|
||||
assert(Width && "no bit width specified");
|
||||
InitStorage.setPointer(
|
||||
InitStorage.getInt()
|
||||
? new (getASTContext())
|
||||
InitAndBitWidth{getInClassInitializer(), Width}
|
||||
: static_cast<void*>(Width));
|
||||
if (hasInClassInitializer())
|
||||
InitAndBitWidth =
|
||||
new (getASTContext()) InitAndBitWidthStorage{Init, Width};
|
||||
else
|
||||
BitWidth = Width;
|
||||
BitField = true;
|
||||
}
|
||||
|
||||
|
|
@ -3055,7 +3082,11 @@ public:
|
|||
// Note: used by some clients (i.e., do not remove it).
|
||||
void removeBitWidth() {
|
||||
assert(isBitField() && "no bitfield width to remove");
|
||||
InitStorage.setPointer(getInClassInitializer());
|
||||
if (hasInClassInitializer()) {
|
||||
// Read the old initializer before we change the active union member.
|
||||
auto ExistingInit = InitAndBitWidth->Init;
|
||||
Init = ExistingInit;
|
||||
}
|
||||
BitField = false;
|
||||
}
|
||||
|
||||
|
|
@ -3069,11 +3100,14 @@ public:
|
|||
/// [[no_unique_address]] attribute.
|
||||
bool isZeroSize(const ASTContext &Ctx) const;
|
||||
|
||||
/// Determine if this field is of potentially-overlapping class type, that
|
||||
/// is, subobject with the [[no_unique_address]] attribute
|
||||
bool isPotentiallyOverlapping() const;
|
||||
|
||||
/// Get the kind of (C++11) default member initializer that this field has.
|
||||
InClassInitStyle getInClassInitStyle() const {
|
||||
InitStorageKind storageKind = InitStorage.getInt();
|
||||
return (storageKind == ISK_CapturedVLAType
|
||||
? ICIS_NoInit : (InClassInitStyle) storageKind);
|
||||
return (StorageKind == ISK_CapturedVLAType ? ICIS_NoInit
|
||||
: (InClassInitStyle)StorageKind);
|
||||
}
|
||||
|
||||
/// Determine whether this member has a C++11 default member initializer.
|
||||
|
|
@ -3081,44 +3115,44 @@ public:
|
|||
return getInClassInitStyle() != ICIS_NoInit;
|
||||
}
|
||||
|
||||
/// Determine whether getInClassInitializer() would return a non-null pointer
|
||||
/// without deserializing the initializer.
|
||||
bool hasNonNullInClassInitializer() const {
|
||||
return hasInClassInitializer() && (BitField ? InitAndBitWidth->Init : Init);
|
||||
}
|
||||
|
||||
/// Get the C++11 default member initializer for this member, or null if one
|
||||
/// has not been set. If a valid declaration has a default member initializer,
|
||||
/// but this returns null, then we have not parsed and attached it yet.
|
||||
Expr *getInClassInitializer() const {
|
||||
if (!hasInClassInitializer())
|
||||
return nullptr;
|
||||
void *Ptr = InitStorage.getPointer();
|
||||
if (BitField)
|
||||
return static_cast<InitAndBitWidth*>(Ptr)->Init;
|
||||
return static_cast<Expr*>(Ptr);
|
||||
}
|
||||
Expr *getInClassInitializer() const;
|
||||
|
||||
/// Set the C++11 in-class initializer for this member.
|
||||
void setInClassInitializer(Expr *Init) {
|
||||
assert(hasInClassInitializer() && !getInClassInitializer());
|
||||
if (BitField)
|
||||
static_cast<InitAndBitWidth*>(InitStorage.getPointer())->Init = Init;
|
||||
else
|
||||
InitStorage.setPointer(Init);
|
||||
}
|
||||
void setInClassInitializer(Expr *NewInit);
|
||||
|
||||
private:
|
||||
void setLazyInClassInitializer(LazyDeclStmtPtr NewInit);
|
||||
|
||||
public:
|
||||
/// Remove the C++11 in-class initializer from this member.
|
||||
void removeInClassInitializer() {
|
||||
assert(hasInClassInitializer() && "no initializer to remove");
|
||||
InitStorage.setPointerAndInt(getBitWidth(), ISK_NoInit);
|
||||
StorageKind = ISK_NoInit;
|
||||
if (BitField) {
|
||||
// Read the bit width before we change the active union member.
|
||||
Expr *ExistingBitWidth = InitAndBitWidth->BitWidth;
|
||||
BitWidth = ExistingBitWidth;
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine whether this member captures the variable length array
|
||||
/// type.
|
||||
bool hasCapturedVLAType() const {
|
||||
return InitStorage.getInt() == ISK_CapturedVLAType;
|
||||
return StorageKind == ISK_CapturedVLAType;
|
||||
}
|
||||
|
||||
/// Get the captured variable length array type.
|
||||
const VariableArrayType *getCapturedVLAType() const {
|
||||
return hasCapturedVLAType() ? static_cast<const VariableArrayType *>(
|
||||
InitStorage.getPointer())
|
||||
: nullptr;
|
||||
return hasCapturedVLAType() ? CapturedVLAType : nullptr;
|
||||
}
|
||||
|
||||
/// Set the captured variable length array type for this field.
|
||||
|
|
@ -3691,6 +3725,7 @@ public:
|
|||
return getExtInfo()->TemplParamLists[i];
|
||||
}
|
||||
|
||||
using TypeDecl::printName;
|
||||
void printName(raw_ostream &OS, const PrintingPolicy &Policy) const override;
|
||||
|
||||
void setTemplateParameterListsInfo(ASTContext &Context,
|
||||
|
|
@ -4305,6 +4340,7 @@ class TopLevelStmtDecl : public Decl {
|
|||
friend class ASTDeclWriter;
|
||||
|
||||
Stmt *Statement = nullptr;
|
||||
bool IsSemiMissing = false;
|
||||
|
||||
TopLevelStmtDecl(DeclContext *DC, SourceLocation L, Stmt *S)
|
||||
: Decl(TopLevelStmt, DC, L), Statement(S) {}
|
||||
|
|
@ -4318,6 +4354,12 @@ public:
|
|||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
Stmt *getStmt() { return Statement; }
|
||||
const Stmt *getStmt() const { return Statement; }
|
||||
void setStmt(Stmt *S) {
|
||||
assert(IsSemiMissing && "Operation supported for printing values only!");
|
||||
Statement = S;
|
||||
}
|
||||
bool isSemiMissing() const { return IsSemiMissing; }
|
||||
void setSemiMissing(bool Missing = true) { IsSemiMissing = Missing; }
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
static bool classofKind(Kind K) { return K == TopLevelStmt; }
|
||||
|
|
@ -4704,7 +4746,7 @@ public:
|
|||
static bool classofKind(Kind K) { return K == Import; }
|
||||
};
|
||||
|
||||
/// Represents a C++ Modules TS module export declaration.
|
||||
/// Represents a standard C++ module export declaration.
|
||||
///
|
||||
/// For example:
|
||||
/// \code
|
||||
|
|
|
|||
|
|
@ -644,6 +644,9 @@ public:
|
|||
return getModuleOwnershipKind() > ModuleOwnershipKind::VisibleWhenImported;
|
||||
}
|
||||
|
||||
/// Whether this declaration comes from another module unit.
|
||||
bool isInAnotherModuleUnit() const;
|
||||
|
||||
/// FIXME: Implement discarding declarations actually in global module
|
||||
/// fragment. See [module.global.frag]p3,4 for details.
|
||||
bool isDiscardedInGlobalModuleFragment() const { return false; }
|
||||
|
|
@ -810,7 +813,7 @@ public:
|
|||
}
|
||||
|
||||
/// Get the module that owns this declaration for linkage purposes.
|
||||
/// There only ever is such a module under the C++ Modules TS.
|
||||
/// There only ever is such a standard C++ module.
|
||||
///
|
||||
/// \param IgnoreLinkage Ignore the linkage of the entity; assume that
|
||||
/// all declarations in a global module fragment are unowned.
|
||||
|
|
@ -1172,6 +1175,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/// Clears the namespace of this declaration.
|
||||
///
|
||||
/// This is useful if we want this declaration to be available for
|
||||
/// redeclaration lookup but otherwise hidden for ordinary name lookups.
|
||||
void clearIdentifierNamespace() { IdentifierNamespace = 0; }
|
||||
|
||||
enum FriendObjectKind {
|
||||
FOK_None, ///< Not a friend object.
|
||||
FOK_Declared, ///< A friend of a previously-declared entity.
|
||||
|
|
@ -1227,6 +1236,10 @@ public:
|
|||
/// have a FunctionType.
|
||||
const FunctionType *getFunctionType(bool BlocksToo = true) const;
|
||||
|
||||
// Looks through the Decl's underlying type to determine if it's a
|
||||
// function pointer type.
|
||||
bool isFunctionPointerType() const;
|
||||
|
||||
private:
|
||||
void setAttrsImpl(const AttrVec& Attrs, ASTContext &Ctx);
|
||||
void setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC,
|
||||
|
|
@ -1369,6 +1382,13 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// Only used by CXXDeductionGuideDecl.
|
||||
enum class DeductionCandidate : unsigned char {
|
||||
Normal,
|
||||
Copy,
|
||||
Aggregate,
|
||||
};
|
||||
|
||||
/// DeclContext - This is used only as base class of specific decl types that
|
||||
/// can act as declaration contexts. These decls are (only the top classes
|
||||
/// that directly derive from DeclContext are mentioned, not their subclasses):
|
||||
|
|
@ -1389,6 +1409,8 @@ public:
|
|||
class DeclContext {
|
||||
/// For makeDeclVisibleInContextImpl
|
||||
friend class ASTDeclReader;
|
||||
/// For checking the new bits in the Serialization part.
|
||||
friend class ASTDeclWriter;
|
||||
/// For reconcileExternalVisibleStorage, CreateStoredDeclsMap,
|
||||
/// hasNeedToReconcileExternalVisibleStorage
|
||||
friend class ExternalASTSource;
|
||||
|
|
@ -1595,7 +1617,7 @@ class DeclContext {
|
|||
uint64_t : NumDeclContextBits;
|
||||
|
||||
/// Kind of initializer,
|
||||
/// function call or omp_priv<init_expr> initializtion.
|
||||
/// function call or omp_priv<init_expr> initialization.
|
||||
uint64_t InitializerKind : 2;
|
||||
};
|
||||
|
||||
|
|
@ -1605,10 +1627,10 @@ class DeclContext {
|
|||
/// Stores the bits used by FunctionDecl.
|
||||
/// If modified NumFunctionDeclBits and the accessor
|
||||
/// methods in FunctionDecl and CXXDeductionGuideDecl
|
||||
/// (for IsCopyDeductionCandidate) should be updated appropriately.
|
||||
/// (for DeductionCandidateKind) should be updated appropriately.
|
||||
class FunctionDeclBitfields {
|
||||
friend class FunctionDecl;
|
||||
/// For IsCopyDeductionCandidate
|
||||
/// For DeductionCandidateKind
|
||||
friend class CXXDeductionGuideDecl;
|
||||
/// For the bits in DeclContextBitfields.
|
||||
uint64_t : NumDeclContextBits;
|
||||
|
|
@ -1644,6 +1666,8 @@ class DeclContext {
|
|||
|
||||
/// Kind of contexpr specifier as defined by ConstexprSpecKind.
|
||||
uint64_t ConstexprKind : 2;
|
||||
uint64_t BodyContainsImmediateEscalatingExpression : 1;
|
||||
|
||||
uint64_t InstantiationIsPending : 1;
|
||||
|
||||
/// Indicates if the function uses __try.
|
||||
|
|
@ -1661,10 +1685,10 @@ class DeclContext {
|
|||
/// function using attribute 'target'.
|
||||
uint64_t IsMultiVersion : 1;
|
||||
|
||||
/// [C++17] Only used by CXXDeductionGuideDecl. Indicates that
|
||||
/// the Deduction Guide is the implicitly generated 'copy
|
||||
/// deduction candidate' (is used during overload resolution).
|
||||
uint64_t IsCopyDeductionCandidate : 1;
|
||||
/// Only used by CXXDeductionGuideDecl. Indicates the kind
|
||||
/// of the Deduction Guide that is implicitly generated
|
||||
/// (used during overload resolution).
|
||||
uint64_t DeductionCandidateKind : 2;
|
||||
|
||||
/// Store the ODRHash after first calculation.
|
||||
uint64_t HasODRHash : 1;
|
||||
|
|
@ -1678,7 +1702,7 @@ class DeclContext {
|
|||
};
|
||||
|
||||
/// Number of non-inherited bits in FunctionDeclBitfields.
|
||||
enum { NumFunctionDeclBits = 29 };
|
||||
enum { NumFunctionDeclBits = 30 };
|
||||
|
||||
/// Stores the bits used by CXXConstructorDecl. If modified
|
||||
/// NumCXXConstructorDeclBits and the accessor
|
||||
|
|
@ -1690,12 +1714,12 @@ class DeclContext {
|
|||
/// For the bits in FunctionDeclBitfields.
|
||||
uint64_t : NumFunctionDeclBits;
|
||||
|
||||
/// 22 bits to fit in the remaining available space.
|
||||
/// 21 bits to fit in the remaining available space.
|
||||
/// Note that this makes CXXConstructorDeclBitfields take
|
||||
/// exactly 64 bits and thus the width of NumCtorInitializers
|
||||
/// will need to be shrunk if some bit is added to NumDeclContextBitfields,
|
||||
/// NumFunctionDeclBitfields or CXXConstructorDeclBitfields.
|
||||
uint64_t NumCtorInitializers : 19;
|
||||
uint64_t NumCtorInitializers : 18;
|
||||
uint64_t IsInheritingConstructor : 1;
|
||||
|
||||
/// Whether this constructor has a trail-allocated explicit specifier.
|
||||
|
|
@ -2525,10 +2549,8 @@ public:
|
|||
D == LastDecl);
|
||||
}
|
||||
|
||||
bool setUseQualifiedLookup(bool use = true) const {
|
||||
bool old_value = DeclContextBits.UseQualifiedLookup;
|
||||
void setUseQualifiedLookup(bool use = true) const {
|
||||
DeclContextBits.UseQualifiedLookup = use;
|
||||
return old_value;
|
||||
}
|
||||
|
||||
bool shouldUseQualifiedLookup() const {
|
||||
|
|
@ -2589,14 +2611,6 @@ private:
|
|||
void reconcileExternalVisibleStorage() const;
|
||||
bool LoadLexicalDeclsFromExternalStorage() const;
|
||||
|
||||
/// Makes a declaration visible within this context, but
|
||||
/// suppresses searches for external declarations with the same
|
||||
/// name.
|
||||
///
|
||||
/// Analogous to makeDeclVisibleInContext, but for the exclusive
|
||||
/// use of addDeclInternal().
|
||||
void makeDeclVisibleInContextInternal(NamedDecl *D);
|
||||
|
||||
StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
|
||||
|
||||
void loadLazyLocalLexicalLookups();
|
||||
|
|
|
|||
|
|
@ -395,7 +395,7 @@ private:
|
|||
unsigned NumCaptures : 15;
|
||||
|
||||
/// The number of explicit captures in this lambda.
|
||||
unsigned NumExplicitCaptures : 13;
|
||||
unsigned NumExplicitCaptures : 12;
|
||||
|
||||
/// Has known `internal` linkage.
|
||||
unsigned HasKnownInternalLinkage : 1;
|
||||
|
|
@ -404,6 +404,10 @@ private:
|
|||
/// mangling in the Itanium C++ ABI.
|
||||
unsigned ManglingNumber : 31;
|
||||
|
||||
/// The index of this lambda within its context declaration. This is not in
|
||||
/// general the same as the mangling number.
|
||||
unsigned IndexInContext;
|
||||
|
||||
/// The declaration that provides context for this lambda, if the
|
||||
/// actual DeclContext does not suffice. This is used for lambdas that
|
||||
/// occur within default arguments of function parameters within the class
|
||||
|
|
@ -424,7 +428,7 @@ private:
|
|||
: DefinitionData(D), DependencyKind(DK), IsGenericLambda(IsGeneric),
|
||||
CaptureDefault(CaptureDefault), NumCaptures(0),
|
||||
NumExplicitCaptures(0), HasKnownInternalLinkage(0), ManglingNumber(0),
|
||||
MethodTyInfo(Info) {
|
||||
IndexInContext(0), MethodTyInfo(Info) {
|
||||
IsLambda = true;
|
||||
|
||||
// C++1z [expr.prim.lambda]p4:
|
||||
|
|
@ -1092,6 +1096,11 @@ public:
|
|||
|
||||
unsigned capture_size() const { return getLambdaData().NumCaptures; }
|
||||
|
||||
const LambdaCapture *getCapture(unsigned I) const {
|
||||
assert(isLambda() && I < capture_size() && "invalid index for capture");
|
||||
return captures_begin() + I;
|
||||
}
|
||||
|
||||
using conversion_iterator = UnresolvedSetIterator;
|
||||
|
||||
conversion_iterator conversion_begin() const {
|
||||
|
|
@ -1160,6 +1169,10 @@ public:
|
|||
///
|
||||
/// \note This does NOT include a check for union-ness.
|
||||
bool isEmpty() const { return data().Empty; }
|
||||
/// Marks this record as empty. This is used by DWARFASTParserClang
|
||||
/// when parsing records with empty fields having [[no_unique_address]]
|
||||
/// attribute
|
||||
void markEmpty() { data().Empty = true; }
|
||||
|
||||
void setInitMethod(bool Val) { data().HasInitMethod = Val; }
|
||||
bool hasInitMethod() const { return data().HasInitMethod; }
|
||||
|
|
@ -1437,7 +1450,7 @@ public:
|
|||
}
|
||||
|
||||
/// Notify the class that this destructor is now selected.
|
||||
///
|
||||
///
|
||||
/// Important properties of the class depend on destructor properties. Since
|
||||
/// C++20, it is possible to have multiple destructor declarations in a class
|
||||
/// out of which one will be selected at the end.
|
||||
|
|
@ -1763,18 +1776,31 @@ public:
|
|||
/// the declaration context suffices.
|
||||
Decl *getLambdaContextDecl() const;
|
||||
|
||||
/// Set the mangling number and context declaration for a lambda
|
||||
/// class.
|
||||
void setLambdaMangling(unsigned ManglingNumber, Decl *ContextDecl,
|
||||
bool HasKnownInternalLinkage = false) {
|
||||
/// Retrieve the index of this lambda within the context declaration returned
|
||||
/// by getLambdaContextDecl().
|
||||
unsigned getLambdaIndexInContext() const {
|
||||
assert(isLambda() && "Not a lambda closure type!");
|
||||
getLambdaData().ManglingNumber = ManglingNumber;
|
||||
getLambdaData().ContextDecl = ContextDecl;
|
||||
getLambdaData().HasKnownInternalLinkage = HasKnownInternalLinkage;
|
||||
return getLambdaData().IndexInContext;
|
||||
}
|
||||
|
||||
/// Set the device side mangling number.
|
||||
void setDeviceLambdaManglingNumber(unsigned Num) const;
|
||||
/// Information about how a lambda is numbered within its context.
|
||||
struct LambdaNumbering {
|
||||
Decl *ContextDecl = nullptr;
|
||||
unsigned IndexInContext = 0;
|
||||
unsigned ManglingNumber = 0;
|
||||
unsigned DeviceManglingNumber = 0;
|
||||
bool HasKnownInternalLinkage = false;
|
||||
};
|
||||
|
||||
/// Set the mangling numbers and context declaration for a lambda class.
|
||||
void setLambdaNumbering(LambdaNumbering Numbering);
|
||||
|
||||
// Get the mangling numbers and context declaration for a lambda class.
|
||||
LambdaNumbering getLambdaNumbering() const {
|
||||
return {getLambdaContextDecl(), getLambdaIndexInContext(),
|
||||
getLambdaManglingNumber(), getDeviceLambdaManglingNumber(),
|
||||
hasKnownLambdaInternalLinkage()};
|
||||
}
|
||||
|
||||
/// Retrieve the device side mangling number.
|
||||
unsigned getDeviceLambdaManglingNumber() const;
|
||||
|
|
@ -1826,6 +1852,20 @@ public:
|
|||
return getLambdaData().MethodTyInfo;
|
||||
}
|
||||
|
||||
void setLambdaTypeInfo(TypeSourceInfo *TS) {
|
||||
assert(DefinitionData && DefinitionData->IsLambda &&
|
||||
"setting lambda property of non-lambda class");
|
||||
auto &DL = static_cast<LambdaDefinitionData &>(*DefinitionData);
|
||||
DL.MethodTyInfo = TS;
|
||||
}
|
||||
|
||||
void setLambdaIsGeneric(bool IsGeneric) {
|
||||
assert(DefinitionData && DefinitionData->IsLambda &&
|
||||
"setting lambda property of non-lambda class");
|
||||
auto &DL = static_cast<LambdaDefinitionData &>(*DefinitionData);
|
||||
DL.IsGenericLambda = IsGeneric;
|
||||
}
|
||||
|
||||
// Determine whether this type is an Interface Like type for
|
||||
// __interface inheritance purposes.
|
||||
bool isInterfaceLike() const;
|
||||
|
|
@ -1902,13 +1942,13 @@ private:
|
|||
ExplicitSpecifier ES,
|
||||
const DeclarationNameInfo &NameInfo, QualType T,
|
||||
TypeSourceInfo *TInfo, SourceLocation EndLocation,
|
||||
CXXConstructorDecl *Ctor)
|
||||
CXXConstructorDecl *Ctor, DeductionCandidate Kind)
|
||||
: FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
|
||||
SC_None, false, false, ConstexprSpecKind::Unspecified),
|
||||
Ctor(Ctor), ExplicitSpec(ES) {
|
||||
if (EndLocation.isValid())
|
||||
setRangeEnd(EndLocation);
|
||||
setIsCopyDeductionCandidate(false);
|
||||
setDeductionCandidateKind(Kind);
|
||||
}
|
||||
|
||||
CXXConstructorDecl *Ctor;
|
||||
|
|
@ -1923,7 +1963,8 @@ public:
|
|||
Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
|
||||
ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
|
||||
TypeSourceInfo *TInfo, SourceLocation EndLocation,
|
||||
CXXConstructorDecl *Ctor = nullptr);
|
||||
CXXConstructorDecl *Ctor = nullptr,
|
||||
DeductionCandidate Kind = DeductionCandidate::Normal);
|
||||
|
||||
static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
|
|
@ -1940,16 +1981,15 @@ public:
|
|||
|
||||
/// Get the constructor from which this deduction guide was generated, if
|
||||
/// this is an implicit deduction guide.
|
||||
CXXConstructorDecl *getCorrespondingConstructor() const {
|
||||
return Ctor;
|
||||
CXXConstructorDecl *getCorrespondingConstructor() const { return Ctor; }
|
||||
|
||||
void setDeductionCandidateKind(DeductionCandidate K) {
|
||||
FunctionDeclBits.DeductionCandidateKind = static_cast<unsigned char>(K);
|
||||
}
|
||||
|
||||
void setIsCopyDeductionCandidate(bool isCDC = true) {
|
||||
FunctionDeclBits.IsCopyDeductionCandidate = isCDC;
|
||||
}
|
||||
|
||||
bool isCopyDeductionCandidate() const {
|
||||
return FunctionDeclBits.IsCopyDeductionCandidate;
|
||||
DeductionCandidate getDeductionCandidateKind() const {
|
||||
return static_cast<DeductionCandidate>(
|
||||
FunctionDeclBits.DeductionCandidateKind);
|
||||
}
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
|
|
@ -3970,12 +4010,12 @@ public:
|
|||
/// Represents a C++11 static_assert declaration.
|
||||
class StaticAssertDecl : public Decl {
|
||||
llvm::PointerIntPair<Expr *, 1, bool> AssertExprAndFailed;
|
||||
StringLiteral *Message;
|
||||
Expr *Message;
|
||||
SourceLocation RParenLoc;
|
||||
|
||||
StaticAssertDecl(DeclContext *DC, SourceLocation StaticAssertLoc,
|
||||
Expr *AssertExpr, StringLiteral *Message,
|
||||
SourceLocation RParenLoc, bool Failed)
|
||||
Expr *AssertExpr, Expr *Message, SourceLocation RParenLoc,
|
||||
bool Failed)
|
||||
: Decl(StaticAssert, DC, StaticAssertLoc),
|
||||
AssertExprAndFailed(AssertExpr, Failed), Message(Message),
|
||||
RParenLoc(RParenLoc) {}
|
||||
|
|
@ -3987,15 +4027,15 @@ public:
|
|||
|
||||
static StaticAssertDecl *Create(ASTContext &C, DeclContext *DC,
|
||||
SourceLocation StaticAssertLoc,
|
||||
Expr *AssertExpr, StringLiteral *Message,
|
||||
Expr *AssertExpr, Expr *Message,
|
||||
SourceLocation RParenLoc, bool Failed);
|
||||
static StaticAssertDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||
|
||||
Expr *getAssertExpr() { return AssertExprAndFailed.getPointer(); }
|
||||
const Expr *getAssertExpr() const { return AssertExprAndFailed.getPointer(); }
|
||||
|
||||
StringLiteral *getMessage() { return Message; }
|
||||
const StringLiteral *getMessage() const { return Message; }
|
||||
Expr *getMessage() { return Message; }
|
||||
const Expr *getMessage() const { return Message; }
|
||||
|
||||
bool isFailed() const { return AssertExprAndFailed.getInt(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ private:
|
|||
Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo,
|
||||
DeclContext *contextDecl, bool isInstance = true,
|
||||
bool isVariadic = false, bool isPropertyAccessor = false,
|
||||
bool isSynthesizedAccessorStub = false,
|
||||
bool isSynthesizedAccessorStub = false,
|
||||
bool isImplicitlyDeclared = false, bool isDefined = false,
|
||||
ImplementationControl impControl = None,
|
||||
bool HasRelatedResultType = false);
|
||||
|
|
|
|||
|
|
@ -117,6 +117,8 @@ public:
|
|||
SourceLocation RAngleLoc,
|
||||
Expr *RequiresClause);
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) const;
|
||||
|
||||
/// Iterates through the template parameters in this list.
|
||||
using iterator = NamedDecl **;
|
||||
|
||||
|
|
@ -616,7 +618,7 @@ public:
|
|||
|
||||
static void
|
||||
Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
|
||||
ASTContext &Context) {
|
||||
const ASTContext &Context) {
|
||||
ID.AddInteger(TemplateArgs.size());
|
||||
for (const TemplateArgument &TemplateArg : TemplateArgs)
|
||||
TemplateArg.Profile(ID, Context);
|
||||
|
|
@ -850,7 +852,7 @@ protected:
|
|||
/// template.
|
||||
///
|
||||
/// This pointer refers to the template arguments (there are as
|
||||
/// many template arguments as template parameaters) for the
|
||||
/// many template arguments as template parameters) for the
|
||||
/// template, and is allocated lazily, since most templates do not
|
||||
/// require the use of this information.
|
||||
TemplateArgument *InjectedArgs = nullptr;
|
||||
|
|
@ -2081,7 +2083,7 @@ public:
|
|||
|
||||
static void
|
||||
Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
|
||||
ASTContext &Context) {
|
||||
const ASTContext &Context) {
|
||||
ID.AddInteger(TemplateArgs.size());
|
||||
for (const TemplateArgument &TemplateArg : TemplateArgs)
|
||||
TemplateArg.Profile(ID, Context);
|
||||
|
|
@ -2257,7 +2259,7 @@ public:
|
|||
|
||||
static void
|
||||
Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
|
||||
TemplateParameterList *TPL, ASTContext &Context);
|
||||
TemplateParameterList *TPL, const ASTContext &Context);
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
|
||||
|
|
@ -2307,9 +2309,15 @@ protected:
|
|||
return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr());
|
||||
}
|
||||
|
||||
void setCommonPtr(Common *C) {
|
||||
RedeclarableTemplateDecl::Common = C;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
friend class ASTDeclReader;
|
||||
friend class ASTDeclWriter;
|
||||
friend class TemplateDeclInstantiator;
|
||||
|
||||
/// Load any lazily-loaded specializations from the external source.
|
||||
void LoadLazySpecializations() const;
|
||||
|
|
@ -2926,13 +2934,7 @@ public:
|
|||
return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
if (isExplicitSpecialization()) {
|
||||
if (const ASTTemplateArgumentListInfo *Info = getTemplateArgsInfo())
|
||||
return SourceRange(getOuterLocStart(), Info->getRAngleLoc());
|
||||
}
|
||||
return VarDecl::getSourceRange();
|
||||
}
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
Profile(ID, TemplateArgs->asArray(), getASTContext());
|
||||
|
|
@ -2940,7 +2942,7 @@ public:
|
|||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID,
|
||||
ArrayRef<TemplateArgument> TemplateArgs,
|
||||
ASTContext &Context) {
|
||||
const ASTContext &Context) {
|
||||
ID.AddInteger(TemplateArgs.size());
|
||||
for (const TemplateArgument &TemplateArg : TemplateArgs)
|
||||
TemplateArg.Profile(ID, Context);
|
||||
|
|
@ -3091,13 +3093,7 @@ public:
|
|||
return First->InstantiatedFromMember.setInt(true);
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const override LLVM_READONLY {
|
||||
if (isExplicitSpecialization()) {
|
||||
if (const ASTTemplateArgumentListInfo *Info = getTemplateArgsAsWritten())
|
||||
return SourceRange(getOuterLocStart(), Info->getRAngleLoc());
|
||||
}
|
||||
return VarDecl::getSourceRange();
|
||||
}
|
||||
SourceRange getSourceRange() const override LLVM_READONLY;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
Profile(ID, getTemplateArgs().asArray(), getTemplateParameters(),
|
||||
|
|
@ -3106,7 +3102,7 @@ public:
|
|||
|
||||
static void
|
||||
Profile(llvm::FoldingSetNodeID &ID, ArrayRef<TemplateArgument> TemplateArgs,
|
||||
TemplateParameterList *TPL, ASTContext &Context);
|
||||
TemplateParameterList *TPL, const ASTContext &Context);
|
||||
|
||||
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
|
||||
|
||||
|
|
|
|||
|
|
@ -118,14 +118,14 @@ class alignas(IdentifierInfoAlignment) CXXLiteralOperatorIdName
|
|||
friend class clang::DeclarationName;
|
||||
friend class clang::DeclarationNameTable;
|
||||
|
||||
IdentifierInfo *ID;
|
||||
const IdentifierInfo *ID;
|
||||
|
||||
/// Extra information associated with this operator name that
|
||||
/// can be used by the front end. All bits are really needed
|
||||
/// so it is not possible to stash something in the low order bits.
|
||||
void *FETokenInfo;
|
||||
|
||||
CXXLiteralOperatorIdName(IdentifierInfo *II)
|
||||
CXXLiteralOperatorIdName(const IdentifierInfo *II)
|
||||
: DeclarationNameExtra(CXXLiteralOperatorName), ID(II),
|
||||
FETokenInfo(nullptr) {}
|
||||
|
||||
|
|
@ -478,7 +478,7 @@ public:
|
|||
|
||||
/// If this name is the name of a literal operator,
|
||||
/// retrieve the identifier associated with it.
|
||||
IdentifierInfo *getCXXLiteralIdentifier() const {
|
||||
const IdentifierInfo *getCXXLiteralIdentifier() const {
|
||||
if (getNameKind() == CXXLiteralOperatorName) {
|
||||
assert(getPtr() && "getCXXLiteralIdentifier on a null DeclarationName!");
|
||||
return castAsCXXLiteralOperatorIdName()->ID;
|
||||
|
|
@ -650,7 +650,7 @@ public:
|
|||
}
|
||||
|
||||
/// Get the name of the literal operator function with II as the identifier.
|
||||
DeclarationName getCXXLiteralOperatorName(IdentifierInfo *II);
|
||||
DeclarationName getCXXLiteralOperatorName(const IdentifierInfo *II);
|
||||
};
|
||||
|
||||
/// DeclarationNameLoc - Additional source/type location info
|
||||
|
|
@ -763,7 +763,7 @@ public:
|
|||
};
|
||||
|
||||
/// DeclarationNameInfo - A collector data type for bundling together
|
||||
/// a DeclarationName and the correspnding source/type location info.
|
||||
/// a DeclarationName and the corresponding source/type location info.
|
||||
struct DeclarationNameInfo {
|
||||
private:
|
||||
/// Name - The declaration name, also encoding name kind.
|
||||
|
|
|
|||
|
|
@ -135,8 +135,8 @@ protected:
|
|||
void setDependence(ExprDependence Deps) {
|
||||
ExprBits.Dependent = static_cast<unsigned>(Deps);
|
||||
}
|
||||
friend class ASTImporter; // Sets dependence dircetly.
|
||||
friend class ASTStmtReader; // Sets dependence dircetly.
|
||||
friend class ASTImporter; // Sets dependence directly.
|
||||
friend class ASTStmtReader; // Sets dependence directly.
|
||||
|
||||
public:
|
||||
QualType getType() const { return TR; }
|
||||
|
|
@ -171,7 +171,7 @@ public:
|
|||
}
|
||||
|
||||
/// Determines whether the type of this expression depends on
|
||||
/// - a template paramter (C++ [temp.dep.expr], which means that its type
|
||||
/// - a template parameter (C++ [temp.dep.expr], which means that its type
|
||||
/// could change from one template instantiation to the next)
|
||||
/// - or an error
|
||||
///
|
||||
|
|
@ -593,12 +593,12 @@ public:
|
|||
struct EvalStatus {
|
||||
/// Whether the evaluated expression has side effects.
|
||||
/// For example, (f() && 0) can be folded, but it still has side effects.
|
||||
bool HasSideEffects;
|
||||
bool HasSideEffects = false;
|
||||
|
||||
/// Whether the evaluation hit undefined behavior.
|
||||
/// For example, 1.0 / 0.0 can be folded to Inf, but has undefined behavior.
|
||||
/// Likewise, INT_MAX + 1 can be folded to INT_MIN, but has UB.
|
||||
bool HasUndefinedBehavior;
|
||||
bool HasUndefinedBehavior = false;
|
||||
|
||||
/// Diag - If this is non-null, it will be filled in with a stack of notes
|
||||
/// indicating why evaluation failed (or why it failed to produce a constant
|
||||
|
|
@ -607,10 +607,9 @@ public:
|
|||
/// foldable. If the expression is foldable, but not a constant expression,
|
||||
/// the notes will describes why it isn't a constant expression. If the
|
||||
/// expression *is* a constant expression, no notes will be produced.
|
||||
SmallVectorImpl<PartialDiagnosticAt> *Diag;
|
||||
SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr;
|
||||
|
||||
EvalStatus()
|
||||
: HasSideEffects(false), HasUndefinedBehavior(false), Diag(nullptr) {}
|
||||
EvalStatus() = default;
|
||||
|
||||
// hasSideEffects - Return true if the evaluated expression has
|
||||
// side effects.
|
||||
|
|
@ -665,8 +664,8 @@ public:
|
|||
SideEffectsKind AllowSideEffects = SE_NoSideEffects,
|
||||
bool InConstantContext = false) const;
|
||||
|
||||
/// EvaluateAsFloat - Return true if this is a constant which we can fold and
|
||||
/// convert to a fixed point value.
|
||||
/// EvaluateAsFixedPoint - Return true if this is a constant which we can fold
|
||||
/// and convert to a fixed point value.
|
||||
bool EvaluateAsFixedPoint(EvalResult &Result, const ASTContext &Ctx,
|
||||
SideEffectsKind AllowSideEffects = SE_NoSideEffects,
|
||||
bool InConstantContext = false) const;
|
||||
|
|
@ -714,7 +713,8 @@ public:
|
|||
/// notes will be produced if the expression is not a constant expression.
|
||||
bool EvaluateAsInitializer(APValue &Result, const ASTContext &Ctx,
|
||||
const VarDecl *VD,
|
||||
SmallVectorImpl<PartialDiagnosticAt> &Notes) const;
|
||||
SmallVectorImpl<PartialDiagnosticAt> &Notes,
|
||||
bool IsConstantInitializer) const;
|
||||
|
||||
/// EvaluateWithSubstitution - Evaluate an expression as if from the context
|
||||
/// of a call to the given function with the given arguments, inside an
|
||||
|
|
@ -762,6 +762,11 @@ public:
|
|||
/// strlen, false otherwise.
|
||||
bool tryEvaluateStrLen(uint64_t &Result, ASTContext &Ctx) const;
|
||||
|
||||
bool EvaluateCharRangeAsString(std::string &Result,
|
||||
const Expr *SizeExpression,
|
||||
const Expr *PtrExpression, ASTContext &Ctx,
|
||||
EvalResult &Status) const;
|
||||
|
||||
/// Enumeration used to describe the kind of Null pointer constant
|
||||
/// returned from \c isNullPointerConstant().
|
||||
enum NullPointerConstantKind {
|
||||
|
|
@ -819,7 +824,7 @@ public:
|
|||
/// member expression.
|
||||
static QualType findBoundMemberType(const Expr *expr);
|
||||
|
||||
/// Skip past any invisble AST nodes which might surround this
|
||||
/// Skip past any invisible AST nodes which might surround this
|
||||
/// statement, such as ExprWithCleanups or ImplicitCastExpr nodes,
|
||||
/// but also injected CXXMemberExpr and CXXConstructExpr which represent
|
||||
/// implicit conversions.
|
||||
|
|
@ -923,7 +928,7 @@ public:
|
|||
return const_cast<Expr *>(this)->IgnoreParenLValueCasts();
|
||||
}
|
||||
|
||||
/// Skip past any parenthese and casts which do not change the value
|
||||
/// Skip past any parentheses and casts which do not change the value
|
||||
/// (including ptr->int casts of the same size) until reaching a fixed point.
|
||||
/// Skips:
|
||||
/// * What IgnoreParens() skips
|
||||
|
|
@ -1436,6 +1441,14 @@ public:
|
|||
return DeclRefExprBits.RefersToEnclosingVariableOrCapture;
|
||||
}
|
||||
|
||||
bool isImmediateEscalating() const {
|
||||
return DeclRefExprBits.IsImmediateEscalating;
|
||||
}
|
||||
|
||||
void setIsImmediateEscalating(bool Set) {
|
||||
DeclRefExprBits.IsImmediateEscalating = Set;
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == DeclRefExprClass;
|
||||
}
|
||||
|
|
@ -1796,7 +1809,7 @@ class StringLiteral final
|
|||
/// * An array of getByteLength() char used to store the string data.
|
||||
|
||||
public:
|
||||
enum StringKind { Ordinary, Wide, UTF8, UTF16, UTF32 };
|
||||
enum StringKind { Ordinary, Wide, UTF8, UTF16, UTF32, Unevaluated };
|
||||
|
||||
private:
|
||||
unsigned numTrailingObjects(OverloadToken<unsigned>) const { return 1; }
|
||||
|
|
@ -1858,7 +1871,7 @@ public:
|
|||
unsigned CharByteWidth);
|
||||
|
||||
StringRef getString() const {
|
||||
assert(getCharByteWidth() == 1 &&
|
||||
assert((isUnevaluated() || getCharByteWidth() == 1) &&
|
||||
"This function is used in places that assume strings use char");
|
||||
return StringRef(getStrDataAsChar(), getByteLength());
|
||||
}
|
||||
|
|
@ -1898,6 +1911,7 @@ public:
|
|||
bool isUTF8() const { return getKind() == UTF8; }
|
||||
bool isUTF16() const { return getKind() == UTF16; }
|
||||
bool isUTF32() const { return getKind() == UTF32; }
|
||||
bool isUnevaluated() const { return getKind() == Unevaluated; }
|
||||
bool isPascal() const { return StringLiteralBits.IsPascal; }
|
||||
|
||||
bool containsNonAscii() const {
|
||||
|
|
@ -1992,7 +2006,7 @@ public:
|
|||
|
||||
private:
|
||||
PredefinedExpr(SourceLocation L, QualType FNTy, IdentKind IK,
|
||||
StringLiteral *SL);
|
||||
bool IsTransparent, StringLiteral *SL);
|
||||
|
||||
explicit PredefinedExpr(EmptyShell Empty, bool HasFunctionName);
|
||||
|
||||
|
|
@ -2007,8 +2021,12 @@ private:
|
|||
|
||||
public:
|
||||
/// Create a PredefinedExpr.
|
||||
///
|
||||
/// If IsTransparent, the PredefinedExpr is transparently handled as a
|
||||
/// StringLiteral.
|
||||
static PredefinedExpr *Create(const ASTContext &Ctx, SourceLocation L,
|
||||
QualType FNTy, IdentKind IK, StringLiteral *SL);
|
||||
QualType FNTy, IdentKind IK, bool IsTransparent,
|
||||
StringLiteral *SL);
|
||||
|
||||
/// Create an empty PredefinedExpr.
|
||||
static PredefinedExpr *CreateEmpty(const ASTContext &Ctx,
|
||||
|
|
@ -2018,6 +2036,8 @@ public:
|
|||
return static_cast<IdentKind>(PredefinedExprBits.Kind);
|
||||
}
|
||||
|
||||
bool isTransparent() const { return PredefinedExprBits.IsTransparent; }
|
||||
|
||||
SourceLocation getLocation() const { return PredefinedExprBits.Loc; }
|
||||
void setLocation(SourceLocation L) { PredefinedExprBits.Loc = L; }
|
||||
|
||||
|
|
@ -2233,14 +2253,14 @@ public:
|
|||
bool canOverflow() const { return UnaryOperatorBits.CanOverflow; }
|
||||
void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; }
|
||||
|
||||
// Get the FP contractability status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
/// Get the FP contractability status of this operator. Only meaningful for
|
||||
/// operations on floating point types.
|
||||
bool isFPContractableWithinStatement(const LangOptions &LO) const {
|
||||
return getFPFeaturesInEffect(LO).allowFPContractWithinStatement();
|
||||
}
|
||||
|
||||
// Get the FENV_ACCESS status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
/// Get the FENV_ACCESS status of this operator. Only meaningful for
|
||||
/// operations on floating point types.
|
||||
bool isFEnvAccessOn(const LangOptions &LO) const {
|
||||
return getFPFeaturesInEffect(LO).getAllowFEnvAccess();
|
||||
}
|
||||
|
|
@ -2325,8 +2345,8 @@ protected:
|
|||
void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; }
|
||||
|
||||
public:
|
||||
// Get the FP features status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
/// Get the FP features status of this operator. Only meaningful for
|
||||
/// operations on floating point types.
|
||||
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const {
|
||||
if (UnaryOperatorBits.HasFPFeatures)
|
||||
return getStoredFPFeatures().applyOverrides(LO);
|
||||
|
|
@ -2814,7 +2834,7 @@ class CallExpr : public Expr {
|
|||
/// The number of arguments in the call expression.
|
||||
unsigned NumArgs;
|
||||
|
||||
/// The location of the right parenthese. This has a different meaning for
|
||||
/// The location of the right parentheses. This has a different meaning for
|
||||
/// the derived classes of CallExpr.
|
||||
SourceLocation RParenLoc;
|
||||
|
||||
|
|
@ -3082,8 +3102,8 @@ public:
|
|||
*getTrailingFPFeatures() = F;
|
||||
}
|
||||
|
||||
// Get the FP features status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
/// Get the FP features status of this operator. Only meaningful for
|
||||
/// operations on floating point types.
|
||||
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const {
|
||||
if (hasStoredFPFeatures())
|
||||
return getStoredFPFeatures().applyOverrides(LO);
|
||||
|
|
@ -3573,8 +3593,8 @@ public:
|
|||
return *getTrailingFPFeatures();
|
||||
}
|
||||
|
||||
// Get the FP features status of this operation. Only meaningful for
|
||||
// operations on floating point types.
|
||||
/// Get the FP features status of this operation. Only meaningful for
|
||||
/// operations on floating point types.
|
||||
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const {
|
||||
if (hasStoredFPFeatures())
|
||||
return getStoredFPFeatures().applyOverrides(LO);
|
||||
|
|
@ -3971,11 +3991,12 @@ public:
|
|||
return isShiftAssignOp(getOpcode());
|
||||
}
|
||||
|
||||
// Return true if a binary operator using the specified opcode and operands
|
||||
// would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized
|
||||
// integer to a pointer.
|
||||
/// Return true if a binary operator using the specified opcode and operands
|
||||
/// would match the 'p = (i8*)nullptr + n' idiom for casting a pointer-sized
|
||||
/// integer to a pointer.
|
||||
static bool isNullPointerArithmeticExtension(ASTContext &Ctx, Opcode Opc,
|
||||
Expr *LHS, Expr *RHS);
|
||||
const Expr *LHS,
|
||||
const Expr *RHS);
|
||||
|
||||
static bool classof(const Stmt *S) {
|
||||
return S->getStmtClass() >= firstBinaryOperatorConstant &&
|
||||
|
|
@ -4006,8 +4027,8 @@ public:
|
|||
*getTrailingFPFeatures() = F;
|
||||
}
|
||||
|
||||
// Get the FP features status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
/// Get the FP features status of this operator. Only meaningful for
|
||||
/// operations on floating point types.
|
||||
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const {
|
||||
if (BinaryOperatorBits.HasFPFeatures)
|
||||
return getStoredFPFeatures().applyOverrides(LO);
|
||||
|
|
@ -4021,14 +4042,14 @@ public:
|
|||
return FPOptionsOverride();
|
||||
}
|
||||
|
||||
// Get the FP contractability status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
/// Get the FP contractability status of this operator. Only meaningful for
|
||||
/// operations on floating point types.
|
||||
bool isFPContractableWithinStatement(const LangOptions &LO) const {
|
||||
return getFPFeaturesInEffect(LO).allowFPContractWithinStatement();
|
||||
}
|
||||
|
||||
// Get the FENV_ACCESS status of this operator. Only meaningful for
|
||||
// operations on floating point types.
|
||||
/// Get the FENV_ACCESS status of this operator. Only meaningful for
|
||||
/// operations on floating point types.
|
||||
bool isFEnvAccessOn(const LangOptions &LO) const {
|
||||
return getFPFeaturesInEffect(LO).getAllowFEnvAccess();
|
||||
}
|
||||
|
|
@ -4124,17 +4145,17 @@ protected:
|
|||
: Expr(SC, Empty) { }
|
||||
|
||||
public:
|
||||
// getCond - Return the expression representing the condition for
|
||||
// the ?: operator.
|
||||
/// getCond - Return the expression representing the condition for
|
||||
/// the ?: operator.
|
||||
Expr *getCond() const;
|
||||
|
||||
// getTrueExpr - Return the subexpression representing the value of
|
||||
// the expression if the condition evaluates to true.
|
||||
/// getTrueExpr - Return the subexpression representing the value of
|
||||
/// the expression if the condition evaluates to true.
|
||||
Expr *getTrueExpr() const;
|
||||
|
||||
// getFalseExpr - Return the subexpression representing the value of
|
||||
// the expression if the condition evaluates to false. This is
|
||||
// the same as getRHS.
|
||||
/// getFalseExpr - Return the subexpression representing the value of
|
||||
/// the expression if the condition evaluates to false. This is
|
||||
/// the same as getRHS.
|
||||
Expr *getFalseExpr() const;
|
||||
|
||||
SourceLocation getQuestionLoc() const { return QuestionLoc; }
|
||||
|
|
@ -4169,17 +4190,17 @@ public:
|
|||
explicit ConditionalOperator(EmptyShell Empty)
|
||||
: AbstractConditionalOperator(ConditionalOperatorClass, Empty) { }
|
||||
|
||||
// getCond - Return the expression representing the condition for
|
||||
// the ?: operator.
|
||||
/// getCond - Return the expression representing the condition for
|
||||
/// the ?: operator.
|
||||
Expr *getCond() const { return cast<Expr>(SubExprs[COND]); }
|
||||
|
||||
// getTrueExpr - Return the subexpression representing the value of
|
||||
// the expression if the condition evaluates to true.
|
||||
/// getTrueExpr - Return the subexpression representing the value of
|
||||
/// the expression if the condition evaluates to true.
|
||||
Expr *getTrueExpr() const { return cast<Expr>(SubExprs[LHS]); }
|
||||
|
||||
// getFalseExpr - Return the subexpression representing the value of
|
||||
// the expression if the condition evaluates to false. This is
|
||||
// the same as getRHS.
|
||||
/// getFalseExpr - Return the subexpression representing the value of
|
||||
/// the expression if the condition evaluates to false. This is
|
||||
/// the same as getRHS.
|
||||
Expr *getFalseExpr() const { return cast<Expr>(SubExprs[RHS]); }
|
||||
|
||||
Expr *getLHS() const { return cast<Expr>(SubExprs[LHS]); }
|
||||
|
|
@ -4684,13 +4705,22 @@ public:
|
|||
};
|
||||
|
||||
/// Represents a function call to one of __builtin_LINE(), __builtin_COLUMN(),
|
||||
/// __builtin_FUNCTION(), __builtin_FILE(), or __builtin_source_location().
|
||||
/// __builtin_FUNCTION(), __builtin_FUNCSIG(), __builtin_FILE(),
|
||||
/// __builtin_FILE_NAME() or __builtin_source_location().
|
||||
class SourceLocExpr final : public Expr {
|
||||
SourceLocation BuiltinLoc, RParenLoc;
|
||||
DeclContext *ParentContext;
|
||||
|
||||
public:
|
||||
enum IdentKind { Function, File, Line, Column, SourceLocStruct };
|
||||
enum IdentKind {
|
||||
Function,
|
||||
FuncSig,
|
||||
File,
|
||||
FileName,
|
||||
Line,
|
||||
Column,
|
||||
SourceLocStruct
|
||||
};
|
||||
|
||||
SourceLocExpr(const ASTContext &Ctx, IdentKind Type, QualType ResultTy,
|
||||
SourceLocation BLoc, SourceLocation RParenLoc,
|
||||
|
|
@ -4714,7 +4744,9 @@ public:
|
|||
bool isIntType() const {
|
||||
switch (getIdentKind()) {
|
||||
case File:
|
||||
case FileName:
|
||||
case Function:
|
||||
case FuncSig:
|
||||
case SourceLocStruct:
|
||||
return false;
|
||||
case Line:
|
||||
|
|
@ -4900,6 +4932,13 @@ public:
|
|||
/// has been set.
|
||||
bool hasArrayFiller() const { return getArrayFiller(); }
|
||||
|
||||
/// Determine whether this initializer list contains a designated initializer.
|
||||
bool hasDesignatedInit() const {
|
||||
return std::any_of(begin(), end(), [](const Stmt *S) {
|
||||
return isa<DesignatedInitExpr>(S);
|
||||
});
|
||||
}
|
||||
|
||||
/// If this initializes a union, specifies which field in the
|
||||
/// union to initialize.
|
||||
///
|
||||
|
|
@ -4928,8 +4967,8 @@ public:
|
|||
return LBraceLoc.isValid() && RBraceLoc.isValid();
|
||||
}
|
||||
|
||||
// Is this an initializer for an array of characters, initialized by a string
|
||||
// literal or an @encode?
|
||||
/// Is this an initializer for an array of characters, initialized by a string
|
||||
/// literal or an @encode?
|
||||
bool isStringLiteralInit() const;
|
||||
|
||||
/// Is this a transparent initializer list (that is, an InitListExpr that is
|
||||
|
|
@ -5068,37 +5107,6 @@ private:
|
|||
NumDesignators(0), NumSubExprs(NumSubExprs), Designators(nullptr) { }
|
||||
|
||||
public:
|
||||
/// A field designator, e.g., ".x".
|
||||
struct FieldDesignator {
|
||||
/// Refers to the field that is being initialized. The low bit
|
||||
/// of this field determines whether this is actually a pointer
|
||||
/// to an IdentifierInfo (if 1) or a FieldDecl (if 0). When
|
||||
/// initially constructed, a field designator will store an
|
||||
/// IdentifierInfo*. After semantic analysis has resolved that
|
||||
/// name, the field designator will instead store a FieldDecl*.
|
||||
uintptr_t NameOrField;
|
||||
|
||||
/// The location of the '.' in the designated initializer.
|
||||
SourceLocation DotLoc;
|
||||
|
||||
/// The location of the field name in the designated initializer.
|
||||
SourceLocation FieldLoc;
|
||||
};
|
||||
|
||||
/// An array or GNU array-range designator, e.g., "[9]" or "[10..15]".
|
||||
struct ArrayOrRangeDesignator {
|
||||
/// Location of the first index expression within the designated
|
||||
/// initializer expression's list of subexpressions.
|
||||
unsigned Index;
|
||||
/// The location of the '[' starting the array range designator.
|
||||
SourceLocation LBracketLoc;
|
||||
/// The location of the ellipsis separating the start and end
|
||||
/// indices. Only valid for GNU array-range designators.
|
||||
SourceLocation EllipsisLoc;
|
||||
/// The location of the ']' terminating the array range designator.
|
||||
SourceLocation RBracketLoc;
|
||||
};
|
||||
|
||||
/// Represents a single C99 designator.
|
||||
///
|
||||
/// @todo This class is infuriatingly similar to clang::Designator,
|
||||
|
|
@ -5106,118 +5114,177 @@ public:
|
|||
/// keep us from reusing it. Try harder, later, to rectify these
|
||||
/// differences.
|
||||
class Designator {
|
||||
/// A field designator, e.g., ".x".
|
||||
struct FieldDesignatorInfo {
|
||||
/// Refers to the field that is being initialized. The low bit
|
||||
/// of this field determines whether this is actually a pointer
|
||||
/// to an IdentifierInfo (if 1) or a FieldDecl (if 0). When
|
||||
/// initially constructed, a field designator will store an
|
||||
/// IdentifierInfo*. After semantic analysis has resolved that
|
||||
/// name, the field designator will instead store a FieldDecl*.
|
||||
uintptr_t NameOrField;
|
||||
|
||||
/// The location of the '.' in the designated initializer.
|
||||
SourceLocation DotLoc;
|
||||
|
||||
/// The location of the field name in the designated initializer.
|
||||
SourceLocation FieldLoc;
|
||||
|
||||
FieldDesignatorInfo(const IdentifierInfo *II, SourceLocation DotLoc,
|
||||
SourceLocation FieldLoc)
|
||||
: NameOrField(reinterpret_cast<uintptr_t>(II) | 0x1), DotLoc(DotLoc),
|
||||
FieldLoc(FieldLoc) {}
|
||||
};
|
||||
|
||||
/// An array or GNU array-range designator, e.g., "[9]" or "[10...15]".
|
||||
struct ArrayOrRangeDesignatorInfo {
|
||||
/// Location of the first index expression within the designated
|
||||
/// initializer expression's list of subexpressions.
|
||||
unsigned Index;
|
||||
|
||||
/// The location of the '[' starting the array range designator.
|
||||
SourceLocation LBracketLoc;
|
||||
|
||||
/// The location of the ellipsis separating the start and end
|
||||
/// indices. Only valid for GNU array-range designators.
|
||||
SourceLocation EllipsisLoc;
|
||||
|
||||
/// The location of the ']' terminating the array range designator.
|
||||
SourceLocation RBracketLoc;
|
||||
|
||||
ArrayOrRangeDesignatorInfo(unsigned Index, SourceLocation LBracketLoc,
|
||||
SourceLocation RBracketLoc)
|
||||
: Index(Index), LBracketLoc(LBracketLoc), RBracketLoc(RBracketLoc) {}
|
||||
|
||||
ArrayOrRangeDesignatorInfo(unsigned Index,
|
||||
SourceLocation LBracketLoc,
|
||||
SourceLocation EllipsisLoc,
|
||||
SourceLocation RBracketLoc)
|
||||
: Index(Index), LBracketLoc(LBracketLoc), EllipsisLoc(EllipsisLoc),
|
||||
RBracketLoc(RBracketLoc) {}
|
||||
};
|
||||
|
||||
/// The kind of designator this describes.
|
||||
enum {
|
||||
enum DesignatorKind {
|
||||
FieldDesignator,
|
||||
ArrayDesignator,
|
||||
ArrayRangeDesignator
|
||||
} Kind;
|
||||
};
|
||||
|
||||
DesignatorKind Kind;
|
||||
|
||||
union {
|
||||
/// A field designator, e.g., ".x".
|
||||
struct FieldDesignator Field;
|
||||
struct FieldDesignatorInfo FieldInfo;
|
||||
|
||||
/// An array or GNU array-range designator, e.g., "[9]" or "[10..15]".
|
||||
struct ArrayOrRangeDesignator ArrayOrRange;
|
||||
struct ArrayOrRangeDesignatorInfo ArrayOrRangeInfo;
|
||||
};
|
||||
friend class DesignatedInitExpr;
|
||||
|
||||
Designator(DesignatorKind Kind) : Kind(Kind) {}
|
||||
|
||||
public:
|
||||
Designator() {}
|
||||
|
||||
/// Initializes a field designator.
|
||||
Designator(const IdentifierInfo *FieldName, SourceLocation DotLoc,
|
||||
SourceLocation FieldLoc)
|
||||
: Kind(FieldDesignator) {
|
||||
new (&Field) DesignatedInitExpr::FieldDesignator;
|
||||
Field.NameOrField = reinterpret_cast<uintptr_t>(FieldName) | 0x01;
|
||||
Field.DotLoc = DotLoc;
|
||||
Field.FieldLoc = FieldLoc;
|
||||
}
|
||||
|
||||
/// Initializes an array designator.
|
||||
Designator(unsigned Index, SourceLocation LBracketLoc,
|
||||
SourceLocation RBracketLoc)
|
||||
: Kind(ArrayDesignator) {
|
||||
new (&ArrayOrRange) DesignatedInitExpr::ArrayOrRangeDesignator;
|
||||
ArrayOrRange.Index = Index;
|
||||
ArrayOrRange.LBracketLoc = LBracketLoc;
|
||||
ArrayOrRange.EllipsisLoc = SourceLocation();
|
||||
ArrayOrRange.RBracketLoc = RBracketLoc;
|
||||
}
|
||||
|
||||
/// Initializes a GNU array-range designator.
|
||||
Designator(unsigned Index, SourceLocation LBracketLoc,
|
||||
SourceLocation EllipsisLoc, SourceLocation RBracketLoc)
|
||||
: Kind(ArrayRangeDesignator) {
|
||||
new (&ArrayOrRange) DesignatedInitExpr::ArrayOrRangeDesignator;
|
||||
ArrayOrRange.Index = Index;
|
||||
ArrayOrRange.LBracketLoc = LBracketLoc;
|
||||
ArrayOrRange.EllipsisLoc = EllipsisLoc;
|
||||
ArrayOrRange.RBracketLoc = RBracketLoc;
|
||||
}
|
||||
|
||||
bool isFieldDesignator() const { return Kind == FieldDesignator; }
|
||||
bool isArrayDesignator() const { return Kind == ArrayDesignator; }
|
||||
bool isArrayRangeDesignator() const { return Kind == ArrayRangeDesignator; }
|
||||
|
||||
IdentifierInfo *getFieldName() const;
|
||||
//===------------------------------------------------------------------===//
|
||||
// FieldDesignatorInfo
|
||||
|
||||
FieldDecl *getField() const {
|
||||
assert(Kind == FieldDesignator && "Only valid on a field designator");
|
||||
if (Field.NameOrField & 0x01)
|
||||
return nullptr;
|
||||
else
|
||||
return reinterpret_cast<FieldDecl *>(Field.NameOrField);
|
||||
/// Creates a field designator.
|
||||
static Designator CreateFieldDesignator(const IdentifierInfo *FieldName,
|
||||
SourceLocation DotLoc,
|
||||
SourceLocation FieldLoc) {
|
||||
Designator D(FieldDesignator);
|
||||
new (&D.FieldInfo) FieldDesignatorInfo(FieldName, DotLoc, FieldLoc);
|
||||
return D;
|
||||
}
|
||||
|
||||
void setField(FieldDecl *FD) {
|
||||
assert(Kind == FieldDesignator && "Only valid on a field designator");
|
||||
Field.NameOrField = reinterpret_cast<uintptr_t>(FD);
|
||||
const IdentifierInfo *getFieldName() const;
|
||||
|
||||
FieldDecl *getFieldDecl() const {
|
||||
assert(isFieldDesignator() && "Only valid on a field designator");
|
||||
if (FieldInfo.NameOrField & 0x01)
|
||||
return nullptr;
|
||||
return reinterpret_cast<FieldDecl *>(FieldInfo.NameOrField);
|
||||
}
|
||||
|
||||
void setFieldDecl(FieldDecl *FD) {
|
||||
assert(isFieldDesignator() && "Only valid on a field designator");
|
||||
FieldInfo.NameOrField = reinterpret_cast<uintptr_t>(FD);
|
||||
}
|
||||
|
||||
SourceLocation getDotLoc() const {
|
||||
assert(Kind == FieldDesignator && "Only valid on a field designator");
|
||||
return Field.DotLoc;
|
||||
assert(isFieldDesignator() && "Only valid on a field designator");
|
||||
return FieldInfo.DotLoc;
|
||||
}
|
||||
|
||||
SourceLocation getFieldLoc() const {
|
||||
assert(Kind == FieldDesignator && "Only valid on a field designator");
|
||||
return Field.FieldLoc;
|
||||
assert(isFieldDesignator() && "Only valid on a field designator");
|
||||
return FieldInfo.FieldLoc;
|
||||
}
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// ArrayOrRangeDesignator
|
||||
|
||||
/// Creates an array designator.
|
||||
static Designator CreateArrayDesignator(unsigned Index,
|
||||
SourceLocation LBracketLoc,
|
||||
SourceLocation RBracketLoc) {
|
||||
Designator D(ArrayDesignator);
|
||||
new (&D.ArrayOrRangeInfo) ArrayOrRangeDesignatorInfo(Index, LBracketLoc,
|
||||
RBracketLoc);
|
||||
return D;
|
||||
}
|
||||
|
||||
/// Creates a GNU array-range designator.
|
||||
static Designator CreateArrayRangeDesignator(unsigned Index,
|
||||
SourceLocation LBracketLoc,
|
||||
SourceLocation EllipsisLoc,
|
||||
SourceLocation RBracketLoc) {
|
||||
Designator D(ArrayRangeDesignator);
|
||||
new (&D.ArrayOrRangeInfo) ArrayOrRangeDesignatorInfo(Index, LBracketLoc,
|
||||
EllipsisLoc,
|
||||
RBracketLoc);
|
||||
return D;
|
||||
}
|
||||
|
||||
unsigned getArrayIndex() const {
|
||||
assert((isArrayDesignator() || isArrayRangeDesignator()) &&
|
||||
"Only valid on an array or array-range designator");
|
||||
return ArrayOrRangeInfo.Index;
|
||||
}
|
||||
|
||||
SourceLocation getLBracketLoc() const {
|
||||
assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) &&
|
||||
assert((isArrayDesignator() || isArrayRangeDesignator()) &&
|
||||
"Only valid on an array or array-range designator");
|
||||
return ArrayOrRange.LBracketLoc;
|
||||
}
|
||||
|
||||
SourceLocation getRBracketLoc() const {
|
||||
assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) &&
|
||||
"Only valid on an array or array-range designator");
|
||||
return ArrayOrRange.RBracketLoc;
|
||||
return ArrayOrRangeInfo.LBracketLoc;
|
||||
}
|
||||
|
||||
SourceLocation getEllipsisLoc() const {
|
||||
assert(Kind == ArrayRangeDesignator &&
|
||||
assert(isArrayRangeDesignator() &&
|
||||
"Only valid on an array-range designator");
|
||||
return ArrayOrRange.EllipsisLoc;
|
||||
return ArrayOrRangeInfo.EllipsisLoc;
|
||||
}
|
||||
|
||||
unsigned getFirstExprIndex() const {
|
||||
assert((Kind == ArrayDesignator || Kind == ArrayRangeDesignator) &&
|
||||
SourceLocation getRBracketLoc() const {
|
||||
assert((isArrayDesignator() || isArrayRangeDesignator()) &&
|
||||
"Only valid on an array or array-range designator");
|
||||
return ArrayOrRange.Index;
|
||||
return ArrayOrRangeInfo.RBracketLoc;
|
||||
}
|
||||
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY {
|
||||
if (Kind == FieldDesignator)
|
||||
return getDotLoc().isInvalid()? getFieldLoc() : getDotLoc();
|
||||
else
|
||||
return getLBracketLoc();
|
||||
if (isFieldDesignator())
|
||||
return getDotLoc().isInvalid() ? getFieldLoc() : getDotLoc();
|
||||
return getLBracketLoc();
|
||||
}
|
||||
|
||||
SourceLocation getEndLoc() const LLVM_READONLY {
|
||||
return Kind == FieldDesignator ? getFieldLoc() : getRBracketLoc();
|
||||
return isFieldDesignator() ? getFieldLoc() : getRBracketLoc();
|
||||
}
|
||||
|
||||
SourceRange getSourceRange() const LLVM_READONLY {
|
||||
return SourceRange(getBeginLoc(), getEndLoc());
|
||||
}
|
||||
|
|
@ -5627,6 +5694,12 @@ public:
|
|||
/// which names a dependent type in its association list is result-dependent,
|
||||
/// which means that the choice of result expression is dependent.
|
||||
/// Result-dependent generic associations are both type- and value-dependent.
|
||||
///
|
||||
/// We also allow an extended form in both C and C++ where the controlling
|
||||
/// predicate for the selection expression is a type rather than an expression.
|
||||
/// This type argument form does not perform any conversions for the
|
||||
/// controlling type, which makes it suitable for use with qualified type
|
||||
/// associations, which is not possible with the expression form.
|
||||
class GenericSelectionExpr final
|
||||
: public Expr,
|
||||
private llvm::TrailingObjects<GenericSelectionExpr, Stmt *,
|
||||
|
|
@ -5639,31 +5712,67 @@ class GenericSelectionExpr final
|
|||
/// expression in the case where the generic selection expression is not
|
||||
/// result-dependent. The result index is equal to ResultDependentIndex
|
||||
/// if and only if the generic selection expression is result-dependent.
|
||||
unsigned NumAssocs, ResultIndex;
|
||||
unsigned NumAssocs : 15;
|
||||
unsigned ResultIndex : 15; // NB: ResultDependentIndex is tied to this width.
|
||||
unsigned IsExprPredicate : 1;
|
||||
enum : unsigned {
|
||||
ResultDependentIndex = std::numeric_limits<unsigned>::max(),
|
||||
ControllingIndex = 0,
|
||||
AssocExprStartIndex = 1
|
||||
ResultDependentIndex = 0x7FFF
|
||||
};
|
||||
|
||||
unsigned getIndexOfControllingExpression() const {
|
||||
// If controlled by an expression, the first offset into the Stmt *
|
||||
// trailing array is the controlling expression, the associated expressions
|
||||
// follow this.
|
||||
assert(isExprPredicate() && "Asking for the controlling expression of a "
|
||||
"selection expr predicated by a type");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned getIndexOfControllingType() const {
|
||||
// If controlled by a type, the first offset into the TypeSourceInfo *
|
||||
// trailing array is the controlling type, the associated types follow this.
|
||||
assert(isTypePredicate() && "Asking for the controlling type of a "
|
||||
"selection expr predicated by an expression");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned getIndexOfStartOfAssociatedExprs() const {
|
||||
// If the predicate is a type, then the associated expressions are the only
|
||||
// Stmt * in the trailing array, otherwise we need to offset past the
|
||||
// predicate expression.
|
||||
return (int)isExprPredicate();
|
||||
}
|
||||
|
||||
unsigned getIndexOfStartOfAssociatedTypes() const {
|
||||
// If the predicate is a type, then the associated types follow it in the
|
||||
// trailing array. Otherwise, the associated types are the only
|
||||
// TypeSourceInfo * in the trailing array.
|
||||
return (int)isTypePredicate();
|
||||
}
|
||||
|
||||
|
||||
/// The location of the "default" and of the right parenthesis.
|
||||
SourceLocation DefaultLoc, RParenLoc;
|
||||
|
||||
// GenericSelectionExpr is followed by several trailing objects.
|
||||
// They are (in order):
|
||||
//
|
||||
// * A single Stmt * for the controlling expression.
|
||||
// * A single Stmt * for the controlling expression or a TypeSourceInfo * for
|
||||
// the controlling type, depending on the result of isTypePredicate() or
|
||||
// isExprPredicate().
|
||||
// * An array of getNumAssocs() Stmt * for the association expressions.
|
||||
// * An array of getNumAssocs() TypeSourceInfo *, one for each of the
|
||||
// association expressions.
|
||||
unsigned numTrailingObjects(OverloadToken<Stmt *>) const {
|
||||
// Add one to account for the controlling expression; the remainder
|
||||
// are the associated expressions.
|
||||
return 1 + getNumAssocs();
|
||||
return getNumAssocs() + (int)isExprPredicate();
|
||||
}
|
||||
|
||||
unsigned numTrailingObjects(OverloadToken<TypeSourceInfo *>) const {
|
||||
return getNumAssocs();
|
||||
// Add one to account for the controlling type predicate, the remainder
|
||||
// are the associated types.
|
||||
return getNumAssocs() + (int)isTypePredicate();
|
||||
}
|
||||
|
||||
template <bool Const> class AssociationIteratorTy;
|
||||
|
|
@ -5744,7 +5853,8 @@ class GenericSelectionExpr final
|
|||
bool operator==(AssociationIteratorTy Other) const { return E == Other.E; }
|
||||
}; // class AssociationIterator
|
||||
|
||||
/// Build a non-result-dependent generic selection expression.
|
||||
/// Build a non-result-dependent generic selection expression accepting an
|
||||
/// expression predicate.
|
||||
GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc,
|
||||
Expr *ControllingExpr,
|
||||
ArrayRef<TypeSourceInfo *> AssocTypes,
|
||||
|
|
@ -5753,7 +5863,8 @@ class GenericSelectionExpr final
|
|||
bool ContainsUnexpandedParameterPack,
|
||||
unsigned ResultIndex);
|
||||
|
||||
/// Build a result-dependent generic selection expression.
|
||||
/// Build a result-dependent generic selection expression accepting an
|
||||
/// expression predicate.
|
||||
GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc,
|
||||
Expr *ControllingExpr,
|
||||
ArrayRef<TypeSourceInfo *> AssocTypes,
|
||||
|
|
@ -5761,11 +5872,31 @@ class GenericSelectionExpr final
|
|||
SourceLocation RParenLoc,
|
||||
bool ContainsUnexpandedParameterPack);
|
||||
|
||||
/// Build a non-result-dependent generic selection expression accepting a
|
||||
/// type predicate.
|
||||
GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc,
|
||||
TypeSourceInfo *ControllingType,
|
||||
ArrayRef<TypeSourceInfo *> AssocTypes,
|
||||
ArrayRef<Expr *> AssocExprs, SourceLocation DefaultLoc,
|
||||
SourceLocation RParenLoc,
|
||||
bool ContainsUnexpandedParameterPack,
|
||||
unsigned ResultIndex);
|
||||
|
||||
/// Build a result-dependent generic selection expression accepting a type
|
||||
/// predicate.
|
||||
GenericSelectionExpr(const ASTContext &Context, SourceLocation GenericLoc,
|
||||
TypeSourceInfo *ControllingType,
|
||||
ArrayRef<TypeSourceInfo *> AssocTypes,
|
||||
ArrayRef<Expr *> AssocExprs, SourceLocation DefaultLoc,
|
||||
SourceLocation RParenLoc,
|
||||
bool ContainsUnexpandedParameterPack);
|
||||
|
||||
/// Build an empty generic selection expression for deserialization.
|
||||
explicit GenericSelectionExpr(EmptyShell Empty, unsigned NumAssocs);
|
||||
|
||||
public:
|
||||
/// Create a non-result-dependent generic selection expression.
|
||||
/// Create a non-result-dependent generic selection expression accepting an
|
||||
/// expression predicate.
|
||||
static GenericSelectionExpr *
|
||||
Create(const ASTContext &Context, SourceLocation GenericLoc,
|
||||
Expr *ControllingExpr, ArrayRef<TypeSourceInfo *> AssocTypes,
|
||||
|
|
@ -5773,13 +5904,31 @@ public:
|
|||
SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack,
|
||||
unsigned ResultIndex);
|
||||
|
||||
/// Create a result-dependent generic selection expression.
|
||||
/// Create a result-dependent generic selection expression accepting an
|
||||
/// expression predicate.
|
||||
static GenericSelectionExpr *
|
||||
Create(const ASTContext &Context, SourceLocation GenericLoc,
|
||||
Expr *ControllingExpr, ArrayRef<TypeSourceInfo *> AssocTypes,
|
||||
ArrayRef<Expr *> AssocExprs, SourceLocation DefaultLoc,
|
||||
SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack);
|
||||
|
||||
/// Create a non-result-dependent generic selection expression accepting a
|
||||
/// type predicate.
|
||||
static GenericSelectionExpr *
|
||||
Create(const ASTContext &Context, SourceLocation GenericLoc,
|
||||
TypeSourceInfo *ControllingType, ArrayRef<TypeSourceInfo *> AssocTypes,
|
||||
ArrayRef<Expr *> AssocExprs, SourceLocation DefaultLoc,
|
||||
SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack,
|
||||
unsigned ResultIndex);
|
||||
|
||||
/// Create a result-dependent generic selection expression accepting a type
|
||||
/// predicate
|
||||
static GenericSelectionExpr *
|
||||
Create(const ASTContext &Context, SourceLocation GenericLoc,
|
||||
TypeSourceInfo *ControllingType, ArrayRef<TypeSourceInfo *> AssocTypes,
|
||||
ArrayRef<Expr *> AssocExprs, SourceLocation DefaultLoc,
|
||||
SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack);
|
||||
|
||||
/// Create an empty generic selection expression for deserialization.
|
||||
static GenericSelectionExpr *CreateEmpty(const ASTContext &Context,
|
||||
unsigned NumAssocs);
|
||||
|
|
@ -5807,32 +5956,56 @@ public:
|
|||
/// Whether this generic selection is result-dependent.
|
||||
bool isResultDependent() const { return ResultIndex == ResultDependentIndex; }
|
||||
|
||||
/// Whether this generic selection uses an expression as its controlling
|
||||
/// argument.
|
||||
bool isExprPredicate() const { return IsExprPredicate; }
|
||||
/// Whether this generic selection uses a type as its controlling argument.
|
||||
bool isTypePredicate() const { return !IsExprPredicate; }
|
||||
|
||||
/// Return the controlling expression of this generic selection expression.
|
||||
/// Only valid to call if the selection expression used an expression as its
|
||||
/// controlling argument.
|
||||
Expr *getControllingExpr() {
|
||||
return cast<Expr>(getTrailingObjects<Stmt *>()[ControllingIndex]);
|
||||
return cast<Expr>(
|
||||
getTrailingObjects<Stmt *>()[getIndexOfControllingExpression()]);
|
||||
}
|
||||
const Expr *getControllingExpr() const {
|
||||
return cast<Expr>(getTrailingObjects<Stmt *>()[ControllingIndex]);
|
||||
return cast<Expr>(
|
||||
getTrailingObjects<Stmt *>()[getIndexOfControllingExpression()]);
|
||||
}
|
||||
|
||||
/// Return the controlling type of this generic selection expression. Only
|
||||
/// valid to call if the selection expression used a type as its controlling
|
||||
/// argument.
|
||||
TypeSourceInfo *getControllingType() {
|
||||
return getTrailingObjects<TypeSourceInfo *>()[getIndexOfControllingType()];
|
||||
}
|
||||
const TypeSourceInfo* getControllingType() const {
|
||||
return getTrailingObjects<TypeSourceInfo *>()[getIndexOfControllingType()];
|
||||
}
|
||||
|
||||
/// Return the result expression of this controlling expression. Defined if
|
||||
/// and only if the generic selection expression is not result-dependent.
|
||||
Expr *getResultExpr() {
|
||||
return cast<Expr>(
|
||||
getTrailingObjects<Stmt *>()[AssocExprStartIndex + getResultIndex()]);
|
||||
getTrailingObjects<Stmt *>()[getIndexOfStartOfAssociatedExprs() +
|
||||
getResultIndex()]);
|
||||
}
|
||||
const Expr *getResultExpr() const {
|
||||
return cast<Expr>(
|
||||
getTrailingObjects<Stmt *>()[AssocExprStartIndex + getResultIndex()]);
|
||||
getTrailingObjects<Stmt *>()[getIndexOfStartOfAssociatedExprs() +
|
||||
getResultIndex()]);
|
||||
}
|
||||
|
||||
ArrayRef<Expr *> getAssocExprs() const {
|
||||
return {reinterpret_cast<Expr *const *>(getTrailingObjects<Stmt *>() +
|
||||
AssocExprStartIndex),
|
||||
getIndexOfStartOfAssociatedExprs()),
|
||||
NumAssocs};
|
||||
}
|
||||
ArrayRef<TypeSourceInfo *> getAssocTypeSourceInfos() const {
|
||||
return {getTrailingObjects<TypeSourceInfo *>(), NumAssocs};
|
||||
return {getTrailingObjects<TypeSourceInfo *>() +
|
||||
getIndexOfStartOfAssociatedTypes(),
|
||||
NumAssocs};
|
||||
}
|
||||
|
||||
/// Return the Ith association expression with its TypeSourceInfo,
|
||||
|
|
@ -5841,23 +6014,30 @@ public:
|
|||
assert(I < getNumAssocs() &&
|
||||
"Out-of-range index in GenericSelectionExpr::getAssociation!");
|
||||
return Association(
|
||||
cast<Expr>(getTrailingObjects<Stmt *>()[AssocExprStartIndex + I]),
|
||||
getTrailingObjects<TypeSourceInfo *>()[I],
|
||||
cast<Expr>(
|
||||
getTrailingObjects<Stmt *>()[getIndexOfStartOfAssociatedExprs() +
|
||||
I]),
|
||||
getTrailingObjects<
|
||||
TypeSourceInfo *>()[getIndexOfStartOfAssociatedTypes() + I],
|
||||
!isResultDependent() && (getResultIndex() == I));
|
||||
}
|
||||
ConstAssociation getAssociation(unsigned I) const {
|
||||
assert(I < getNumAssocs() &&
|
||||
"Out-of-range index in GenericSelectionExpr::getAssociation!");
|
||||
return ConstAssociation(
|
||||
cast<Expr>(getTrailingObjects<Stmt *>()[AssocExprStartIndex + I]),
|
||||
getTrailingObjects<TypeSourceInfo *>()[I],
|
||||
cast<Expr>(
|
||||
getTrailingObjects<Stmt *>()[getIndexOfStartOfAssociatedExprs() +
|
||||
I]),
|
||||
getTrailingObjects<
|
||||
TypeSourceInfo *>()[getIndexOfStartOfAssociatedTypes() + I],
|
||||
!isResultDependent() && (getResultIndex() == I));
|
||||
}
|
||||
|
||||
association_range associations() {
|
||||
AssociationIterator Begin(getTrailingObjects<Stmt *>() +
|
||||
AssocExprStartIndex,
|
||||
getTrailingObjects<TypeSourceInfo *>(),
|
||||
getIndexOfStartOfAssociatedExprs(),
|
||||
getTrailingObjects<TypeSourceInfo *>() +
|
||||
getIndexOfStartOfAssociatedTypes(),
|
||||
/*Offset=*/0, ResultIndex);
|
||||
AssociationIterator End(Begin.E + NumAssocs, Begin.TSI + NumAssocs,
|
||||
/*Offset=*/NumAssocs, ResultIndex);
|
||||
|
|
@ -5866,8 +6046,9 @@ public:
|
|||
|
||||
const_association_range associations() const {
|
||||
ConstAssociationIterator Begin(getTrailingObjects<Stmt *>() +
|
||||
AssocExprStartIndex,
|
||||
getTrailingObjects<TypeSourceInfo *>(),
|
||||
getIndexOfStartOfAssociatedExprs(),
|
||||
getTrailingObjects<TypeSourceInfo *>() +
|
||||
getIndexOfStartOfAssociatedTypes(),
|
||||
/*Offset=*/0, ResultIndex);
|
||||
ConstAssociationIterator End(Begin.E + NumAssocs, Begin.TSI + NumAssocs,
|
||||
/*Offset=*/NumAssocs, ResultIndex);
|
||||
|
|
@ -6180,11 +6361,11 @@ public:
|
|||
return getSubExprsBuffer() + getNumSubExprs();
|
||||
}
|
||||
|
||||
llvm::iterator_range<semantics_iterator> semantics() {
|
||||
return llvm::make_range(semantics_begin(), semantics_end());
|
||||
ArrayRef<Expr*> semantics() {
|
||||
return ArrayRef(semantics_begin(), semantics_end());
|
||||
}
|
||||
llvm::iterator_range<const_semantics_iterator> semantics() const {
|
||||
return llvm::make_range(semantics_begin(), semantics_end());
|
||||
ArrayRef<const Expr*> semantics() const {
|
||||
return ArrayRef(semantics_begin(), semantics_end());
|
||||
}
|
||||
|
||||
Expr *getSemanticExpr(unsigned index) {
|
||||
|
|
|
|||
|
|
@ -1681,6 +1681,14 @@ public:
|
|||
getArgs()[Arg] = ArgExpr;
|
||||
}
|
||||
|
||||
bool isImmediateEscalating() const {
|
||||
return CXXConstructExprBits.IsImmediateEscalating;
|
||||
}
|
||||
|
||||
void setIsImmediateEscalating(bool Set) {
|
||||
CXXConstructExprBits.IsImmediateEscalating = Set;
|
||||
}
|
||||
|
||||
SourceLocation getBeginLoc() const LLVM_READONLY;
|
||||
SourceLocation getEndLoc() const LLVM_READONLY;
|
||||
SourceRange getParenOrBraceRange() const { return ParenOrBraceRange; }
|
||||
|
|
@ -2321,7 +2329,7 @@ public:
|
|||
|
||||
/// This might return std::nullopt even if isArray() returns true,
|
||||
/// since there might not be an array size expression.
|
||||
/// If the result is not-None, it will never wrap a nullptr.
|
||||
/// If the result is not std::nullopt, it will never wrap a nullptr.
|
||||
std::optional<Expr *> getArraySize() {
|
||||
if (!isArray())
|
||||
return std::nullopt;
|
||||
|
|
@ -2335,7 +2343,7 @@ public:
|
|||
|
||||
/// This might return std::nullopt even if isArray() returns true,
|
||||
/// since there might not be an array size expression.
|
||||
/// If the result is not-None, it will never wrap a nullptr.
|
||||
/// If the result is not std::nullopt, it will never wrap a nullptr.
|
||||
std::optional<const Expr *> getArraySize() const {
|
||||
if (!isArray())
|
||||
return std::nullopt;
|
||||
|
|
@ -3504,8 +3512,9 @@ class CXXUnresolvedConstructExpr final
|
|||
friend class ASTStmtReader;
|
||||
friend TrailingObjects;
|
||||
|
||||
/// The type being constructed.
|
||||
TypeSourceInfo *TSI;
|
||||
/// The type being constructed, and whether the construct expression models
|
||||
/// list initialization or not.
|
||||
llvm::PointerIntPair<TypeSourceInfo *, 1> TypeAndInitForm;
|
||||
|
||||
/// The location of the left parentheses ('(').
|
||||
SourceLocation LParenLoc;
|
||||
|
|
@ -3515,30 +3524,31 @@ class CXXUnresolvedConstructExpr final
|
|||
|
||||
CXXUnresolvedConstructExpr(QualType T, TypeSourceInfo *TSI,
|
||||
SourceLocation LParenLoc, ArrayRef<Expr *> Args,
|
||||
SourceLocation RParenLoc);
|
||||
SourceLocation RParenLoc, bool IsListInit);
|
||||
|
||||
CXXUnresolvedConstructExpr(EmptyShell Empty, unsigned NumArgs)
|
||||
: Expr(CXXUnresolvedConstructExprClass, Empty), TSI(nullptr) {
|
||||
: Expr(CXXUnresolvedConstructExprClass, Empty) {
|
||||
CXXUnresolvedConstructExprBits.NumArgs = NumArgs;
|
||||
}
|
||||
|
||||
public:
|
||||
static CXXUnresolvedConstructExpr *Create(const ASTContext &Context,
|
||||
QualType T, TypeSourceInfo *TSI,
|
||||
SourceLocation LParenLoc,
|
||||
ArrayRef<Expr *> Args,
|
||||
SourceLocation RParenLoc);
|
||||
static CXXUnresolvedConstructExpr *
|
||||
Create(const ASTContext &Context, QualType T, TypeSourceInfo *TSI,
|
||||
SourceLocation LParenLoc, ArrayRef<Expr *> Args,
|
||||
SourceLocation RParenLoc, bool IsListInit);
|
||||
|
||||
static CXXUnresolvedConstructExpr *CreateEmpty(const ASTContext &Context,
|
||||
unsigned NumArgs);
|
||||
|
||||
/// Retrieve the type that is being constructed, as specified
|
||||
/// in the source code.
|
||||
QualType getTypeAsWritten() const { return TSI->getType(); }
|
||||
QualType getTypeAsWritten() const { return getTypeSourceInfo()->getType(); }
|
||||
|
||||
/// Retrieve the type source information for the type being
|
||||
/// constructed.
|
||||
TypeSourceInfo *getTypeSourceInfo() const { return TSI; }
|
||||
TypeSourceInfo *getTypeSourceInfo() const {
|
||||
return TypeAndInitForm.getPointer();
|
||||
}
|
||||
|
||||
/// Retrieve the location of the left parentheses ('(') that
|
||||
/// precedes the argument list.
|
||||
|
|
@ -3553,7 +3563,7 @@ public:
|
|||
/// Determine whether this expression models list-initialization.
|
||||
/// If so, there will be exactly one subexpression, which will be
|
||||
/// an InitListExpr.
|
||||
bool isListInitialization() const { return LParenLoc.isInvalid(); }
|
||||
bool isListInitialization() const { return TypeAndInitForm.getInt(); }
|
||||
|
||||
/// Retrieve the number of arguments.
|
||||
unsigned getNumArgs() const { return CXXUnresolvedConstructExprBits.NumArgs; }
|
||||
|
|
|
|||
|
|
@ -80,12 +80,6 @@ public:
|
|||
ImplicitConceptSpecializationDecl *SpecDecl,
|
||||
const ConstraintSatisfaction *Satisfaction);
|
||||
|
||||
static ConceptSpecializationExpr *
|
||||
Create(const ASTContext &C, ConceptDecl *NamedConcept,
|
||||
ImplicitConceptSpecializationDecl *SpecDecl,
|
||||
const ConstraintSatisfaction *Satisfaction, bool Dependent,
|
||||
bool ContainsUnexpandedParameterPack);
|
||||
|
||||
static ConceptSpecializationExpr *
|
||||
Create(const ASTContext &C, ConceptDecl *NamedConcept,
|
||||
const ASTTemplateArgumentListInfo *ArgsAsWritten,
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ public:
|
|||
/// \param Source the external AST source.
|
||||
///
|
||||
/// \returns a pointer to the AST node.
|
||||
T* get(ExternalASTSource *Source) const {
|
||||
T *get(ExternalASTSource *Source) const {
|
||||
if (isOffset()) {
|
||||
assert(Source &&
|
||||
"Cannot deserialize a lazy pointer without an AST source");
|
||||
|
|
@ -379,6 +379,14 @@ public:
|
|||
}
|
||||
return reinterpret_cast<T*>(Ptr);
|
||||
}
|
||||
|
||||
/// Retrieve the address of the AST node pointer. Deserializes the pointee if
|
||||
/// necessary.
|
||||
T **getAddressOfPointer(ExternalASTSource *Source) const {
|
||||
// Ensure the integer is in pointer form.
|
||||
(void)get(Source);
|
||||
return reinterpret_cast<T**>(&Ptr);
|
||||
}
|
||||
};
|
||||
|
||||
/// A lazy value (of type T) that is within an AST node of type Owner,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,8 @@ namespace detail {
|
|||
inline Expr *IgnoreExprNodesImpl(Expr *E) { return E; }
|
||||
template <typename FnTy, typename... FnTys>
|
||||
Expr *IgnoreExprNodesImpl(Expr *E, FnTy &&Fn, FnTys &&... Fns) {
|
||||
return IgnoreExprNodesImpl(Fn(E), std::forward<FnTys>(Fns)...);
|
||||
return IgnoreExprNodesImpl(std::forward<FnTy>(Fn)(E),
|
||||
std::forward<FnTys>(Fns)...);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
|
|
@ -165,6 +166,11 @@ inline Expr *IgnoreParensSingleStep(Expr *E) {
|
|||
return CE->getChosenSubExpr();
|
||||
}
|
||||
|
||||
else if (auto *PE = dyn_cast<PredefinedExpr>(E)) {
|
||||
if (PE->isTransparent() && PE->getFunctionName())
|
||||
return PE->getFunctionName();
|
||||
}
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -140,7 +140,8 @@ public:
|
|||
unsigned ManglingNumber,
|
||||
raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTIName(QualType T, raw_ostream &) = 0;
|
||||
virtual void mangleCXXRTTIName(QualType T, raw_ostream &,
|
||||
bool NormalizeIntegers = false) = 0;
|
||||
virtual void mangleStringLiteral(const StringLiteral *SL, raw_ostream &) = 0;
|
||||
virtual void mangleMSGuidDecl(const MSGuidDecl *GD, raw_ostream&);
|
||||
|
||||
|
|
@ -177,7 +178,8 @@ public:
|
|||
/// or type uniquing.
|
||||
/// TODO: Extend this to internal types by generating names that are unique
|
||||
/// across translation units so it can be used with LTO.
|
||||
virtual void mangleTypeName(QualType T, raw_ostream &) = 0;
|
||||
virtual void mangleTypeName(QualType T, raw_ostream &,
|
||||
bool NormalizeIntegers = false) = 0;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ class VarDecl;
|
|||
/// Keeps track of the mangled names of lambda expressions and block
|
||||
/// literals within a particular context.
|
||||
class MangleNumberingContext {
|
||||
// The index of the next lambda we encounter in this context.
|
||||
unsigned LambdaIndex = 0;
|
||||
|
||||
public:
|
||||
virtual ~MangleNumberingContext() {}
|
||||
|
||||
|
|
@ -55,6 +58,11 @@ public:
|
|||
/// given call operator within the device context. No device number is
|
||||
/// assigned if there's no device numbering context is associated.
|
||||
virtual unsigned getDeviceManglingNumber(const CXXMethodDecl *) { return 0; }
|
||||
|
||||
// Retrieve the index of the next lambda appearing in this context, which is
|
||||
// used for deduplicating lambdas across modules. Note that this is a simple
|
||||
// sequence number and is not ABI-dependent.
|
||||
unsigned getNextLambdaIndex() { return LambdaIndex++; }
|
||||
};
|
||||
|
||||
} // end namespace clang
|
||||
|
|
|
|||
|
|
@ -9046,6 +9046,132 @@ public:
|
|||
Expr *getSize() const { return getStmtAs<Expr>(); }
|
||||
};
|
||||
|
||||
/// This represents the 'doacross' clause for the '#pragma omp ordered'
|
||||
/// directive.
|
||||
///
|
||||
/// \code
|
||||
/// #pragma omp ordered doacross(sink: i-1, j-1)
|
||||
/// \endcode
|
||||
/// In this example directive '#pragma omp ordered' with clause 'doacross' with
|
||||
/// a dependence-type 'sink' and loop-iteration vector expressions i-1 and j-1.
|
||||
class OMPDoacrossClause final
|
||||
: public OMPVarListClause<OMPDoacrossClause>,
|
||||
private llvm::TrailingObjects<OMPDoacrossClause, Expr *> {
|
||||
friend class OMPClauseReader;
|
||||
friend OMPVarListClause;
|
||||
friend TrailingObjects;
|
||||
|
||||
/// Dependence type (sink or source).
|
||||
OpenMPDoacrossClauseModifier DepType = OMPC_DOACROSS_unknown;
|
||||
|
||||
/// Dependence type location.
|
||||
SourceLocation DepLoc;
|
||||
|
||||
/// Colon location.
|
||||
SourceLocation ColonLoc;
|
||||
|
||||
/// Number of loops, associated with the doacross clause.
|
||||
unsigned NumLoops = 0;
|
||||
|
||||
/// Build clause with number of expressions \a N.
|
||||
///
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param N Number of expressions in the clause.
|
||||
/// \param NumLoops Number of loops associated with the clause.
|
||||
OMPDoacrossClause(SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc, unsigned N, unsigned NumLoops)
|
||||
: OMPVarListClause<OMPDoacrossClause>(llvm::omp::OMPC_doacross, StartLoc,
|
||||
LParenLoc, EndLoc, N),
|
||||
NumLoops(NumLoops) {}
|
||||
|
||||
/// Build an empty clause.
|
||||
///
|
||||
/// \param N Number of expressions in the clause.
|
||||
/// \param NumLoops Number of loops associated with the clause.
|
||||
explicit OMPDoacrossClause(unsigned N, unsigned NumLoops)
|
||||
: OMPVarListClause<OMPDoacrossClause>(llvm::omp::OMPC_doacross,
|
||||
SourceLocation(), SourceLocation(),
|
||||
SourceLocation(), N),
|
||||
NumLoops(NumLoops) {}
|
||||
|
||||
/// Set dependence type.
|
||||
void setDependenceType(OpenMPDoacrossClauseModifier M) { DepType = M; }
|
||||
|
||||
/// Set dependence type location.
|
||||
void setDependenceLoc(SourceLocation Loc) { DepLoc = Loc; }
|
||||
|
||||
/// Set colon location.
|
||||
void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; }
|
||||
|
||||
public:
|
||||
/// Creates clause with a list of expressions \a VL.
|
||||
///
|
||||
/// \param C AST context.
|
||||
/// \param StartLoc Starting location of the clause.
|
||||
/// \param LParenLoc Location of '('.
|
||||
/// \param EndLoc Ending location of the clause.
|
||||
/// \param DepType The dependence type.
|
||||
/// \param DepLoc Location of the dependence type.
|
||||
/// \param ColonLoc Location of ':'.
|
||||
/// \param VL List of references to the expressions.
|
||||
/// \param NumLoops Number of loops that associated with the clause.
|
||||
static OMPDoacrossClause *
|
||||
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
|
||||
SourceLocation EndLoc, OpenMPDoacrossClauseModifier DepType,
|
||||
SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL,
|
||||
unsigned NumLoops);
|
||||
|
||||
/// Creates an empty clause with \a N expressions.
|
||||
///
|
||||
/// \param C AST context.
|
||||
/// \param N The number of expressions.
|
||||
/// \param NumLoops Number of loops that is associated with this clause.
|
||||
static OMPDoacrossClause *CreateEmpty(const ASTContext &C, unsigned N,
|
||||
unsigned NumLoops);
|
||||
|
||||
/// Get dependence type.
|
||||
OpenMPDoacrossClauseModifier getDependenceType() const { return DepType; }
|
||||
|
||||
/// Get dependence type location.
|
||||
SourceLocation getDependenceLoc() const { return DepLoc; }
|
||||
|
||||
/// Get colon location.
|
||||
SourceLocation getColonLoc() const { return ColonLoc; }
|
||||
|
||||
/// Get number of loops associated with the clause.
|
||||
unsigned getNumLoops() const { return NumLoops; }
|
||||
|
||||
/// Set the loop data.
|
||||
void setLoopData(unsigned NumLoop, Expr *Cnt);
|
||||
|
||||
/// Get the loop data.
|
||||
Expr *getLoopData(unsigned NumLoop);
|
||||
const Expr *getLoopData(unsigned NumLoop) const;
|
||||
|
||||
child_range children() {
|
||||
return child_range(reinterpret_cast<Stmt **>(varlist_begin()),
|
||||
reinterpret_cast<Stmt **>(varlist_end()));
|
||||
}
|
||||
|
||||
const_child_range children() const {
|
||||
auto Children = const_cast<OMPDoacrossClause *>(this)->children();
|
||||
return const_child_range(Children.begin(), Children.end());
|
||||
}
|
||||
|
||||
child_range used_children() {
|
||||
return child_range(child_iterator(), child_iterator());
|
||||
}
|
||||
const_child_range used_children() const {
|
||||
return const_child_range(const_child_iterator(), const_child_iterator());
|
||||
}
|
||||
|
||||
static bool classof(const OMPClause *T) {
|
||||
return T->getClauseKind() == llvm::omp::OMPC_doacross;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_AST_OPENMPCLAUSE_H
|
||||
|
|
|
|||
|
|
@ -362,8 +362,8 @@ CAST_OPERATION(IntToOCLSampler)
|
|||
|
||||
//===- Binary Operations -------------------------------------------------===//
|
||||
// Operators listed in order of precedence.
|
||||
// Note that additions to this should also update the StmtVisitor class and
|
||||
// BinaryOperator::getOverloadedOperator.
|
||||
// Note that additions to this should also update the StmtVisitor class,
|
||||
// BinaryOperator::getOverloadedOperator and CXBinaryOperatorKind enum.
|
||||
|
||||
// [C++ 5.5] Pointer-to-member operators.
|
||||
BINARY_OPERATION(PtrMemD, ".*")
|
||||
|
|
@ -415,8 +415,8 @@ BINARY_OPERATION(Comma, ",")
|
|||
|
||||
|
||||
//===- Unary Operations ---------------------------------------------------===//
|
||||
// Note that additions to this should also update the StmtVisitor class and
|
||||
// UnaryOperator::getOverloadedOperator.
|
||||
// Note that additions to this should also update the StmtVisitor class,
|
||||
// UnaryOperator::getOverloadedOperator and CXUnaryOperatorKind enum.
|
||||
|
||||
// [C99 6.5.2.4] Postfix increment and decrement
|
||||
UNARY_OPERATION(PostInc, "++")
|
||||
|
|
|
|||
|
|
@ -60,14 +60,15 @@ struct PrintingPolicy {
|
|||
: Indentation(2), SuppressSpecifiers(false),
|
||||
SuppressTagKeyword(LO.CPlusPlus), IncludeTagDefinition(false),
|
||||
SuppressScope(false), SuppressUnwrittenScope(false),
|
||||
SuppressInlineNamespace(true), SuppressInitializers(false),
|
||||
ConstantArraySizeAsWritten(false), AnonymousTagLocations(true),
|
||||
SuppressStrongLifetime(false), SuppressLifetimeQualifiers(false),
|
||||
SuppressInlineNamespace(true), SuppressElaboration(false),
|
||||
SuppressInitializers(false), ConstantArraySizeAsWritten(false),
|
||||
AnonymousTagLocations(true), SuppressStrongLifetime(false),
|
||||
SuppressLifetimeQualifiers(false),
|
||||
SuppressTemplateArgsInCXXConstructors(false),
|
||||
SuppressDefaultTemplateArgs(true), Bool(LO.Bool),
|
||||
Nullptr(LO.CPlusPlus11 || LO.C2x), NullptrTypeInNamespace(LO.CPlusPlus),
|
||||
Restrict(LO.C99), Alignof(LO.CPlusPlus11),
|
||||
UnderscoreAlignof(LO.C11), UseVoidForZeroParams(!LO.CPlusPlus),
|
||||
Restrict(LO.C99), Alignof(LO.CPlusPlus11), UnderscoreAlignof(LO.C11),
|
||||
UseVoidForZeroParams(!LO.CPlusPlus),
|
||||
SplitTemplateClosers(!LO.CPlusPlus11), TerseOutput(false),
|
||||
PolishForDeclaration(false), Half(LO.Half),
|
||||
MSWChar(LO.MicrosoftExt && !LO.WChar), IncludeNewlines(true),
|
||||
|
|
@ -139,6 +140,10 @@ struct PrintingPolicy {
|
|||
/// removed.
|
||||
unsigned SuppressInlineNamespace : 1;
|
||||
|
||||
/// Ignore qualifiers and tag keywords as specified by elaborated type sugar,
|
||||
/// instead letting the underlying type print as normal.
|
||||
unsigned SuppressElaboration : 1;
|
||||
|
||||
/// Suppress printing of variable initializers.
|
||||
///
|
||||
/// This flag is used when printing the loop variable in a for-range
|
||||
|
|
|
|||
|
|
@ -450,10 +450,13 @@ let Class = PropertyTypeCase<APValue, "LValue"> in {
|
|||
lvalueBase ? lvalueBase.dyn_cast<const Expr *>() : nullptr;
|
||||
bool lvalueBaseIsExpr = (bool) expr;
|
||||
bool lvalueBaseIsTypeInfo = lvalueBase.is<TypeInfoLValue>();
|
||||
bool lvalueBaseIsDynamicAlloc = lvalueBase.is<DynamicAllocLValue>();
|
||||
QualType elemTy;
|
||||
if (lvalueBase) {
|
||||
if (lvalueBaseIsTypeInfo) {
|
||||
elemTy = lvalueBase.getTypeInfoType();
|
||||
} else if (lvalueBaseIsDynamicAlloc) {
|
||||
elemTy = lvalueBase.getDynamicAllocType();
|
||||
} else if (lvalueBaseIsExpr) {
|
||||
elemTy = expr->getType();
|
||||
} else {
|
||||
|
|
@ -473,6 +476,9 @@ let Class = PropertyTypeCase<APValue, "LValue"> in {
|
|||
def : Property<"isTypeInfo", Bool> {
|
||||
let Read = [{ lvalueBaseIsTypeInfo }];
|
||||
}
|
||||
def : Property<"isDynamicAlloc", Bool> {
|
||||
let Read = [{ lvalueBaseIsDynamicAlloc }];
|
||||
}
|
||||
def : Property<"hasBase", Bool> {
|
||||
let Read = [{ static_cast<bool>(lvalueBase) }];
|
||||
}
|
||||
|
|
@ -485,9 +491,17 @@ let Class = PropertyTypeCase<APValue, "LValue"> in {
|
|||
QualType(node.getLValueBase().get<TypeInfoLValue>().getType(), 0)
|
||||
}];
|
||||
}
|
||||
def : Property<"dynamicAlloc", UInt32> {
|
||||
let Conditional = [{ hasBase && isDynamicAlloc }];
|
||||
let Read = [{ node.getLValueBase().get<DynamicAllocLValue>().getIndex() }];
|
||||
}
|
||||
def : Property<"type", QualType> {
|
||||
let Conditional = [{ hasBase && isTypeInfo }];
|
||||
let Read = [{ node.getLValueBase().getTypeInfoType() }];
|
||||
let Conditional = [{ hasBase && (isTypeInfo || isDynamicAlloc) }];
|
||||
let Read = [{
|
||||
isTypeInfo
|
||||
? node.getLValueBase().getTypeInfoType()
|
||||
: node.getLValueBase().getDynamicAllocType()
|
||||
}];
|
||||
}
|
||||
def : Property<"callIndex", UInt32> {
|
||||
let Conditional = [{ hasBase && !isTypeInfo }];
|
||||
|
|
@ -502,7 +516,7 @@ let Class = PropertyTypeCase<APValue, "LValue"> in {
|
|||
let Read = [{ const_cast<Expr *>(expr) }];
|
||||
}
|
||||
def : Property<"decl", DeclRef> {
|
||||
let Conditional = [{ hasBase && !isTypeInfo && !isExpr }];
|
||||
let Conditional = [{ hasBase && !isTypeInfo && !isDynamicAlloc && !isExpr }];
|
||||
let Read = [{ lvalueBase.get<const ValueDecl *>() }];
|
||||
}
|
||||
def : Property<"offsetQuantity", UInt32> {
|
||||
|
|
@ -521,6 +535,9 @@ let Class = PropertyTypeCase<APValue, "LValue"> in {
|
|||
if (isTypeInfo) {
|
||||
base = APValue::LValueBase::getTypeInfo(
|
||||
TypeInfoLValue(typeInfo->getTypePtr()), *type);
|
||||
} else if (isDynamicAlloc) {
|
||||
base = APValue::LValueBase::getDynamicAlloc(
|
||||
DynamicAllocLValue(*dynamicAlloc), *type);
|
||||
} else if (isExpr) {
|
||||
base = APValue::LValueBase(cast<Expr>(*stmt),
|
||||
*callIndex, *version);
|
||||
|
|
@ -745,8 +762,11 @@ let Class = PropertyTypeCase<TemplateArgument, "Type"> in {
|
|||
def : Property<"type", QualType> {
|
||||
let Read = [{ node.getAsType() }];
|
||||
}
|
||||
def : Property<"isDefaulted", Bool> {
|
||||
let Read = [{ node.getIsDefaulted() }];
|
||||
}
|
||||
def : Creator<[{
|
||||
return TemplateArgument(type);
|
||||
return TemplateArgument(type, /* isNullPtr */ false, isDefaulted);
|
||||
}]>;
|
||||
}
|
||||
let Class = PropertyTypeCase<TemplateArgument, "Declaration"> in {
|
||||
|
|
@ -756,16 +776,22 @@ let Class = PropertyTypeCase<TemplateArgument, "Declaration"> in {
|
|||
def : Property<"parameterType", QualType> {
|
||||
let Read = [{ node.getParamTypeForDecl() }];
|
||||
}
|
||||
def : Property<"isDefaulted", Bool> {
|
||||
let Read = [{ node.getIsDefaulted() }];
|
||||
}
|
||||
def : Creator<[{
|
||||
return TemplateArgument(declaration, parameterType);
|
||||
return TemplateArgument(declaration, parameterType, isDefaulted);
|
||||
}]>;
|
||||
}
|
||||
let Class = PropertyTypeCase<TemplateArgument, "NullPtr"> in {
|
||||
def : Property<"type", QualType> {
|
||||
let Read = [{ node.getNullPtrType() }];
|
||||
}
|
||||
def : Property<"isDefaulted", Bool> {
|
||||
let Read = [{ node.getIsDefaulted() }];
|
||||
}
|
||||
def : Creator<[{
|
||||
return TemplateArgument(type, /*nullptr*/ true);
|
||||
return TemplateArgument(type, /*nullptr*/ true, isDefaulted);
|
||||
}]>;
|
||||
}
|
||||
let Class = PropertyTypeCase<TemplateArgument, "Integral"> in {
|
||||
|
|
@ -775,16 +801,22 @@ let Class = PropertyTypeCase<TemplateArgument, "Integral"> in {
|
|||
def : Property<"type", QualType> {
|
||||
let Read = [{ node.getIntegralType() }];
|
||||
}
|
||||
def : Property<"isDefaulted", Bool> {
|
||||
let Read = [{ node.getIsDefaulted() }];
|
||||
}
|
||||
def : Creator<[{
|
||||
return TemplateArgument(ctx, value, type);
|
||||
return TemplateArgument(ctx, value, type, isDefaulted);
|
||||
}]>;
|
||||
}
|
||||
let Class = PropertyTypeCase<TemplateArgument, "Template"> in {
|
||||
def : Property<"name", TemplateName> {
|
||||
let Read = [{ node.getAsTemplateOrTemplatePattern() }];
|
||||
}
|
||||
def : Property<"isDefaulted", Bool> {
|
||||
let Read = [{ node.getIsDefaulted() }];
|
||||
}
|
||||
def : Creator<[{
|
||||
return TemplateArgument(name);
|
||||
return TemplateArgument(name, isDefaulted);
|
||||
}]>;
|
||||
}
|
||||
let Class = PropertyTypeCase<TemplateArgument, "TemplateExpansion"> in {
|
||||
|
|
@ -798,19 +830,25 @@ let Class = PropertyTypeCase<TemplateArgument, "TemplateExpansion"> in {
|
|||
[](unsigned i) { return uint32_t(i); })
|
||||
}];
|
||||
}
|
||||
def : Property<"isDefaulted", Bool> {
|
||||
let Read = [{ node.getIsDefaulted() }];
|
||||
}
|
||||
def : Creator<[{
|
||||
auto numExpansionsUnsigned = llvm::transformOptional(
|
||||
numExpansions, [](uint32_t i) { return unsigned(i); });
|
||||
|
||||
return TemplateArgument(name, numExpansionsUnsigned);
|
||||
return TemplateArgument(name, numExpansionsUnsigned, isDefaulted);
|
||||
}]>;
|
||||
}
|
||||
let Class = PropertyTypeCase<TemplateArgument, "Expression"> in {
|
||||
def : Property<"expression", ExprRef> {
|
||||
let Read = [{ node.getAsExpr() }];
|
||||
}
|
||||
def : Property<"isDefaulted", Bool> {
|
||||
let Read = [{ node.getIsDefaulted() }];
|
||||
}
|
||||
def : Creator<[{
|
||||
return TemplateArgument(expression);
|
||||
return TemplateArgument(expression, isDefaulted);
|
||||
}]>;
|
||||
}
|
||||
let Class = PropertyTypeCase<TemplateArgument, "Pack"> in {
|
||||
|
|
|
|||
|
|
@ -115,6 +115,17 @@ public:
|
|||
return extractBriefText(Context);
|
||||
}
|
||||
|
||||
bool hasUnsupportedSplice(const SourceManager &SourceMgr) const {
|
||||
if (!isInvalid())
|
||||
return false;
|
||||
StringRef Text = getRawText(SourceMgr);
|
||||
if (Text.size() < 6 || Text[0] != '/')
|
||||
return false;
|
||||
if (Text[1] == '*')
|
||||
return Text[Text.size() - 1] != '/' || Text[Text.size() - 2] != '*';
|
||||
return Text[1] != '/';
|
||||
}
|
||||
|
||||
/// Returns sanitized comment text, suitable for presentation in editor UIs.
|
||||
/// E.g. will transform:
|
||||
/// // This is a long multiline comment.
|
||||
|
|
@ -162,7 +173,7 @@ private:
|
|||
SourceRange Range;
|
||||
|
||||
mutable StringRef RawText;
|
||||
mutable const char *BriefText;
|
||||
mutable const char *BriefText = nullptr;
|
||||
|
||||
mutable bool RawTextValid : 1; ///< True if RawText is valid
|
||||
mutable bool BriefTextValid : 1; ///< True if BriefText is valid
|
||||
|
|
|
|||
|
|
@ -2553,7 +2553,11 @@ bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(
|
|||
// are interleaved. We also need to watch out for null types (default
|
||||
// generic associations).
|
||||
DEF_TRAVERSE_STMT(GenericSelectionExpr, {
|
||||
TRY_TO(TraverseStmt(S->getControllingExpr()));
|
||||
if (S->isExprPredicate())
|
||||
TRY_TO(TraverseStmt(S->getControllingExpr()));
|
||||
else
|
||||
TRY_TO(TraverseTypeLoc(S->getControllingType()->getTypeLoc()));
|
||||
|
||||
for (const GenericSelectionExpr::Association Assoc : S->associations()) {
|
||||
if (TypeSourceInfo *TSI = Assoc.getTypeSourceInfo())
|
||||
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));
|
||||
|
|
@ -2723,7 +2727,11 @@ DEF_TRAVERSE_STMT(CXXDefaultArgExpr, {
|
|||
TRY_TO(TraverseStmt(S->getExpr()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXDefaultInitExpr, {})
|
||||
DEF_TRAVERSE_STMT(CXXDefaultInitExpr, {
|
||||
if (getDerived().shouldVisitImplicitCode())
|
||||
TRY_TO(TraverseStmt(S->getExpr()));
|
||||
})
|
||||
|
||||
DEF_TRAVERSE_STMT(CXXDeleteExpr, {})
|
||||
DEF_TRAVERSE_STMT(ExprWithCleanups, {})
|
||||
DEF_TRAVERSE_STMT(CXXInheritedCtorInitExpr, {})
|
||||
|
|
@ -3860,6 +3868,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPXDynCGroupMemClause(
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool RecursiveASTVisitor<Derived>::VisitOMPDoacrossClause(
|
||||
OMPDoacrossClause *C) {
|
||||
TRY_TO(VisitOMPClauseList(C));
|
||||
return true;
|
||||
}
|
||||
|
||||
// FIXME: look at the following tricky-seeming exprs to see if we
|
||||
// need to recurse on anything. These are ones that have methods
|
||||
// returning decls or qualtypes or nestednamespecifier -- though I'm
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ public:
|
|||
class redecl_iterator {
|
||||
/// Current - The current declaration.
|
||||
decl_type *Current = nullptr;
|
||||
decl_type *Starter;
|
||||
decl_type *Starter = nullptr;
|
||||
bool PassedFirst = false;
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -364,6 +364,10 @@ protected:
|
|||
/// for the predefined identifier.
|
||||
unsigned HasFunctionName : 1;
|
||||
|
||||
/// True if this PredefinedExpr should be treated as a StringLiteral (for
|
||||
/// MSVC compatibility).
|
||||
unsigned IsTransparent : 1;
|
||||
|
||||
/// The location of this PredefinedExpr.
|
||||
SourceLocation Loc;
|
||||
};
|
||||
|
|
@ -380,6 +384,7 @@ protected:
|
|||
unsigned HadMultipleCandidates : 1;
|
||||
unsigned RefersToEnclosingVariableOrCapture : 1;
|
||||
unsigned NonOdrUseReason : 2;
|
||||
unsigned IsImmediateEscalating : 1;
|
||||
|
||||
/// The location of the declaration name itself.
|
||||
SourceLocation Loc;
|
||||
|
|
@ -588,10 +593,8 @@ protected:
|
|||
|
||||
unsigned : NumExprBits;
|
||||
|
||||
// These don't need to be particularly wide, because they're
|
||||
// strictly limited by the forms of expressions we permit.
|
||||
unsigned NumSubExprs : 8;
|
||||
unsigned ResultIndex : 32 - 8 - NumExprBits;
|
||||
unsigned NumSubExprs : 16;
|
||||
unsigned ResultIndex : 16;
|
||||
};
|
||||
|
||||
class SourceLocExprBitfields {
|
||||
|
|
@ -823,6 +826,7 @@ protected:
|
|||
unsigned StdInitListInitialization : 1;
|
||||
unsigned ZeroInitialization : 1;
|
||||
unsigned ConstructionKind : 3;
|
||||
unsigned IsImmediateEscalating : 1;
|
||||
|
||||
SourceLocation Loc;
|
||||
};
|
||||
|
|
@ -978,7 +982,7 @@ protected:
|
|||
SourceLocation RequiresKWLoc;
|
||||
};
|
||||
|
||||
//===--- C++ Coroutines TS bitfields classes ---===//
|
||||
//===--- C++ Coroutines bitfields classes ---===//
|
||||
|
||||
class CoawaitExprBitfields {
|
||||
friend class CoawaitExpr;
|
||||
|
|
@ -1082,7 +1086,7 @@ protected:
|
|||
LambdaExprBitfields LambdaExprBits;
|
||||
RequiresExprBitfields RequiresExprBits;
|
||||
|
||||
// C++ Coroutines TS expressions
|
||||
// C++ Coroutines expressions
|
||||
CoawaitExprBitfields CoawaitBits;
|
||||
|
||||
// Obj-C Expressions
|
||||
|
|
@ -1291,8 +1295,13 @@ public:
|
|||
/// parameters are identified by index/level rather than their
|
||||
/// declaration pointers) or the exact representation of the statement as
|
||||
/// written in the source.
|
||||
/// \param ProfileLambdaExpr whether or not to profile lambda expressions.
|
||||
/// When false, the lambda expressions are never considered to be equal to
|
||||
/// other lambda expressions. When true, the lambda expressions with the same
|
||||
/// implementation will be considered to be the same. ProfileLambdaExpr should
|
||||
/// only be true when we try to merge two declarations within modules.
|
||||
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
|
||||
bool Canonical) const;
|
||||
bool Canonical, bool ProfileLambdaExpr = false) const;
|
||||
|
||||
/// Calculate a unique representation for a statement that is
|
||||
/// stable across compiler invocations.
|
||||
|
|
@ -2092,6 +2101,11 @@ public:
|
|||
: nullptr;
|
||||
}
|
||||
|
||||
void setConditionVariableDeclStmt(DeclStmt *CondVar) {
|
||||
assert(hasVarStorage());
|
||||
getTrailingObjects<Stmt *>()[varOffset()] = CondVar;
|
||||
}
|
||||
|
||||
Stmt *getInit() {
|
||||
return hasInitStorage() ? getTrailingObjects<Stmt *>()[initOffset()]
|
||||
: nullptr;
|
||||
|
|
@ -2324,6 +2338,11 @@ public:
|
|||
: nullptr;
|
||||
}
|
||||
|
||||
void setConditionVariableDeclStmt(DeclStmt *CondVar) {
|
||||
assert(hasVarStorage());
|
||||
getTrailingObjects<Stmt *>()[varOffset()] = CondVar;
|
||||
}
|
||||
|
||||
SwitchCase *getSwitchCaseList() { return FirstCase; }
|
||||
const SwitchCase *getSwitchCaseList() const { return FirstCase; }
|
||||
void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; }
|
||||
|
|
@ -2487,6 +2506,11 @@ public:
|
|||
: nullptr;
|
||||
}
|
||||
|
||||
void setConditionVariableDeclStmt(DeclStmt *CondVar) {
|
||||
assert(hasVarStorage());
|
||||
getTrailingObjects<Stmt *>()[varOffset()] = CondVar;
|
||||
}
|
||||
|
||||
SourceLocation getWhileLoc() const { return WhileStmtBits.WhileLoc; }
|
||||
void setWhileLoc(SourceLocation L) { WhileStmtBits.WhileLoc = L; }
|
||||
|
||||
|
|
@ -2576,6 +2600,8 @@ public:
|
|||
/// the init/cond/inc parts of the ForStmt will be null if they were not
|
||||
/// specified in the source.
|
||||
class ForStmt : public Stmt {
|
||||
friend class ASTStmtReader;
|
||||
|
||||
enum { INIT, CONDVAR, COND, INC, BODY, END_EXPR };
|
||||
Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt.
|
||||
SourceLocation LParenLoc, RParenLoc;
|
||||
|
|
@ -2603,10 +2629,18 @@ public:
|
|||
|
||||
/// If this ForStmt has a condition variable, return the faux DeclStmt
|
||||
/// associated with the creation of that condition variable.
|
||||
DeclStmt *getConditionVariableDeclStmt() {
|
||||
return reinterpret_cast<DeclStmt*>(SubExprs[CONDVAR]);
|
||||
}
|
||||
|
||||
const DeclStmt *getConditionVariableDeclStmt() const {
|
||||
return reinterpret_cast<DeclStmt*>(SubExprs[CONDVAR]);
|
||||
}
|
||||
|
||||
void setConditionVariableDeclStmt(DeclStmt *CondVar) {
|
||||
SubExprs[CONDVAR] = CondVar;
|
||||
}
|
||||
|
||||
Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); }
|
||||
Expr *getInc() { return reinterpret_cast<Expr*>(SubExprs[INC]); }
|
||||
Stmt *getBody() { return SubExprs[BODY]; }
|
||||
|
|
@ -3558,8 +3592,11 @@ public:
|
|||
llvm::PointerIntPair<VarDecl *, 2, VariableCaptureKind> VarAndKind;
|
||||
SourceLocation Loc;
|
||||
|
||||
Capture() = default;
|
||||
|
||||
public:
|
||||
friend class ASTStmtReader;
|
||||
friend class CapturedStmt;
|
||||
|
||||
/// Create a new capture.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -75,7 +75,8 @@ class CXXTryStmt final : public Stmt,
|
|||
unsigned NumHandlers;
|
||||
size_t numTrailingObjects(OverloadToken<Stmt *>) const { return NumHandlers; }
|
||||
|
||||
CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, ArrayRef<Stmt*> handlers);
|
||||
CXXTryStmt(SourceLocation tryLoc, CompoundStmt *tryBlock,
|
||||
ArrayRef<Stmt *> handlers);
|
||||
CXXTryStmt(EmptyShell Empty, unsigned numHandlers)
|
||||
: Stmt(CXXTryStmtClass), NumHandlers(numHandlers) { }
|
||||
|
||||
|
|
@ -84,7 +85,7 @@ class CXXTryStmt final : public Stmt,
|
|||
|
||||
public:
|
||||
static CXXTryStmt *Create(const ASTContext &C, SourceLocation tryLoc,
|
||||
Stmt *tryBlock, ArrayRef<Stmt*> handlers);
|
||||
CompoundStmt *tryBlock, ArrayRef<Stmt *> handlers);
|
||||
|
||||
static CXXTryStmt *Create(const ASTContext &C, EmptyShell Empty,
|
||||
unsigned numHandlers);
|
||||
|
|
@ -326,6 +327,7 @@ class CoroutineBodyStmt final
|
|||
OnFallthrough, ///< Handler for control flow falling off the body.
|
||||
Allocate, ///< Coroutine frame memory allocation.
|
||||
Deallocate, ///< Coroutine frame memory deallocation.
|
||||
ResultDecl, ///< Declaration holding the result of get_return_object.
|
||||
ReturnValue, ///< Return value for thunk function: p.get_return_object().
|
||||
ReturnStmt, ///< Return statement for the thunk function.
|
||||
ReturnStmtOnAllocFailure, ///< Return statement if allocation failed.
|
||||
|
|
@ -352,6 +354,7 @@ public:
|
|||
Stmt *OnFallthrough = nullptr;
|
||||
Expr *Allocate = nullptr;
|
||||
Expr *Deallocate = nullptr;
|
||||
Stmt *ResultDecl = nullptr;
|
||||
Expr *ReturnValue = nullptr;
|
||||
Stmt *ReturnStmt = nullptr;
|
||||
Stmt *ReturnStmtOnAllocFailure = nullptr;
|
||||
|
|
@ -372,9 +375,10 @@ public:
|
|||
}
|
||||
|
||||
/// Retrieve the body of the coroutine as written. This will be either
|
||||
/// a CompoundStmt or a TryStmt.
|
||||
Stmt *getBody() const {
|
||||
return getStoredStmts()[SubStmt::Body];
|
||||
/// a CompoundStmt. If the coroutine is in function-try-block, we will
|
||||
/// wrap the CXXTryStmt into a CompoundStmt to keep consistency.
|
||||
CompoundStmt *getBody() const {
|
||||
return cast<CompoundStmt>(getStoredStmts()[SubStmt::Body]);
|
||||
}
|
||||
|
||||
Stmt *getPromiseDeclStmt() const {
|
||||
|
|
@ -404,13 +408,13 @@ public:
|
|||
Expr *getDeallocate() const {
|
||||
return cast_or_null<Expr>(getStoredStmts()[SubStmt::Deallocate]);
|
||||
}
|
||||
Stmt *getResultDecl() const { return getStoredStmts()[SubStmt::ResultDecl]; }
|
||||
Expr *getReturnValueInit() const {
|
||||
return cast<Expr>(getStoredStmts()[SubStmt::ReturnValue]);
|
||||
}
|
||||
Expr *getReturnValue() const {
|
||||
assert(getReturnStmt());
|
||||
auto *RS = cast<clang::ReturnStmt>(getReturnStmt());
|
||||
return RS->getRetValue();
|
||||
auto *RS = dyn_cast_or_null<clang::ReturnStmt>(getReturnStmt());
|
||||
return RS ? RS->getRetValue() : nullptr;
|
||||
}
|
||||
Stmt *getReturnStmt() const { return getStoredStmts()[SubStmt::ReturnStmt]; }
|
||||
Stmt *getReturnStmtOnAllocFailure() const {
|
||||
|
|
@ -439,6 +443,17 @@ public:
|
|||
NumParams);
|
||||
}
|
||||
|
||||
child_range childrenExclBody() {
|
||||
return child_range(getStoredStmts() + SubStmt::Body + 1,
|
||||
getStoredStmts() + SubStmt::FirstParamMove + NumParams);
|
||||
}
|
||||
|
||||
const_child_range childrenExclBody() const {
|
||||
return const_child_range(getStoredStmts() + SubStmt::Body + 1,
|
||||
getStoredStmts() + SubStmt::FirstParamMove +
|
||||
NumParams);
|
||||
}
|
||||
|
||||
static bool classof(const Stmt *T) {
|
||||
return T->getStmtClass() == CoroutineBodyStmtClass;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,12 +103,14 @@ private:
|
|||
/// The kind of template argument we're storing.
|
||||
|
||||
struct DA {
|
||||
unsigned Kind;
|
||||
unsigned Kind : 31;
|
||||
unsigned IsDefaulted : 1;
|
||||
void *QT;
|
||||
ValueDecl *D;
|
||||
};
|
||||
struct I {
|
||||
unsigned Kind;
|
||||
unsigned Kind : 31;
|
||||
unsigned IsDefaulted : 1;
|
||||
// We store a decomposed APSInt with the data allocated by ASTContext if
|
||||
// BitWidth > 64. The memory may be shared between multiple
|
||||
// TemplateArgument instances.
|
||||
|
|
@ -124,17 +126,20 @@ private:
|
|||
void *Type;
|
||||
};
|
||||
struct A {
|
||||
unsigned Kind;
|
||||
unsigned Kind : 31;
|
||||
unsigned IsDefaulted : 1;
|
||||
unsigned NumArgs;
|
||||
const TemplateArgument *Args;
|
||||
};
|
||||
struct TA {
|
||||
unsigned Kind;
|
||||
unsigned Kind : 31;
|
||||
unsigned IsDefaulted : 1;
|
||||
unsigned NumExpansions;
|
||||
void *Name;
|
||||
};
|
||||
struct TV {
|
||||
unsigned Kind;
|
||||
unsigned Kind : 31;
|
||||
unsigned IsDefaulted : 1;
|
||||
uintptr_t V;
|
||||
};
|
||||
union {
|
||||
|
|
@ -147,27 +152,31 @@ private:
|
|||
|
||||
public:
|
||||
/// Construct an empty, invalid template argument.
|
||||
constexpr TemplateArgument() : TypeOrValue({Null, 0}) {}
|
||||
constexpr TemplateArgument() : TypeOrValue({Null, 0, /* IsDefaulted */ 0}) {}
|
||||
|
||||
/// Construct a template type argument.
|
||||
TemplateArgument(QualType T, bool isNullPtr = false) {
|
||||
TemplateArgument(QualType T, bool isNullPtr = false,
|
||||
bool IsDefaulted = false) {
|
||||
TypeOrValue.Kind = isNullPtr ? NullPtr : Type;
|
||||
TypeOrValue.IsDefaulted = IsDefaulted;
|
||||
TypeOrValue.V = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
|
||||
}
|
||||
|
||||
/// Construct a template argument that refers to a
|
||||
/// declaration, which is either an external declaration or a
|
||||
/// template declaration.
|
||||
TemplateArgument(ValueDecl *D, QualType QT) {
|
||||
TemplateArgument(ValueDecl *D, QualType QT, bool IsDefaulted = false) {
|
||||
assert(D && "Expected decl");
|
||||
DeclArg.Kind = Declaration;
|
||||
DeclArg.IsDefaulted = IsDefaulted;
|
||||
DeclArg.QT = QT.getAsOpaquePtr();
|
||||
DeclArg.D = D;
|
||||
}
|
||||
|
||||
/// Construct an integral constant template argument. The memory to
|
||||
/// store the value is allocated with Ctx.
|
||||
TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type);
|
||||
TemplateArgument(ASTContext &Ctx, const llvm::APSInt &Value, QualType Type,
|
||||
bool IsDefaulted = false);
|
||||
|
||||
/// Construct an integral constant template argument with the same
|
||||
/// value as Other but a different type.
|
||||
|
|
@ -184,8 +193,12 @@ public:
|
|||
/// is taken.
|
||||
///
|
||||
/// \param Name The template name.
|
||||
TemplateArgument(TemplateName Name) {
|
||||
///
|
||||
/// \param IsDefaulted If 'true', implies that this TemplateArgument
|
||||
/// corresponds to a default template parameter
|
||||
TemplateArgument(TemplateName Name, bool IsDefaulted = false) {
|
||||
TemplateArg.Kind = Template;
|
||||
TemplateArg.IsDefaulted = IsDefaulted;
|
||||
TemplateArg.Name = Name.getAsVoidPointer();
|
||||
TemplateArg.NumExpansions = 0;
|
||||
}
|
||||
|
|
@ -201,8 +214,13 @@ public:
|
|||
///
|
||||
/// \param NumExpansions The number of expansions that will be generated by
|
||||
/// instantiating
|
||||
TemplateArgument(TemplateName Name, std::optional<unsigned> NumExpansions) {
|
||||
///
|
||||
/// \param IsDefaulted If 'true', implies that this TemplateArgument
|
||||
/// corresponds to a default template parameter
|
||||
TemplateArgument(TemplateName Name, std::optional<unsigned> NumExpansions,
|
||||
bool IsDefaulted = false) {
|
||||
TemplateArg.Kind = TemplateExpansion;
|
||||
TemplateArg.IsDefaulted = IsDefaulted;
|
||||
TemplateArg.Name = Name.getAsVoidPointer();
|
||||
if (NumExpansions)
|
||||
TemplateArg.NumExpansions = *NumExpansions + 1;
|
||||
|
|
@ -215,8 +233,9 @@ public:
|
|||
/// This form of template argument only occurs in template argument
|
||||
/// lists used for dependent types and for expression; it will not
|
||||
/// occur in a non-dependent, canonical template argument list.
|
||||
TemplateArgument(Expr *E) {
|
||||
TemplateArgument(Expr *E, bool IsDefaulted = false) {
|
||||
TypeOrValue.Kind = Expression;
|
||||
TypeOrValue.IsDefaulted = IsDefaulted;
|
||||
TypeOrValue.V = reinterpret_cast<uintptr_t>(E);
|
||||
}
|
||||
|
||||
|
|
@ -226,12 +245,11 @@ public:
|
|||
/// outlives the TemplateArgument itself.
|
||||
explicit TemplateArgument(ArrayRef<TemplateArgument> Args) {
|
||||
this->Args.Kind = Pack;
|
||||
this->Args.IsDefaulted = false;
|
||||
this->Args.Args = Args.data();
|
||||
this->Args.NumArgs = Args.size();
|
||||
}
|
||||
|
||||
TemplateArgument(TemplateName, bool) = delete;
|
||||
|
||||
static TemplateArgument getEmptyPack() {
|
||||
return TemplateArgument(std::nullopt);
|
||||
}
|
||||
|
|
@ -334,6 +352,14 @@ public:
|
|||
Integer.Type = T.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
/// Set to 'true' if this TemplateArgument corresponds to a
|
||||
/// default template parameter.
|
||||
void setIsDefaulted(bool v) { TypeOrValue.IsDefaulted = v; }
|
||||
|
||||
/// If returns 'true', this TemplateArgument corresponds to a
|
||||
/// default template parameter.
|
||||
bool getIsDefaulted() const { return (bool)TypeOrValue.IsDefaulted; }
|
||||
|
||||
/// If this is a non-type template argument, get its type. Otherwise,
|
||||
/// returns a null QualType.
|
||||
QualType getNonTypeTemplateArgumentType() const;
|
||||
|
|
|
|||
|
|
@ -351,9 +351,7 @@ public:
|
|||
/// error.
|
||||
void dump() const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
ID.AddPointer(Storage.getOpaqueValue());
|
||||
}
|
||||
void Profile(llvm::FoldingSetNodeID &ID);
|
||||
|
||||
/// Retrieve the template name as a void pointer.
|
||||
void *getAsVoidPointer() const { return Storage.getOpaqueValue(); }
|
||||
|
|
|
|||
|
|
@ -899,12 +899,24 @@ public:
|
|||
/// Return true if this is a trivially relocatable type.
|
||||
bool isTriviallyRelocatableType(const ASTContext &Context) const;
|
||||
|
||||
/// Return true if this is a trivially equality comparable type.
|
||||
bool isTriviallyEqualityComparableType(const ASTContext &Context) const;
|
||||
|
||||
/// Returns true if it is a class and it might be dynamic.
|
||||
bool mayBeDynamicClass() const;
|
||||
|
||||
/// Returns true if it is not a class or if the class might not be dynamic.
|
||||
bool mayBeNotDynamicClass() const;
|
||||
|
||||
/// Returns true if it is a WebAssembly Reference Type.
|
||||
bool isWebAssemblyReferenceType() const;
|
||||
|
||||
/// Returns true if it is a WebAssembly Externref Type.
|
||||
bool isWebAssemblyExternrefType() const;
|
||||
|
||||
/// Returns true if it is a WebAssembly Funcref Type.
|
||||
bool isWebAssemblyFuncrefType() const;
|
||||
|
||||
// Don't promise in the API that anything besides 'const' can be
|
||||
// easily added.
|
||||
|
||||
|
|
@ -945,7 +957,6 @@ public:
|
|||
void removeLocalConst();
|
||||
void removeLocalVolatile();
|
||||
void removeLocalRestrict();
|
||||
void removeLocalCVRQualifiers(unsigned Mask);
|
||||
|
||||
void removeLocalFastQualifiers() { Value.setInt(0); }
|
||||
void removeLocalFastQualifiers(unsigned Mask) {
|
||||
|
|
@ -1647,7 +1658,8 @@ protected:
|
|||
unsigned : NumTypeBits;
|
||||
|
||||
/// The kind (BuiltinType::Kind) of builtin type this is.
|
||||
unsigned Kind : 8;
|
||||
static constexpr unsigned NumOfBuiltinTypeBits = 9;
|
||||
unsigned Kind : NumOfBuiltinTypeBits;
|
||||
};
|
||||
|
||||
/// FunctionTypeBitfields store various bits belonging to FunctionProtoType.
|
||||
|
|
@ -1767,7 +1779,7 @@ protected:
|
|||
|
||||
/// The kind of vector, either a generic vector type or some
|
||||
/// target-specific vector type such as for AltiVec or Neon.
|
||||
unsigned VecKind : 3;
|
||||
unsigned VecKind : 4;
|
||||
/// The number of elements in the vector.
|
||||
uint32_t NumElements;
|
||||
};
|
||||
|
|
@ -2029,6 +2041,17 @@ public:
|
|||
/// Returns true for SVE scalable vector types.
|
||||
bool isSVESizelessBuiltinType() const;
|
||||
|
||||
/// Returns true for RVV scalable vector types.
|
||||
bool isRVVSizelessBuiltinType() const;
|
||||
|
||||
/// Check if this is a WebAssembly Externref Type.
|
||||
bool isWebAssemblyExternrefType() const;
|
||||
|
||||
/// Returns true if this is a WebAssembly table type: either an array of
|
||||
/// reference types, or a pointer to a reference type (which can only be
|
||||
/// created by array to pointer decay).
|
||||
bool isWebAssemblyTableType() const;
|
||||
|
||||
/// Determines if this is a sizeless type supported by the
|
||||
/// 'arm_sve_vector_bits' type attribute, which can be applied to a single
|
||||
/// SVE vector or predicate, excluding tuple types such as svint32x4_t.
|
||||
|
|
@ -2039,6 +2062,16 @@ public:
|
|||
/// 'arm_sve_vector_bits' type attribute as VectorType.
|
||||
QualType getSveEltType(const ASTContext &Ctx) const;
|
||||
|
||||
/// Determines if this is a sizeless type supported by the
|
||||
/// 'riscv_rvv_vector_bits' type attribute, which can be applied to a single
|
||||
/// RVV vector or mask.
|
||||
bool isRVVVLSBuiltinType() const;
|
||||
|
||||
/// Returns the representative type for the element of an RVV builtin type.
|
||||
/// This is used to represent fixed-length RVV vectors created with the
|
||||
/// 'riscv_rvv_vector_bits' type attribute as VectorType.
|
||||
QualType getRVVEltType(const ASTContext &Ctx) const;
|
||||
|
||||
/// Types are partitioned into 3 broad categories (C99 6.2.5p1):
|
||||
/// object types, function types, and incomplete types.
|
||||
|
||||
|
|
@ -2273,8 +2306,12 @@ public:
|
|||
/// Check if the type is the CUDA device builtin texture type.
|
||||
bool isCUDADeviceBuiltinTextureType() const;
|
||||
|
||||
bool isRVVType(unsigned ElementCount) const;
|
||||
|
||||
bool isRVVType() const;
|
||||
|
||||
bool isRVVType(unsigned Bitwidth, bool IsFloat) const;
|
||||
|
||||
/// Return the implicit lifetime for this type, which must not be dependent.
|
||||
Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const;
|
||||
|
||||
|
|
@ -2640,6 +2677,9 @@ public:
|
|||
// RVV Types
|
||||
#define RVV_TYPE(Name, Id, SingletonId) Id,
|
||||
#include "clang/Basic/RISCVVTypes.def"
|
||||
// WebAssembly reference types
|
||||
#define WASM_TYPE(Name, Id, SingletonId) Id,
|
||||
#include "clang/Basic/WebAssemblyReferenceTypes.def"
|
||||
// All other builtin types
|
||||
#define BUILTIN_TYPE(Id, SingletonId) Id,
|
||||
#define LAST_BUILTIN_TYPE(Id) LastKind = Id
|
||||
|
|
@ -2653,6 +2693,10 @@ private:
|
|||
: Type(Builtin, QualType(),
|
||||
K == Dependent ? TypeDependence::DependentInstantiation
|
||||
: TypeDependence::None) {
|
||||
static_assert(Kind::LastKind <
|
||||
(1 << BuiltinTypeBitfields::NumOfBuiltinTypeBits) &&
|
||||
"Defined builtin type exceeds the allocated space for serial "
|
||||
"numbering");
|
||||
BuiltinTypeBits.Kind = K;
|
||||
}
|
||||
|
||||
|
|
@ -2688,6 +2732,8 @@ public:
|
|||
|
||||
bool isSVEBool() const { return getKind() == Kind::SveBool; }
|
||||
|
||||
bool isSVECount() const { return getKind() == Kind::SveCount; }
|
||||
|
||||
/// Determines whether the given kind corresponds to a placeholder type.
|
||||
static bool isPlaceholderTypeKind(Kind K) {
|
||||
return K >= Overload;
|
||||
|
|
@ -3385,7 +3431,10 @@ public:
|
|||
SveFixedLengthDataVector,
|
||||
|
||||
/// is AArch64 SVE fixed-length predicate vector
|
||||
SveFixedLengthPredicateVector
|
||||
SveFixedLengthPredicateVector,
|
||||
|
||||
/// is RISC-V RVV fixed-length data vector
|
||||
RVVFixedLengthDataVector,
|
||||
};
|
||||
|
||||
protected:
|
||||
|
|
@ -3924,7 +3973,7 @@ public:
|
|||
/// The number of types in the exception specification.
|
||||
/// A whole unsigned is not needed here and according to
|
||||
/// [implimits] 8 bits would be enough here.
|
||||
unsigned NumExceptionType = 0;
|
||||
uint16_t NumExceptionType = 0;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
|
@ -4920,6 +4969,8 @@ public:
|
|||
|
||||
bool isMSTypeSpec() const;
|
||||
|
||||
bool isWebAssemblyFuncrefSpec() const;
|
||||
|
||||
bool isCallingConv() const;
|
||||
|
||||
std::optional<NullabilityKind> getImmediateNullability() const;
|
||||
|
|
@ -6608,7 +6659,7 @@ class alignas(8) TypeSourceInfo {
|
|||
|
||||
QualType Ty;
|
||||
|
||||
TypeSourceInfo(QualType ty) : Ty(ty) {}
|
||||
TypeSourceInfo(QualType ty, size_t DataSize); // implemented in TypeLoc.h
|
||||
|
||||
public:
|
||||
/// Return the type wrapped by this type source info.
|
||||
|
|
@ -6749,15 +6800,6 @@ inline void QualType::removeLocalVolatile() {
|
|||
removeLocalFastQualifiers(Qualifiers::Volatile);
|
||||
}
|
||||
|
||||
inline void QualType::removeLocalCVRQualifiers(unsigned Mask) {
|
||||
assert(!(Mask & ~Qualifiers::CVRMask) && "mask has non-CVR bits");
|
||||
static_assert((int)Qualifiers::CVRMask == (int)Qualifiers::FastMask,
|
||||
"Fast bits differ from CVR bits!");
|
||||
|
||||
// Fast path: we don't need to touch the slow qualifiers.
|
||||
removeLocalFastQualifiers(Mask);
|
||||
}
|
||||
|
||||
/// Check if this type has any address space qualifier.
|
||||
inline bool QualType::hasAddressSpace() const {
|
||||
return getQualifiers().hasAddressSpace();
|
||||
|
|
@ -7153,6 +7195,27 @@ inline bool Type::isRVVType() const {
|
|||
false; // end of boolean or operation.
|
||||
}
|
||||
|
||||
inline bool Type::isRVVType(unsigned ElementCount) const {
|
||||
bool Ret = false;
|
||||
#define RVV_VECTOR_TYPE(Name, Id, SingletonId, NumEls, ElBits, NF, IsSigned, \
|
||||
IsFP) \
|
||||
if (NumEls == ElementCount) \
|
||||
Ret |= isSpecificBuiltinType(BuiltinType::Id);
|
||||
#include "clang/Basic/RISCVVTypes.def"
|
||||
return Ret;
|
||||
}
|
||||
|
||||
inline bool Type::isRVVType(unsigned Bitwidth, bool IsFloat) const {
|
||||
bool Ret = false;
|
||||
#define RVV_TYPE(Name, Id, SingletonId)
|
||||
#define RVV_VECTOR_TYPE(Name, Id, SingletonId, NumEls, ElBits, NF, IsSigned, \
|
||||
IsFP) \
|
||||
if (ElBits == Bitwidth && IsFloat == IsFP) \
|
||||
Ret |= isSpecificBuiltinType(BuiltinType::Id);
|
||||
#include "clang/Basic/RISCVVTypes.def"
|
||||
return Ret;
|
||||
}
|
||||
|
||||
inline bool Type::isTemplateTypeParmType() const {
|
||||
return isa<TemplateTypeParmType>(CanonicalType);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,6 +240,11 @@ private:
|
|||
static SourceRange getLocalSourceRangeImpl(TypeLoc TL);
|
||||
};
|
||||
|
||||
inline TypeSourceInfo::TypeSourceInfo(QualType ty, size_t DataSize) : Ty(ty) {
|
||||
// Init data attached to the object. See getTypeLoc.
|
||||
memset(this + 1, 0, DataSize);
|
||||
}
|
||||
|
||||
/// Return the TypeLoc for a type source info.
|
||||
inline TypeLoc TypeSourceInfo::getTypeLoc() const {
|
||||
// TODO: is this alignment already sufficient?
|
||||
|
|
@ -2102,7 +2107,7 @@ struct AutoTypeLocInfo : TypeSpecLocInfo {
|
|||
NestedNameSpecifierLoc NestedNameSpec;
|
||||
SourceLocation TemplateKWLoc;
|
||||
SourceLocation ConceptNameLoc;
|
||||
NamedDecl *FoundDecl;
|
||||
NamedDecl *FoundDecl = nullptr;
|
||||
SourceLocation LAngleLoc;
|
||||
SourceLocation RAngleLoc;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ include "clang/Basic/TypeNodes.td"
|
|||
|
||||
let Class = ComplexType in {
|
||||
def : Property<"elementType", QualType> {
|
||||
let Read = [{ node->getElementType() }];
|
||||
let Read = [{ node->getElementType() }];
|
||||
}
|
||||
|
||||
def : Creator<[{ return ctx.getComplexType(elementType); }]>;
|
||||
|
|
@ -591,7 +591,7 @@ let Class = ParenType in {
|
|||
|
||||
def : Creator<[{
|
||||
return ctx.getParenType(innerType);
|
||||
}]>;
|
||||
}]>;
|
||||
}
|
||||
|
||||
let Class = MacroQualifiedType in {
|
||||
|
|
@ -813,6 +813,10 @@ let Class = BuiltinType in {
|
|||
case BuiltinType::ID: return ctx.SINGLETON_ID;
|
||||
#include "clang/Basic/RISCVVTypes.def"
|
||||
|
||||
#define WASM_TYPE(NAME, ID, SINGLETON_ID) \
|
||||
case BuiltinType::ID: return ctx.SINGLETON_ID;
|
||||
#include "clang/Basic/WebAssemblyReferenceTypes.def"
|
||||
|
||||
#define BUILTIN_TYPE(ID, SINGLETON_ID) \
|
||||
case BuiltinType::ID: return ctx.SINGLETON_ID;
|
||||
#include "clang/AST/BuiltinTypes.def"
|
||||
|
|
@ -889,7 +893,7 @@ let Class = ObjCInterfaceType in {
|
|||
let Class = ObjCTypeParamType in {
|
||||
def : Property<"declaration", ObjCTypeParamDeclRef> {
|
||||
let Read = [{ node->getDecl() }];
|
||||
}
|
||||
}
|
||||
def : Property<"qualifiers", Array<ObjCProtocolDeclRef>> {
|
||||
let Read = [{ node->getProtocols() }];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,9 +114,17 @@ public:
|
|||
I.I->set(New, AS);
|
||||
}
|
||||
|
||||
void erase(unsigned I) { decls()[I] = decls().pop_back_val(); }
|
||||
void erase(unsigned I) {
|
||||
auto val = decls().pop_back_val();
|
||||
if (I < size())
|
||||
decls()[I] = val;
|
||||
}
|
||||
|
||||
void erase(iterator I) { *I.I = decls().pop_back_val(); }
|
||||
void erase(iterator I) {
|
||||
auto val = decls().pop_back_val();
|
||||
if (I != end())
|
||||
*I.I = val;
|
||||
}
|
||||
|
||||
void setAccess(iterator I, AccessSpecifier AS) { I.I->setAccess(AS); }
|
||||
|
||||
|
|
|
|||
|
|
@ -563,8 +563,6 @@ private:
|
|||
llvm::DenseMap<const CXXRecordDecl *, std::unique_ptr<VirtualBaseInfo>>
|
||||
VBaseInfo;
|
||||
|
||||
void enumerateVFPtrs(const CXXRecordDecl *ForClass, VPtrInfoVector &Result);
|
||||
|
||||
void computeVTableRelatedInformation(const CXXRecordDecl *RD) override;
|
||||
|
||||
void dumpMethodLocations(const CXXRecordDecl *RD,
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@
|
|||
#include "clang/Basic/TypeTraits.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
|
|
@ -1333,6 +1334,16 @@ extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXConversionDecl>
|
|||
extern const internal::VariadicDynCastAllOfMatcher<Decl, CXXDeductionGuideDecl>
|
||||
cxxDeductionGuideDecl;
|
||||
|
||||
/// Matches concept declarations.
|
||||
///
|
||||
/// Example matches integral
|
||||
/// \code
|
||||
/// template<typename T>
|
||||
/// concept integral = std::is_integral_v<T>;
|
||||
/// \endcode
|
||||
extern const internal::VariadicDynCastAllOfMatcher<Decl, ConceptDecl>
|
||||
conceptDecl;
|
||||
|
||||
/// Matches variable declarations.
|
||||
///
|
||||
/// Note: this does not match declarations of member variables, which are
|
||||
|
|
@ -1970,6 +1981,45 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXDeleteExpr>
|
|||
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNoexceptExpr>
|
||||
cxxNoexceptExpr;
|
||||
|
||||
/// Matches a loop initializing the elements of an array in a number of contexts:
|
||||
/// * in the implicit copy/move constructor for a class with an array member
|
||||
/// * when a lambda-expression captures an array by value
|
||||
/// * when a decomposition declaration decomposes an array
|
||||
///
|
||||
/// Given
|
||||
/// \code
|
||||
/// void testLambdaCapture() {
|
||||
/// int a[10];
|
||||
/// auto Lam1 = [a]() {
|
||||
/// return;
|
||||
/// };
|
||||
/// }
|
||||
/// \endcode
|
||||
/// arrayInitLoopExpr() matches the implicit loop that initializes each element of
|
||||
/// the implicit array field inside the lambda object, that represents the array `a`
|
||||
/// captured by value.
|
||||
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ArrayInitLoopExpr>
|
||||
arrayInitLoopExpr;
|
||||
|
||||
/// The arrayInitIndexExpr consists of two subexpressions: a common expression
|
||||
/// (the source array) that is evaluated once up-front, and a per-element initializer
|
||||
/// that runs once for each array element. Within the per-element initializer,
|
||||
/// the current index may be obtained via an ArrayInitIndexExpr.
|
||||
///
|
||||
/// Given
|
||||
/// \code
|
||||
/// void testStructBinding() {
|
||||
/// int a[2] = {1, 2};
|
||||
/// auto [x, y] = a;
|
||||
/// }
|
||||
/// \endcode
|
||||
/// arrayInitIndexExpr() matches the array index that implicitly iterates
|
||||
/// over the array `a` to copy each element to the anonymous array
|
||||
/// that backs the structured binding `[x, y]` elements of which are
|
||||
/// referred to by their aliases `x` and `y`.
|
||||
extern const internal::VariadicDynCastAllOfMatcher<Stmt, ArrayInitIndexExpr>
|
||||
arrayInitIndexExpr;
|
||||
|
||||
/// Matches array subscript expressions.
|
||||
///
|
||||
/// Given
|
||||
|
|
@ -2450,6 +2500,17 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, DependentCoawaitExpr>
|
|||
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CoyieldExpr>
|
||||
coyieldExpr;
|
||||
|
||||
/// Matches coroutine body statements.
|
||||
///
|
||||
/// coroutineBodyStmt() matches the coroutine below
|
||||
/// \code
|
||||
/// generator<int> gen() {
|
||||
/// co_return;
|
||||
/// }
|
||||
/// \endcode
|
||||
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CoroutineBodyStmt>
|
||||
coroutineBodyStmt;
|
||||
|
||||
/// Matches nullptr literal.
|
||||
extern const internal::VariadicDynCastAllOfMatcher<Stmt, CXXNullPtrLiteralExpr>
|
||||
cxxNullPtrLiteralExpr;
|
||||
|
|
@ -4419,6 +4480,33 @@ AST_POLYMORPHIC_MATCHER_P(argumentCountIs,
|
|||
return NumArgs == N;
|
||||
}
|
||||
|
||||
/// Checks that a call expression or a constructor call expression has at least
|
||||
/// the specified number of arguments (including absent default arguments).
|
||||
///
|
||||
/// Example matches f(0, 0) and g(0, 0, 0)
|
||||
/// (matcher = callExpr(argumentCountAtLeast(2)))
|
||||
/// \code
|
||||
/// void f(int x, int y);
|
||||
/// void g(int x, int y, int z);
|
||||
/// f(0, 0);
|
||||
/// g(0, 0, 0);
|
||||
/// \endcode
|
||||
AST_POLYMORPHIC_MATCHER_P(argumentCountAtLeast,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(
|
||||
CallExpr, CXXConstructExpr,
|
||||
CXXUnresolvedConstructExpr, ObjCMessageExpr),
|
||||
unsigned, N) {
|
||||
unsigned NumArgs = Node.getNumArgs();
|
||||
if (!Finder->isTraversalIgnoringImplicitNodes())
|
||||
return NumArgs >= N;
|
||||
while (NumArgs) {
|
||||
if (!isa<CXXDefaultArgExpr>(Node.getArg(NumArgs - 1)))
|
||||
break;
|
||||
--NumArgs;
|
||||
}
|
||||
return NumArgs >= N;
|
||||
}
|
||||
|
||||
/// Matches the n'th argument of a call expression or a constructor
|
||||
/// call expression.
|
||||
///
|
||||
|
|
@ -5460,9 +5548,10 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
|
|||
return false;
|
||||
}
|
||||
|
||||
/// Matches a 'for', 'while', 'do' statement or a function definition that has
|
||||
/// a given body. Note that in case of functions this matcher only matches the
|
||||
/// definition itself and not the other declarations of the same function.
|
||||
/// Matches a 'for', 'while', 'while' statement or a function or coroutine
|
||||
/// definition that has a given body. Note that in case of functions or
|
||||
/// coroutines this matcher only matches the definition itself and not the
|
||||
/// other declarations of the same function or coroutine.
|
||||
///
|
||||
/// Given
|
||||
/// \code
|
||||
|
|
@ -5483,12 +5572,11 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
|
|||
/// with compoundStmt()
|
||||
/// matching '{}'
|
||||
/// but does not match 'void f();'
|
||||
AST_POLYMORPHIC_MATCHER_P(hasBody,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt,
|
||||
WhileStmt,
|
||||
CXXForRangeStmt,
|
||||
FunctionDecl),
|
||||
internal::Matcher<Stmt>, InnerMatcher) {
|
||||
AST_POLYMORPHIC_MATCHER_P(
|
||||
hasBody,
|
||||
AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt, WhileStmt, CXXForRangeStmt,
|
||||
FunctionDecl, CoroutineBodyStmt),
|
||||
internal::Matcher<Stmt>, InnerMatcher) {
|
||||
if (Finder->isTraversalIgnoringImplicitNodes() && isDefaultedHelper(&Node))
|
||||
return false;
|
||||
const Stmt *const Statement = internal::GetBodyMatcher<NodeType>::get(Node);
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@ namespace ast_matchers {
|
|||
namespace dynamic {
|
||||
|
||||
struct SourceLocation {
|
||||
SourceLocation() : Line(), Column() {}
|
||||
unsigned Line;
|
||||
unsigned Column;
|
||||
SourceLocation() = default;
|
||||
unsigned Line = 0;
|
||||
unsigned Column = 0;
|
||||
};
|
||||
|
||||
struct SourceRange {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class Stmt;
|
|||
/// \enum IfThen -- then branch of the if statement has no call.
|
||||
/// \enum IfElse -- else branch of the if statement has no call.
|
||||
/// \enum Switch -- one of the switch cases doesn't have a call.
|
||||
/// \enum SwitchSkipped -- there is no call if none of the cases appies.
|
||||
/// \enum SwitchSkipped -- there is no call if none of the cases applies.
|
||||
/// \enum LoopEntered -- no call when the loop is entered.
|
||||
/// \enum LoopSkipped -- no call when the loop is not entered.
|
||||
/// \enum FallbackReason -- fallback case when we were not able to figure out
|
||||
|
|
|
|||
|
|
@ -155,6 +155,10 @@ namespace consumed {
|
|||
ConsumedStateMap(const ConsumedStateMap &Other)
|
||||
: Reachable(Other.Reachable), From(Other.From), VarMap(Other.VarMap) {}
|
||||
|
||||
// The copy assignment operator is defined as deleted pending further
|
||||
// motivation.
|
||||
ConsumedStateMap &operator=(const ConsumedStateMap &) = delete;
|
||||
|
||||
/// Warn if any of the parameters being tracked are not in the state
|
||||
/// they were declared to be in upon return from a function.
|
||||
void checkParamsForReturnTypestate(SourceLocation BlameLoc,
|
||||
|
|
@ -240,7 +244,7 @@ namespace consumed {
|
|||
ConsumedBlockInfo BlockInfo;
|
||||
std::unique_ptr<ConsumedStateMap> CurrStates;
|
||||
|
||||
ConsumedState ExpectedReturnState;
|
||||
ConsumedState ExpectedReturnState = CS_None;
|
||||
|
||||
void determineExpectedReturnState(AnalysisDeclContext &AC,
|
||||
const FunctionDecl *D);
|
||||
|
|
@ -258,7 +262,7 @@ namespace consumed {
|
|||
/// Check a function's CFG for consumed violations.
|
||||
///
|
||||
/// We traverse the blocks in the CFG, keeping track of the state of each
|
||||
/// value who's type has uniquness annotations. If methods are invoked in
|
||||
/// value who's type has uniqueness annotations. If methods are invoked in
|
||||
/// the wrong state a warning is issued. Each block in the CFG is traversed
|
||||
/// exactly once.
|
||||
void run(AnalysisDeclContext &AC);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
//===- IntervalPartition.h - CFG Partitioning into Intervals -----*- C++-*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines functionality for partitioning a CFG into intervals. The
|
||||
// concepts and implementations are based on the presentation in "Compilers" by
|
||||
// Aho, Sethi and Ullman (the "dragon book"), pages 664-666.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_INTERVALPARTITION_H
|
||||
#define LLVM_CLANG_ANALYSIS_ANALYSES_INTERVALPARTITION_H
|
||||
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
|
||||
// An interval is a strongly-connected component of the CFG along with a
|
||||
// trailing acyclic structure. The _header_ of the interval is either the CFG
|
||||
// entry block or has at least one predecessor outside of the interval. All
|
||||
// other blocks in the interval have only predecessors also in the interval.
|
||||
struct CFGInterval {
|
||||
CFGInterval(const CFGBlock *Header) : Header(Header), Blocks({Header}) {}
|
||||
|
||||
// The block from which the interval was constructed. Is either the CFG entry
|
||||
// block or has at least one predecessor outside the interval.
|
||||
const CFGBlock *Header;
|
||||
|
||||
llvm::SmallDenseSet<const CFGBlock *> Blocks;
|
||||
|
||||
// Successor blocks of the *interval*: blocks outside the interval for
|
||||
// reachable (in one edge) from within the interval.
|
||||
llvm::SmallDenseSet<const CFGBlock *> Successors;
|
||||
};
|
||||
|
||||
CFGInterval buildInterval(const CFG &Cfg, const CFGBlock &Header);
|
||||
|
||||
// Partitions `Cfg` into intervals and constructs a graph of the intervals,
|
||||
// based on the edges between nodes in these intervals.
|
||||
std::vector<CFGInterval> partitionIntoIntervals(const CFG &Cfg);
|
||||
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_ANALYSES_INTERVALPARTITION_H
|
||||
|
|
@ -48,11 +48,9 @@ class Callback {
|
|||
virtual void anchor();
|
||||
public:
|
||||
virtual ~Callback() {}
|
||||
virtual void HandleUnreachable(UnreachableKind UK,
|
||||
SourceLocation L,
|
||||
SourceRange ConditionVal,
|
||||
SourceRange R1,
|
||||
SourceRange R2) = 0;
|
||||
virtual void HandleUnreachable(UnreachableKind UK, SourceLocation L,
|
||||
SourceRange ConditionVal, SourceRange R1,
|
||||
SourceRange R2, bool HasFallThroughAttr) = 0;
|
||||
};
|
||||
|
||||
/// ScanReachableFromBlock - Mark all blocks reachable from Start.
|
||||
|
|
|
|||
|
|
@ -484,8 +484,6 @@ private:
|
|||
SMap.insert(std::make_pair(S, E));
|
||||
}
|
||||
|
||||
til::SExpr *getCurrentLVarDefinition(const ValueDecl *VD);
|
||||
|
||||
til::SExpr *addStatement(til::SExpr *E, const Stmt *S,
|
||||
const ValueDecl *VD = nullptr);
|
||||
til::SExpr *lookupVarDecl(const ValueDecl *VD);
|
||||
|
|
|
|||
|
|
@ -319,6 +319,7 @@ public:
|
|||
protected:
|
||||
SExpr(TIL_Opcode Op) : Opcode(Op) {}
|
||||
SExpr(const SExpr &E) : Opcode(E.Opcode), Flags(E.Flags) {}
|
||||
SExpr &operator=(const SExpr &) = delete;
|
||||
|
||||
const TIL_Opcode Opcode;
|
||||
unsigned char Reserved = 0;
|
||||
|
|
@ -488,6 +489,10 @@ public:
|
|||
Undefined(const Stmt *S = nullptr) : SExpr(COP_Undefined), Cstmt(S) {}
|
||||
Undefined(const Undefined &U) : SExpr(U), Cstmt(U.Cstmt) {}
|
||||
|
||||
// The copy assignment operator is defined as deleted pending further
|
||||
// motivation.
|
||||
Undefined &operator=(const Undefined &) = delete;
|
||||
|
||||
static bool classof(const SExpr *E) { return E->opcode() == COP_Undefined; }
|
||||
|
||||
template <class V>
|
||||
|
|
@ -566,6 +571,10 @@ public:
|
|||
LiteralT(T Dat) : Literal(ValueType::getValueType<T>()), Val(Dat) {}
|
||||
LiteralT(const LiteralT<T> &L) : Literal(L), Val(L.Val) {}
|
||||
|
||||
// The copy assignment operator is defined as deleted pending further
|
||||
// motivation.
|
||||
LiteralT &operator=(const LiteralT<T> &) = delete;
|
||||
|
||||
T value() const { return Val;}
|
||||
T& value() { return Val; }
|
||||
|
||||
|
|
|
|||
|
|
@ -240,6 +240,10 @@ class CopyOnWriteVector {
|
|||
|
||||
VectorData() = default;
|
||||
VectorData(const VectorData &VD) : Vect(VD.Vect) {}
|
||||
|
||||
// The copy assignment operator is defined as deleted pending further
|
||||
// motivation.
|
||||
VectorData &operator=(const VectorData &) = delete;
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
using DefMapTy = llvm::DenseMap<const VarDecl *, std::vector<const VarDecl *>>;
|
||||
|
||||
/// The interface that lets the caller handle unsafe buffer usage analysis
|
||||
/// results by overriding this class's handle... methods.
|
||||
class UnsafeBufferUsageHandler {
|
||||
|
|
@ -34,15 +36,32 @@ public:
|
|||
virtual void handleUnsafeOperation(const Stmt *Operation,
|
||||
bool IsRelatedToDecl) = 0;
|
||||
|
||||
/// Invoked when a fix is suggested against a variable.
|
||||
virtual void handleFixableVariable(const VarDecl *Variable,
|
||||
FixItList &&List) = 0;
|
||||
/// Invoked when a fix is suggested against a variable. This function groups
|
||||
/// all variables that must be fixed together (i.e their types must be changed to the
|
||||
/// same target type to prevent type mismatches) into a single fixit.
|
||||
virtual void handleUnsafeVariableGroup(const VarDecl *Variable,
|
||||
const DefMapTy &VarGrpMap,
|
||||
FixItList &&Fixes) = 0;
|
||||
|
||||
/// Returns a reference to the `Preprocessor`:
|
||||
virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const = 0;
|
||||
|
||||
virtual std::string
|
||||
getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
|
||||
StringRef WSSuffix = "") const = 0;
|
||||
};
|
||||
|
||||
// This function invokes the analysis and allows the caller to react to it
|
||||
// through the handler class.
|
||||
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler);
|
||||
void checkUnsafeBufferUsage(const Decl *D, UnsafeBufferUsageHandler &Handler,
|
||||
bool EmitSuggestions);
|
||||
|
||||
namespace internal {
|
||||
// Tests if any two `FixItHint`s in `FixIts` conflict. Two `FixItHint`s
|
||||
// conflict if they have overlapping source ranges.
|
||||
bool anyConflict(const llvm::SmallVectorImpl<FixItHint> &FixIts,
|
||||
const SourceManager &SM);
|
||||
} // namespace internal
|
||||
} // end namespace clang
|
||||
|
||||
#endif /* LLVM_CLANG_ANALYSIS_ANALYSES_UNSAFEBUFFERUSAGE_H */
|
||||
|
|
|
|||
|
|
@ -29,6 +29,15 @@ WARNING_GADGET(Increment)
|
|||
WARNING_GADGET(Decrement)
|
||||
WARNING_GADGET(ArraySubscript)
|
||||
WARNING_GADGET(PointerArithmetic)
|
||||
WARNING_GADGET(UnsafeBufferUsageAttr)
|
||||
FIXABLE_GADGET(ULCArraySubscript) // `DRE[any]` in an Unspecified Lvalue Context
|
||||
FIXABLE_GADGET(DerefSimplePtrArithFixable)
|
||||
FIXABLE_GADGET(PointerDereference)
|
||||
FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified Pointer Context
|
||||
FIXABLE_GADGET(UPCStandalonePointer)
|
||||
FIXABLE_GADGET(UPCPreIncrement) // '++Ptr' in an Unspecified Pointer Context
|
||||
FIXABLE_GADGET(PointerAssignment)
|
||||
FIXABLE_GADGET(PointerInit)
|
||||
|
||||
#undef FIXABLE_GADGET
|
||||
#undef WARNING_GADGET
|
||||
|
|
|
|||
|
|
@ -331,7 +331,7 @@ public:
|
|||
unsigned getIndex() const { return Index; }
|
||||
|
||||
CFGElement getCallSiteCFGElement() const { return (*Block)[Index]; }
|
||||
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) override;
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ADC,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ public:
|
|||
/// Remove copy constructor to avoid accidental copying.
|
||||
BodyFarm(const BodyFarm &other) = delete;
|
||||
|
||||
/// Delete copy assignment operator.
|
||||
BodyFarm &operator=(const BodyFarm &other) = delete;
|
||||
|
||||
private:
|
||||
typedef llvm::DenseMap<const Decl *, std::optional<Stmt *>> BodyMap;
|
||||
|
||||
|
|
|
|||
|
|
@ -1122,19 +1122,10 @@ public:
|
|||
Elements.push_back(CFGScopeBegin(VD, S), C);
|
||||
}
|
||||
|
||||
void prependScopeBegin(const VarDecl *VD, const Stmt *S,
|
||||
BumpVectorContext &C) {
|
||||
Elements.insert(Elements.rbegin(), 1, CFGScopeBegin(VD, S), C);
|
||||
}
|
||||
|
||||
void appendScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGScopeEnd(VD, S), C);
|
||||
}
|
||||
|
||||
void prependScopeEnd(const VarDecl *VD, const Stmt *S, BumpVectorContext &C) {
|
||||
Elements.insert(Elements.rbegin(), 1, CFGScopeEnd(VD, S), C);
|
||||
}
|
||||
|
||||
void appendBaseDtor(const CXXBaseSpecifier *BS, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGBaseDtor(BS), C);
|
||||
}
|
||||
|
|
@ -1162,44 +1153,6 @@ public:
|
|||
void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
|
||||
Elements.push_back(CFGDeleteDtor(RD, DE), C);
|
||||
}
|
||||
|
||||
// Destructors must be inserted in reversed order. So insertion is in two
|
||||
// steps. First we prepare space for some number of elements, then we insert
|
||||
// the elements beginning at the last position in prepared space.
|
||||
iterator beginAutomaticObjDtorsInsert(iterator I, size_t Cnt,
|
||||
BumpVectorContext &C) {
|
||||
return iterator(Elements.insert(I.base(), Cnt,
|
||||
CFGAutomaticObjDtor(nullptr, nullptr), C));
|
||||
}
|
||||
iterator insertAutomaticObjDtor(iterator I, VarDecl *VD, Stmt *S) {
|
||||
*I = CFGAutomaticObjDtor(VD, S);
|
||||
return ++I;
|
||||
}
|
||||
|
||||
// Scope leaving must be performed in reversed order. So insertion is in two
|
||||
// steps. First we prepare space for some number of elements, then we insert
|
||||
// the elements beginning at the last position in prepared space.
|
||||
iterator beginLifetimeEndsInsert(iterator I, size_t Cnt,
|
||||
BumpVectorContext &C) {
|
||||
return iterator(
|
||||
Elements.insert(I.base(), Cnt, CFGLifetimeEnds(nullptr, nullptr), C));
|
||||
}
|
||||
iterator insertLifetimeEnds(iterator I, VarDecl *VD, Stmt *S) {
|
||||
*I = CFGLifetimeEnds(VD, S);
|
||||
return ++I;
|
||||
}
|
||||
|
||||
// Scope leaving must be performed in reversed order. So insertion is in two
|
||||
// steps. First we prepare space for some number of elements, then we insert
|
||||
// the elements beginning at the last position in prepared space.
|
||||
iterator beginScopeEndInsert(iterator I, size_t Cnt, BumpVectorContext &C) {
|
||||
return iterator(
|
||||
Elements.insert(I.base(), Cnt, CFGScopeEnd(nullptr, nullptr), C));
|
||||
}
|
||||
iterator insertScopeEnd(iterator I, VarDecl *VD, Stmt *S) {
|
||||
*I = CFGScopeEnd(VD, S);
|
||||
return ++I;
|
||||
}
|
||||
};
|
||||
|
||||
/// CFGCallback defines methods that should be called when a logical
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public:
|
|||
/// Determine if a declaration should be included in the graph.
|
||||
static bool includeInGraph(const Decl *D);
|
||||
|
||||
/// Determine if a declaration should be included in the graph for the
|
||||
/// Determine if a declaration should be included in the graph for the
|
||||
/// purposes of being a callee. This is similar to includeInGraph except
|
||||
/// it permits declarations, not just definitions.
|
||||
static bool includeCalleeInGraph(const Decl *D);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,147 @@
|
|||
//===-- Arena.h -------------------------------*- C++ -------------------*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__ARENA_H
|
||||
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__ARENA_H
|
||||
|
||||
#include "clang/Analysis/FlowSensitive/Formula.h"
|
||||
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang::dataflow {
|
||||
|
||||
/// The Arena owns the objects that model data within an analysis.
|
||||
/// For example, `Value`, `StorageLocation`, `Atom`, and `Formula`.
|
||||
class Arena {
|
||||
public:
|
||||
Arena() : True(makeAtom()), False(makeAtom()) {}
|
||||
Arena(const Arena &) = delete;
|
||||
Arena &operator=(const Arena &) = delete;
|
||||
|
||||
/// Creates a `T` (some subclass of `StorageLocation`), forwarding `args` to
|
||||
/// the constructor, and returns a reference to it.
|
||||
///
|
||||
/// The `DataflowAnalysisContext` takes ownership of the created object. The
|
||||
/// object will be destroyed when the `DataflowAnalysisContext` is destroyed.
|
||||
template <typename T, typename... Args>
|
||||
std::enable_if_t<std::is_base_of<StorageLocation, T>::value, T &>
|
||||
create(Args &&...args) {
|
||||
// Note: If allocation of individual `StorageLocation`s turns out to be
|
||||
// costly, consider creating specializations of `create<T>` for commonly
|
||||
// used `StorageLocation` subclasses and make them use a `BumpPtrAllocator`.
|
||||
return *cast<T>(
|
||||
Locs.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
|
||||
.get());
|
||||
}
|
||||
|
||||
/// Creates a `T` (some subclass of `Value`), forwarding `args` to the
|
||||
/// constructor, and returns a reference to it.
|
||||
///
|
||||
/// The `DataflowAnalysisContext` takes ownership of the created object. The
|
||||
/// object will be destroyed when the `DataflowAnalysisContext` is destroyed.
|
||||
template <typename T, typename... Args>
|
||||
std::enable_if_t<std::is_base_of<Value, T>::value, T &>
|
||||
create(Args &&...args) {
|
||||
// Note: If allocation of individual `Value`s turns out to be costly,
|
||||
// consider creating specializations of `create<T>` for commonly used
|
||||
// `Value` subclasses and make them use a `BumpPtrAllocator`.
|
||||
return *cast<T>(
|
||||
Vals.emplace_back(std::make_unique<T>(std::forward<Args>(args)...))
|
||||
.get());
|
||||
}
|
||||
|
||||
/// Creates a BoolValue wrapping a particular formula.
|
||||
///
|
||||
/// Passing in the same formula will result in the same BoolValue.
|
||||
/// FIXME: Interning BoolValues but not other Values is inconsistent.
|
||||
/// Decide whether we want Value interning or not.
|
||||
BoolValue &makeBoolValue(const Formula &);
|
||||
|
||||
/// Creates a fresh atom and wraps in in an AtomicBoolValue.
|
||||
/// FIXME: For now, identical-address AtomicBoolValue <=> identical atom.
|
||||
/// Stop relying on pointer identity and remove this guarantee.
|
||||
AtomicBoolValue &makeAtomValue() {
|
||||
return cast<AtomicBoolValue>(makeBoolValue(makeAtomRef(makeAtom())));
|
||||
}
|
||||
|
||||
/// Creates a fresh Top boolean value.
|
||||
TopBoolValue &makeTopValue() {
|
||||
// No need for deduplicating: there's no way to create aliasing Tops.
|
||||
return create<TopBoolValue>(makeAtomRef(makeAtom()));
|
||||
}
|
||||
|
||||
/// Returns a symbolic integer value that models an integer literal equal to
|
||||
/// `Value`. These literals are the same every time.
|
||||
/// Integer literals are not typed; the type is determined by the `Expr` that
|
||||
/// an integer literal is associated with.
|
||||
IntegerValue &makeIntLiteral(llvm::APInt Value);
|
||||
|
||||
// Factories for boolean formulas.
|
||||
// Formulas are interned: passing the same arguments return the same result.
|
||||
// For commutative operations like And/Or, interning ignores order.
|
||||
// Simplifications are applied: makeOr(X, X) => X, etc.
|
||||
|
||||
/// Returns a formula for the conjunction of `LHS` and `RHS`.
|
||||
const Formula &makeAnd(const Formula &LHS, const Formula &RHS);
|
||||
|
||||
/// Returns a formula for the disjunction of `LHS` and `RHS`.
|
||||
const Formula &makeOr(const Formula &LHS, const Formula &RHS);
|
||||
|
||||
/// Returns a formula for the negation of `Val`.
|
||||
const Formula &makeNot(const Formula &Val);
|
||||
|
||||
/// Returns a formula for `LHS => RHS`.
|
||||
const Formula &makeImplies(const Formula &LHS, const Formula &RHS);
|
||||
|
||||
/// Returns a formula for `LHS <=> RHS`.
|
||||
const Formula &makeEquals(const Formula &LHS, const Formula &RHS);
|
||||
|
||||
/// Returns a formula for the variable A.
|
||||
const Formula &makeAtomRef(Atom A);
|
||||
|
||||
/// Returns a formula for a literal true/false.
|
||||
const Formula &makeLiteral(bool Value) {
|
||||
return makeAtomRef(Value ? True : False);
|
||||
}
|
||||
|
||||
/// Returns a new atomic boolean variable, distinct from any other.
|
||||
Atom makeAtom() { return static_cast<Atom>(NextAtom++); };
|
||||
|
||||
/// Creates a fresh flow condition and returns a token that identifies it. The
|
||||
/// token can be used to perform various operations on the flow condition such
|
||||
/// as adding constraints to it, forking it, joining it with another flow
|
||||
/// condition, or checking implications.
|
||||
Atom makeFlowConditionToken() { return makeAtom(); }
|
||||
|
||||
private:
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
|
||||
// Storage for the state of a program.
|
||||
std::vector<std::unique_ptr<StorageLocation>> Locs;
|
||||
std::vector<std::unique_ptr<Value>> Vals;
|
||||
|
||||
// Indices that are used to avoid recreating the same integer literals and
|
||||
// composite boolean values.
|
||||
llvm::DenseMap<llvm::APInt, IntegerValue *> IntegerLiterals;
|
||||
using FormulaPair = std::pair<const Formula *, const Formula *>;
|
||||
llvm::DenseMap<FormulaPair, const Formula *> Ands;
|
||||
llvm::DenseMap<FormulaPair, const Formula *> Ors;
|
||||
llvm::DenseMap<const Formula *, const Formula *> Nots;
|
||||
llvm::DenseMap<FormulaPair, const Formula *> Implies;
|
||||
llvm::DenseMap<FormulaPair, const Formula *> Equals;
|
||||
llvm::DenseMap<Atom, const Formula *> AtomRefs;
|
||||
|
||||
llvm::DenseMap<const Formula *, BoolValue *> FormulaValues;
|
||||
unsigned NextAtom = 0;
|
||||
|
||||
Atom True, False;
|
||||
};
|
||||
|
||||
} // namespace clang::dataflow
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE__ARENA_H
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <memory>
|
||||
|
|
@ -30,8 +31,18 @@ namespace dataflow {
|
|||
/// analysis.
|
||||
class ControlFlowContext {
|
||||
public:
|
||||
/// Builds a ControlFlowContext from a `FunctionDecl`.
|
||||
/// `Func.hasBody()` must be true, and `Func.isTemplated()` must be false.
|
||||
static llvm::Expected<ControlFlowContext> build(const FunctionDecl &Func);
|
||||
|
||||
/// Builds a ControlFlowContext from an AST node. `D` is the function in which
|
||||
/// `S` resides and must not be null.
|
||||
/// `S` resides. `D.isTemplated()` must be false.
|
||||
static llvm::Expected<ControlFlowContext> build(const Decl &D, Stmt &S,
|
||||
ASTContext &C);
|
||||
|
||||
/// Builds a ControlFlowContext from an AST node. `D` is the function in which
|
||||
/// `S` resides. `D` must not be null and `D->isTemplated()` must be false.
|
||||
LLVM_DEPRECATED("Use the version that takes a const Decl & instead", "")
|
||||
static llvm::Expected<ControlFlowContext> build(const Decl *D, Stmt &S,
|
||||
ASTContext &C);
|
||||
|
||||
|
|
@ -47,18 +58,26 @@ public:
|
|||
return StmtToBlock;
|
||||
}
|
||||
|
||||
/// Returns whether `B` is reachable from the entry block.
|
||||
bool isBlockReachable(const CFGBlock &B) const {
|
||||
return BlockReachable[B.getBlockID()];
|
||||
}
|
||||
|
||||
private:
|
||||
// FIXME: Once the deprecated `build` method is removed, mark `D` as "must not
|
||||
// be null" and add an assertion.
|
||||
ControlFlowContext(const Decl *D, std::unique_ptr<CFG> Cfg,
|
||||
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock)
|
||||
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock,
|
||||
llvm::BitVector BlockReachable)
|
||||
: ContainingDecl(D), Cfg(std::move(Cfg)),
|
||||
StmtToBlock(std::move(StmtToBlock)) {}
|
||||
StmtToBlock(std::move(StmtToBlock)),
|
||||
BlockReachable(std::move(BlockReachable)) {}
|
||||
|
||||
/// The `Decl` containing the statement used to construct the CFG.
|
||||
const Decl *ContainingDecl;
|
||||
std::unique_ptr<CFG> Cfg;
|
||||
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock;
|
||||
llvm::BitVector BlockReachable;
|
||||
};
|
||||
|
||||
} // namespace dataflow
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace dataflow {
|
|||
/// must provide the following public members:
|
||||
/// * `LatticeT initialElement()` - returns a lattice element that models the
|
||||
/// initial state of a basic block;
|
||||
/// * `void transfer(const CFGElement *, LatticeT &, Environment &)` - applies
|
||||
/// * `void transfer(const CFGElement &, LatticeT &, Environment &)` - applies
|
||||
/// the analysis transfer function for a given CFG element and lattice
|
||||
/// element.
|
||||
///
|
||||
|
|
@ -61,6 +61,7 @@ namespace dataflow {
|
|||
/// argument by computing their least upper bound, modifies the object if
|
||||
/// necessary, and returns an effect indicating whether any changes were
|
||||
/// made to it;
|
||||
/// FIXME: make it `static LatticeT join(const LatticeT&, const LatticeT&)`
|
||||
/// * `bool operator==(const LatticeT &) const` - returns true if and only if
|
||||
/// the object is equal to the argument.
|
||||
///
|
||||
|
|
@ -98,11 +99,13 @@ public:
|
|||
return {static_cast<Derived *>(this)->initialElement()};
|
||||
}
|
||||
|
||||
LatticeJoinEffect joinTypeErased(TypeErasedLattice &E1,
|
||||
TypeErasedLattice joinTypeErased(const TypeErasedLattice &E1,
|
||||
const TypeErasedLattice &E2) final {
|
||||
Lattice &L1 = llvm::any_cast<Lattice &>(E1.Value);
|
||||
// FIXME: change the signature of join() to avoid copying here.
|
||||
Lattice L1 = llvm::any_cast<const Lattice &>(E1.Value);
|
||||
const Lattice &L2 = llvm::any_cast<const Lattice &>(E2.Value);
|
||||
return L1.join(L2);
|
||||
L1.join(L2);
|
||||
return {std::move(L1)};
|
||||
}
|
||||
|
||||
LatticeJoinEffect widenTypeErased(TypeErasedLattice &Current,
|
||||
|
|
@ -119,7 +122,7 @@ public:
|
|||
return L1 == L2;
|
||||
}
|
||||
|
||||
void transferTypeErased(const CFGElement *Element, TypeErasedLattice &E,
|
||||
void transferTypeErased(const CFGElement &Element, TypeErasedLattice &E,
|
||||
Environment &Env) final {
|
||||
Lattice &L = llvm::any_cast<Lattice &>(E.Value);
|
||||
static_cast<Derived *>(this)->transfer(Element, L, Env);
|
||||
|
|
@ -205,8 +208,10 @@ runDataflowAnalysis(
|
|||
const TypeErasedDataflowAnalysisState &State) {
|
||||
auto *Lattice =
|
||||
llvm::any_cast<typename AnalysisT::Lattice>(&State.Lattice.Value);
|
||||
// FIXME: we should not be copying the environment here!
|
||||
// Ultimately the PostVisitCFG only gets a const reference anyway.
|
||||
PostVisitCFG(Element, DataflowAnalysisState<typename AnalysisT::Lattice>{
|
||||
*Lattice, State.Env});
|
||||
*Lattice, State.Env.fork()});
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -222,14 +227,15 @@ runDataflowAnalysis(
|
|||
llvm::transform(
|
||||
std::move(*TypeErasedBlockStates), std::back_inserter(BlockStates),
|
||||
[](auto &OptState) {
|
||||
return llvm::transformOptional(std::move(OptState), [](auto &&State) {
|
||||
return DataflowAnalysisState<typename AnalysisT::Lattice>{
|
||||
llvm::any_cast<typename AnalysisT::Lattice>(
|
||||
std::move(State.Lattice.Value)),
|
||||
std::move(State.Env)};
|
||||
});
|
||||
return llvm::transformOptional(
|
||||
std::move(OptState), [](TypeErasedDataflowAnalysisState &&State) {
|
||||
return DataflowAnalysisState<typename AnalysisT::Lattice>{
|
||||
llvm::any_cast<typename AnalysisT::Lattice>(
|
||||
std::move(State.Lattice.Value)),
|
||||
std::move(State.Env)};
|
||||
});
|
||||
});
|
||||
return BlockStates;
|
||||
return std::move(BlockStates);
|
||||
}
|
||||
|
||||
/// Abstract base class for dataflow "models": reusable analysis components that
|
||||
|
|
@ -238,7 +244,7 @@ runDataflowAnalysis(
|
|||
class DataflowModel : public Environment::ValueModel {
|
||||
public:
|
||||
/// Return value indicates whether the model processed the `Element`.
|
||||
virtual bool transfer(const CFGElement *Element, Environment &Env) = 0;
|
||||
virtual bool transfer(const CFGElement &Element, Environment &Env) = 0;
|
||||
};
|
||||
|
||||
} // namespace dataflow
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@
|
|||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/TypeOrdering.h"
|
||||
#include "clang/Analysis/FlowSensitive/Arena.h"
|
||||
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
|
||||
#include "clang/Analysis/FlowSensitive/Solver.h"
|
||||
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
|
|
@ -34,6 +36,7 @@
|
|||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
class Logger;
|
||||
|
||||
/// Skip past nodes that the CFG does not emit. These nodes are invisible to
|
||||
/// flow-sensitive analysis, and should be ignored as they will effectively not
|
||||
|
|
@ -48,8 +51,12 @@ namespace dataflow {
|
|||
const Expr &ignoreCFGOmittedNodes(const Expr &E);
|
||||
const Stmt &ignoreCFGOmittedNodes(const Stmt &S);
|
||||
|
||||
/// A set of `FieldDecl *`. Use `SmallSetVector` to guarantee deterministic
|
||||
/// iteration order.
|
||||
using FieldSet = llvm::SmallSetVector<const FieldDecl *, 4>;
|
||||
|
||||
/// Returns the set of all fields in the type.
|
||||
llvm::DenseSet<const FieldDecl *> getObjectFields(QualType Type);
|
||||
FieldSet getObjectFields(QualType Type);
|
||||
|
||||
struct ContextSensitiveOptions {
|
||||
/// The maximum depth to analyze. A value of zero is equivalent to disabling
|
||||
|
|
@ -67,6 +74,11 @@ public:
|
|||
/// fundamentally limited: some constructs, such as recursion, are
|
||||
/// explicitly unsupported.
|
||||
std::optional<ContextSensitiveOptions> ContextSensitiveOpts;
|
||||
|
||||
/// If provided, analysis details will be recorded here.
|
||||
/// (This is always non-null within an AnalysisContext, the framework
|
||||
/// provides a fallback no-op logger).
|
||||
Logger *Log = nullptr;
|
||||
};
|
||||
|
||||
/// Constructs a dataflow analysis context.
|
||||
|
|
@ -76,37 +88,9 @@ public:
|
|||
/// `S` must not be null.
|
||||
DataflowAnalysisContext(std::unique_ptr<Solver> S,
|
||||
Options Opts = Options{
|
||||
/*ContextSensitiveOpts=*/std::nullopt})
|
||||
: S(std::move(S)), TrueVal(createAtomicBoolValue()),
|
||||
FalseVal(createAtomicBoolValue()), Opts(Opts) {
|
||||
assert(this->S != nullptr);
|
||||
}
|
||||
|
||||
/// Takes ownership of `Loc` and returns a reference to it.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `Loc` must not be null.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_base_of<StorageLocation, T>::value, T &>
|
||||
takeOwnership(std::unique_ptr<T> Loc) {
|
||||
assert(Loc != nullptr);
|
||||
Locs.push_back(std::move(Loc));
|
||||
return *cast<T>(Locs.back().get());
|
||||
}
|
||||
|
||||
/// Takes ownership of `Val` and returns a reference to it.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `Val` must not be null.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_base_of<Value, T>::value, T &>
|
||||
takeOwnership(std::unique_ptr<T> Val) {
|
||||
assert(Val != nullptr);
|
||||
Vals.push_back(std::move(Val));
|
||||
return *cast<T>(Vals.back().get());
|
||||
}
|
||||
/*ContextSensitiveOpts=*/std::nullopt,
|
||||
/*Logger=*/nullptr});
|
||||
~DataflowAnalysisContext();
|
||||
|
||||
/// Returns a new storage location appropriate for `Type`.
|
||||
///
|
||||
|
|
@ -125,15 +109,14 @@ public:
|
|||
///
|
||||
/// `D` must not be assigned a storage location.
|
||||
void setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
|
||||
assert(DeclToLoc.find(&D) == DeclToLoc.end());
|
||||
assert(!DeclToLoc.contains(&D));
|
||||
DeclToLoc[&D] = &Loc;
|
||||
}
|
||||
|
||||
/// Returns the storage location assigned to `D` or null if `D` has no
|
||||
/// assigned storage location.
|
||||
StorageLocation *getStorageLocation(const ValueDecl &D) const {
|
||||
auto It = DeclToLoc.find(&D);
|
||||
return It == DeclToLoc.end() ? nullptr : It->second;
|
||||
return DeclToLoc.lookup(&D);
|
||||
}
|
||||
|
||||
/// Assigns `Loc` as the storage location of `E`.
|
||||
|
|
@ -143,15 +126,14 @@ public:
|
|||
/// `E` must not be assigned a storage location.
|
||||
void setStorageLocation(const Expr &E, StorageLocation &Loc) {
|
||||
const Expr &CanonE = ignoreCFGOmittedNodes(E);
|
||||
assert(ExprToLoc.find(&CanonE) == ExprToLoc.end());
|
||||
assert(!ExprToLoc.contains(&CanonE));
|
||||
ExprToLoc[&CanonE] = &Loc;
|
||||
}
|
||||
|
||||
/// Returns the storage location assigned to `E` or null if `E` has no
|
||||
/// assigned storage location.
|
||||
StorageLocation *getStorageLocation(const Expr &E) const {
|
||||
auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
|
||||
return It == ExprToLoc.end() ? nullptr : It->second;
|
||||
return ExprToLoc.lookup(&ignoreCFGOmittedNodes(E));
|
||||
}
|
||||
|
||||
/// Returns a pointer value that represents a null pointer. Calls with
|
||||
|
|
@ -159,112 +141,33 @@ public:
|
|||
/// A null `PointeeType` can be used for the pointee of `std::nullptr_t`.
|
||||
PointerValue &getOrCreateNullPointerValue(QualType PointeeType);
|
||||
|
||||
/// Returns a symbolic boolean value that models a boolean literal equal to
|
||||
/// `Value`.
|
||||
AtomicBoolValue &getBoolLiteralValue(bool Value) const {
|
||||
return Value ? TrueVal : FalseVal;
|
||||
}
|
||||
|
||||
/// Creates an atomic boolean value.
|
||||
AtomicBoolValue &createAtomicBoolValue() {
|
||||
return takeOwnership(std::make_unique<AtomicBoolValue>());
|
||||
}
|
||||
|
||||
/// Creates a Top value for booleans. Each instance is unique and can be
|
||||
/// assigned a distinct truth value during solving.
|
||||
///
|
||||
/// FIXME: `Top iff Top` is true when both Tops are identical (by pointer
|
||||
/// equality), but not when they are distinct values. We should improve the
|
||||
/// implementation so that `Top iff Top` has a consistent meaning, regardless
|
||||
/// of the identity of `Top`. Moreover, I think the meaning should be
|
||||
/// `false`.
|
||||
TopBoolValue &createTopBoolValue() {
|
||||
return takeOwnership(std::make_unique<TopBoolValue>());
|
||||
}
|
||||
|
||||
/// Returns a boolean value that represents the conjunction of `LHS` and
|
||||
/// `RHS`. Subsequent calls with the same arguments, regardless of their
|
||||
/// order, will return the same result. If the given boolean values represent
|
||||
/// the same value, the result will be the value itself.
|
||||
BoolValue &getOrCreateConjunction(BoolValue &LHS, BoolValue &RHS);
|
||||
|
||||
/// Returns a boolean value that represents the disjunction of `LHS` and
|
||||
/// `RHS`. Subsequent calls with the same arguments, regardless of their
|
||||
/// order, will return the same result. If the given boolean values represent
|
||||
/// the same value, the result will be the value itself.
|
||||
BoolValue &getOrCreateDisjunction(BoolValue &LHS, BoolValue &RHS);
|
||||
|
||||
/// Returns a boolean value that represents the negation of `Val`. Subsequent
|
||||
/// calls with the same argument will return the same result.
|
||||
BoolValue &getOrCreateNegation(BoolValue &Val);
|
||||
|
||||
/// Returns a boolean value that represents `LHS => RHS`. Subsequent calls
|
||||
/// with the same arguments, will return the same result. If the given boolean
|
||||
/// values represent the same value, the result will be a value that
|
||||
/// represents the true boolean literal.
|
||||
BoolValue &getOrCreateImplication(BoolValue &LHS, BoolValue &RHS);
|
||||
|
||||
/// Returns a boolean value that represents `LHS <=> RHS`. Subsequent calls
|
||||
/// with the same arguments, regardless of their order, will return the same
|
||||
/// result. If the given boolean values represent the same value, the result
|
||||
/// will be a value that represents the true boolean literal.
|
||||
BoolValue &getOrCreateIff(BoolValue &LHS, BoolValue &RHS);
|
||||
|
||||
/// Creates a fresh flow condition and returns a token that identifies it. The
|
||||
/// token can be used to perform various operations on the flow condition such
|
||||
/// as adding constraints to it, forking it, joining it with another flow
|
||||
/// condition, or checking implications.
|
||||
AtomicBoolValue &makeFlowConditionToken();
|
||||
|
||||
/// Adds `Constraint` to the flow condition identified by `Token`.
|
||||
void addFlowConditionConstraint(AtomicBoolValue &Token,
|
||||
BoolValue &Constraint);
|
||||
void addFlowConditionConstraint(Atom Token, const Formula &Constraint);
|
||||
|
||||
/// Creates a new flow condition with the same constraints as the flow
|
||||
/// condition identified by `Token` and returns its token.
|
||||
AtomicBoolValue &forkFlowCondition(AtomicBoolValue &Token);
|
||||
Atom forkFlowCondition(Atom Token);
|
||||
|
||||
/// Creates a new flow condition that represents the disjunction of the flow
|
||||
/// conditions identified by `FirstToken` and `SecondToken`, and returns its
|
||||
/// token.
|
||||
AtomicBoolValue &joinFlowConditions(AtomicBoolValue &FirstToken,
|
||||
AtomicBoolValue &SecondToken);
|
||||
|
||||
// FIXME: This function returns the flow condition expressed directly as its
|
||||
// constraints: (C1 AND C2 AND ...). This differs from the general approach in
|
||||
// the framework where a flow condition is represented as a token (an atomic
|
||||
// boolean) with dependencies and constraints tracked in `FlowConditionDeps`
|
||||
// and `FlowConditionConstraints`: (FC <=> C1 AND C2 AND ...).
|
||||
// Consider if we should make the representation of flow condition consistent,
|
||||
// returning an atomic boolean token with separate constraints instead.
|
||||
//
|
||||
/// Builds and returns the logical formula defining the flow condition
|
||||
/// identified by `Token`. If a value in the formula is present as a key in
|
||||
/// `Substitutions`, it will be substituted with the value it maps to.
|
||||
/// As an example, say we have flow condition tokens FC1, FC2, FC3 and
|
||||
/// FlowConditionConstraints: { FC1: C1,
|
||||
/// FC2: C2,
|
||||
/// FC3: (FC1 v FC2) ^ C3 }
|
||||
/// buildAndSubstituteFlowCondition(FC3, {{C1 -> C1'}}) will return a value
|
||||
/// corresponding to (C1' v C2) ^ C3.
|
||||
BoolValue &buildAndSubstituteFlowCondition(
|
||||
AtomicBoolValue &Token,
|
||||
llvm::DenseMap<AtomicBoolValue *, BoolValue *> Substitutions);
|
||||
Atom joinFlowConditions(Atom FirstToken, Atom SecondToken);
|
||||
|
||||
/// Returns true if and only if the constraints of the flow condition
|
||||
/// identified by `Token` imply that `Val` is true.
|
||||
bool flowConditionImplies(AtomicBoolValue &Token, BoolValue &Val);
|
||||
bool flowConditionImplies(Atom Token, const Formula &);
|
||||
|
||||
/// Returns true if and only if the constraints of the flow condition
|
||||
/// identified by `Token` are always true.
|
||||
bool flowConditionIsTautology(AtomicBoolValue &Token);
|
||||
bool flowConditionIsTautology(Atom Token);
|
||||
|
||||
/// Returns true if `Val1` is equivalent to `Val2`.
|
||||
/// Note: This function doesn't take into account constraints on `Val1` and
|
||||
/// `Val2` imposed by the flow condition.
|
||||
bool equivalentBoolValues(BoolValue &Val1, BoolValue &Val2);
|
||||
bool equivalentFormulas(const Formula &Val1, const Formula &Val2);
|
||||
|
||||
LLVM_DUMP_METHOD void dumpFlowCondition(AtomicBoolValue &Token);
|
||||
LLVM_DUMP_METHOD void dumpFlowCondition(Atom Token,
|
||||
llvm::raw_ostream &OS = llvm::dbgs());
|
||||
|
||||
/// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise,
|
||||
/// returns null.
|
||||
|
|
@ -272,6 +175,20 @@ public:
|
|||
|
||||
const Options &getOptions() { return Opts; }
|
||||
|
||||
Arena &arena() { return *A; }
|
||||
|
||||
/// Returns the outcome of satisfiability checking on `Constraints`.
|
||||
///
|
||||
/// Flow conditions are not incorporated, so they may need to be manually
|
||||
/// included in `Constraints` to provide contextually-accurate results, e.g.
|
||||
/// if any definitions or relationships of the values in `Constraints` have
|
||||
/// been stored in flow conditions.
|
||||
Solver::Result querySolver(llvm::SetVector<const Formula *> Constraints);
|
||||
|
||||
/// Returns the fields of `Type`, limited to the set of fields modeled by this
|
||||
/// context.
|
||||
FieldSet getModeledFields(QualType Type);
|
||||
|
||||
private:
|
||||
friend class Environment;
|
||||
|
||||
|
|
@ -287,56 +204,25 @@ private:
|
|||
};
|
||||
|
||||
// Extends the set of modeled field declarations.
|
||||
void addModeledFields(const llvm::DenseSet<const FieldDecl *> &Fields);
|
||||
|
||||
/// Returns the fields of `Type`, limited to the set of fields modeled by this
|
||||
/// context.
|
||||
llvm::DenseSet<const FieldDecl *> getReferencedFields(QualType Type);
|
||||
void addModeledFields(const FieldSet &Fields);
|
||||
|
||||
/// Adds all constraints of the flow condition identified by `Token` and all
|
||||
/// of its transitive dependencies to `Constraints`. `VisitedTokens` is used
|
||||
/// to track tokens of flow conditions that were already visited by recursive
|
||||
/// calls.
|
||||
void addTransitiveFlowConditionConstraints(
|
||||
AtomicBoolValue &Token, llvm::DenseSet<BoolValue *> &Constraints,
|
||||
llvm::DenseSet<AtomicBoolValue *> &VisitedTokens);
|
||||
|
||||
/// Returns the outcome of satisfiability checking on `Constraints`.
|
||||
/// Possible outcomes are:
|
||||
/// - `Satisfiable`: A satisfying assignment exists and is returned.
|
||||
/// - `Unsatisfiable`: A satisfying assignment does not exist.
|
||||
/// - `TimedOut`: The search for a satisfying assignment was not completed.
|
||||
Solver::Result querySolver(llvm::DenseSet<BoolValue *> Constraints);
|
||||
Atom Token, llvm::SetVector<const Formula *> &Constraints,
|
||||
llvm::DenseSet<Atom> &VisitedTokens);
|
||||
|
||||
/// Returns true if the solver is able to prove that there is no satisfying
|
||||
/// assignment for `Constraints`
|
||||
bool isUnsatisfiable(llvm::DenseSet<BoolValue *> Constraints) {
|
||||
bool isUnsatisfiable(llvm::SetVector<const Formula *> Constraints) {
|
||||
return querySolver(std::move(Constraints)).getStatus() ==
|
||||
Solver::Result::Status::Unsatisfiable;
|
||||
}
|
||||
|
||||
/// Returns a boolean value as a result of substituting `Val` and its sub
|
||||
/// values based on entries in `SubstitutionsCache`. Intermediate results are
|
||||
/// stored in `SubstitutionsCache` to avoid reprocessing values that have
|
||||
/// already been visited.
|
||||
BoolValue &substituteBoolValue(
|
||||
BoolValue &Val,
|
||||
llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache);
|
||||
|
||||
/// Builds and returns the logical formula defining the flow condition
|
||||
/// identified by `Token`, sub values may be substituted based on entries in
|
||||
/// `SubstitutionsCache`. Intermediate results are stored in
|
||||
/// `SubstitutionsCache` to avoid reprocessing values that have already been
|
||||
/// visited.
|
||||
BoolValue &buildAndSubstituteFlowConditionWithCache(
|
||||
AtomicBoolValue &Token,
|
||||
llvm::DenseMap<BoolValue *, BoolValue *> &SubstitutionsCache);
|
||||
|
||||
std::unique_ptr<Solver> S;
|
||||
|
||||
// Storage for the state of a program.
|
||||
std::vector<std::unique_ptr<StorageLocation>> Locs;
|
||||
std::vector<std::unique_ptr<Value>> Vals;
|
||||
std::unique_ptr<Arena> A;
|
||||
|
||||
// Maps from program declarations and statements to storage locations that are
|
||||
// assigned to them. These assignments are global (aggregated across all basic
|
||||
|
|
@ -355,23 +241,8 @@ private:
|
|||
llvm::DenseMap<QualType, PointerValue *, NullableQualTypeDenseMapInfo>
|
||||
NullPointerVals;
|
||||
|
||||
AtomicBoolValue &TrueVal;
|
||||
AtomicBoolValue &FalseVal;
|
||||
|
||||
Options Opts;
|
||||
|
||||
// Indices that are used to avoid recreating the same composite boolean
|
||||
// values.
|
||||
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, ConjunctionValue *>
|
||||
ConjunctionVals;
|
||||
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, DisjunctionValue *>
|
||||
DisjunctionVals;
|
||||
llvm::DenseMap<BoolValue *, NegationValue *> NegationVals;
|
||||
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, ImplicationValue *>
|
||||
ImplicationVals;
|
||||
llvm::DenseMap<std::pair<BoolValue *, BoolValue *>, BiconditionalValue *>
|
||||
BiconditionalVals;
|
||||
|
||||
// Flow conditions are tracked symbolically: each unique flow condition is
|
||||
// associated with a fresh symbolic variable (token), bound to the clause that
|
||||
// defines the flow condition. Conceptually, each binding corresponds to an
|
||||
|
|
@ -384,14 +255,15 @@ private:
|
|||
// Flow conditions depend on other flow conditions if they are created using
|
||||
// `forkFlowCondition` or `joinFlowConditions`. The graph of flow condition
|
||||
// dependencies is stored in the `FlowConditionDeps` map.
|
||||
llvm::DenseMap<AtomicBoolValue *, llvm::DenseSet<AtomicBoolValue *>>
|
||||
FlowConditionDeps;
|
||||
llvm::DenseMap<AtomicBoolValue *, BoolValue *> FlowConditionConstraints;
|
||||
llvm::DenseMap<Atom, llvm::DenseSet<Atom>> FlowConditionDeps;
|
||||
llvm::DenseMap<Atom, const Formula *> FlowConditionConstraints;
|
||||
|
||||
llvm::DenseMap<const FunctionDecl *, ControlFlowContext> FunctionContexts;
|
||||
|
||||
// Fields modeled by environments covered by this context.
|
||||
llvm::DenseSet<const FieldDecl *> ModeledFields;
|
||||
FieldSet ModeledFields;
|
||||
|
||||
std::unique_ptr<Logger> LogOwner; // If created via flags.
|
||||
};
|
||||
|
||||
} // namespace dataflow
|
||||
|
|
|
|||
|
|
@ -22,10 +22,14 @@
|
|||
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
|
||||
#include "clang/Analysis/FlowSensitive/Formula.h"
|
||||
#include "clang/Analysis/FlowSensitive/Logger.h"
|
||||
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
|
@ -44,9 +48,6 @@ enum class SkipPast {
|
|||
None,
|
||||
/// An optional reference should be skipped past.
|
||||
Reference,
|
||||
/// An optional reference should be skipped past, then an optional pointer
|
||||
/// should be skipped past.
|
||||
ReferenceThenPointer,
|
||||
};
|
||||
|
||||
/// Indicates the result of a tentative comparison.
|
||||
|
|
@ -161,8 +162,8 @@ public:
|
|||
/// the state of a program.
|
||||
explicit Environment(DataflowAnalysisContext &DACtx);
|
||||
|
||||
Environment(const Environment &Other);
|
||||
Environment &operator=(const Environment &Other);
|
||||
// Copy-constructor is private, Environments should not be copied. See fork().
|
||||
Environment &operator=(const Environment &Other) = delete;
|
||||
|
||||
Environment(Environment &&Other) = default;
|
||||
Environment &operator=(Environment &&Other) = default;
|
||||
|
|
@ -177,9 +178,15 @@ public:
|
|||
/// with a symbolic representation of the `this` pointee.
|
||||
Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);
|
||||
|
||||
const DataflowAnalysisContext::Options &getAnalysisOptions() {
|
||||
return DACtx->getOptions();
|
||||
}
|
||||
/// Returns a new environment that is a copy of this one.
|
||||
///
|
||||
/// The state of the program is initially the same, but can be mutated without
|
||||
/// affecting the original.
|
||||
///
|
||||
/// However the original should not be further mutated, as this may interfere
|
||||
/// with the fork. (In practice, values are stored independently, but the
|
||||
/// forked flow condition references the original).
|
||||
Environment fork() const;
|
||||
|
||||
/// Creates and returns an environment to use for an inline analysis of the
|
||||
/// callee. Uses the storage location from each argument in the `Call` as the
|
||||
|
|
@ -197,7 +204,8 @@ public:
|
|||
|
||||
/// Moves gathered information back into `this` from a `CalleeEnv` created via
|
||||
/// `pushCall`.
|
||||
void popCall(const Environment &CalleeEnv);
|
||||
void popCall(const CallExpr *Call, const Environment &CalleeEnv);
|
||||
void popCall(const CXXConstructExpr *Call, const Environment &CalleeEnv);
|
||||
|
||||
/// Returns true if and only if the environment is equivalent to `Other`, i.e
|
||||
/// the two environments:
|
||||
|
|
@ -212,17 +220,15 @@ public:
|
|||
bool equivalentTo(const Environment &Other,
|
||||
Environment::ValueModel &Model) const;
|
||||
|
||||
/// Joins the environment with `Other` by taking the intersection of storage
|
||||
/// locations and values that are stored in them. Distinct values that are
|
||||
/// assigned to the same storage locations in the environment and `Other` are
|
||||
/// merged using `Model`.
|
||||
/// Joins two environments by taking the intersection of storage locations and
|
||||
/// values that are stored in them. Distinct values that are assigned to the
|
||||
/// same storage locations in `EnvA` and `EnvB` are merged using `Model`.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `Other` and `this` must use the same `DataflowAnalysisContext`.
|
||||
LatticeJoinEffect join(const Environment &Other,
|
||||
Environment::ValueModel &Model);
|
||||
|
||||
/// `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`.
|
||||
static Environment join(const Environment &EnvA, const Environment &EnvB,
|
||||
Environment::ValueModel &Model);
|
||||
|
||||
/// Widens the environment point-wise, using `PrevEnv` as needed to inform the
|
||||
/// approximation.
|
||||
|
|
@ -259,101 +265,290 @@ public:
|
|||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `D` must not be assigned a storage location in the environment.
|
||||
/// `D` must not already have a storage location in the environment.
|
||||
///
|
||||
/// If `D` has reference type, `Loc` must refer directly to the referenced
|
||||
/// object (if any), not to a `ReferenceValue`, and it is not permitted to
|
||||
/// later change `Loc` to refer to a `ReferenceValue.`
|
||||
void setStorageLocation(const ValueDecl &D, StorageLocation &Loc);
|
||||
|
||||
/// Returns the storage location assigned to `D` in the environment, applying
|
||||
/// the `SP` policy for skipping past indirections, or null if `D` isn't
|
||||
/// assigned a storage location in the environment.
|
||||
StorageLocation *getStorageLocation(const ValueDecl &D, SkipPast SP) const;
|
||||
/// Returns the storage location assigned to `D` in the environment, or null
|
||||
/// if `D` isn't assigned a storage location in the environment.
|
||||
///
|
||||
/// Note that if `D` has reference type, the storage location that is returned
|
||||
/// refers directly to the referenced object, not a `ReferenceValue`.
|
||||
StorageLocation *getStorageLocation(const ValueDecl &D) const;
|
||||
|
||||
/// Assigns `Loc` as the storage location of `E` in the environment.
|
||||
///
|
||||
/// This function is deprecated; prefer `setStorageLocationStrict()`.
|
||||
/// For details, see https://discourse.llvm.org/t/70086.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `E` must not be assigned a storage location in the environment.
|
||||
void setStorageLocation(const Expr &E, StorageLocation &Loc);
|
||||
|
||||
/// Assigns `Loc` as the storage location of the glvalue `E` in the
|
||||
/// environment.
|
||||
///
|
||||
/// This function is the preferred alternative to
|
||||
/// `setStorageLocation(const Expr &, StorageLocation &)`. Once the migration
|
||||
/// to strict handling of value categories is complete (see
|
||||
/// https://discourse.llvm.org/t/70086), `setStorageLocation()` will be
|
||||
/// removed and this function will be renamed to `setStorageLocation()`.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `E` must not be assigned a storage location in the environment.
|
||||
/// `E` must be a glvalue or a `BuiltinType::BuiltinFn`
|
||||
void setStorageLocationStrict(const Expr &E, StorageLocation &Loc);
|
||||
|
||||
/// Returns the storage location assigned to `E` in the environment, applying
|
||||
/// the `SP` policy for skipping past indirections, or null if `E` isn't
|
||||
/// assigned a storage location in the environment.
|
||||
///
|
||||
/// This function is deprecated; prefer `getStorageLocationStrict()`.
|
||||
/// For details, see https://discourse.llvm.org/t/70086.
|
||||
StorageLocation *getStorageLocation(const Expr &E, SkipPast SP) const;
|
||||
|
||||
/// Returns the storage location assigned to the glvalue `E` in the
|
||||
/// environment, or null if `E` isn't assigned a storage location in the
|
||||
/// environment.
|
||||
///
|
||||
/// If the storage location for `E` is associated with a
|
||||
/// `ReferenceValue RefVal`, returns `RefVal.getReferentLoc()` instead.
|
||||
///
|
||||
/// This function is the preferred alternative to
|
||||
/// `getStorageLocation(const Expr &, SkipPast)`. Once the migration
|
||||
/// to strict handling of value categories is complete (see
|
||||
/// https://discourse.llvm.org/t/70086), `getStorageLocation()` will be
|
||||
/// removed and this function will be renamed to `getStorageLocation()`.
|
||||
///
|
||||
/// Requirements:
|
||||
/// `E` must be a glvalue or a `BuiltinType::BuiltinFn`
|
||||
StorageLocation *getStorageLocationStrict(const Expr &E) const;
|
||||
|
||||
/// Returns the storage location assigned to the `this` pointee in the
|
||||
/// environment or null if the `this` pointee has no assigned storage location
|
||||
/// in the environment.
|
||||
StorageLocation *getThisPointeeStorageLocation() const;
|
||||
AggregateStorageLocation *getThisPointeeStorageLocation() const;
|
||||
|
||||
/// Returns the storage location of the return value or null, if unset.
|
||||
StorageLocation *getReturnStorageLocation() const;
|
||||
/// Returns the location of the result object for a record-type prvalue.
|
||||
///
|
||||
/// In C++, prvalues of record type serve only a limited purpose: They can
|
||||
/// only be used to initialize a result object (e.g. a variable or a
|
||||
/// temporary). This function returns the location of that result object.
|
||||
///
|
||||
/// When creating a prvalue of record type, we already need the storage
|
||||
/// location of the result object to pass in `this`, even though prvalues are
|
||||
/// otherwise not associated with storage locations.
|
||||
///
|
||||
/// FIXME: Currently, this simply returns a stable storage location for `E`,
|
||||
/// but this doesn't do the right thing in scenarios like the following:
|
||||
/// ```
|
||||
/// MyClass c = some_condition()? MyClass(foo) : MyClass(bar);
|
||||
/// ```
|
||||
/// Here, `MyClass(foo)` and `MyClass(bar)` will have two different storage
|
||||
/// locations, when in fact their storage locations should be the same.
|
||||
/// Eventually, we want to propagate storage locations from result objects
|
||||
/// down to the prvalues that initialize them, similar to the way that this is
|
||||
/// done in Clang's CodeGen.
|
||||
///
|
||||
/// Requirements:
|
||||
/// `E` must be a prvalue of record type.
|
||||
AggregateStorageLocation &getResultObjectLocation(const Expr &RecordPRValue);
|
||||
|
||||
/// Returns the return value of the current function. This can be null if:
|
||||
/// - The function has a void return type
|
||||
/// - No return value could be determined for the function, for example
|
||||
/// because it calls a function without a body.
|
||||
///
|
||||
/// Requirements:
|
||||
/// The current function must have a non-reference return type.
|
||||
Value *getReturnValue() const {
|
||||
assert(getCurrentFunc() != nullptr &&
|
||||
!getCurrentFunc()->getReturnType()->isReferenceType());
|
||||
return ReturnVal;
|
||||
}
|
||||
|
||||
/// Returns the storage location for the reference returned by the current
|
||||
/// function. This can be null if function doesn't return a single consistent
|
||||
/// reference.
|
||||
///
|
||||
/// Requirements:
|
||||
/// The current function must have a reference return type.
|
||||
StorageLocation *getReturnStorageLocation() const {
|
||||
assert(getCurrentFunc() != nullptr &&
|
||||
getCurrentFunc()->getReturnType()->isReferenceType());
|
||||
return ReturnLoc;
|
||||
}
|
||||
|
||||
/// Sets the return value of the current function.
|
||||
///
|
||||
/// Requirements:
|
||||
/// The current function must have a non-reference return type.
|
||||
void setReturnValue(Value *Val) {
|
||||
assert(getCurrentFunc() != nullptr &&
|
||||
!getCurrentFunc()->getReturnType()->isReferenceType());
|
||||
ReturnVal = Val;
|
||||
}
|
||||
|
||||
/// Sets the storage location for the reference returned by the current
|
||||
/// function.
|
||||
///
|
||||
/// Requirements:
|
||||
/// The current function must have a reference return type.
|
||||
void setReturnStorageLocation(StorageLocation *Loc) {
|
||||
assert(getCurrentFunc() != nullptr &&
|
||||
getCurrentFunc()->getReturnType()->isReferenceType());
|
||||
ReturnLoc = Loc;
|
||||
}
|
||||
|
||||
/// Returns a pointer value that represents a null pointer. Calls with
|
||||
/// `PointeeType` that are canonically equivalent will return the same result.
|
||||
PointerValue &getOrCreateNullPointerValue(QualType PointeeType);
|
||||
|
||||
/// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
|
||||
/// return null. If `Type` is a pointer or reference type, creates all the
|
||||
/// necessary storage locations and values for indirections until it finds a
|
||||
/// returns null.
|
||||
///
|
||||
/// If `Type` is a pointer or reference type, creates all the necessary
|
||||
/// storage locations and values for indirections until it finds a
|
||||
/// non-pointer/non-reference type.
|
||||
///
|
||||
/// If `Type` is a class, struct, or union type, calls `setValue()` to
|
||||
/// associate the `StructValue` with its storage location
|
||||
/// (`StructValue::getAggregateLoc()`).
|
||||
///
|
||||
/// If `Type` is one of the following types, this function will always return
|
||||
/// a non-null pointer:
|
||||
/// - `bool`
|
||||
/// - Any integer type
|
||||
/// - Any class, struct, or union type
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `Type` must not be null.
|
||||
Value *createValue(QualType Type);
|
||||
|
||||
/// Creates an object (i.e. a storage location with an associated value) of
|
||||
/// type `Ty`. If `InitExpr` is non-null and has a value associated with it,
|
||||
/// initializes the object with this value. Otherwise, initializes the object
|
||||
/// with a value created using `createValue()`.
|
||||
StorageLocation &createObject(QualType Ty, const Expr *InitExpr = nullptr) {
|
||||
return createObjectInternal(nullptr, Ty, InitExpr);
|
||||
}
|
||||
|
||||
/// Creates an object for the variable declaration `D`. If `D` has an
|
||||
/// initializer and this initializer is associated with a value, initializes
|
||||
/// the object with this value. Otherwise, initializes the object with a
|
||||
/// value created using `createValue()`. Uses the storage location returned by
|
||||
/// `DataflowAnalysisContext::getStableStorageLocation(D)`.
|
||||
StorageLocation &createObject(const VarDecl &D) {
|
||||
return createObjectInternal(&D, D.getType(), D.getInit());
|
||||
}
|
||||
|
||||
/// Creates an object for the variable declaration `D`. If `InitExpr` is
|
||||
/// non-null and has a value associated with it, initializes the object with
|
||||
/// this value. Otherwise, initializes the object with a value created using
|
||||
/// `createValue()`. Uses the storage location returned by
|
||||
/// `DataflowAnalysisContext::getStableStorageLocation(D)`.
|
||||
StorageLocation &createObject(const VarDecl &D, const Expr *InitExpr) {
|
||||
return createObjectInternal(&D, D.getType(), InitExpr);
|
||||
}
|
||||
|
||||
/// Assigns `Val` as the value of `Loc` in the environment.
|
||||
void setValue(const StorageLocation &Loc, Value &Val);
|
||||
|
||||
/// Clears any association between `Loc` and a value in the environment.
|
||||
void clearValue(const StorageLocation &Loc) { LocToVal.erase(&Loc); }
|
||||
|
||||
/// Assigns `Val` as the value of the prvalue `E` in the environment.
|
||||
///
|
||||
/// If `E` is not yet associated with a storage location, associates it with
|
||||
/// a newly created storage location. In any case, associates the storage
|
||||
/// location of `E` with `Val`.
|
||||
///
|
||||
/// Once the migration to strict handling of value categories is complete
|
||||
/// (see https://discourse.llvm.org/t/70086), this function will be renamed to
|
||||
/// `setValue()`. At this point, prvalue expressions will be associated
|
||||
/// directly with `Value`s, and the legacy behavior of associating prvalue
|
||||
/// expressions with storage locations (as described above) will be
|
||||
/// eliminated.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `E` must be a prvalue
|
||||
/// `Val` must not be a `ReferenceValue`
|
||||
/// If `Val` is a `StructValue`, its `AggregateStorageLocation` must be the
|
||||
/// same as that of any `StructValue` that has already been associated with
|
||||
/// `E`. This is to guarantee that the result object initialized by a prvalue
|
||||
/// `StructValue` has a durable storage location.
|
||||
void setValueStrict(const Expr &E, Value &Val);
|
||||
|
||||
/// Returns the value assigned to `Loc` in the environment or null if `Loc`
|
||||
/// isn't assigned a value in the environment.
|
||||
Value *getValue(const StorageLocation &Loc) const;
|
||||
|
||||
/// Equivalent to `getValue(getStorageLocation(D, SP), SkipPast::None)` if `D`
|
||||
/// is assigned a storage location in the environment, otherwise returns null.
|
||||
Value *getValue(const ValueDecl &D, SkipPast SP) const;
|
||||
Value *getValue(const ValueDecl &D) const;
|
||||
|
||||
/// Equivalent to `getValue(getStorageLocation(E, SP), SkipPast::None)` if `E`
|
||||
/// is assigned a storage location in the environment, otherwise returns null.
|
||||
///
|
||||
/// This function is deprecated; prefer `getValueStrict()`. For details, see
|
||||
/// https://discourse.llvm.org/t/70086.
|
||||
Value *getValue(const Expr &E, SkipPast SP) const;
|
||||
|
||||
/// Transfers ownership of `Loc` to the analysis context and returns a
|
||||
/// reference to it.
|
||||
/// Returns the `Value` assigned to the prvalue `E` in the environment, or
|
||||
/// null if `E` isn't assigned a value in the environment.
|
||||
///
|
||||
/// This function is the preferred alternative to
|
||||
/// `getValue(const Expr &, SkipPast)`. Once the migration to strict handling
|
||||
/// of value categories is complete (see https://discourse.llvm.org/t/70086),
|
||||
/// `getValue()` will be removed and this function will be renamed to
|
||||
/// `getValue()`.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `Loc` must not be null.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_base_of<StorageLocation, T>::value, T &>
|
||||
takeOwnership(std::unique_ptr<T> Loc) {
|
||||
return DACtx->takeOwnership(std::move(Loc));
|
||||
/// `E` must be a prvalue
|
||||
Value *getValueStrict(const Expr &E) const;
|
||||
|
||||
// FIXME: should we deprecate the following & call arena().create() directly?
|
||||
|
||||
/// Creates a `T` (some subclass of `Value`), forwarding `args` to the
|
||||
/// constructor, and returns a reference to it.
|
||||
///
|
||||
/// The analysis context takes ownership of the created object. The object
|
||||
/// will be destroyed when the analysis context is destroyed.
|
||||
template <typename T, typename... Args>
|
||||
std::enable_if_t<std::is_base_of<Value, T>::value, T &>
|
||||
create(Args &&...args) {
|
||||
return arena().create<T>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Transfers ownership of `Val` to the analysis context and returns a
|
||||
/// reference to it.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `Val` must not be null.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_base_of<Value, T>::value, T &>
|
||||
takeOwnership(std::unique_ptr<T> Val) {
|
||||
return DACtx->takeOwnership(std::move(Val));
|
||||
/// Returns a symbolic integer value that models an integer literal equal to
|
||||
/// `Value`
|
||||
IntegerValue &getIntLiteralValue(llvm::APInt Value) const {
|
||||
return arena().makeIntLiteral(Value);
|
||||
}
|
||||
|
||||
/// Returns a symbolic boolean value that models a boolean literal equal to
|
||||
/// `Value`
|
||||
AtomicBoolValue &getBoolLiteralValue(bool Value) const {
|
||||
return DACtx->getBoolLiteralValue(Value);
|
||||
return cast<AtomicBoolValue>(
|
||||
arena().makeBoolValue(arena().makeLiteral(Value)));
|
||||
}
|
||||
|
||||
/// Returns an atomic boolean value.
|
||||
BoolValue &makeAtomicBoolValue() const {
|
||||
return DACtx->createAtomicBoolValue();
|
||||
return arena().makeAtomValue();
|
||||
}
|
||||
|
||||
/// Returns a unique instance of boolean Top.
|
||||
BoolValue &makeTopBoolValue() const {
|
||||
return DACtx->createTopBoolValue();
|
||||
return arena().makeTopValue();
|
||||
}
|
||||
|
||||
/// Returns a boolean value that represents the conjunction of `LHS` and
|
||||
|
|
@ -361,7 +556,8 @@ public:
|
|||
/// order, will return the same result. If the given boolean values represent
|
||||
/// the same value, the result will be the value itself.
|
||||
BoolValue &makeAnd(BoolValue &LHS, BoolValue &RHS) const {
|
||||
return DACtx->getOrCreateConjunction(LHS, RHS);
|
||||
return arena().makeBoolValue(
|
||||
arena().makeAnd(LHS.formula(), RHS.formula()));
|
||||
}
|
||||
|
||||
/// Returns a boolean value that represents the disjunction of `LHS` and
|
||||
|
|
@ -369,13 +565,14 @@ public:
|
|||
/// order, will return the same result. If the given boolean values represent
|
||||
/// the same value, the result will be the value itself.
|
||||
BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const {
|
||||
return DACtx->getOrCreateDisjunction(LHS, RHS);
|
||||
return arena().makeBoolValue(
|
||||
arena().makeOr(LHS.formula(), RHS.formula()));
|
||||
}
|
||||
|
||||
/// Returns a boolean value that represents the negation of `Val`. Subsequent
|
||||
/// calls with the same argument will return the same result.
|
||||
BoolValue &makeNot(BoolValue &Val) const {
|
||||
return DACtx->getOrCreateNegation(Val);
|
||||
return arena().makeBoolValue(arena().makeNot(Val.formula()));
|
||||
}
|
||||
|
||||
/// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with
|
||||
|
|
@ -383,7 +580,8 @@ public:
|
|||
/// values represent the same value, the result will be a value that
|
||||
/// represents the true boolean literal.
|
||||
BoolValue &makeImplication(BoolValue &LHS, BoolValue &RHS) const {
|
||||
return DACtx->getOrCreateImplication(LHS, RHS);
|
||||
return arena().makeBoolValue(
|
||||
arena().makeImplies(LHS.formula(), RHS.formula()));
|
||||
}
|
||||
|
||||
/// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with
|
||||
|
|
@ -391,48 +589,61 @@ public:
|
|||
/// result. If the given boolean values represent the same value, the result
|
||||
/// will be a value that represents the true boolean literal.
|
||||
BoolValue &makeIff(BoolValue &LHS, BoolValue &RHS) const {
|
||||
return DACtx->getOrCreateIff(LHS, RHS);
|
||||
return arena().makeBoolValue(
|
||||
arena().makeEquals(LHS.formula(), RHS.formula()));
|
||||
}
|
||||
|
||||
/// Returns the token that identifies the flow condition of the environment.
|
||||
AtomicBoolValue &getFlowConditionToken() const { return *FlowConditionToken; }
|
||||
/// Returns a boolean variable that identifies the flow condition (FC).
|
||||
///
|
||||
/// The flow condition is a set of facts that are necessarily true when the
|
||||
/// program reaches the current point, expressed as boolean formulas.
|
||||
/// The flow condition token is equivalent to the AND of these facts.
|
||||
///
|
||||
/// These may e.g. constrain the value of certain variables. A pointer
|
||||
/// variable may have a consistent modeled PointerValue throughout, but at a
|
||||
/// given point the Environment may tell us that the value must be non-null.
|
||||
///
|
||||
/// The FC is necessary but not sufficient for this point to be reachable.
|
||||
/// In particular, where the FC token appears in flow conditions of successor
|
||||
/// environments, it means "point X may have been reached", not
|
||||
/// "point X was reached".
|
||||
Atom getFlowConditionToken() const { return FlowConditionToken; }
|
||||
|
||||
/// Builds and returns the logical formula defining the flow condition
|
||||
/// identified by `Token`. If a value in the formula is present as a key in
|
||||
/// `Substitutions`, it will be substituted with the value it maps to.
|
||||
BoolValue &buildAndSubstituteFlowCondition(
|
||||
AtomicBoolValue &Token,
|
||||
llvm::DenseMap<AtomicBoolValue *, BoolValue *> Substitutions) {
|
||||
return DACtx->buildAndSubstituteFlowCondition(Token,
|
||||
std::move(Substitutions));
|
||||
}
|
||||
/// Record a fact that must be true if this point in the program is reached.
|
||||
void addToFlowCondition(const Formula &);
|
||||
|
||||
/// Adds `Val` to the set of clauses that constitute the flow condition.
|
||||
void addToFlowCondition(BoolValue &Val);
|
||||
|
||||
/// Returns true if and only if the clauses that constitute the flow condition
|
||||
/// imply that `Val` is true.
|
||||
bool flowConditionImplies(BoolValue &Val) const;
|
||||
/// Returns true if the formula is always true when this point is reached.
|
||||
/// Returns false if the formula may be false, or if the flow condition isn't
|
||||
/// sufficiently precise to prove that it is true.
|
||||
bool flowConditionImplies(const Formula &) const;
|
||||
|
||||
/// Returns the `DeclContext` of the block being analysed, if any. Otherwise,
|
||||
/// returns null.
|
||||
const DeclContext *getDeclCtx() const { return CallStack.back(); }
|
||||
|
||||
/// Returns the function currently being analyzed, or null if the code being
|
||||
/// analyzed isn't part of a function.
|
||||
const FunctionDecl *getCurrentFunc() const {
|
||||
return dyn_cast<FunctionDecl>(getDeclCtx());
|
||||
}
|
||||
|
||||
/// Returns whether this `Environment` can be extended to analyze the given
|
||||
/// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a
|
||||
/// given `MaxDepth`.
|
||||
bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const;
|
||||
|
||||
/// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise,
|
||||
/// returns null.
|
||||
const ControlFlowContext *getControlFlowContext(const FunctionDecl *F) {
|
||||
return DACtx->getControlFlowContext(F);
|
||||
}
|
||||
/// Returns the `DataflowAnalysisContext` used by the environment.
|
||||
DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; }
|
||||
|
||||
Arena &arena() const { return DACtx->arena(); }
|
||||
|
||||
LLVM_DUMP_METHOD void dump() const;
|
||||
LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;
|
||||
|
||||
private:
|
||||
// The copy-constructor is for use in fork() only.
|
||||
Environment(const Environment &) = default;
|
||||
|
||||
/// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
|
||||
/// return null.
|
||||
///
|
||||
|
|
@ -448,6 +659,19 @@ private:
|
|||
llvm::DenseSet<QualType> &Visited,
|
||||
int Depth, int &CreatedValuesCount);
|
||||
|
||||
/// Creates a storage location for `Ty`. Also creates and associates a value
|
||||
/// with the storage location, unless values of this type are not supported or
|
||||
/// we hit one of the limits at which we stop producing values (controlled by
|
||||
/// `Visited`, `Depth`, and `CreatedValuesCount`).
|
||||
StorageLocation &createLocAndMaybeValue(QualType Ty,
|
||||
llvm::DenseSet<QualType> &Visited,
|
||||
int Depth, int &CreatedValuesCount);
|
||||
|
||||
/// Shared implementation of `createObject()` overloads.
|
||||
/// `D` and `InitExpr` may be null.
|
||||
StorageLocation &createObjectInternal(const VarDecl *D, QualType Ty,
|
||||
const Expr *InitExpr);
|
||||
|
||||
StorageLocation &skip(StorageLocation &Loc, SkipPast SP) const;
|
||||
const StorageLocation &skip(const StorageLocation &Loc, SkipPast SP) const;
|
||||
|
||||
|
|
@ -457,26 +681,29 @@ private:
|
|||
void pushCallInternal(const FunctionDecl *FuncDecl,
|
||||
ArrayRef<const Expr *> Args);
|
||||
|
||||
/// Assigns storage locations and values to all variables in `Vars`.
|
||||
void initVars(llvm::DenseSet<const VarDecl *> Vars);
|
||||
/// Assigns storage locations and values to all global variables, fields
|
||||
/// and functions referenced in `FuncDecl`. `FuncDecl` must have a body.
|
||||
void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl);
|
||||
|
||||
// `DACtx` is not null and not owned by this object.
|
||||
DataflowAnalysisContext *DACtx;
|
||||
|
||||
|
||||
// FIXME: move the fields `CallStack`, `ReturnLoc` and `ThisPointeeLoc` into a
|
||||
// separate call-context object, shared between environments in the same call.
|
||||
// FIXME: move the fields `CallStack`, `ReturnVal`, `ReturnLoc` and
|
||||
// `ThisPointeeLoc` into a separate call-context object, shared between
|
||||
// environments in the same call.
|
||||
// https://github.com/llvm/llvm-project/issues/59005
|
||||
|
||||
// `DeclContext` of the block being analysed if provided.
|
||||
std::vector<const DeclContext *> CallStack;
|
||||
|
||||
// In a properly initialized `Environment`, `ReturnLoc` should only be null if
|
||||
// its `DeclContext` could not be cast to a `FunctionDecl`.
|
||||
// Value returned by the function (if it has non-reference return type).
|
||||
Value *ReturnVal = nullptr;
|
||||
// Storage location of the reference returned by the function (if it has
|
||||
// reference return type).
|
||||
StorageLocation *ReturnLoc = nullptr;
|
||||
// The storage location of the `this` pointee. Should only be null if the
|
||||
// function being analyzed is only a function and not a method.
|
||||
StorageLocation *ThisPointeeLoc = nullptr;
|
||||
AggregateStorageLocation *ThisPointeeLoc = nullptr;
|
||||
|
||||
// Maps from program declarations and statements to storage locations that are
|
||||
// assigned to them. Unlike the maps in `DataflowAnalysisContext`, these
|
||||
|
|
@ -484,18 +711,48 @@ private:
|
|||
// block.
|
||||
llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc;
|
||||
llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc;
|
||||
// We preserve insertion order so that join/widen process values in
|
||||
// deterministic sequence. This in turn produces deterministic SAT formulas.
|
||||
llvm::MapVector<const StorageLocation *, Value *> LocToVal;
|
||||
|
||||
llvm::DenseMap<const StorageLocation *, Value *> LocToVal;
|
||||
|
||||
// Maps locations of struct members to symbolic values of the structs that own
|
||||
// them and the decls of the struct members.
|
||||
llvm::DenseMap<const StorageLocation *,
|
||||
std::pair<StructValue *, const ValueDecl *>>
|
||||
MemberLocToStruct;
|
||||
|
||||
AtomicBoolValue *FlowConditionToken;
|
||||
Atom FlowConditionToken;
|
||||
};
|
||||
|
||||
/// Returns the storage location for the implicit object of a
|
||||
/// `CXXMemberCallExpr`, or null if none is defined in the environment.
|
||||
/// Dereferences the pointer if the member call expression was written using
|
||||
/// `->`.
|
||||
AggregateStorageLocation *
|
||||
getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment &Env);
|
||||
|
||||
/// Returns the storage location for the base object of a `MemberExpr`, or null
|
||||
/// if none is defined in the environment. Dereferences the pointer if the
|
||||
/// member expression was written using `->`.
|
||||
AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
|
||||
const Environment &Env);
|
||||
|
||||
/// Returns the fields of `RD` that are initialized by an `InitListExpr`, in the
|
||||
/// order in which they appear in `InitListExpr::inits()`.
|
||||
std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD);
|
||||
|
||||
/// Associates a new `StructValue` with `Loc` and returns the new value.
|
||||
/// It is not defined whether the field values remain the same or not.
|
||||
///
|
||||
/// This function is primarily intended for use by checks that set custom
|
||||
/// properties on `StructValue`s to model the state of these values. Such checks
|
||||
/// should avoid modifying the properties of an existing `StructValue` because
|
||||
/// these changes would be visible to other `Environment`s that share the same
|
||||
/// `StructValue`. Instead, call `refreshStructValue()`, then set the properties
|
||||
/// on the new `StructValue` that it returns. Typical usage:
|
||||
///
|
||||
/// refreshStructValue(Loc, Env).setProperty("my_prop", MyPropValue);
|
||||
StructValue &refreshStructValue(AggregateStorageLocation &Loc,
|
||||
Environment &Env);
|
||||
|
||||
/// Associates a new `StructValue` with `Expr` and returns the new value.
|
||||
/// See also documentation for the overload above.
|
||||
StructValue &refreshStructValue(const Expr &Expr, Environment &Env);
|
||||
|
||||
} // namespace dataflow
|
||||
} // namespace clang
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include "clang/Analysis/FlowSensitive/Solver.h"
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clang {
|
||||
|
|
@ -28,60 +27,9 @@ namespace dataflow {
|
|||
/// Returns a string representation of a value kind.
|
||||
llvm::StringRef debugString(Value::Kind Kind);
|
||||
|
||||
/// Returns a string representation of a boolean assignment to true or false.
|
||||
llvm::StringRef debugString(Solver::Result::Assignment Assignment);
|
||||
|
||||
/// Returns a string representation of the result status of a SAT check.
|
||||
llvm::StringRef debugString(Solver::Result::Status Status);
|
||||
|
||||
/// Returns a string representation for the boolean value `B`.
|
||||
///
|
||||
/// Atomic booleans appearing in the boolean value `B` are assigned to labels
|
||||
/// either specified in `AtomNames` or created by default rules as B0, B1, ...
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// Names assigned to atoms should not be repeated in `AtomNames`.
|
||||
std::string debugString(
|
||||
const BoolValue &B,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}});
|
||||
|
||||
/// Returns a string representation for `Constraints` - a collection of boolean
|
||||
/// formulas.
|
||||
///
|
||||
/// Atomic booleans appearing in the boolean value `Constraints` are assigned to
|
||||
/// labels either specified in `AtomNames` or created by default rules as B0,
|
||||
/// B1, ...
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// Names assigned to atoms should not be repeated in `AtomNames`.
|
||||
std::string debugString(
|
||||
const llvm::DenseSet<BoolValue *> &Constraints,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}});
|
||||
|
||||
/// Returns a string representation for `Constraints` - a collection of boolean
|
||||
/// formulas and the `Result` of satisfiability checking.
|
||||
///
|
||||
/// Atomic booleans appearing in `Constraints` and `Result` are assigned to
|
||||
/// labels either specified in `AtomNames` or created by default rules as B0,
|
||||
/// B1, ...
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// Names assigned to atoms should not be repeated in `AtomNames`.
|
||||
std::string debugString(
|
||||
ArrayRef<BoolValue *> Constraints, const Solver::Result &Result,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}});
|
||||
inline std::string debugString(
|
||||
const llvm::DenseSet<BoolValue *> &Constraints,
|
||||
const Solver::Result &Result,
|
||||
llvm::DenseMap<const AtomicBoolValue *, std::string> AtomNames = {{}}) {
|
||||
std::vector<BoolValue *> ConstraintsVec(Constraints.begin(),
|
||||
Constraints.end());
|
||||
return debugString(ConstraintsVec, Result, std::move(AtomNames));
|
||||
}
|
||||
|
||||
} // namespace dataflow
|
||||
} // namespace clang
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
//===- Formula.h - Boolean formulas -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_FORMULA_H
|
||||
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_FORMULA_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseMapInfo.h"
|
||||
#include "llvm/ADT/STLFunctionalExtras.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace clang::dataflow {
|
||||
|
||||
/// Identifies an atomic boolean variable such as "V1".
|
||||
///
|
||||
/// This often represents an assertion that is interesting to the analysis but
|
||||
/// cannot immediately be proven true or false. For example:
|
||||
/// - V1 may mean "the program reaches this point",
|
||||
/// - V2 may mean "the parameter was null"
|
||||
///
|
||||
/// We can use these variables in formulas to describe relationships we know
|
||||
/// to be true: "if the parameter was null, the program reaches this point".
|
||||
/// We also express hypotheses as formulas, and use a SAT solver to check
|
||||
/// whether they are consistent with the known facts.
|
||||
enum class Atom : unsigned {};
|
||||
|
||||
/// A boolean expression such as "true" or "V1 & !V2".
|
||||
/// Expressions may refer to boolean atomic variables. These should take a
|
||||
/// consistent true/false value across the set of formulas being considered.
|
||||
///
|
||||
/// (Formulas are always expressions in terms of boolean variables rather than
|
||||
/// e.g. integers because our underlying model is SAT rather than e.g. SMT).
|
||||
///
|
||||
/// Simple formulas such as "true" and "V1" are self-contained.
|
||||
/// Compound formulas connect other formulas, e.g. "(V1 & V2) || V3" is an 'or'
|
||||
/// formula, with pointers to its operands "(V1 & V2)" and "V3" stored as
|
||||
/// trailing objects.
|
||||
/// For this reason, Formulas are Arena-allocated and over-aligned.
|
||||
class Formula;
|
||||
class alignas(const Formula *) Formula {
|
||||
public:
|
||||
enum Kind : unsigned {
|
||||
/// A reference to an atomic boolean variable.
|
||||
/// We name these e.g. "V3", where 3 == atom identity == Value.
|
||||
AtomRef,
|
||||
// FIXME: add const true/false rather than modeling them as variables
|
||||
|
||||
Not, /// True if its only operand is false
|
||||
|
||||
// These kinds connect two operands LHS and RHS
|
||||
And, /// True if LHS and RHS are both true
|
||||
Or, /// True if either LHS or RHS is true
|
||||
Implies, /// True if LHS is false or RHS is true
|
||||
Equal, /// True if LHS and RHS have the same truth value
|
||||
};
|
||||
Kind kind() const { return FormulaKind; }
|
||||
|
||||
Atom getAtom() const {
|
||||
assert(kind() == AtomRef);
|
||||
return static_cast<Atom>(Value);
|
||||
}
|
||||
|
||||
ArrayRef<const Formula *> operands() const {
|
||||
return ArrayRef(reinterpret_cast<Formula *const *>(this + 1),
|
||||
numOperands(kind()));
|
||||
}
|
||||
|
||||
using AtomNames = llvm::DenseMap<Atom, std::string>;
|
||||
// Produce a stable human-readable representation of this formula.
|
||||
// For example: (V3 | !(V1 & V2))
|
||||
// If AtomNames is provided, these override the default V0, V1... names.
|
||||
void print(llvm::raw_ostream &OS, const AtomNames * = nullptr) const;
|
||||
|
||||
// Allocate Formulas using Arena rather than calling this function directly.
|
||||
static Formula &create(llvm::BumpPtrAllocator &Alloc, Kind K,
|
||||
ArrayRef<const Formula *> Operands,
|
||||
unsigned Value = 0);
|
||||
|
||||
private:
|
||||
Formula() = default;
|
||||
Formula(const Formula &) = delete;
|
||||
Formula &operator=(const Formula &) = delete;
|
||||
|
||||
static unsigned numOperands(Kind K) {
|
||||
switch (K) {
|
||||
case AtomRef:
|
||||
return 0;
|
||||
case Not:
|
||||
return 1;
|
||||
case And:
|
||||
case Or:
|
||||
case Implies:
|
||||
case Equal:
|
||||
return 2;
|
||||
}
|
||||
llvm_unreachable("Unhandled Formula::Kind enum");
|
||||
}
|
||||
|
||||
Kind FormulaKind;
|
||||
// Some kinds of formula have scalar values, e.g. AtomRef's atom number.
|
||||
unsigned Value;
|
||||
};
|
||||
|
||||
// The default names of atoms are V0, V1 etc in order of creation.
|
||||
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, Atom A) {
|
||||
return OS << 'V' << static_cast<unsigned>(A);
|
||||
}
|
||||
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Formula &F) {
|
||||
F.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
} // namespace clang::dataflow
|
||||
namespace llvm {
|
||||
template <> struct DenseMapInfo<clang::dataflow::Atom> {
|
||||
using Atom = clang::dataflow::Atom;
|
||||
using Underlying = std::underlying_type_t<Atom>;
|
||||
|
||||
static inline Atom getEmptyKey() { return Atom(Underlying(-1)); }
|
||||
static inline Atom getTombstoneKey() { return Atom(Underlying(-2)); }
|
||||
static unsigned getHashValue(const Atom &Val) {
|
||||
return DenseMapInfo<Underlying>::getHashValue(Underlying(Val));
|
||||
}
|
||||
static bool isEqual(const Atom &LHS, const Atom &RHS) { return LHS == RHS; }
|
||||
};
|
||||
} // namespace llvm
|
||||
#endif
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
//===-- Logger.h ------------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_LOGGER_H
|
||||
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_LOGGER_H
|
||||
|
||||
#include "clang/Analysis/CFG.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <memory>
|
||||
|
||||
namespace clang::dataflow {
|
||||
// Forward declarations so we can use Logger anywhere in the framework.
|
||||
class ControlFlowContext;
|
||||
class TypeErasedDataflowAnalysis;
|
||||
struct TypeErasedDataflowAnalysisState;
|
||||
|
||||
/// A logger is notified as the analysis progresses.
|
||||
/// It can produce a report of the analysis's findings and how it came to them.
|
||||
///
|
||||
/// The framework reports key structural events (e.g. traversal of blocks).
|
||||
/// The specific analysis can add extra details to be presented in context.
|
||||
class Logger {
|
||||
public:
|
||||
/// Returns a dummy logger that does nothing.
|
||||
static Logger &null();
|
||||
/// A logger that simply writes messages to the specified ostream in real
|
||||
/// time.
|
||||
static std::unique_ptr<Logger> textual(llvm::raw_ostream &);
|
||||
/// A logger that builds an HTML UI to inspect the analysis results.
|
||||
/// Each function's analysis is written to a stream obtained from the factory.
|
||||
static std::unique_ptr<Logger>
|
||||
html(std::function<std::unique_ptr<llvm::raw_ostream>()>);
|
||||
|
||||
virtual ~Logger() = default;
|
||||
|
||||
/// Called by the framework as we start analyzing a new function or statement.
|
||||
/// Forms a pair with endAnalysis().
|
||||
virtual void beginAnalysis(const ControlFlowContext &,
|
||||
TypeErasedDataflowAnalysis &) {}
|
||||
virtual void endAnalysis() {}
|
||||
|
||||
// At any time during the analysis, we're computing the state for some target
|
||||
// program point.
|
||||
|
||||
/// Called when we start (re-)processing a block in the CFG.
|
||||
/// The target program point is the entry to the specified block.
|
||||
/// Calls to log() describe transferBranch(), join() etc.
|
||||
virtual void enterBlock(const CFGBlock &) {}
|
||||
/// Called when we start processing an element in the current CFG block.
|
||||
/// The target program point is after the specified element.
|
||||
/// Calls to log() describe the transfer() function.
|
||||
virtual void enterElement(const CFGElement &) {}
|
||||
|
||||
/// Records the analysis state computed for the current program point.
|
||||
virtual void recordState(TypeErasedDataflowAnalysisState &) {}
|
||||
/// Records that the analysis state for the current block is now final.
|
||||
virtual void blockConverged() {}
|
||||
|
||||
/// Called by the framework or user code to report some event.
|
||||
/// The event is associated with the current context (program point).
|
||||
/// The Emit function produces the log message. It may or may not be called,
|
||||
/// depending on if the logger is interested; it should have no side effects.
|
||||
void log(llvm::function_ref<void(llvm::raw_ostream &)> Emit) {
|
||||
if (!ShouldLogText)
|
||||
return;
|
||||
std::string S;
|
||||
llvm::raw_string_ostream OS(S);
|
||||
Emit(OS);
|
||||
logText(S);
|
||||
}
|
||||
|
||||
protected:
|
||||
/// ShouldLogText should be false for trivial loggers that ignore logText().
|
||||
/// This allows log() to skip evaluating its Emit function.
|
||||
Logger(bool ShouldLogText = true) : ShouldLogText(ShouldLogText) {}
|
||||
|
||||
private:
|
||||
bool ShouldLogText;
|
||||
virtual void logText(llvm::StringRef) {}
|
||||
};
|
||||
|
||||
} // namespace clang::dataflow
|
||||
|
||||
#endif
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the `MatchSwitch` abstraction for building a "switch"
|
||||
// This file defines the `ASTMatchSwitch` abstraction for building a "switch"
|
||||
// statement, where each case of the switch is defined by an AST matcher. The
|
||||
// cases are considered in order, like pattern matching in functional
|
||||
// languages.
|
||||
|
|
@ -17,8 +17,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// FIXME: Rename to ASTMatchSwitch.h and update documentation when all usages of
|
||||
// `MatchSwitch` are updated to `ASTMatchSwitch<Stmt>`
|
||||
// FIXME: Rename to ASTMatchSwitch.h
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_
|
||||
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_
|
||||
|
|
@ -69,11 +68,6 @@ template <typename BaseT, typename State, typename Result = void>
|
|||
using ASTMatchSwitch =
|
||||
std::function<Result(const BaseT &, ASTContext &, State &)>;
|
||||
|
||||
// FIXME: Remove this alias when all usages of `MatchSwitch` are updated to
|
||||
// `ASTMatchSwitch<Stmt>`.
|
||||
template <typename State, typename Result = void>
|
||||
using MatchSwitch = ASTMatchSwitch<Stmt, State, Result>;
|
||||
|
||||
/// Collects cases of a "match switch": a collection of matchers paired with
|
||||
/// callbacks, which together define a switch that can be applied to a node
|
||||
/// whose type derives from `BaseT`. This structure can simplify the definition
|
||||
|
|
@ -171,11 +165,6 @@ private:
|
|||
std::vector<MatchSwitchAction<BaseT, State, Result>> Actions;
|
||||
};
|
||||
|
||||
// FIXME: Remove this alias when all usages of `MatchSwitchBuilder` are updated
|
||||
// to `ASTMatchSwitchBuilder<Stmt>`.
|
||||
template <typename State, typename Result = void>
|
||||
using MatchSwitchBuilder = ASTMatchSwitchBuilder<Stmt, State, Result>;
|
||||
|
||||
} // namespace dataflow
|
||||
} // namespace clang
|
||||
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_MATCHSWITCH_H_
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
#define CLANG_ANALYSIS_FLOWSENSITIVE_MODELS_CHROMIUMCHECKMODEL_H
|
||||
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowAnalysis.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
|
|
@ -26,7 +25,7 @@ namespace dataflow {
|
|||
class ChromiumCheckModel : public DataflowModel {
|
||||
public:
|
||||
ChromiumCheckModel() = default;
|
||||
bool transfer(const CFGElement *Element, Environment &Env) override;
|
||||
bool transfer(const CFGElement &Element, Environment &Env) override;
|
||||
|
||||
private:
|
||||
/// Declarations for `::logging::CheckError::.*Check`, lazily initialized.
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public:
|
|||
|
||||
static NoopLattice initialElement() { return {}; }
|
||||
|
||||
void transfer(const CFGElement *Elt, NoopLattice &L, Environment &Env);
|
||||
void transfer(const CFGElement &Elt, NoopLattice &L, Environment &Env);
|
||||
|
||||
ComparisonResult compare(QualType Type, const Value &Val1,
|
||||
const Environment &Env1, const Value &Val2,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public:
|
|||
|
||||
static NoopLattice initialElement() { return {}; }
|
||||
|
||||
void transfer(const CFGElement *E, NoopLattice &L, Environment &Env) {}
|
||||
void transfer(const CFGElement &E, NoopLattice &L, Environment &Env) {}
|
||||
};
|
||||
|
||||
} // namespace dataflow
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
//===-- RecordOps.h ---------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Operations on records (structs, classes, and unions).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_RECORDOPS_H
|
||||
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_RECORDOPS_H
|
||||
|
||||
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
|
||||
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
|
||||
/// Copies a record (struct, class, or union) from `Src` to `Dst`.
|
||||
///
|
||||
/// This performs a deep copy, i.e. it copies every field and recurses on
|
||||
/// fields of record type. It also copies properties from the `StructValue`
|
||||
/// associated with `Src` to the `StructValue` associated with `Dst` (if these
|
||||
/// `StructValue`s exist).
|
||||
///
|
||||
/// If there is a `StructValue` associated with `Dst` in the environment, this
|
||||
/// function creates a new `StructValue` and associates it with `Dst`; clients
|
||||
/// need to be aware of this and must not assume that the `StructValue`
|
||||
/// associated with `Dst` remains the same after the call.
|
||||
///
|
||||
/// We create a new `StructValue` rather than modifying properties on the old
|
||||
/// `StructValue` because the old `StructValue` may be shared with other
|
||||
/// `Environment`s, and we don't want changes to properties to be visible there.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `Src` and `Dst` must have the same canonical unqualified type.
|
||||
void copyRecord(AggregateStorageLocation &Src, AggregateStorageLocation &Dst,
|
||||
Environment &Env);
|
||||
|
||||
/// Returns whether the records `Loc1` and `Loc2` are equal.
|
||||
///
|
||||
/// Values for `Loc1` are retrieved from `Env1`, and values for `Loc2` are
|
||||
/// retrieved from `Env2`. A convenience overload retrieves values for `Loc1`
|
||||
/// and `Loc2` from the same environment.
|
||||
///
|
||||
/// This performs a deep comparison, i.e. it compares every field and recurses
|
||||
/// on fields of record type. Fields of reference type compare equal if they
|
||||
/// refer to the same storage location. If `StructValue`s are associated with
|
||||
/// `Loc1` and `Loc2`, it also compares the properties on those `StructValue`s.
|
||||
///
|
||||
/// Note on how to interpret the result:
|
||||
/// - If this returns true, the records are guaranteed to be equal at runtime.
|
||||
/// - If this returns false, the records may still be equal at runtime; our
|
||||
/// analysis merely cannot guarantee that they will be equal.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `Src` and `Dst` must have the same canonical unqualified type.
|
||||
bool recordsEqual(const AggregateStorageLocation &Loc1, const Environment &Env1,
|
||||
const AggregateStorageLocation &Loc2,
|
||||
const Environment &Env2);
|
||||
|
||||
inline bool recordsEqual(const AggregateStorageLocation &Loc1,
|
||||
const AggregateStorageLocation &Loc2,
|
||||
const Environment &Env) {
|
||||
return recordsEqual(Loc1, Env, Loc2, Env);
|
||||
}
|
||||
|
||||
} // namespace dataflow
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_RECORDOPS_H
|
||||
|
|
@ -14,10 +14,12 @@
|
|||
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOLVER_H
|
||||
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_SOLVER_H
|
||||
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "clang/Analysis/FlowSensitive/Formula.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
|
|
@ -45,8 +47,7 @@ public:
|
|||
|
||||
/// Constructs a result indicating that the queried boolean formula is
|
||||
/// satisfiable. The result will hold a solution found by the solver.
|
||||
static Result
|
||||
Satisfiable(llvm::DenseMap<AtomicBoolValue *, Assignment> Solution) {
|
||||
static Result Satisfiable(llvm::DenseMap<Atom, Assignment> Solution) {
|
||||
return Result(Status::Satisfiable, std::move(Solution));
|
||||
}
|
||||
|
||||
|
|
@ -64,19 +65,17 @@ public:
|
|||
|
||||
/// Returns a truth assignment to boolean values that satisfies the queried
|
||||
/// boolean formula if available. Otherwise, an empty optional is returned.
|
||||
std::optional<llvm::DenseMap<AtomicBoolValue *, Assignment>>
|
||||
getSolution() const {
|
||||
std::optional<llvm::DenseMap<Atom, Assignment>> getSolution() const {
|
||||
return Solution;
|
||||
}
|
||||
|
||||
private:
|
||||
Result(
|
||||
enum Status SATCheckStatus,
|
||||
std::optional<llvm::DenseMap<AtomicBoolValue *, Assignment>> Solution)
|
||||
Result(Status SATCheckStatus,
|
||||
std::optional<llvm::DenseMap<Atom, Assignment>> Solution)
|
||||
: SATCheckStatus(SATCheckStatus), Solution(std::move(Solution)) {}
|
||||
|
||||
Status SATCheckStatus;
|
||||
std::optional<llvm::DenseMap<AtomicBoolValue *, Assignment>> Solution;
|
||||
std::optional<llvm::DenseMap<Atom, Assignment>> Solution;
|
||||
};
|
||||
|
||||
virtual ~Solver() = default;
|
||||
|
|
@ -87,9 +86,12 @@ public:
|
|||
/// Requirements:
|
||||
///
|
||||
/// All elements in `Vals` must not be null.
|
||||
virtual Result solve(llvm::DenseSet<BoolValue *> Vals) = 0;
|
||||
virtual Result solve(llvm::ArrayRef<const Formula *> Vals) = 0;
|
||||
};
|
||||
|
||||
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Solver::Result &);
|
||||
llvm::raw_ostream &operator<<(llvm::raw_ostream &, Solver::Result::Assignment);
|
||||
|
||||
} // namespace dataflow
|
||||
} // namespace clang
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@
|
|||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include <cassert>
|
||||
|
||||
#define DEBUG_TYPE "dataflow"
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
|
|
@ -29,7 +33,9 @@ class StorageLocation {
|
|||
public:
|
||||
enum class Kind { Scalar, Aggregate };
|
||||
|
||||
StorageLocation(Kind LocKind, QualType Type) : LocKind(LocKind), Type(Type) {}
|
||||
StorageLocation(Kind LocKind, QualType Type) : LocKind(LocKind), Type(Type) {
|
||||
assert(Type.isNull() || !Type->isReferenceType());
|
||||
}
|
||||
|
||||
// Non-copyable because addresses of storage locations are used as their
|
||||
// identities throughout framework and user code. The framework is responsible
|
||||
|
|
@ -65,36 +71,89 @@ public:
|
|||
/// struct with public members. The child map is flat, so when used for a struct
|
||||
/// or class type, all accessible members of base struct and class types are
|
||||
/// directly accesible as children of this location.
|
||||
///
|
||||
/// The storage location for a field of reference type may be null. This
|
||||
/// typically occurs in one of two situations:
|
||||
/// - The record has not been fully initialized.
|
||||
/// - The maximum depth for modelling a self-referential data structure has been
|
||||
/// reached.
|
||||
/// Storage locations for fields of all other types must be non-null.
|
||||
///
|
||||
/// FIXME: Currently, the storage location of unions is modelled the same way as
|
||||
/// that of structs or classes. Eventually, we need to change this modelling so
|
||||
/// that all of the members of a given union have the same storage location.
|
||||
class AggregateStorageLocation final : public StorageLocation {
|
||||
public:
|
||||
explicit AggregateStorageLocation(QualType Type)
|
||||
: AggregateStorageLocation(
|
||||
Type, llvm::DenseMap<const ValueDecl *, StorageLocation *>()) {}
|
||||
using FieldToLoc = llvm::DenseMap<const ValueDecl *, StorageLocation *>;
|
||||
|
||||
AggregateStorageLocation(
|
||||
QualType Type,
|
||||
llvm::DenseMap<const ValueDecl *, StorageLocation *> Children)
|
||||
: StorageLocation(Kind::Aggregate, Type), Children(std::move(Children)) {}
|
||||
explicit AggregateStorageLocation(QualType Type)
|
||||
: AggregateStorageLocation(Type, FieldToLoc()) {}
|
||||
|
||||
AggregateStorageLocation(QualType Type, FieldToLoc TheChildren)
|
||||
: StorageLocation(Kind::Aggregate, Type),
|
||||
Children(std::move(TheChildren)) {
|
||||
assert(!Type.isNull());
|
||||
assert(Type->isRecordType());
|
||||
assert([this] {
|
||||
for (auto [Field, Loc] : Children) {
|
||||
if (!Field->getType()->isReferenceType() && Loc == nullptr)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
}
|
||||
|
||||
static bool classof(const StorageLocation *Loc) {
|
||||
return Loc->getKind() == Kind::Aggregate;
|
||||
}
|
||||
|
||||
/// Returns the child storage location for `D`.
|
||||
StorageLocation &getChild(const ValueDecl &D) const {
|
||||
///
|
||||
/// May return null if `D` has reference type; guaranteed to return non-null
|
||||
/// in all other cases.
|
||||
///
|
||||
/// Note that it is an error to call this with a field that does not exist.
|
||||
/// The function does not return null in this case.
|
||||
StorageLocation *getChild(const ValueDecl &D) const {
|
||||
auto It = Children.find(&D);
|
||||
LLVM_DEBUG({
|
||||
if (It == Children.end()) {
|
||||
llvm::dbgs() << "Couldn't find child " << D.getNameAsString()
|
||||
<< " on StorageLocation " << this << " of type "
|
||||
<< getType() << "\n";
|
||||
llvm::dbgs() << "Existing children:\n";
|
||||
for ([[maybe_unused]] auto [Field, Loc] : Children) {
|
||||
llvm::dbgs() << Field->getNameAsString() << "\n";
|
||||
}
|
||||
}
|
||||
});
|
||||
assert(It != Children.end());
|
||||
return *It->second;
|
||||
return It->second;
|
||||
}
|
||||
|
||||
/// Changes the child storage location for a field `D` of reference type.
|
||||
/// All other fields cannot change their storage location and always retain
|
||||
/// the storage location passed to the `AggregateStorageLocation` constructor.
|
||||
///
|
||||
/// Requirements:
|
||||
///
|
||||
/// `D` must have reference type.
|
||||
void setChild(const ValueDecl &D, StorageLocation *Loc) {
|
||||
assert(D.getType()->isReferenceType());
|
||||
Children[&D] = Loc;
|
||||
}
|
||||
|
||||
llvm::iterator_range<FieldToLoc::const_iterator> children() const {
|
||||
return {Children.begin(), Children.end()};
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::DenseMap<const ValueDecl *, StorageLocation *> Children;
|
||||
FieldToLoc Children;
|
||||
};
|
||||
|
||||
} // namespace dataflow
|
||||
} // namespace clang
|
||||
|
||||
#undef DEBUG_TYPE
|
||||
|
||||
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_STORAGELOCATION_H
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
|
||||
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
|
||||
#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h"
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
|
|
@ -24,12 +25,18 @@ namespace dataflow {
|
|||
/// Maps statements to the environments of basic blocks that contain them.
|
||||
class StmtToEnvMap {
|
||||
public:
|
||||
virtual ~StmtToEnvMap() = default;
|
||||
StmtToEnvMap(const ControlFlowContext &CFCtx,
|
||||
llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>>
|
||||
BlockToState)
|
||||
: CFCtx(CFCtx), BlockToState(BlockToState) {}
|
||||
|
||||
/// Returns the environment of the basic block that contains `S` or nullptr if
|
||||
/// there isn't one.
|
||||
/// FIXME: Ensure that the result can't be null and return a const reference.
|
||||
virtual const Environment *getEnvironment(const Stmt &S) const = 0;
|
||||
/// Returns the environment of the basic block that contains `S`.
|
||||
/// The result is guaranteed never to be null.
|
||||
const Environment *getEnvironment(const Stmt &S) const;
|
||||
|
||||
private:
|
||||
const ControlFlowContext &CFCtx;
|
||||
llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>> BlockToState;
|
||||
};
|
||||
|
||||
/// Evaluates `S` and updates `Env` accordingly.
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ public:
|
|||
/// Joins two type-erased lattice elements by computing their least upper
|
||||
/// bound. Places the join result in the left element and returns an effect
|
||||
/// indicating whether any changes were made to it.
|
||||
virtual LatticeJoinEffect joinTypeErased(TypeErasedLattice &,
|
||||
virtual TypeErasedLattice joinTypeErased(const TypeErasedLattice &,
|
||||
const TypeErasedLattice &) = 0;
|
||||
|
||||
/// Chooses a lattice element that approximates the current element at a
|
||||
|
|
@ -96,7 +96,7 @@ public:
|
|||
|
||||
/// Applies the analysis transfer function for a given control flow graph
|
||||
/// element and type-erased lattice element.
|
||||
virtual void transferTypeErased(const CFGElement *, TypeErasedLattice &,
|
||||
virtual void transferTypeErased(const CFGElement &, TypeErasedLattice &,
|
||||
Environment &) = 0;
|
||||
|
||||
/// Applies the analysis transfer function for a given edge from a CFG block
|
||||
|
|
@ -104,6 +104,7 @@ public:
|
|||
/// @param Stmt The condition which is responsible for the split in the CFG.
|
||||
/// @param Branch True if the edge goes to the basic block where the
|
||||
/// condition is true.
|
||||
// FIXME: Change `Stmt` argument to a reference.
|
||||
virtual void transferBranchTypeErased(bool Branch, const Stmt *,
|
||||
TypeErasedLattice &, Environment &) = 0;
|
||||
|
||||
|
|
@ -125,6 +126,10 @@ struct TypeErasedDataflowAnalysisState {
|
|||
|
||||
TypeErasedDataflowAnalysisState(TypeErasedLattice Lattice, Environment Env)
|
||||
: Lattice(std::move(Lattice)), Env(std::move(Env)) {}
|
||||
|
||||
TypeErasedDataflowAnalysisState fork() const {
|
||||
return TypeErasedDataflowAnalysisState(Lattice, Env.fork());
|
||||
}
|
||||
};
|
||||
|
||||
/// Transfers the state of a basic block by evaluating each of its elements in
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@
|
|||
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_VALUE_H
|
||||
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/Analysis/FlowSensitive/Formula.h"
|
||||
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
|
|
@ -38,14 +38,10 @@ public:
|
|||
Pointer,
|
||||
Struct,
|
||||
|
||||
// Synthetic boolean values are either atomic values or logical connectives.
|
||||
// TODO: Top values should not be need to be type-specific.
|
||||
TopBool,
|
||||
AtomicBool,
|
||||
Conjunction,
|
||||
Disjunction,
|
||||
Negation,
|
||||
Implication,
|
||||
Biconditional,
|
||||
FormulaBool,
|
||||
};
|
||||
|
||||
explicit Value(Kind ValKind) : ValKind(ValKind) {}
|
||||
|
|
@ -63,8 +59,7 @@ public:
|
|||
/// Returns the value of the synthetic property with the given `Name` or null
|
||||
/// if the property isn't assigned a value.
|
||||
Value *getProperty(llvm::StringRef Name) const {
|
||||
auto It = Properties.find(Name);
|
||||
return It == Properties.end() ? nullptr : It->second;
|
||||
return Properties.lookup(Name);
|
||||
}
|
||||
|
||||
/// Assigns `Val` as the value of the synthetic property with the given
|
||||
|
|
@ -73,6 +68,11 @@ public:
|
|||
Properties.insert_or_assign(Name, &Val);
|
||||
}
|
||||
|
||||
llvm::iterator_range<llvm::StringMap<Value *>::const_iterator>
|
||||
properties() const {
|
||||
return {Properties.begin(), Properties.end()};
|
||||
}
|
||||
|
||||
private:
|
||||
Kind ValKind;
|
||||
llvm::StringMap<Value *> Properties;
|
||||
|
|
@ -91,151 +91,68 @@ bool areEquivalentValues(const Value &Val1, const Value &Val2);
|
|||
|
||||
/// Models a boolean.
|
||||
class BoolValue : public Value {
|
||||
const Formula *F;
|
||||
|
||||
public:
|
||||
explicit BoolValue(Kind ValueKind) : Value(ValueKind) {}
|
||||
explicit BoolValue(Kind ValueKind, const Formula &F)
|
||||
: Value(ValueKind), F(&F) {}
|
||||
|
||||
static bool classof(const Value *Val) {
|
||||
return Val->getKind() == Kind::TopBool ||
|
||||
Val->getKind() == Kind::AtomicBool ||
|
||||
Val->getKind() == Kind::Conjunction ||
|
||||
Val->getKind() == Kind::Disjunction ||
|
||||
Val->getKind() == Kind::Negation ||
|
||||
Val->getKind() == Kind::Implication ||
|
||||
Val->getKind() == Kind::Biconditional;
|
||||
Val->getKind() == Kind::FormulaBool;
|
||||
}
|
||||
|
||||
const Formula &formula() const { return *F; }
|
||||
};
|
||||
|
||||
/// Models the trivially true formula, which is Top in the lattice of boolean
|
||||
/// formulas.
|
||||
/// A TopBoolValue represents a boolean that is explicitly unconstrained.
|
||||
///
|
||||
/// This is equivalent to an AtomicBoolValue that does not appear anywhere
|
||||
/// else in a system of formula.
|
||||
/// Knowing the value is unconstrained is useful when e.g. reasoning about
|
||||
/// convergence.
|
||||
class TopBoolValue final : public BoolValue {
|
||||
public:
|
||||
TopBoolValue() : BoolValue(Kind::TopBool) {}
|
||||
TopBoolValue(const Formula &F) : BoolValue(Kind::TopBool, F) {
|
||||
assert(F.kind() == Formula::AtomRef);
|
||||
}
|
||||
|
||||
static bool classof(const Value *Val) {
|
||||
return Val->getKind() == Kind::TopBool;
|
||||
}
|
||||
|
||||
Atom getAtom() const { return formula().getAtom(); }
|
||||
};
|
||||
|
||||
/// Models an atomic boolean.
|
||||
class AtomicBoolValue : public BoolValue {
|
||||
///
|
||||
/// FIXME: Merge this class into FormulaBoolValue.
|
||||
/// When we want to specify atom identity, use Atom.
|
||||
class AtomicBoolValue final : public BoolValue {
|
||||
public:
|
||||
explicit AtomicBoolValue() : BoolValue(Kind::AtomicBool) {}
|
||||
explicit AtomicBoolValue(const Formula &F) : BoolValue(Kind::AtomicBool, F) {
|
||||
assert(F.kind() == Formula::AtomRef);
|
||||
}
|
||||
|
||||
static bool classof(const Value *Val) {
|
||||
return Val->getKind() == Kind::AtomicBool;
|
||||
}
|
||||
|
||||
Atom getAtom() const { return formula().getAtom(); }
|
||||
};
|
||||
|
||||
/// Models a boolean conjunction.
|
||||
// FIXME: Consider representing binary and unary boolean operations similar
|
||||
// to how they are represented in the AST. This might become more pressing
|
||||
// when such operations need to be added for other data types.
|
||||
class ConjunctionValue : public BoolValue {
|
||||
/// Models a compound boolean formula.
|
||||
class FormulaBoolValue final : public BoolValue {
|
||||
public:
|
||||
explicit ConjunctionValue(BoolValue &LeftSubVal, BoolValue &RightSubVal)
|
||||
: BoolValue(Kind::Conjunction), LeftSubVal(LeftSubVal),
|
||||
RightSubVal(RightSubVal) {}
|
||||
|
||||
static bool classof(const Value *Val) {
|
||||
return Val->getKind() == Kind::Conjunction;
|
||||
explicit FormulaBoolValue(const Formula &F)
|
||||
: BoolValue(Kind::FormulaBool, F) {
|
||||
assert(F.kind() != Formula::AtomRef && "For now, use AtomicBoolValue");
|
||||
}
|
||||
|
||||
/// Returns the left sub-value of the conjunction.
|
||||
BoolValue &getLeftSubValue() const { return LeftSubVal; }
|
||||
|
||||
/// Returns the right sub-value of the conjunction.
|
||||
BoolValue &getRightSubValue() const { return RightSubVal; }
|
||||
|
||||
private:
|
||||
BoolValue &LeftSubVal;
|
||||
BoolValue &RightSubVal;
|
||||
};
|
||||
|
||||
/// Models a boolean disjunction.
|
||||
class DisjunctionValue : public BoolValue {
|
||||
public:
|
||||
explicit DisjunctionValue(BoolValue &LeftSubVal, BoolValue &RightSubVal)
|
||||
: BoolValue(Kind::Disjunction), LeftSubVal(LeftSubVal),
|
||||
RightSubVal(RightSubVal) {}
|
||||
|
||||
static bool classof(const Value *Val) {
|
||||
return Val->getKind() == Kind::Disjunction;
|
||||
return Val->getKind() == Kind::FormulaBool;
|
||||
}
|
||||
|
||||
/// Returns the left sub-value of the disjunction.
|
||||
BoolValue &getLeftSubValue() const { return LeftSubVal; }
|
||||
|
||||
/// Returns the right sub-value of the disjunction.
|
||||
BoolValue &getRightSubValue() const { return RightSubVal; }
|
||||
|
||||
private:
|
||||
BoolValue &LeftSubVal;
|
||||
BoolValue &RightSubVal;
|
||||
};
|
||||
|
||||
/// Models a boolean negation.
|
||||
class NegationValue : public BoolValue {
|
||||
public:
|
||||
explicit NegationValue(BoolValue &SubVal)
|
||||
: BoolValue(Kind::Negation), SubVal(SubVal) {}
|
||||
|
||||
static bool classof(const Value *Val) {
|
||||
return Val->getKind() == Kind::Negation;
|
||||
}
|
||||
|
||||
/// Returns the sub-value of the negation.
|
||||
BoolValue &getSubVal() const { return SubVal; }
|
||||
|
||||
private:
|
||||
BoolValue &SubVal;
|
||||
};
|
||||
|
||||
/// Models a boolean implication.
|
||||
///
|
||||
/// Equivalent to `!LHS v RHS`.
|
||||
class ImplicationValue : public BoolValue {
|
||||
public:
|
||||
explicit ImplicationValue(BoolValue &LeftSubVal, BoolValue &RightSubVal)
|
||||
: BoolValue(Kind::Implication), LeftSubVal(LeftSubVal),
|
||||
RightSubVal(RightSubVal) {}
|
||||
|
||||
static bool classof(const Value *Val) {
|
||||
return Val->getKind() == Kind::Implication;
|
||||
}
|
||||
|
||||
/// Returns the left sub-value of the implication.
|
||||
BoolValue &getLeftSubValue() const { return LeftSubVal; }
|
||||
|
||||
/// Returns the right sub-value of the implication.
|
||||
BoolValue &getRightSubValue() const { return RightSubVal; }
|
||||
|
||||
private:
|
||||
BoolValue &LeftSubVal;
|
||||
BoolValue &RightSubVal;
|
||||
};
|
||||
|
||||
/// Models a boolean biconditional.
|
||||
///
|
||||
/// Equivalent to `(LHS ^ RHS) v (!LHS ^ !RHS)`.
|
||||
class BiconditionalValue : public BoolValue {
|
||||
public:
|
||||
explicit BiconditionalValue(BoolValue &LeftSubVal, BoolValue &RightSubVal)
|
||||
: BoolValue(Kind::Biconditional), LeftSubVal(LeftSubVal),
|
||||
RightSubVal(RightSubVal) {}
|
||||
|
||||
static bool classof(const Value *Val) {
|
||||
return Val->getKind() == Kind::Biconditional;
|
||||
}
|
||||
|
||||
/// Returns the left sub-value of the biconditional.
|
||||
BoolValue &getLeftSubValue() const { return LeftSubVal; }
|
||||
|
||||
/// Returns the right sub-value of the biconditional.
|
||||
BoolValue &getRightSubValue() const { return RightSubVal; }
|
||||
|
||||
private:
|
||||
BoolValue &LeftSubVal;
|
||||
BoolValue &RightSubVal;
|
||||
};
|
||||
|
||||
/// Models an integer.
|
||||
|
|
@ -281,34 +198,59 @@ private:
|
|||
StorageLocation &PointeeLoc;
|
||||
};
|
||||
|
||||
/// Models a value of `struct` or `class` type, with a flat map of fields to
|
||||
/// child storage locations, containing all accessible members of base struct
|
||||
/// and class types.
|
||||
/// Models a value of `struct` or `class` type.
|
||||
/// In C++, prvalues of class type serve only a limited purpose: They can only
|
||||
/// be used to initialize a result object. It is not possible to access member
|
||||
/// variables or call member functions on a prvalue of class type.
|
||||
/// Correspondingly, `StructValue` also serves only two limited purposes:
|
||||
/// - It conveys a prvalue of class type from the place where the object is
|
||||
/// constructed to the result object that it initializes.
|
||||
///
|
||||
/// When creating a prvalue of class type, we already need a storage location
|
||||
/// for `this`, even though prvalues are otherwise not associated with storage
|
||||
/// locations. `StructValue` is therefore essentially a wrapper for a storage
|
||||
/// location, which is then used to set the storage location for the result
|
||||
/// object when we process the AST node for that result object.
|
||||
///
|
||||
/// For example:
|
||||
/// MyStruct S = MyStruct(3);
|
||||
///
|
||||
/// In this example, `MyStruct(3) is a prvalue, which is modeled as a
|
||||
/// `StructValue` that wraps an `AbstractStorageLocation`. This
|
||||
// `AbstractStorageLocation` is then used as the storage location for `S`.
|
||||
///
|
||||
/// - It allows properties to be associated with an object of class type.
|
||||
/// Note that when doing so, you should avoid mutating the properties of an
|
||||
/// existing `StructValue` in place, as these changes would be visible to
|
||||
/// other `Environment`s that share the same `StructValue`. Instead, associate
|
||||
/// a new `StructValue` with the `AggregateStorageLocation` and set the
|
||||
/// properties on this new `StructValue`. (See also `refreshStructValue()` in
|
||||
/// DataflowEnvironment.h, which makes this easy.)
|
||||
/// Note also that this implies that it is common for the same
|
||||
/// `AggregateStorageLocation` to be associated with different `StructValue`s
|
||||
/// in different environments.
|
||||
/// Over time, we may eliminate `StructValue` entirely. See also the discussion
|
||||
/// here: https://reviews.llvm.org/D155204#inline-1503204
|
||||
class StructValue final : public Value {
|
||||
public:
|
||||
StructValue() : StructValue(llvm::DenseMap<const ValueDecl *, Value *>()) {}
|
||||
|
||||
explicit StructValue(llvm::DenseMap<const ValueDecl *, Value *> Children)
|
||||
: Value(Kind::Struct), Children(std::move(Children)) {}
|
||||
explicit StructValue(AggregateStorageLocation &Loc)
|
||||
: Value(Kind::Struct), Loc(Loc) {}
|
||||
|
||||
static bool classof(const Value *Val) {
|
||||
return Val->getKind() == Kind::Struct;
|
||||
}
|
||||
|
||||
/// Returns the child value that is assigned for `D` or null if the child is
|
||||
/// not initialized.
|
||||
Value *getChild(const ValueDecl &D) const {
|
||||
auto It = Children.find(&D);
|
||||
if (It == Children.end())
|
||||
return nullptr;
|
||||
return It->second;
|
||||
/// Returns the storage location that this `StructValue` is associated with.
|
||||
AggregateStorageLocation &getAggregateLoc() const { return Loc; }
|
||||
|
||||
/// Convenience function that returns the child storage location for `Field`.
|
||||
/// See also the documentation for `AggregateStorageLocation::getChild()`.
|
||||
StorageLocation *getChild(const ValueDecl &Field) const {
|
||||
return Loc.getChild(Field);
|
||||
}
|
||||
|
||||
/// Assigns `Val` as the child value for `D`.
|
||||
void setChild(const ValueDecl &D, Value &Val) { Children[&D] = &Val; }
|
||||
|
||||
private:
|
||||
llvm::DenseMap<const ValueDecl *, Value *> Children;
|
||||
AggregateStorageLocation &Loc;
|
||||
};
|
||||
|
||||
raw_ostream &operator<<(raw_ostream &OS, const Value &Val);
|
||||
|
|
|
|||
|
|
@ -14,9 +14,10 @@
|
|||
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_WATCHEDLITERALSSOLVER_H
|
||||
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_WATCHEDLITERALSSOLVER_H
|
||||
|
||||
#include "clang/Analysis/FlowSensitive/Formula.h"
|
||||
#include "clang/Analysis/FlowSensitive/Solver.h"
|
||||
#include "clang/Analysis/FlowSensitive/Value.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include <limits>
|
||||
|
||||
namespace clang {
|
||||
namespace dataflow {
|
||||
|
|
@ -27,8 +28,28 @@ namespace dataflow {
|
|||
/// single "watched" literal per clause, and uses a set of "active" variables
|
||||
/// for unit propagation.
|
||||
class WatchedLiteralsSolver : public Solver {
|
||||
// Count of the iterations of the main loop of the solver. This spans *all*
|
||||
// calls to the underlying solver across the life of this object. It is
|
||||
// reduced with every (non-trivial) call to the solver.
|
||||
//
|
||||
// We give control over the abstract count of iterations instead of concrete
|
||||
// measurements like CPU cycles or time to ensure deterministic results.
|
||||
std::int64_t MaxIterations = std::numeric_limits<std::int64_t>::max();
|
||||
|
||||
public:
|
||||
Result solve(llvm::DenseSet<BoolValue *> Vals) override;
|
||||
WatchedLiteralsSolver() = default;
|
||||
|
||||
// `Work` specifies a computational limit on the solver. Units of "work"
|
||||
// roughly correspond to attempts to assign a value to a single
|
||||
// variable. Since the algorithm is exponential in the number of variables,
|
||||
// this is the most direct (abstract) unit to target.
|
||||
explicit WatchedLiteralsSolver(std::int64_t WorkLimit)
|
||||
: MaxIterations(WorkLimit) {}
|
||||
|
||||
Result solve(llvm::ArrayRef<const Formula *> Vals) override;
|
||||
|
||||
// The solver reached its maximum number of iterations.
|
||||
bool reachedLimit() const { return MaxIterations == 0; }
|
||||
};
|
||||
|
||||
} // namespace dataflow
|
||||
|
|
|
|||
|
|
@ -95,35 +95,33 @@ private:
|
|||
|
||||
llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag;
|
||||
|
||||
CFGBlock::ConstCFGElementRef ElemRef = {nullptr, 0};
|
||||
|
||||
protected:
|
||||
ProgramPoint() = default;
|
||||
ProgramPoint(const void *P,
|
||||
Kind k,
|
||||
const LocationContext *l,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: Data1(P),
|
||||
Data2(nullptr, (((unsigned) k) >> 0) & 0x3),
|
||||
L(l, (((unsigned) k) >> 2) & 0x3),
|
||||
Tag(tag, (((unsigned) k) >> 4) & 0x3) {
|
||||
assert(getKind() == k);
|
||||
assert(getLocationContext() == l);
|
||||
assert(getData1() == P);
|
||||
}
|
||||
ProgramPoint(const void *P, Kind k, const LocationContext *l,
|
||||
const ProgramPointTag *tag = nullptr,
|
||||
CFGBlock::ConstCFGElementRef ElemRef = {nullptr, 0})
|
||||
: Data1(P), Data2(nullptr, (((unsigned)k) >> 0) & 0x3),
|
||||
L(l, (((unsigned)k) >> 2) & 0x3), Tag(tag, (((unsigned)k) >> 4) & 0x3),
|
||||
ElemRef(ElemRef) {
|
||||
assert(getKind() == k);
|
||||
assert(getLocationContext() == l);
|
||||
assert(getData1() == P);
|
||||
}
|
||||
|
||||
ProgramPoint(const void *P1,
|
||||
const void *P2,
|
||||
Kind k,
|
||||
const LocationContext *l,
|
||||
const ProgramPointTag *tag = nullptr)
|
||||
: Data1(P1),
|
||||
Data2(P2, (((unsigned) k) >> 0) & 0x3),
|
||||
L(l, (((unsigned) k) >> 2) & 0x3),
|
||||
Tag(tag, (((unsigned) k) >> 4) & 0x3) {}
|
||||
ProgramPoint(const void *P1, const void *P2, Kind k, const LocationContext *l,
|
||||
const ProgramPointTag *tag = nullptr,
|
||||
CFGBlock::ConstCFGElementRef ElemRef = {nullptr, 0})
|
||||
: Data1(P1), Data2(P2, (((unsigned)k) >> 0) & 0x3),
|
||||
L(l, (((unsigned)k) >> 2) & 0x3), Tag(tag, (((unsigned)k) >> 4) & 0x3),
|
||||
ElemRef(ElemRef) {}
|
||||
|
||||
protected:
|
||||
const void *getData1() const { return Data1; }
|
||||
const void *getData2() const { return Data2.getPointer(); }
|
||||
void setData2(const void *d) { Data2.setPointer(d); }
|
||||
CFGBlock::ConstCFGElementRef getElementRef() const { return ElemRef; }
|
||||
|
||||
public:
|
||||
/// Create a new ProgramPoint object that is the same as the original
|
||||
|
|
@ -190,17 +188,13 @@ public:
|
|||
}
|
||||
|
||||
bool operator==(const ProgramPoint & RHS) const {
|
||||
return Data1 == RHS.Data1 &&
|
||||
Data2 == RHS.Data2 &&
|
||||
L == RHS.L &&
|
||||
Tag == RHS.Tag;
|
||||
return Data1 == RHS.Data1 && Data2 == RHS.Data2 && L == RHS.L &&
|
||||
Tag == RHS.Tag && ElemRef == RHS.ElemRef;
|
||||
}
|
||||
|
||||
bool operator!=(const ProgramPoint &RHS) const {
|
||||
return Data1 != RHS.Data1 ||
|
||||
Data2 != RHS.Data2 ||
|
||||
L != RHS.L ||
|
||||
Tag != RHS.Tag;
|
||||
return Data1 != RHS.Data1 || Data2 != RHS.Data2 || L != RHS.L ||
|
||||
Tag != RHS.Tag || ElemRef != RHS.ElemRef;
|
||||
}
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
|
|
@ -209,6 +203,8 @@ public:
|
|||
ID.AddPointer(getData2());
|
||||
ID.AddPointer(getLocationContext());
|
||||
ID.AddPointer(getTag());
|
||||
ID.AddPointer(ElemRef.getParent());
|
||||
ID.AddInteger(ElemRef.getIndexInBlock());
|
||||
}
|
||||
|
||||
void printJson(llvm::raw_ostream &Out, const char *NL = "\n") const;
|
||||
|
|
@ -266,6 +262,7 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
// FIXME: Eventually we want to take a CFGElementRef as parameter here too.
|
||||
class StmtPoint : public ProgramPoint {
|
||||
public:
|
||||
StmtPoint(const Stmt *S, const void *p2, Kind k, const LocationContext *L,
|
||||
|
|
@ -557,8 +554,9 @@ private:
|
|||
class ImplicitCallPoint : public ProgramPoint {
|
||||
public:
|
||||
ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K,
|
||||
const LocationContext *L, const ProgramPointTag *Tag)
|
||||
: ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {}
|
||||
const LocationContext *L, const ProgramPointTag *Tag,
|
||||
CFGBlock::ConstCFGElementRef ElemRef)
|
||||
: ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag, ElemRef) {}
|
||||
|
||||
const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); }
|
||||
SourceLocation getLocation() const {
|
||||
|
|
@ -581,8 +579,9 @@ private:
|
|||
class PreImplicitCall : public ImplicitCallPoint {
|
||||
public:
|
||||
PreImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
|
||||
CFGBlock::ConstCFGElementRef ElemRef,
|
||||
const ProgramPointTag *Tag = nullptr)
|
||||
: ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {}
|
||||
: ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag, ElemRef) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
@ -598,8 +597,9 @@ private:
|
|||
class PostImplicitCall : public ImplicitCallPoint {
|
||||
public:
|
||||
PostImplicitCall(const Decl *D, SourceLocation Loc, const LocationContext *L,
|
||||
CFGBlock::ConstCFGElementRef ElemRef,
|
||||
const ProgramPointTag *Tag = nullptr)
|
||||
: ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {}
|
||||
: ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag, ElemRef) {}
|
||||
|
||||
private:
|
||||
friend class ProgramPoint;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,15 @@ public:
|
|||
Other.Alloc.setPointer(nullptr);
|
||||
}
|
||||
|
||||
// The move assignment operator is defined as deleted pending further
|
||||
// motivation.
|
||||
BumpVectorContext &operator=(BumpVectorContext &&) = delete;
|
||||
|
||||
// The copy constrcutor and copy assignment operator is defined as deleted
|
||||
// pending further motivation.
|
||||
BumpVectorContext(const BumpVectorContext &) = delete;
|
||||
BumpVectorContext &operator=(const BumpVectorContext &) = delete;
|
||||
|
||||
/// Construct a new BumpVectorContext that reuses an existing
|
||||
/// BumpPtrAllocator. This BumpPtrAllocator is not destroyed when the
|
||||
/// BumpVectorContext object is destroyed.
|
||||
|
|
|
|||
|
|
@ -49,6 +49,11 @@
|
|||
SVE_TYPE(Name, Id, SingletonId)
|
||||
#endif
|
||||
|
||||
#ifndef SVE_OPAQUE_TYPE
|
||||
#define SVE_OPAQUE_TYPE(Name, MangledName, Id, SingletonId) \
|
||||
SVE_TYPE(Name, Id, SingletonId)
|
||||
#endif
|
||||
|
||||
//===- Vector point types -----------------------------------------------===//
|
||||
|
||||
|
||||
|
|
@ -124,7 +129,12 @@ SVE_VECTOR_TYPE("__clang_svfloat64x4_t", "svfloat64x4_t", SveFloat64x4, SveFloat
|
|||
SVE_VECTOR_TYPE("__clang_svbfloat16x4_t", "svbfloat16x4_t", SveBFloat16x4, SveBFloat16x4Ty, 32, 16, true, false, true)
|
||||
|
||||
SVE_PREDICATE_TYPE("__SVBool_t", "__SVBool_t", SveBool, SveBoolTy, 16)
|
||||
SVE_PREDICATE_TYPE("__clang_svboolx2_t", "svboolx2_t", SveBoolx2, SveBoolx2Ty, 32)
|
||||
SVE_PREDICATE_TYPE("__clang_svboolx4_t", "svboolx4_t", SveBoolx4, SveBoolx4Ty, 64)
|
||||
|
||||
SVE_OPAQUE_TYPE("__SVCount_t", "__SVCount_t", SveCount, SveCountTy)
|
||||
|
||||
#undef SVE_VECTOR_TYPE
|
||||
#undef SVE_PREDICATE_TYPE
|
||||
#undef SVE_OPAQUE_TYPE
|
||||
#undef SVE_TYPE
|
||||
|
|
|
|||
|
|
@ -59,6 +59,9 @@ enum class LangAS : unsigned {
|
|||
// HLSL specific address spaces.
|
||||
hlsl_groupshared,
|
||||
|
||||
// Wasm specific address spaces.
|
||||
wasm_funcref,
|
||||
|
||||
// This denotes the count of language-specific address spaces and also
|
||||
// the offset added to the target-specific address spaces, which are usually
|
||||
// specified by address space attributes __attribute__(address_space(n))).
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@
|
|||
#ifndef LLVM_CLANG_BASIC_ALIGNEDALLOCATION_H
|
||||
#define LLVM_CLANG_BASIC_ALIGNEDALLOCATION_H
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/VersionTuple.h"
|
||||
#include "llvm/TargetParser/Triple.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
|
|
|
|||
|
|
@ -168,6 +168,12 @@ def FunctionLike : SubsetSubject<DeclBase,
|
|||
[{S->getFunctionType(false) != nullptr}],
|
||||
"functions, function pointers">;
|
||||
|
||||
// Function Pointer is a stricter version of FunctionLike that only allows function
|
||||
// pointers.
|
||||
def FunctionPointer : SubsetSubject<DeclBase,
|
||||
[{S->isFunctionPointerType()}],
|
||||
"functions pointers">;
|
||||
|
||||
def OpenCLKernelFunction
|
||||
: SubsetSubject<Function, [{S->hasAttr<OpenCLKernelAttr>()}],
|
||||
"kernel functions">;
|
||||
|
|
@ -287,26 +293,38 @@ class VariadicEnumArgument<string name, string type, list<string> values,
|
|||
}
|
||||
|
||||
// This handles one spelling of an attribute.
|
||||
class Spelling<string name, string variety> {
|
||||
class Spelling<string name, string variety, int version = 1> {
|
||||
string Name = name;
|
||||
string Variety = variety;
|
||||
int Version = version;
|
||||
}
|
||||
|
||||
class GNU<string name> : Spelling<name, "GNU">;
|
||||
class Declspec<string name> : Spelling<name, "Declspec">;
|
||||
class Microsoft<string name> : Spelling<name, "Microsoft">;
|
||||
class CXX11<string namespace, string name, int version = 1>
|
||||
: Spelling<name, "CXX11"> {
|
||||
: Spelling<name, "CXX11", version> {
|
||||
string Namespace = namespace;
|
||||
int Version = version;
|
||||
}
|
||||
class C2x<string namespace, string name, int version = 1>
|
||||
: Spelling<name, "C2x"> {
|
||||
: Spelling<name, "C2x", version> {
|
||||
string Namespace = namespace;
|
||||
int Version = version;
|
||||
}
|
||||
|
||||
class Keyword<string name> : Spelling<name, "Keyword">;
|
||||
class Keyword<string name, bit hasOwnParseRules>
|
||||
: Spelling<name, "Keyword"> {
|
||||
bit HasOwnParseRules = hasOwnParseRules;
|
||||
}
|
||||
|
||||
// A keyword that can appear wherever a standard attribute can appear,
|
||||
// and that appertains to whatever a standard attribute would appertain to.
|
||||
// This is useful for things that affect semantics but that should otherwise
|
||||
// be treated like standard attributes.
|
||||
class RegularKeyword<string name> : Keyword<name, 0> {}
|
||||
|
||||
// A keyword that has its own individual parsing rules.
|
||||
class CustomKeyword<string name> : Keyword<name, 1> {}
|
||||
|
||||
class Pragma<string namespace, string name> : Spelling<name, "Pragma"> {
|
||||
string Namespace = namespace;
|
||||
}
|
||||
|
|
@ -321,7 +339,8 @@ class GCC<string name, bit allowInC = 1> : Spelling<name, "GCC"> {
|
|||
// The Clang spelling implies GNU<name>, CXX11<"clang", name>, and optionally,
|
||||
// C2x<"clang", name>. This spelling should be used for any Clang-specific
|
||||
// attributes.
|
||||
class Clang<string name, bit allowInC = 1> : Spelling<name, "Clang"> {
|
||||
class Clang<string name, bit allowInC = 1, int version = 1>
|
||||
: Spelling<name, "Clang", version> {
|
||||
bit AllowInC = allowInC;
|
||||
}
|
||||
|
||||
|
|
@ -408,6 +427,7 @@ def TargetRISCV : TargetArch<["riscv32", "riscv64"]>;
|
|||
def TargetX86 : TargetArch<["x86"]>;
|
||||
def TargetAnyX86 : TargetArch<["x86", "x86_64"]>;
|
||||
def TargetWebAssembly : TargetArch<["wasm32", "wasm64"]>;
|
||||
def TargetNVPTX : TargetArch<["nvptx", "nvptx64"]>;
|
||||
def TargetWindows : TargetSpec {
|
||||
let OSes = ["Win32"];
|
||||
}
|
||||
|
|
@ -702,13 +722,13 @@ def ArmBuiltinAlias : InheritableAttr, TargetSpecificAttr<TargetAnyArm> {
|
|||
}
|
||||
|
||||
def Aligned : InheritableAttr {
|
||||
let Spellings = [GCC<"aligned">, Declspec<"align">, Keyword<"alignas">,
|
||||
Keyword<"_Alignas">];
|
||||
let Spellings = [GCC<"aligned">, Declspec<"align">, CustomKeyword<"alignas">,
|
||||
CustomKeyword<"_Alignas">];
|
||||
let Args = [AlignedArgument<"Alignment", 1>];
|
||||
let Accessors = [Accessor<"isGNU", [GCC<"aligned">]>,
|
||||
Accessor<"isC11", [Keyword<"_Alignas">]>,
|
||||
Accessor<"isAlignas", [Keyword<"alignas">,
|
||||
Keyword<"_Alignas">]>,
|
||||
Accessor<"isC11", [CustomKeyword<"_Alignas">]>,
|
||||
Accessor<"isAlignas", [CustomKeyword<"alignas">,
|
||||
CustomKeyword<"_Alignas">]>,
|
||||
Accessor<"isDeclspec",[Declspec<"align">]>];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
|
@ -749,7 +769,7 @@ def AlignNatural : InheritableAttr {
|
|||
|
||||
def AlwaysInline : DeclOrStmtAttr {
|
||||
let Spellings = [GCC<"always_inline">, CXX11<"clang", "always_inline">,
|
||||
C2x<"clang", "always_inline">, Keyword<"__forceinline">];
|
||||
C2x<"clang", "always_inline">, CustomKeyword<"__forceinline">];
|
||||
let Accessors = [Accessor<"isClangAlwaysInline", [CXX11<"clang", "always_inline">,
|
||||
C2x<"clang", "always_inline">]>];
|
||||
let Subjects = SubjectList<[Function, Stmt], WarnDiag,
|
||||
|
|
@ -792,7 +812,8 @@ def XRayLogArgs : InheritableAttr {
|
|||
def PatchableFunctionEntry
|
||||
: InheritableAttr,
|
||||
TargetSpecificAttr<TargetArch<
|
||||
["aarch64", "aarch64_be", "riscv32", "riscv64", "x86", "x86_64"]>> {
|
||||
["aarch64", "aarch64_be", "loongarch32", "loongarch64", "riscv32",
|
||||
"riscv64", "x86", "x86_64"]>> {
|
||||
let Spellings = [GCC<"patchable_function_entry">];
|
||||
let Subjects = SubjectList<[Function, ObjCMethod]>;
|
||||
let Args = [UnsignedArgument<"Count">, DefaultIntArgument<"Offset", 0>];
|
||||
|
|
@ -826,7 +847,7 @@ def Annotate : InheritableParamAttr {
|
|||
return AnnotateAttr::Create(Ctx, Annotation, nullptr, 0, CommonInfo);
|
||||
}
|
||||
static AnnotateAttr *CreateImplicit(ASTContext &Ctx, llvm::StringRef Annotation, \
|
||||
const AttributeCommonInfo &CommonInfo = {SourceRange{}}) {
|
||||
const AttributeCommonInfo &CommonInfo) {
|
||||
return AnnotateAttr::CreateImplicit(Ctx, Annotation, nullptr, 0, CommonInfo);
|
||||
}
|
||||
}];
|
||||
|
|
@ -871,7 +892,7 @@ def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> {
|
|||
}
|
||||
|
||||
def AsmLabel : InheritableAttr {
|
||||
let Spellings = [Keyword<"asm">, Keyword<"__asm__">];
|
||||
let Spellings = [CustomKeyword<"asm">, CustomKeyword<"__asm__">];
|
||||
let Args = [
|
||||
// Label specifies the mangled name for the decl.
|
||||
StringArgument<"Label">,
|
||||
|
|
@ -918,6 +939,7 @@ def Availability : InheritableAttr {
|
|||
.Case("maccatalyst_app_extension", "macCatalyst (App Extension)")
|
||||
.Case("swift", "Swift")
|
||||
.Case("shadermodel", "HLSL ShaderModel")
|
||||
.Case("ohos", "OpenHarmony OS")
|
||||
.Default(llvm::StringRef());
|
||||
}
|
||||
static llvm::StringRef getPlatformNameSourceSpelling(llvm::StringRef Platform) {
|
||||
|
|
@ -958,10 +980,12 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
|
|||
}
|
||||
|
||||
def ExternalSourceSymbol : InheritableAttr {
|
||||
let Spellings = [Clang<"external_source_symbol">];
|
||||
let Spellings = [Clang<"external_source_symbol", /*allowInC=*/1,
|
||||
/*version=*/20230206>];
|
||||
let Args = [StringArgument<"language", 1>,
|
||||
StringArgument<"definedIn", 1>,
|
||||
BoolArgument<"generatedDeclaration", 1>];
|
||||
BoolArgument<"generatedDeclaration", 1>,
|
||||
StringArgument<"USR", 1>];
|
||||
let HasCustomParsing = 1;
|
||||
let Subjects = SubjectList<[Named]>;
|
||||
let Documentation = [ExternalSourceSymbolDocs];
|
||||
|
|
@ -986,7 +1010,7 @@ def CarriesDependency : InheritableParamAttr {
|
|||
}
|
||||
|
||||
def CDecl : DeclOrTypeAttr {
|
||||
let Spellings = [GCC<"cdecl">, Keyword<"__cdecl">, Keyword<"_cdecl">];
|
||||
let Spellings = [GCC<"cdecl">, CustomKeyword<"__cdecl">, CustomKeyword<"_cdecl">];
|
||||
// let Subjects = [Function, ObjCMethod];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
|
@ -1073,7 +1097,7 @@ def Cleanup : InheritableAttr {
|
|||
let Spellings = [GCC<"cleanup">];
|
||||
let Args = [DeclArgument<Function, "FunctionDecl">];
|
||||
let Subjects = SubjectList<[LocalVar]>;
|
||||
let Documentation = [Undocumented];
|
||||
let Documentation = [CleanupDocs];
|
||||
}
|
||||
|
||||
def CmseNSEntry : InheritableAttr, TargetSpecificAttr<TargetARM> {
|
||||
|
|
@ -1111,10 +1135,10 @@ def Const : InheritableAttr {
|
|||
def ConstInit : InheritableAttr {
|
||||
// This attribute does not have a C [[]] spelling because it requires the
|
||||
// CPlusPlus language option.
|
||||
let Spellings = [Keyword<"constinit">,
|
||||
let Spellings = [CustomKeyword<"constinit">,
|
||||
Clang<"require_constant_initialization", 0>];
|
||||
let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
|
||||
let Accessors = [Accessor<"isConstinit", [Keyword<"constinit">]>];
|
||||
let Accessors = [Accessor<"isConstinit", [CustomKeyword<"constinit">]>];
|
||||
let Documentation = [ConstInitDocs];
|
||||
let LangOpts = [CPlusPlus];
|
||||
let SimpleHandler = 1;
|
||||
|
|
@ -1211,6 +1235,12 @@ def CUDAHost : InheritableAttr {
|
|||
}
|
||||
def : MutualExclusions<[CUDAGlobal, CUDAHost]>;
|
||||
|
||||
def NVPTXKernel : InheritableAttr, TargetSpecificAttr<TargetNVPTX> {
|
||||
let Spellings = [Clang<"nvptx_kernel">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
def HIPManaged : InheritableAttr {
|
||||
let Spellings = [GNU<"managed">, Declspec<"__managed__">];
|
||||
let Subjects = SubjectList<[Var]>;
|
||||
|
|
@ -1259,7 +1289,7 @@ def SYCLSpecialClass: InheritableAttr {
|
|||
}
|
||||
|
||||
def C11NoReturn : InheritableAttr {
|
||||
let Spellings = [Keyword<"_Noreturn">];
|
||||
let Spellings = [CustomKeyword<"_Noreturn">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let SemaHandler = 0;
|
||||
let Documentation = [C11NoReturnDocs];
|
||||
|
|
@ -1275,7 +1305,7 @@ def CXX11NoReturn : InheritableAttr {
|
|||
// Similar to CUDA, OpenCL attributes do not receive a [[]] spelling because
|
||||
// the specification does not expose them with one currently.
|
||||
def OpenCLKernel : InheritableAttr {
|
||||
let Spellings = [Keyword<"__kernel">, Keyword<"kernel">];
|
||||
let Spellings = [CustomKeyword<"__kernel">, CustomKeyword<"kernel">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [Undocumented];
|
||||
let SimpleHandler = 1;
|
||||
|
|
@ -1299,26 +1329,28 @@ def OpenCLIntelReqdSubGroupSize: InheritableAttr {
|
|||
// This attribute is both a type attribute, and a declaration attribute (for
|
||||
// parameter variables).
|
||||
def OpenCLAccess : Attr {
|
||||
let Spellings = [Keyword<"__read_only">, Keyword<"read_only">,
|
||||
Keyword<"__write_only">, Keyword<"write_only">,
|
||||
Keyword<"__read_write">, Keyword<"read_write">];
|
||||
let Spellings = [CustomKeyword<"__read_only">, CustomKeyword<"read_only">,
|
||||
CustomKeyword<"__write_only">, CustomKeyword<"write_only">,
|
||||
CustomKeyword<"__read_write">, CustomKeyword<"read_write">];
|
||||
let Subjects = SubjectList<[ParmVar, TypedefName], ErrorDiag>;
|
||||
let Accessors = [Accessor<"isReadOnly", [Keyword<"__read_only">,
|
||||
Keyword<"read_only">]>,
|
||||
Accessor<"isReadWrite", [Keyword<"__read_write">,
|
||||
Keyword<"read_write">]>,
|
||||
Accessor<"isWriteOnly", [Keyword<"__write_only">,
|
||||
Keyword<"write_only">]>];
|
||||
let Accessors = [Accessor<"isReadOnly", [CustomKeyword<"__read_only">,
|
||||
CustomKeyword<"read_only">]>,
|
||||
Accessor<"isReadWrite", [CustomKeyword<"__read_write">,
|
||||
CustomKeyword<"read_write">]>,
|
||||
Accessor<"isWriteOnly", [CustomKeyword<"__write_only">,
|
||||
CustomKeyword<"write_only">]>];
|
||||
let Documentation = [OpenCLAccessDocs];
|
||||
}
|
||||
|
||||
def OpenCLPrivateAddressSpace : TypeAttr {
|
||||
let Spellings = [Keyword<"__private">, Keyword<"private">, Clang<"opencl_private">];
|
||||
let Spellings = [CustomKeyword<"__private">, CustomKeyword<"private">,
|
||||
Clang<"opencl_private">];
|
||||
let Documentation = [OpenCLAddressSpacePrivateDocs];
|
||||
}
|
||||
|
||||
def OpenCLGlobalAddressSpace : TypeAttr {
|
||||
let Spellings = [Keyword<"__global">, Keyword<"global">, Clang<"opencl_global">];
|
||||
let Spellings = [CustomKeyword<"__global">, CustomKeyword<"global">,
|
||||
Clang<"opencl_global">];
|
||||
let Documentation = [OpenCLAddressSpaceGlobalDocs];
|
||||
}
|
||||
|
||||
|
|
@ -1333,17 +1365,20 @@ def OpenCLGlobalHostAddressSpace : TypeAttr {
|
|||
}
|
||||
|
||||
def OpenCLLocalAddressSpace : TypeAttr {
|
||||
let Spellings = [Keyword<"__local">, Keyword<"local">, Clang<"opencl_local">];
|
||||
let Spellings = [CustomKeyword<"__local">, CustomKeyword<"local">,
|
||||
Clang<"opencl_local">];
|
||||
let Documentation = [OpenCLAddressSpaceLocalDocs];
|
||||
}
|
||||
|
||||
def OpenCLConstantAddressSpace : TypeAttr {
|
||||
let Spellings = [Keyword<"__constant">, Keyword<"constant">, Clang<"opencl_constant">];
|
||||
let Spellings = [CustomKeyword<"__constant">, CustomKeyword<"constant">,
|
||||
Clang<"opencl_constant">];
|
||||
let Documentation = [OpenCLAddressSpaceConstantDocs];
|
||||
}
|
||||
|
||||
def OpenCLGenericAddressSpace : TypeAttr {
|
||||
let Spellings = [Keyword<"__generic">, Keyword<"generic">, Clang<"opencl_generic">];
|
||||
let Spellings = [CustomKeyword<"__generic">, CustomKeyword<"generic">,
|
||||
Clang<"opencl_generic">];
|
||||
let Documentation = [OpenCLAddressSpaceGenericDocs];
|
||||
}
|
||||
|
||||
|
|
@ -1447,9 +1482,8 @@ def : MutualExclusions<[Likely, Unlikely]>;
|
|||
def NoMerge : DeclOrStmtAttr {
|
||||
let Spellings = [Clang<"nomerge">];
|
||||
let Documentation = [NoMergeDocs];
|
||||
let Subjects = SubjectList<[Function, Stmt], ErrorDiag,
|
||||
"functions and statements">;
|
||||
let SimpleHandler = 1;
|
||||
let Subjects = SubjectList<[Function, Stmt, Var], ErrorDiag,
|
||||
"functions, statements and variables">;
|
||||
}
|
||||
|
||||
def MustTail : StmtAttr {
|
||||
|
|
@ -1459,20 +1493,20 @@ def MustTail : StmtAttr {
|
|||
}
|
||||
|
||||
def FastCall : DeclOrTypeAttr {
|
||||
let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">,
|
||||
Keyword<"_fastcall">];
|
||||
let Spellings = [GCC<"fastcall">, CustomKeyword<"__fastcall">,
|
||||
CustomKeyword<"_fastcall">];
|
||||
// let Subjects = [Function, ObjCMethod];
|
||||
let Documentation = [FastCallDocs];
|
||||
}
|
||||
|
||||
def RegCall : DeclOrTypeAttr {
|
||||
let Spellings = [GCC<"regcall">, Keyword<"__regcall">];
|
||||
let Spellings = [GCC<"regcall">, CustomKeyword<"__regcall">];
|
||||
let Documentation = [RegCallDocs];
|
||||
}
|
||||
|
||||
def Final : InheritableAttr {
|
||||
let Spellings = [Keyword<"final">, Keyword<"sealed">];
|
||||
let Accessors = [Accessor<"isSpelledAsSealed", [Keyword<"sealed">]>];
|
||||
let Spellings = [CustomKeyword<"final">, CustomKeyword<"sealed">];
|
||||
let Accessors = [Accessor<"isSpelledAsSealed", [CustomKeyword<"sealed">]>];
|
||||
let SemaHandler = 0;
|
||||
// Omitted from docs, since this is language syntax, not an attribute, as far
|
||||
// as users are concerned.
|
||||
|
|
@ -1818,7 +1852,7 @@ def Convergent : InheritableAttr {
|
|||
}
|
||||
|
||||
def NoInline : DeclOrStmtAttr {
|
||||
let Spellings = [Keyword<"__noinline__">, GCC<"noinline">,
|
||||
let Spellings = [CustomKeyword<"__noinline__">, GCC<"noinline">,
|
||||
CXX11<"clang", "noinline">, C2x<"clang", "noinline">,
|
||||
Declspec<"noinline">];
|
||||
let Accessors = [Accessor<"isClangNoInline", [CXX11<"clang", "noinline">,
|
||||
|
|
@ -1847,13 +1881,23 @@ def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
|
|||
let Spellings = [GCC<"interrupt">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Args = [EnumArgument<"Interrupt", "InterruptType",
|
||||
["user", "supervisor", "machine"],
|
||||
["user", "supervisor", "machine"],
|
||||
["supervisor", "machine"],
|
||||
["supervisor", "machine"],
|
||||
1>];
|
||||
let ParseKind = "Interrupt";
|
||||
let Documentation = [RISCVInterruptDocs];
|
||||
}
|
||||
|
||||
def RISCVRVVVectorBits : TypeAttr {
|
||||
let Spellings = [GNU<"riscv_rvv_vector_bits">];
|
||||
let Subjects = SubjectList<[TypedefName], ErrorDiag>;
|
||||
let Args = [UnsignedArgument<"NumBits">];
|
||||
let Documentation = [RISCVRVVVectorBitsDocs];
|
||||
let PragmaAttributeSupport = 0;
|
||||
// Represented as VectorType instead.
|
||||
let ASTNode = 0;
|
||||
}
|
||||
|
||||
// This is not a TargetSpecificAttr so that is silently accepted and
|
||||
// ignored on other targets as encouraged by the OpenCL spec.
|
||||
//
|
||||
|
|
@ -2004,22 +2048,22 @@ def PassObjectSize : InheritableParamAttr {
|
|||
|
||||
// Nullability type attributes.
|
||||
def TypeNonNull : TypeAttr {
|
||||
let Spellings = [Keyword<"_Nonnull">];
|
||||
let Spellings = [CustomKeyword<"_Nonnull">];
|
||||
let Documentation = [TypeNonNullDocs];
|
||||
}
|
||||
|
||||
def TypeNullable : TypeAttr {
|
||||
let Spellings = [Keyword<"_Nullable">];
|
||||
let Spellings = [CustomKeyword<"_Nullable">];
|
||||
let Documentation = [TypeNullableDocs];
|
||||
}
|
||||
|
||||
def TypeNullableResult : TypeAttr {
|
||||
let Spellings = [Keyword<"_Nullable_result">];
|
||||
let Spellings = [CustomKeyword<"_Nullable_result">];
|
||||
let Documentation = [TypeNullableResultDocs];
|
||||
}
|
||||
|
||||
def TypeNullUnspecified : TypeAttr {
|
||||
let Spellings = [Keyword<"_Null_unspecified">];
|
||||
let Spellings = [CustomKeyword<"_Null_unspecified">];
|
||||
let Documentation = [TypeNullUnspecifiedDocs];
|
||||
}
|
||||
|
||||
|
|
@ -2027,12 +2071,12 @@ def TypeNullUnspecified : TypeAttr {
|
|||
// ignored because ARC is not enabled. The usual representation for this
|
||||
// qualifier is as an ObjCOwnership attribute with Kind == "none".
|
||||
def ObjCInertUnsafeUnretained : TypeAttr {
|
||||
let Spellings = [Keyword<"__unsafe_unretained">];
|
||||
let Spellings = [CustomKeyword<"__unsafe_unretained">];
|
||||
let Documentation = [InternalOnly];
|
||||
}
|
||||
|
||||
def ObjCKindOf : TypeAttr {
|
||||
let Spellings = [Keyword<"__kindof">];
|
||||
let Spellings = [CustomKeyword<"__kindof">];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
|
|
@ -2331,7 +2375,7 @@ def Overloadable : Attr {
|
|||
}
|
||||
|
||||
def Override : InheritableAttr {
|
||||
let Spellings = [Keyword<"override">];
|
||||
let Spellings = [CustomKeyword<"override">];
|
||||
let SemaHandler = 0;
|
||||
// Omitted from docs, since this is language syntax, not an attribute, as far
|
||||
// as users are concerned.
|
||||
|
|
@ -2389,6 +2433,11 @@ def AArch64SVEPcs: DeclOrTypeAttr {
|
|||
let Documentation = [AArch64SVEPcsDocs];
|
||||
}
|
||||
|
||||
def ArmStreaming : TypeAttr, TargetSpecificAttr<TargetAArch64> {
|
||||
let Spellings = [RegularKeyword<"__arm_streaming">];
|
||||
let Documentation = [ArmStreamingDocs];
|
||||
}
|
||||
|
||||
def Pure : InheritableAttr {
|
||||
let Spellings = [GCC<"pure">];
|
||||
let Documentation = [Undocumented];
|
||||
|
|
@ -2576,7 +2625,8 @@ def Sentinel : InheritableAttr {
|
|||
}
|
||||
|
||||
def StdCall : DeclOrTypeAttr {
|
||||
let Spellings = [GCC<"stdcall">, Keyword<"__stdcall">, Keyword<"_stdcall">];
|
||||
let Spellings = [GCC<"stdcall">, CustomKeyword<"__stdcall">,
|
||||
CustomKeyword<"_stdcall">];
|
||||
// let Subjects = [Function, ObjCMethod];
|
||||
let Documentation = [StdCallDocs];
|
||||
}
|
||||
|
|
@ -2645,15 +2695,15 @@ def SysVABI : DeclOrTypeAttr {
|
|||
}
|
||||
|
||||
def ThisCall : DeclOrTypeAttr {
|
||||
let Spellings = [GCC<"thiscall">, Keyword<"__thiscall">,
|
||||
Keyword<"_thiscall">];
|
||||
let Spellings = [GCC<"thiscall">, CustomKeyword<"__thiscall">,
|
||||
CustomKeyword<"_thiscall">];
|
||||
// let Subjects = [Function, ObjCMethod];
|
||||
let Documentation = [ThisCallDocs];
|
||||
}
|
||||
|
||||
def VectorCall : DeclOrTypeAttr {
|
||||
let Spellings = [Clang<"vectorcall">, Keyword<"__vectorcall">,
|
||||
Keyword<"_vectorcall">];
|
||||
let Spellings = [Clang<"vectorcall">, CustomKeyword<"__vectorcall">,
|
||||
CustomKeyword<"_vectorcall">];
|
||||
// let Subjects = [Function, ObjCMethod];
|
||||
let Documentation = [VectorCallDocs];
|
||||
}
|
||||
|
|
@ -2672,7 +2722,8 @@ def ZeroCallUsedRegs : InheritableAttr {
|
|||
}
|
||||
|
||||
def Pascal : DeclOrTypeAttr {
|
||||
let Spellings = [Clang<"pascal">, Keyword<"__pascal">, Keyword<"_pascal">];
|
||||
let Spellings = [Clang<"pascal">, CustomKeyword<"__pascal">,
|
||||
CustomKeyword<"_pascal">];
|
||||
// let Subjects = [Function, ObjCMethod];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
|
@ -2831,6 +2882,7 @@ def Unavailable : InheritableAttr {
|
|||
"IR_ARCInitReturnsUnrelated",
|
||||
"IR_ARCFieldWithOwnership"], 1, /*fake*/ 1>];
|
||||
let Documentation = [Undocumented];
|
||||
let MeaningfulToClassTemplateDefinition = 1;
|
||||
}
|
||||
|
||||
def DiagnoseIf : InheritableAttr {
|
||||
|
|
@ -3568,37 +3620,37 @@ def Thread : Attr {
|
|||
}
|
||||
|
||||
def Win64 : IgnoredAttr {
|
||||
let Spellings = [Keyword<"__w64">];
|
||||
let Spellings = [CustomKeyword<"__w64">];
|
||||
let LangOpts = [MicrosoftExt];
|
||||
}
|
||||
|
||||
def Ptr32 : TypeAttr {
|
||||
let Spellings = [Keyword<"__ptr32">];
|
||||
let Spellings = [CustomKeyword<"__ptr32">];
|
||||
let Documentation = [Ptr32Docs];
|
||||
}
|
||||
|
||||
def Ptr64 : TypeAttr {
|
||||
let Spellings = [Keyword<"__ptr64">];
|
||||
let Spellings = [CustomKeyword<"__ptr64">];
|
||||
let Documentation = [Ptr64Docs];
|
||||
}
|
||||
|
||||
def SPtr : TypeAttr {
|
||||
let Spellings = [Keyword<"__sptr">];
|
||||
let Spellings = [CustomKeyword<"__sptr">];
|
||||
let Documentation = [SPtrDocs];
|
||||
}
|
||||
|
||||
def UPtr : TypeAttr {
|
||||
let Spellings = [Keyword<"__uptr">];
|
||||
let Spellings = [CustomKeyword<"__uptr">];
|
||||
let Documentation = [UPtrDocs];
|
||||
}
|
||||
|
||||
def MSInheritance : InheritableAttr {
|
||||
let LangOpts = [MicrosoftExt];
|
||||
let Args = [DefaultBoolArgument<"BestCase", /*default*/1, /*fake*/1>];
|
||||
let Spellings = [Keyword<"__single_inheritance">,
|
||||
Keyword<"__multiple_inheritance">,
|
||||
Keyword<"__virtual_inheritance">,
|
||||
Keyword<"__unspecified_inheritance">];
|
||||
let Spellings = [CustomKeyword<"__single_inheritance">,
|
||||
CustomKeyword<"__multiple_inheritance">,
|
||||
CustomKeyword<"__virtual_inheritance">,
|
||||
CustomKeyword<"__unspecified_inheritance">];
|
||||
let AdditionalMembers = [{
|
||||
MSInheritanceModel getInheritanceModel() const {
|
||||
// The spelling enum should agree with MSInheritanceModel.
|
||||
|
|
@ -3966,6 +4018,12 @@ def ReleaseHandle : InheritableParamAttr {
|
|||
let Documentation = [ReleaseHandleDocs];
|
||||
}
|
||||
|
||||
def UnsafeBufferUsage : InheritableAttr {
|
||||
let Spellings = [Clang<"unsafe_buffer_usage">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [UnsafeBufferUsageDocs];
|
||||
}
|
||||
|
||||
def DiagnoseAsBuiltin : InheritableAttr {
|
||||
let Spellings = [Clang<"diagnose_as_builtin">];
|
||||
let Args = [DeclArgument<Function, "Function">,
|
||||
|
|
@ -4092,7 +4150,7 @@ def HLSLResource : InheritableAttr {
|
|||
}
|
||||
|
||||
def HLSLGroupSharedAddressSpace : TypeAttr {
|
||||
let Spellings = [Keyword<"groupshared">];
|
||||
let Spellings = [CustomKeyword<"groupshared">];
|
||||
let Subjects = SubjectList<[Var]>;
|
||||
let Documentation = [HLSLGroupSharedAddressSpaceDocs];
|
||||
}
|
||||
|
|
@ -4122,8 +4180,22 @@ def FunctionReturnThunks : InheritableAttr,
|
|||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [FunctionReturnThunksDocs];
|
||||
}
|
||||
|
||||
def WebAssemblyFuncref : TypeAttr, TargetSpecificAttr<TargetWebAssembly> {
|
||||
let Spellings = [CustomKeyword<"__funcref">];
|
||||
let Documentation = [WebAssemblyExportNameDocs];
|
||||
let Subjects = SubjectList<[FunctionPointer], ErrorDiag>;
|
||||
}
|
||||
|
||||
def ReadOnlyPlacement : InheritableAttr {
|
||||
let Spellings = [Clang<"enforce_read_only_placement">];
|
||||
let Subjects = SubjectList<[Record]>;
|
||||
let Documentation = [ReadOnlyPlacementDocs];
|
||||
}
|
||||
|
||||
def AvailableOnlyInDefaultEvalMethod : InheritableAttr {
|
||||
let Spellings = [Clang<"available_only_in_default_eval_method">];
|
||||
let Subjects = SubjectList<[TypedefName], ErrorDiag>;
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -539,17 +539,41 @@ def NoMergeDocs : Documentation {
|
|||
let Category = DocCatStmt;
|
||||
let Content = [{
|
||||
If a statement is marked ``nomerge`` and contains call expressions, those call
|
||||
expressions inside the statement will not be merged during optimization. This
|
||||
expressions inside the statement will not be merged during optimization. This
|
||||
attribute can be used to prevent the optimizer from obscuring the source
|
||||
location of certain calls. For example, it will prevent tail merging otherwise
|
||||
identical code sequences that raise an exception or terminate the program. Tail
|
||||
merging normally reduces the precision of source location information, making
|
||||
stack traces less useful for debugging. This attribute gives the user control
|
||||
over the tradeoff between code size and debug information precision.
|
||||
over the tradeoff between code size and debug information precision.
|
||||
|
||||
``nomerge`` attribute can also be used as function attribute to prevent all
|
||||
calls to the specified function from merging. It has no effect on indirect
|
||||
calls.
|
||||
``nomerge`` attribute can also be used as function attribute to prevent all
|
||||
calls to the specified function from merging. It has no effect on indirect
|
||||
calls to such functions. For example:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
[[clang::nomerge]] void foo(int) {}
|
||||
|
||||
void bar(int x) {
|
||||
auto *ptr = foo;
|
||||
if (x) foo(1); else foo(2); // will not be merged
|
||||
if (x) ptr(1); else ptr(2); // indirect call, can be merged
|
||||
}
|
||||
|
||||
``nomerge`` attribute can also be used for pointers to functions to
|
||||
prevent calls through such pointer from merging. In such case the
|
||||
effect applies only to a specific function pointer. For example:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
[[clang::nomerge]] void (*foo)(int);
|
||||
|
||||
void bar(int x) {
|
||||
auto *ptr = foo;
|
||||
if (x) foo(1); else foo(2); // will not be merged
|
||||
if (x) ptr(1); else ptr(2); // 'ptr' has no 'nomerge' attribute, can be merged
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
@ -603,6 +627,9 @@ Any variables in scope, including all arguments to the function and the
|
|||
return value must be trivially destructible. The calling convention of the
|
||||
caller and callee must match, and they must not be variadic functions or have
|
||||
old style K&R C function declarations.
|
||||
|
||||
``clang::musttail`` provides assurances that the tail call can be optimized on
|
||||
all targets, not just one.
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
@ -1581,7 +1608,7 @@ attributes are ignored. Supported platforms are:
|
|||
``watchos``
|
||||
Apple's watchOS operating system. The minimum deployment target is specified by
|
||||
the ``-mwatchos-version-min=*version*`` command-line argument.
|
||||
|
||||
|
||||
``driverkit``
|
||||
Apple's DriverKit userspace kernel extensions. The minimum deployment target
|
||||
is specified as part of the triple.
|
||||
|
|
@ -1750,6 +1777,19 @@ defined_in=\ *string-literal*
|
|||
source containers are modules, so ``defined_in`` should specify the Swift
|
||||
module name.
|
||||
|
||||
USR=\ *string-literal*
|
||||
String that specifies a unified symbol resolution (USR) value for this
|
||||
declaration. USR string uniquely identifies this particular declaration, and
|
||||
is typically used when constructing an index of a codebase.
|
||||
The USR value in this attribute is expected to be generated by an external
|
||||
compiler that compiled the native declaration using its original source
|
||||
language. The exact format of the USR string and its other attributes
|
||||
are determined by the specification of this declaration's source language.
|
||||
When not specified, Clang's indexer will use the Clang USR for this symbol.
|
||||
User can query to see if Clang supports the use of the ``USR`` clause in
|
||||
the ``external_source_symbol`` attribute with
|
||||
``__has_attribute(external_source_symbol) >= 20230206``.
|
||||
|
||||
generated_declaration
|
||||
This declaration was automatically generated by some tool.
|
||||
|
||||
|
|
@ -2280,7 +2320,7 @@ as ``-mlong-calls`` and ``-mno-long-calls``.
|
|||
|
||||
def RISCVInterruptDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Heading = "interrupt (RISCV)";
|
||||
let Heading = "interrupt (RISC-V)";
|
||||
let Content = [{
|
||||
Clang supports the GNU style ``__attribute__((interrupt))`` attribute on RISCV
|
||||
targets. This attribute may be attached to a function definition and instructs
|
||||
|
|
@ -2301,6 +2341,40 @@ Version 1.10.
|
|||
}];
|
||||
}
|
||||
|
||||
def RISCVRVVVectorBitsDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
On RISC-V targets, the ``riscv_rvv_vector_bits(N)`` attribute is used to define
|
||||
fixed-length variants of sizeless types.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <riscv_vector.h>
|
||||
|
||||
#if defined(__riscv_v_fixed_vlen)
|
||||
typedef vint8m1_t fixed_vint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen)));
|
||||
#endif
|
||||
|
||||
Creates a type ``fixed_vint8m1_t_t`` that is a fixed-length variant of
|
||||
``vint8m1_t`` that contains exactly 512 bits. Unlike ``vint8m1_t``, this type
|
||||
can be used in globals, structs, unions, and arrays, all of which are
|
||||
unsupported for sizeless types.
|
||||
|
||||
The attribute can be attached to a single RVV vector (such as ``vint8m1_t``).
|
||||
The attribute will be rejected unless
|
||||
``N==(__riscv_v_fixed_vlen*LMUL)``, the implementation defined feature macro that
|
||||
is enabled under the ``-mrvv-vector-bits`` flag. ``__riscv_v_fixed_vlen`` can
|
||||
only be a power of 2 between 64 and 65536.
|
||||
|
||||
For types where LMUL!=1, ``__riscv_v_fixed_vlen`` needs to be scaled by the LMUL
|
||||
of the type before passing to the attribute.
|
||||
|
||||
``vbool*_t`` types are not supported at this time.
|
||||
}];
|
||||
}
|
||||
|
||||
def AVRInterruptDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Heading = "interrupt (AVR)";
|
||||
|
|
@ -3883,7 +3957,7 @@ Whether a particular pointer may be "null" is an important concern when working
|
|||
with pointers in the C family of languages. The various nullability attributes
|
||||
indicate whether a particular pointer can be null or not, which makes APIs more
|
||||
expressive and can help static analysis tools identify bugs involving null
|
||||
pointers. Clang supports several kinds of nullability attributes: the
|
||||
pointers. Clang supports several kinds of nullability attributes: the
|
||||
``nonnull`` and ``returns_nonnull`` attributes indicate which function or
|
||||
method parameters and result types can never be null, while nullability type
|
||||
qualifiers indicate which pointer types can be null (``_Nullable``) or cannot
|
||||
|
|
@ -4059,7 +4133,7 @@ memory is not available rather than returning a null pointer:
|
|||
The ``returns_nonnull`` attribute implies that returning a null pointer is
|
||||
undefined behavior, which the optimizer may take advantage of. The ``_Nonnull``
|
||||
type qualifier indicates that a pointer cannot be null in a more general manner
|
||||
(because it is part of the type system) and does not imply undefined behavior,
|
||||
(because it is part of the type system) and does not imply undefined behavior,
|
||||
making it more widely applicable
|
||||
}];
|
||||
}
|
||||
|
|
@ -5166,6 +5240,9 @@ apply for values returned in callee-saved registers.
|
|||
R11. R11 can be used as a scratch register. Floating-point registers
|
||||
(XMMs/YMMs) are not preserved and need to be saved by the caller.
|
||||
|
||||
- On AArch64 the callee preserve all general purpose registers, except X0-X8 and
|
||||
X16-X18.
|
||||
|
||||
The idea behind this convention is to support calls to runtime functions
|
||||
that have a hot path and a cold path. The hot path is usually a small piece
|
||||
of code that doesn't use many registers. The cold path might need to call out to
|
||||
|
|
@ -5206,6 +5283,10 @@ returned in callee-saved registers.
|
|||
R11. R11 can be used as a scratch register. Furthermore it also preserves
|
||||
all floating-point registers (XMMs/YMMs).
|
||||
|
||||
- On AArch64 the callee preserve all general purpose registers, except X0-X8 and
|
||||
X16-X18. Furthermore it also preserves lower 128 bits of V8-V31 SIMD - floating
|
||||
point registers.
|
||||
|
||||
The idea behind this convention is to support calls to runtime functions
|
||||
that don't need to call out to any other functions.
|
||||
|
||||
|
|
@ -5315,7 +5396,7 @@ takes precedence over the command line option ``-fpatchable-function-entry=N,M``
|
|||
``M`` defaults to 0 if omitted.
|
||||
|
||||
This attribute is only supported on
|
||||
aarch64/aarch64-be/riscv32/riscv64/i386/x86-64 targets.
|
||||
aarch64/aarch64-be/loongarch32/loongarch64/riscv32/riscv64/i386/x86-64 targets.
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
@ -6008,15 +6089,15 @@ def CFGuardDocs : Documentation {
|
|||
let Content = [{
|
||||
Code can indicate CFG checks are not wanted with the ``__declspec(guard(nocf))``
|
||||
attribute. This directs the compiler to not insert any CFG checks for the entire
|
||||
function. This approach is typically used only sparingly in specific situations
|
||||
where the programmer has manually inserted "CFG-equivalent" protection. The
|
||||
programmer knows that they are calling through some read-only function table
|
||||
whose address is obtained through read-only memory references and for which the
|
||||
index is masked to the function table limit. This approach may also be applied
|
||||
to small wrapper functions that are not inlined and that do nothing more than
|
||||
make a call through a function pointer. Since incorrect usage of this directive
|
||||
can compromise the security of CFG, the programmer must be very careful using
|
||||
the directive. Typically, this usage is limited to very small functions that
|
||||
function. This approach is typically used only sparingly in specific situations
|
||||
where the programmer has manually inserted "CFG-equivalent" protection. The
|
||||
programmer knows that they are calling through some read-only function table
|
||||
whose address is obtained through read-only memory references and for which the
|
||||
index is masked to the function table limit. This approach may also be applied
|
||||
to small wrapper functions that are not inlined and that do nothing more than
|
||||
make a call through a function pointer. Since incorrect usage of this directive
|
||||
can compromise the security of CFG, the programmer must be very careful using
|
||||
the directive. Typically, this usage is limited to very small functions that
|
||||
only call one function.
|
||||
|
||||
`Control Flow Guard documentation <https://docs.microsoft.com/en-us/windows/win32/secbp/pe-metadata>`
|
||||
|
|
@ -6274,6 +6355,84 @@ attribute requires a string literal argument to identify the handle being releas
|
|||
}];
|
||||
}
|
||||
|
||||
def UnsafeBufferUsageDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
The attribute ``[[clang::unsafe_buffer_usage]]`` should be placed on functions
|
||||
that need to be avoided as they are prone to buffer overflows. It is designed to
|
||||
work together with the off-by-default compiler warning ``-Wunsafe-buffer-usage``
|
||||
to help codebases transition away from raw pointer based buffer management,
|
||||
in favor of safer abstractions such as C++20 ``std::span``. The attribute causes
|
||||
``-Wunsafe-buffer-usage`` to warn on every use of the function, and it may
|
||||
enable ``-Wunsafe-buffer-usage`` to emit automatic fix-it hints
|
||||
which would help the user replace such unsafe functions with safe
|
||||
alternatives, though the attribute can be used even when the fix can't be automated.
|
||||
|
||||
The attribute does not suppress ``-Wunsafe-buffer-usage`` inside the function
|
||||
to which it is attached. These warnings still need to be addressed.
|
||||
|
||||
The attribute is warranted even if the only way a function can overflow
|
||||
the buffer is by violating the function's preconditions. For example, it
|
||||
would make sense to put the attribute on function ``foo()`` below because
|
||||
passing an incorrect size parameter would cause a buffer overflow:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
[[clang::unsafe_buffer_usage]]
|
||||
void foo(int *buf, size_t size) {
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
buf[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
The attribute is NOT warranted when the function uses safe abstractions,
|
||||
assuming that these abstractions weren't misused outside the function.
|
||||
For example, function ``bar()`` below doesn't need the attribute,
|
||||
because assuming that the container ``buf`` is well-formed (has size that
|
||||
fits the original buffer it refers to), overflow cannot occur:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void bar(std::span<int> buf) {
|
||||
for (size_t i = 0; i < buf.size(); ++i) {
|
||||
buf[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
In this case function ``bar()`` enables the user to keep the buffer
|
||||
"containerized" in a span for as long as possible. On the other hand,
|
||||
Function ``foo()`` in the previous example may have internal
|
||||
consistency, but by accepting a raw buffer it requires the user to unwrap
|
||||
their span, which is undesirable according to the programming model
|
||||
behind ``-Wunsafe-buffer-usage``.
|
||||
|
||||
The attribute is warranted when a function accepts a raw buffer only to
|
||||
immediately put it into a span:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
[[clang::unsafe_buffer_usage]]
|
||||
void baz(int *buf, size_t size) {
|
||||
std::span<int> sp{ buf, size };
|
||||
for (size_t i = 0; i < sp.size(); ++i) {
|
||||
sp[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
In this case ``baz()`` does not contain any unsafe operations, but the awkward
|
||||
parameter type causes the caller to unwrap the span unnecessarily.
|
||||
Note that regardless of the attribute, code inside ``baz()`` isn't flagged
|
||||
by ``-Wunsafe-buffer-usage`` as unsafe. It is definitely undesirable,
|
||||
but if ``baz()`` is on an API surface, there is no way to improve it
|
||||
to make it as safe as ``bar()`` without breaking the source and binary
|
||||
compatibility with existing users of the function. In such cases
|
||||
the proper solution would be to create a different function (possibly
|
||||
an overload of ``baz()``) that accepts a safe container like ``bar()``,
|
||||
and then use the attribute on the original ``baz()`` to help the users
|
||||
update their code to use the new function.
|
||||
}];
|
||||
}
|
||||
|
||||
def DiagnoseAsBuiltinDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
|
|
@ -6419,6 +6578,41 @@ Requirements on Development Tools - Engineering Specification Documentation
|
|||
}];
|
||||
}
|
||||
|
||||
def ArmStreamingDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
.. Note:: This attribute has not been implemented yet, but once it is
|
||||
implemented, it will behave as described below.
|
||||
|
||||
The ``__arm_streaming`` keyword is only available on AArch64 targets.
|
||||
It applies to function types and specifies that the function has a
|
||||
"streaming interface". This means that:
|
||||
|
||||
* the function requires the Scalable Matrix Extension (SME)
|
||||
|
||||
* the function must be entered in streaming mode (that is, with PSTATE.SM
|
||||
set to 1)
|
||||
|
||||
* the function must return in streaming mode
|
||||
|
||||
See `Procedure Call Standard for the Arm® 64-bit Architecture (AArch64)
|
||||
<https://github.com/ARM-software/abi-aa>`_ for more details about
|
||||
streaming-interface functions.
|
||||
|
||||
Clang manages PSTATE.SM automatically; it is not the source code's
|
||||
responsibility to do this. For example, if a normal non-streaming
|
||||
function calls an ``__arm_streaming`` function, Clang generates code
|
||||
that switches into streaming mode before calling the function and
|
||||
switches back to non-streaming mode on return.
|
||||
|
||||
``__arm_streaming`` can appear anywhere that a standard ``[[...]]`` type
|
||||
attribute can appear.
|
||||
|
||||
See `Arm C Language Extensions <https://github.com/ARM-software/acle>`_
|
||||
for more details about this extension, and for other related SME features.
|
||||
}];
|
||||
}
|
||||
|
||||
def AlwaysInlineDocs : Documentation {
|
||||
let Category = DocCatFunction;
|
||||
let Content = [{
|
||||
|
|
@ -6847,3 +7041,39 @@ def ReadOnlyPlacementDocs : Documentation {
|
|||
``enforce_read_only_placement`` attribute.
|
||||
}];
|
||||
}
|
||||
|
||||
def WebAssemblyFuncrefDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
Clang supports the ``__funcref`` attribute for the WebAssembly target.
|
||||
This attribute may be attached to a function pointer type, where it modifies
|
||||
its underlying representation to be a WebAssembly ``funcref``.
|
||||
}];
|
||||
}
|
||||
|
||||
def CleanupDocs : Documentation {
|
||||
let Category = DocCatType;
|
||||
let Content = [{
|
||||
This attribute allows a function to be run when a local variable goes out of
|
||||
scope. The attribute takes the identifier of a function with a parameter type
|
||||
that is a pointer to the type with the attribute.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void foo (int *) { ... }
|
||||
static void bar (int *) { ... }
|
||||
void baz (void) {
|
||||
int x __attribute__((cleanup(foo)));
|
||||
{
|
||||
int y __attribute__((cleanup(bar)));
|
||||
}
|
||||
}
|
||||
|
||||
The above example will result in a call to ``bar`` being passed the address of
|
||||
`y`` when ``y`` goes out of scope, then a call to ``foo`` being passed the
|
||||
address of ``x`` when ``x`` goes out of scope. If two or more variables share
|
||||
the same scope, their ``cleanup`` callbacks are invoked in the reverse order
|
||||
the variables were declared in. It is not possible to check the return value
|
||||
(if any) of these ``cleanup`` callback functions.
|
||||
}];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
|
||||
#define LLVM_CLANG_BASIC_ATTRIBUTECOMMONINFO_H
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
|
||||
namespace clang {
|
||||
class IdentifierInfo;
|
||||
|
|
@ -24,7 +25,7 @@ public:
|
|||
/// The style used to specify an attribute.
|
||||
enum Syntax {
|
||||
/// __attribute__((...))
|
||||
AS_GNU,
|
||||
AS_GNU = 1,
|
||||
|
||||
/// [[...]]
|
||||
AS_CXX11,
|
||||
|
|
@ -51,6 +52,10 @@ public:
|
|||
|
||||
/// <vardecl> : <semantic>
|
||||
AS_HLSLSemantic,
|
||||
|
||||
/// The attibute has no source code manifestation and is only created
|
||||
/// implicitly.
|
||||
AS_Implicit
|
||||
};
|
||||
enum Kind {
|
||||
#define PARSED_ATTR(NAME) AT_##NAME,
|
||||
|
|
@ -71,63 +76,96 @@ private:
|
|||
/// Corresponds to the Syntax enum.
|
||||
unsigned SyntaxUsed : 4;
|
||||
unsigned SpellingIndex : 4;
|
||||
unsigned IsAlignas : 1;
|
||||
unsigned IsRegularKeywordAttribute : 1;
|
||||
|
||||
protected:
|
||||
static constexpr unsigned SpellingNotCalculated = 0xf;
|
||||
|
||||
public:
|
||||
AttributeCommonInfo(SourceRange AttrRange)
|
||||
: AttrRange(AttrRange), ScopeLoc(), AttrKind(0), SyntaxUsed(0),
|
||||
SpellingIndex(SpellingNotCalculated) {}
|
||||
/// Combines information about the source-code form of an attribute,
|
||||
/// including its syntax and spelling.
|
||||
class Form {
|
||||
public:
|
||||
constexpr Form(Syntax SyntaxUsed, unsigned SpellingIndex, bool IsAlignas,
|
||||
bool IsRegularKeywordAttribute)
|
||||
: SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingIndex),
|
||||
IsAlignas(IsAlignas),
|
||||
IsRegularKeywordAttribute(IsRegularKeywordAttribute) {}
|
||||
constexpr Form(tok::TokenKind Tok)
|
||||
: SyntaxUsed(AS_Keyword), SpellingIndex(SpellingNotCalculated),
|
||||
IsAlignas(Tok == tok::kw_alignas),
|
||||
IsRegularKeywordAttribute(tok::isRegularKeywordAttribute(Tok)) {}
|
||||
|
||||
AttributeCommonInfo(SourceLocation AttrLoc)
|
||||
: AttrRange(AttrLoc), ScopeLoc(), AttrKind(0), SyntaxUsed(0),
|
||||
SpellingIndex(SpellingNotCalculated) {}
|
||||
Syntax getSyntax() const { return Syntax(SyntaxUsed); }
|
||||
unsigned getSpellingIndex() const { return SpellingIndex; }
|
||||
bool isAlignas() const { return IsAlignas; }
|
||||
bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; }
|
||||
|
||||
static Form GNU() { return AS_GNU; }
|
||||
static Form CXX11() { return AS_CXX11; }
|
||||
static Form C2x() { return AS_C2x; }
|
||||
static Form Declspec() { return AS_Declspec; }
|
||||
static Form Microsoft() { return AS_Microsoft; }
|
||||
static Form Keyword(bool IsAlignas, bool IsRegularKeywordAttribute) {
|
||||
return Form(AS_Keyword, SpellingNotCalculated, IsAlignas,
|
||||
IsRegularKeywordAttribute);
|
||||
}
|
||||
static Form Pragma() { return AS_Pragma; }
|
||||
static Form ContextSensitiveKeyword() { return AS_ContextSensitiveKeyword; }
|
||||
static Form HLSLSemantic() { return AS_HLSLSemantic; }
|
||||
static Form Implicit() { return AS_Implicit; }
|
||||
|
||||
private:
|
||||
constexpr Form(Syntax SyntaxUsed)
|
||||
: SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated),
|
||||
IsAlignas(0), IsRegularKeywordAttribute(0) {}
|
||||
|
||||
unsigned SyntaxUsed : 4;
|
||||
unsigned SpellingIndex : 4;
|
||||
unsigned IsAlignas : 1;
|
||||
unsigned IsRegularKeywordAttribute : 1;
|
||||
};
|
||||
|
||||
AttributeCommonInfo(const IdentifierInfo *AttrName,
|
||||
const IdentifierInfo *ScopeName, SourceRange AttrRange,
|
||||
SourceLocation ScopeLoc, Syntax SyntaxUsed)
|
||||
SourceLocation ScopeLoc, Kind AttrKind, Form FormUsed)
|
||||
: AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
|
||||
ScopeLoc(ScopeLoc),
|
||||
AttrKind(getParsedKind(AttrName, ScopeName, SyntaxUsed)),
|
||||
SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated) {}
|
||||
ScopeLoc(ScopeLoc), AttrKind(AttrKind),
|
||||
SyntaxUsed(FormUsed.getSyntax()),
|
||||
SpellingIndex(FormUsed.getSpellingIndex()),
|
||||
IsAlignas(FormUsed.isAlignas()),
|
||||
IsRegularKeywordAttribute(FormUsed.isRegularKeywordAttribute()) {
|
||||
assert(SyntaxUsed >= AS_GNU && SyntaxUsed <= AS_Implicit &&
|
||||
"Invalid syntax!");
|
||||
}
|
||||
|
||||
AttributeCommonInfo(const IdentifierInfo *AttrName,
|
||||
const IdentifierInfo *ScopeName, SourceRange AttrRange,
|
||||
SourceLocation ScopeLoc, Kind AttrKind, Syntax SyntaxUsed)
|
||||
: AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
|
||||
ScopeLoc(ScopeLoc), AttrKind(AttrKind), SyntaxUsed(SyntaxUsed),
|
||||
SpellingIndex(SpellingNotCalculated) {}
|
||||
|
||||
AttributeCommonInfo(const IdentifierInfo *AttrName,
|
||||
const IdentifierInfo *ScopeName, SourceRange AttrRange,
|
||||
SourceLocation ScopeLoc, Kind AttrKind, Syntax SyntaxUsed,
|
||||
unsigned Spelling)
|
||||
: AttrName(AttrName), ScopeName(ScopeName), AttrRange(AttrRange),
|
||||
ScopeLoc(ScopeLoc), AttrKind(AttrKind), SyntaxUsed(SyntaxUsed),
|
||||
SpellingIndex(Spelling) {}
|
||||
SourceLocation ScopeLoc, Form FormUsed)
|
||||
: AttributeCommonInfo(
|
||||
AttrName, ScopeName, AttrRange, ScopeLoc,
|
||||
getParsedKind(AttrName, ScopeName, FormUsed.getSyntax()),
|
||||
FormUsed) {}
|
||||
|
||||
AttributeCommonInfo(const IdentifierInfo *AttrName, SourceRange AttrRange,
|
||||
Syntax SyntaxUsed)
|
||||
: AttrName(AttrName), ScopeName(nullptr), AttrRange(AttrRange),
|
||||
ScopeLoc(), AttrKind(getParsedKind(AttrName, ScopeName, SyntaxUsed)),
|
||||
SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated) {}
|
||||
Form FormUsed)
|
||||
: AttributeCommonInfo(AttrName, nullptr, AttrRange, SourceLocation(),
|
||||
FormUsed) {}
|
||||
|
||||
AttributeCommonInfo(SourceRange AttrRange, Kind K, Syntax SyntaxUsed)
|
||||
: AttrName(nullptr), ScopeName(nullptr), AttrRange(AttrRange), ScopeLoc(),
|
||||
AttrKind(K), SyntaxUsed(SyntaxUsed),
|
||||
SpellingIndex(SpellingNotCalculated) {}
|
||||
|
||||
AttributeCommonInfo(SourceRange AttrRange, Kind K, Syntax SyntaxUsed,
|
||||
unsigned Spelling)
|
||||
: AttrName(nullptr), ScopeName(nullptr), AttrRange(AttrRange), ScopeLoc(),
|
||||
AttrKind(K), SyntaxUsed(SyntaxUsed), SpellingIndex(Spelling) {}
|
||||
AttributeCommonInfo(SourceRange AttrRange, Kind K, Form FormUsed)
|
||||
: AttributeCommonInfo(nullptr, nullptr, AttrRange, SourceLocation(), K,
|
||||
FormUsed) {}
|
||||
|
||||
AttributeCommonInfo(AttributeCommonInfo &&) = default;
|
||||
AttributeCommonInfo(const AttributeCommonInfo &) = default;
|
||||
|
||||
Kind getParsedKind() const { return Kind(AttrKind); }
|
||||
Syntax getSyntax() const { return Syntax(SyntaxUsed); }
|
||||
Form getForm() const {
|
||||
return Form(getSyntax(), SpellingIndex, IsAlignas,
|
||||
IsRegularKeywordAttribute);
|
||||
}
|
||||
const IdentifierInfo *getAttrName() const { return AttrName; }
|
||||
SourceLocation getLoc() const { return AttrRange.getBegin(); }
|
||||
SourceRange getRange() const { return AttrRange; }
|
||||
|
|
@ -148,29 +186,7 @@ public:
|
|||
bool isGNUScope() const;
|
||||
bool isClangScope() const;
|
||||
|
||||
bool isAlignasAttribute() const {
|
||||
// FIXME: Use a better mechanism to determine this.
|
||||
// We use this in `isCXX11Attribute` below, so it _should_ only return
|
||||
// true for the `alignas` spelling, but it currently also returns true
|
||||
// for the `_Alignas` spelling, which only exists in C11. Distinguishing
|
||||
// between the two is important because they behave differently:
|
||||
// - `alignas` may only appear in the attribute-specifier-seq before
|
||||
// the decl-specifier-seq and is therefore associated with the
|
||||
// declaration.
|
||||
// - `_Alignas` may appear anywhere within the declaration-specifiers
|
||||
// and is therefore associated with the `DeclSpec`.
|
||||
// It's not clear how best to fix this:
|
||||
// - We have the necessary information in the form of the `SpellingIndex`,
|
||||
// but we would need to compare against AlignedAttr::Keyword_alignas,
|
||||
// and we can't depend on clang/AST/Attr.h here.
|
||||
// - We could test `getAttrName()->getName() == "alignas"`, but this is
|
||||
// inefficient.
|
||||
return getParsedKind() == AT_Aligned && isKeywordAttribute();
|
||||
}
|
||||
|
||||
bool isCXX11Attribute() const {
|
||||
return SyntaxUsed == AS_CXX11 || isAlignasAttribute();
|
||||
}
|
||||
bool isCXX11Attribute() const { return SyntaxUsed == AS_CXX11 || IsAlignas; }
|
||||
|
||||
bool isC2xAttribute() const { return SyntaxUsed == AS_C2x; }
|
||||
|
||||
|
|
@ -186,6 +202,8 @@ public:
|
|||
return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
|
||||
}
|
||||
|
||||
bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; }
|
||||
|
||||
bool isContextSensitiveKeywordAttribute() const {
|
||||
return SyntaxUsed == AS_ContextSensitiveKeyword;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@
|
|||
// A -> "reference" to __builtin_va_list
|
||||
// V -> Vector, followed by the number of elements and the base type.
|
||||
// q -> Scalable vector, followed by the number of elements and the base type.
|
||||
// Q -> target builtin type, followed by a character to distinguish the builtin type
|
||||
// Qa -> AArch64 svcount_t builtin type.
|
||||
// E -> ext_vector, followed by the number of elements and the base type.
|
||||
// X -> _Complex, followed by the base type.
|
||||
// Y -> ptrdiff_t
|
||||
|
|
@ -141,6 +143,7 @@ BUILTIN(__builtin_frexp , "ddi*" , "Fn")
|
|||
BUILTIN(__builtin_frexpf, "ffi*" , "Fn")
|
||||
BUILTIN(__builtin_frexpl, "LdLdi*", "Fn")
|
||||
BUILTIN(__builtin_frexpf128, "LLdLLdi*", "Fn")
|
||||
BUILTIN(__builtin_frexpf16, "hhi*" , "Fn")
|
||||
BUILTIN(__builtin_huge_val, "d", "ncE")
|
||||
BUILTIN(__builtin_huge_valf, "f", "ncE")
|
||||
BUILTIN(__builtin_huge_vall, "Ld", "ncE")
|
||||
|
|
@ -157,6 +160,7 @@ BUILTIN(__builtin_ldexp , "ddi" , "Fne")
|
|||
BUILTIN(__builtin_ldexpf, "ffi" , "Fne")
|
||||
BUILTIN(__builtin_ldexpl, "LdLdi", "Fne")
|
||||
BUILTIN(__builtin_ldexpf128, "LLdLLdi", "Fne")
|
||||
BUILTIN(__builtin_ldexpf16, "hhi", "Fne")
|
||||
BUILTIN(__builtin_modf , "ddd*" , "Fn")
|
||||
BUILTIN(__builtin_modff, "fff*" , "Fn")
|
||||
BUILTIN(__builtin_modfl, "LdLdLd*", "Fn")
|
||||
|
|
@ -350,6 +354,11 @@ BUILTIN(__builtin_roundf, "ff" , "Fnc")
|
|||
BUILTIN(__builtin_roundf16, "hh" , "Fnc")
|
||||
BUILTIN(__builtin_roundl, "LdLd" , "Fnc")
|
||||
BUILTIN(__builtin_roundf128, "LLdLLd" , "Fnc")
|
||||
BUILTIN(__builtin_roundeven, "dd" , "Fnc")
|
||||
BUILTIN(__builtin_roundevenf, "ff" , "Fnc")
|
||||
BUILTIN(__builtin_roundevenf16, "hh" , "Fnc")
|
||||
BUILTIN(__builtin_roundevenl, "LdLd" , "Fnc")
|
||||
BUILTIN(__builtin_roundevenf128, "LLdLLd" , "Fnc")
|
||||
BUILTIN(__builtin_scalbln , "ddLi", "Fne")
|
||||
BUILTIN(__builtin_scalblnf, "ffLi", "Fne")
|
||||
BUILTIN(__builtin_scalblnl, "LdLdLi", "Fne")
|
||||
|
|
@ -392,6 +401,7 @@ BUILTIN(__builtin_truncf16, "hh", "Fnc")
|
|||
|
||||
// Access to floating point environment
|
||||
BUILTIN(__builtin_flt_rounds, "i", "n")
|
||||
BUILTIN(__builtin_set_flt_rounds, "vi", "n")
|
||||
|
||||
// C99 complex builtins
|
||||
BUILTIN(__builtin_cabs, "dXd", "Fne")
|
||||
|
|
@ -479,6 +489,7 @@ BUILTIN(__builtin_isinf, "i.", "FnctE")
|
|||
BUILTIN(__builtin_isinf_sign, "i.", "FnctE")
|
||||
BUILTIN(__builtin_isnan, "i.", "FnctE")
|
||||
BUILTIN(__builtin_isnormal, "i.", "FnctE")
|
||||
BUILTIN(__builtin_isfpclass, "i.", "nctE")
|
||||
|
||||
// FP signbit builtins
|
||||
BUILTIN(__builtin_signbit, "i.", "Fnct")
|
||||
|
|
@ -551,7 +562,6 @@ BUILTIN(__builtin_assume_aligned, "v*vC*z.", "nctE")
|
|||
BUILTIN(__builtin_bcmp, "ivC*vC*z", "FnE")
|
||||
BUILTIN(__builtin_bcopy, "vv*v*z", "n")
|
||||
BUILTIN(__builtin_bzero, "vv*z", "nF")
|
||||
BUILTIN(__builtin_fprintf, "iP*cC*.", "Fp:1:")
|
||||
BUILTIN(__builtin_free, "vv*", "nF")
|
||||
BUILTIN(__builtin_malloc, "v*z", "nF")
|
||||
BUILTIN(__builtin_memchr, "v*vC*iz", "nFE")
|
||||
|
|
@ -562,7 +572,6 @@ BUILTIN(__builtin_memmove, "v*v*vC*z", "nFE")
|
|||
BUILTIN(__builtin_mempcpy, "v*v*vC*z", "nF")
|
||||
BUILTIN(__builtin_memset, "v*v*iz", "nF")
|
||||
BUILTIN(__builtin_memset_inline, "vv*iIz", "n")
|
||||
BUILTIN(__builtin_printf, "icC*.", "Fp:0:")
|
||||
BUILTIN(__builtin_stpcpy, "c*c*cC*", "nF")
|
||||
BUILTIN(__builtin_stpncpy, "c*c*cC*z", "nF")
|
||||
BUILTIN(__builtin_strcasecmp, "icC*cC*", "nF")
|
||||
|
|
@ -599,10 +608,20 @@ BUILTIN(__builtin_setjmp, "iv**", "j")
|
|||
BUILTIN(__builtin_longjmp, "vv**i", "r")
|
||||
BUILTIN(__builtin_unwind_init, "v", "")
|
||||
BUILTIN(__builtin_eh_return_data_regno, "iIi", "ncE")
|
||||
BUILTIN(__builtin_snprintf, "ic*zcC*.", "nFp:2:")
|
||||
BUILTIN(__builtin_sprintf, "ic*cC*.", "nFP:1:")
|
||||
BUILTIN(__builtin_vsnprintf, "ic*zcC*a", "nFP:2:")
|
||||
BUILTIN(__builtin_vsprintf, "ic*cC*a", "nFP:1:")
|
||||
BUILTIN(__builtin_fprintf, "iP*RcC*R.", "nFp:1:")
|
||||
BUILTIN(__builtin_printf, "icC*R.", "nFp:0:")
|
||||
BUILTIN(__builtin_sprintf, "ic*RcC*R.", "nFp:1:")
|
||||
BUILTIN(__builtin_snprintf, "ic*RzcC*R.", "nFp:2:")
|
||||
BUILTIN(__builtin_vprintf, "icC*Ra", "nFP:0:")
|
||||
BUILTIN(__builtin_vfprintf, "iP*RcC*Ra", "nFP:1:")
|
||||
BUILTIN(__builtin_vsprintf, "ic*RcC*Ra", "nFP:1:")
|
||||
BUILTIN(__builtin_vsnprintf, "ic*RzcC*Ra", "nFP:2:")
|
||||
BUILTIN(__builtin_fscanf, "iP*RcC*R.", "Fs:1:")
|
||||
BUILTIN(__builtin_scanf, "icC*R.", "Fs:0:")
|
||||
BUILTIN(__builtin_sscanf, "icC*RcC*R.", "Fs:1:")
|
||||
BUILTIN(__builtin_vfscanf, "iP*RcC*Ra", "FS:1:")
|
||||
BUILTIN(__builtin_vscanf, "icC*Ra", "FS:0:")
|
||||
BUILTIN(__builtin_vsscanf, "icC*RcC*Ra", "FS:1:")
|
||||
BUILTIN(__builtin_thread_pointer, "v*", "nc")
|
||||
BUILTIN(__builtin_launder, "v*v*", "ntE")
|
||||
LANGBUILTIN(__builtin_is_constant_evaluated, "b", "nE", CXX_LANG)
|
||||
|
|
@ -631,14 +650,14 @@ BUILTIN(__builtin___strlcpy_chk, "zc*cC*zz", "nF")
|
|||
BUILTIN(__builtin___strncat_chk, "c*c*cC*zz", "nF")
|
||||
BUILTIN(__builtin___strncpy_chk, "c*c*cC*zz", "nF")
|
||||
BUILTIN(__builtin___stpncpy_chk, "c*c*cC*zz", "nF")
|
||||
BUILTIN(__builtin___snprintf_chk, "ic*zizcC*.", "Fp:4:")
|
||||
BUILTIN(__builtin___sprintf_chk, "ic*izcC*.", "Fp:3:")
|
||||
BUILTIN(__builtin___vsnprintf_chk, "ic*zizcC*a", "FP:4:")
|
||||
BUILTIN(__builtin___vsprintf_chk, "ic*izcC*a", "FP:3:")
|
||||
BUILTIN(__builtin___fprintf_chk, "iP*icC*.", "Fp:2:")
|
||||
BUILTIN(__builtin___printf_chk, "iicC*.", "Fp:1:")
|
||||
BUILTIN(__builtin___vfprintf_chk, "iP*icC*a", "FP:2:")
|
||||
BUILTIN(__builtin___vprintf_chk, "iicC*a", "FP:1:")
|
||||
BUILTIN(__builtin___snprintf_chk, "ic*RzizcC*R.", "Fp:4:")
|
||||
BUILTIN(__builtin___sprintf_chk, "ic*RizcC*R.", "Fp:3:")
|
||||
BUILTIN(__builtin___vsnprintf_chk, "ic*RzizcC*Ra", "FP:4:")
|
||||
BUILTIN(__builtin___vsprintf_chk, "ic*RizcC*Ra", "FP:3:")
|
||||
BUILTIN(__builtin___fprintf_chk, "iP*RicC*R.", "Fp:2:")
|
||||
BUILTIN(__builtin___printf_chk, "iicC*R.", "Fp:1:")
|
||||
BUILTIN(__builtin___vfprintf_chk, "iP*RicC*Ra", "FP:2:")
|
||||
BUILTIN(__builtin___vprintf_chk, "iicC*Ra", "FP:1:")
|
||||
|
||||
BUILTIN(__builtin_unpredictable, "LiLi" , "nc")
|
||||
BUILTIN(__builtin_expect, "LiLiLi" , "ncE")
|
||||
|
|
@ -655,18 +674,29 @@ BUILTIN(__builtin_alloca_uninitialized, "v*z", "Fn")
|
|||
BUILTIN(__builtin_alloca_with_align, "v*zIz", "Fn")
|
||||
BUILTIN(__builtin_alloca_with_align_uninitialized, "v*zIz", "Fn")
|
||||
BUILTIN(__builtin_call_with_static_chain, "v.", "nt")
|
||||
BUILTIN(__builtin_nondeterministic_value, "v.", "nt")
|
||||
|
||||
BUILTIN(__builtin_elementwise_abs, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_max, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_min, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_ceil, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_cos, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_exp, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_exp2, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_floor, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_log, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_log2, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_log10, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_pow, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_roundeven, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_round, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_rint, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_nearbyint, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_sin, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_trunc, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_canonicalize, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_copysign, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_fma, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_add_sat, "v.", "nct")
|
||||
BUILTIN(__builtin_elementwise_sub_sat, "v.", "nct")
|
||||
BUILTIN(__builtin_reduce_max, "v.", "nct")
|
||||
|
|
@ -889,6 +919,7 @@ ATOMIC_BUILTIN(__hip_atomic_compare_exchange_weak, "v.", "t")
|
|||
ATOMIC_BUILTIN(__hip_atomic_compare_exchange_strong, "v.", "t")
|
||||
ATOMIC_BUILTIN(__hip_atomic_exchange, "v.", "t")
|
||||
ATOMIC_BUILTIN(__hip_atomic_fetch_add, "v.", "t")
|
||||
ATOMIC_BUILTIN(__hip_atomic_fetch_sub, "v.", "t")
|
||||
ATOMIC_BUILTIN(__hip_atomic_fetch_and, "v.", "t")
|
||||
ATOMIC_BUILTIN(__hip_atomic_fetch_or, "v.", "t")
|
||||
ATOMIC_BUILTIN(__hip_atomic_fetch_xor, "v.", "t")
|
||||
|
|
@ -1415,6 +1446,10 @@ LIBBUILTIN(round, "dd", "fnc", MATH_H, ALL_LANGUAGES)
|
|||
LIBBUILTIN(roundf, "ff", "fnc", MATH_H, ALL_LANGUAGES)
|
||||
LIBBUILTIN(roundl, "LdLd", "fnc", MATH_H, ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(roundeven, "dd", "fnc", MATH_H, ALL_LANGUAGES)
|
||||
LIBBUILTIN(roundevenf, "ff", "fnc", MATH_H, ALL_LANGUAGES)
|
||||
LIBBUILTIN(roundevenl, "LdLd", "fnc", MATH_H, ALL_LANGUAGES)
|
||||
|
||||
LIBBUILTIN(scalbln, "ddLi", "fne", MATH_H, ALL_LANGUAGES)
|
||||
LIBBUILTIN(scalblnf, "ffLi", "fne", MATH_H, ALL_LANGUAGES)
|
||||
LIBBUILTIN(scalblnl, "LdLdLi", "fne", MATH_H, ALL_LANGUAGES)
|
||||
|
|
@ -1565,6 +1600,7 @@ LIBBUILTIN(addressof, "v*v&", "zfncThE", MEMORY, CXX_LANG)
|
|||
LANGBUILTIN(__addressof, "v*v&", "zfncTE", CXX_LANG)
|
||||
LIBBUILTIN(as_const, "v&v&", "zfncThE", UTILITY, CXX_LANG)
|
||||
LIBBUILTIN(forward, "v&v&", "zfncThE", UTILITY, CXX_LANG)
|
||||
LIBBUILTIN(forward_like, "v&v&", "zfncThE", UTILITY, CXX_LANG)
|
||||
LIBBUILTIN(move, "v&v&", "zfncThE", UTILITY, CXX_LANG)
|
||||
LIBBUILTIN(move_if_noexcept, "v&v&", "zfncThE", UTILITY, CXX_LANG)
|
||||
|
||||
|
|
@ -1573,6 +1609,7 @@ BUILTIN(__builtin_annotation, "v.", "tn")
|
|||
|
||||
// Invariants
|
||||
BUILTIN(__builtin_assume, "vb", "nE")
|
||||
BUILTIN(__builtin_assume_separate_storage, "vvCD*vCD*", "nE")
|
||||
|
||||
// Multiprecision Arithmetic Builtins.
|
||||
BUILTIN(__builtin_addcb, "UcUcCUcCUcCUc*", "n")
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ BUILTIN(__builtin_arm_rbit, "UiUi", "nc")
|
|||
BUILTIN(__builtin_arm_rbit64, "WUiWUi", "nc")
|
||||
BUILTIN(__builtin_arm_cls, "UiZUi", "nc")
|
||||
BUILTIN(__builtin_arm_cls64, "UiWUi", "nc")
|
||||
BUILTIN(__builtin_arm_clz, "UiZUi", "nc")
|
||||
BUILTIN(__builtin_arm_clz64, "UiWUi", "nc")
|
||||
|
||||
// HINT
|
||||
BUILTIN(__builtin_arm_nop, "v", "")
|
||||
|
|
@ -257,16 +259,18 @@ TARGET_HEADER_BUILTIN(__umulh, "ULLiULLiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES,
|
|||
|
||||
TARGET_HEADER_BUILTIN(__break, "vi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
|
||||
TARGET_HEADER_BUILTIN(__writex18byte, "vULiUc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__writex18word, "vULiUs", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__writex18dword, "vULiULi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__writex18qword, "vULiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
|
||||
TARGET_HEADER_BUILTIN(__readx18byte, "UcULi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readx18word, "UsULi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readx18dword, "ULiULi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readx18qword, "ULLiULi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__writex18byte, "vUNiUc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__writex18word, "vUNiUs", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__writex18dword, "vUNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__writex18qword, "vUNiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
|
||||
TARGET_HEADER_BUILTIN(__readx18byte, "UcUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readx18word, "UsUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readx18dword, "UNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readx18qword, "ULLiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef LANGBUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
#undef TARGET_HEADER_BUILTIN
|
||||
|
|
|
|||
|
|
@ -100,6 +100,8 @@ BUILTIN(__builtin_amdgcn_rsq_clamp, "dd", "nc")
|
|||
BUILTIN(__builtin_amdgcn_rsq_clampf, "ff", "nc")
|
||||
BUILTIN(__builtin_amdgcn_sinf, "ff", "nc")
|
||||
BUILTIN(__builtin_amdgcn_cosf, "ff", "nc")
|
||||
BUILTIN(__builtin_amdgcn_logf, "ff", "nc")
|
||||
BUILTIN(__builtin_amdgcn_exp2f, "ff", "nc")
|
||||
BUILTIN(__builtin_amdgcn_log_clampf, "ff", "nc")
|
||||
BUILTIN(__builtin_amdgcn_ldexp, "ddi", "nc")
|
||||
BUILTIN(__builtin_amdgcn_ldexpf, "ffi", "nc")
|
||||
|
|
@ -214,8 +216,8 @@ TARGET_BUILTIN(__builtin_amdgcn_perm, "UiUiUiUi", "nc", "gfx8-insts")
|
|||
TARGET_BUILTIN(__builtin_amdgcn_fmed3h, "hhhh", "nc", "gfx9-insts")
|
||||
|
||||
TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_f64, "dd*1d", "t", "gfx90a-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_f32, "ff*1f", "t", "gfx90a-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_v2f16, "V2hV2h*1V2h", "t", "gfx90a-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_f32, "ff*1f", "t", "atomic-fadd-rtn-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_v2f16, "V2hV2h*1V2h", "t", "atomic-buffer-global-pk-add-f16-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fmin_f64, "dd*1d", "t", "gfx90a-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fmax_f64, "dd*1d", "t", "gfx90a-insts")
|
||||
|
||||
|
|
@ -227,16 +229,17 @@ TARGET_BUILTIN(__builtin_amdgcn_ds_atomic_fadd_f64, "dd*3d", "t", "gfx90a-insts"
|
|||
TARGET_BUILTIN(__builtin_amdgcn_ds_atomic_fadd_f32, "ff*3f", "t", "gfx8-insts")
|
||||
|
||||
TARGET_BUILTIN(__builtin_amdgcn_flat_atomic_fadd_f32, "ff*0f", "t", "gfx940-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_flat_atomic_fadd_v2f16, "V2hV2h*0V2h", "t", "gfx940-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_flat_atomic_fadd_v2bf16, "V2sV2s*0V2s", "t", "gfx940-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_v2bf16, "V2sV2s*1V2s", "t", "gfx940-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_ds_atomic_fadd_v2bf16, "V2sV2s*3V2s", "t", "gfx940-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_flat_atomic_fadd_v2f16, "V2hV2h*0V2h", "t", "atomic-flat-pk-add-16-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_flat_atomic_fadd_v2bf16, "V2sV2s*0V2s", "t", "atomic-flat-pk-add-16-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_global_atomic_fadd_v2bf16, "V2sV2s*1V2s", "t", "atomic-global-pk-add-bf16-inst")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_ds_atomic_fadd_v2bf16, "V2sV2s*3V2s", "t", "atomic-ds-pk-add-16-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_ds_atomic_fadd_v2f16, "V2hV2h*3V2h", "t", "atomic-ds-pk-add-16-insts")
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Deep learning builtins.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
TARGET_BUILTIN(__builtin_amdgcn_fdot2, "fV2hV2hfIb", "nc", "dot7-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_fdot2, "fV2hV2hfIb", "nc", "dot10-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_fdot2_f16_f16, "hV2hV2hh", "nc", "dot9-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_fdot2_bf16_bf16, "sV2sV2ss", "nc", "dot9-insts")
|
||||
TARGET_BUILTIN(__builtin_amdgcn_fdot2_f32_bf16, "fV2sV2sfIb", "nc", "dot9-insts")
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ BUILTIN(__builtin_arm_smusdx, "iii", "nc")
|
|||
|
||||
// Bit manipulation
|
||||
BUILTIN(__builtin_arm_rbit, "UiUi", "nc")
|
||||
BUILTIN(__builtin_arm_clz, "UiZUi", "nc")
|
||||
BUILTIN(__builtin_arm_clz64, "UiWUi", "nc")
|
||||
BUILTIN(__builtin_arm_cls, "UiZUi", "nc")
|
||||
BUILTIN(__builtin_arm_cls64, "UiWUi", "nc")
|
||||
|
||||
|
|
@ -343,4 +345,5 @@ TARGET_HEADER_BUILTIN(_InterlockedDecrement64_rel, "LLiLLiD*", "nh", INTRIN_H, A
|
|||
|
||||
#undef BUILTIN
|
||||
#undef LANGBUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
#undef TARGET_HEADER_BUILTIN
|
||||
|
|
|
|||
|
|
@ -19,3 +19,4 @@
|
|||
#undef GET_NEON_BUILTINS
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
|
|
|
|||
|
|
@ -54,7 +54,11 @@
|
|||
#pragma push_macro("PTX76")
|
||||
#pragma push_macro("PTX77")
|
||||
#pragma push_macro("PTX78")
|
||||
#define PTX78 "ptx78"
|
||||
#pragma push_macro("PTX80")
|
||||
#pragma push_macro("PTX81")
|
||||
#define PTX81 "ptx81"
|
||||
#define PTX80 "ptx80|" PTX81
|
||||
#define PTX78 "ptx78|" PTX80
|
||||
#define PTX77 "ptx77|" PTX78
|
||||
#define PTX76 "ptx76|" PTX77
|
||||
#define PTX75 "ptx75|" PTX76
|
||||
|
|
@ -95,6 +99,31 @@ BUILTIN(__nvvm_read_ptx_sreg_nctaid_y, "i", "nc")
|
|||
BUILTIN(__nvvm_read_ptx_sreg_nctaid_z, "i", "nc")
|
||||
BUILTIN(__nvvm_read_ptx_sreg_nctaid_w, "i", "nc")
|
||||
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_clusterid_x, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_clusterid_y, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_clusterid_z, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_clusterid_w, "i", "nc", AND(SM_90, PTX78))
|
||||
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_nclusterid_x, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_nclusterid_y, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_nclusterid_z, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_nclusterid_w, "i", "nc", AND(SM_90, PTX78))
|
||||
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_cluster_ctaid_x, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_cluster_ctaid_y, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_cluster_ctaid_z, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_cluster_ctaid_w, "i", "nc", AND(SM_90, PTX78))
|
||||
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_cluster_nctaid_x, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_cluster_nctaid_y, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_cluster_nctaid_z, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_cluster_nctaid_w, "i", "nc", AND(SM_90, PTX78))
|
||||
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_cluster_ctarank, "i", "nc", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_read_ptx_sreg_cluster_nctarank, "i", "nc", AND(SM_90, PTX78))
|
||||
|
||||
TARGET_BUILTIN(__nvvm_is_explicit_cluster, "b", "nc", AND(SM_90, PTX78))
|
||||
|
||||
BUILTIN(__nvvm_read_ptx_sreg_laneid, "i", "nc")
|
||||
BUILTIN(__nvvm_read_ptx_sreg_warpid, "i", "nc")
|
||||
BUILTIN(__nvvm_read_ptx_sreg_nwarpid, "i", "nc")
|
||||
|
|
@ -144,16 +173,20 @@ TARGET_BUILTIN(__nvvm_fmin_nan_xorsign_abs_f16x2, "V2hV2hV2h", "",
|
|||
AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmin_ftz_nan_xorsign_abs_f16x2, "V2hV2hV2h", "",
|
||||
AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmin_bf16, "UsUsUs", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_nan_bf16, "UsUsUs", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_xorsign_abs_bf16, "UsUsUs", "", AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmin_nan_xorsign_abs_bf16, "UsUsUs", "",
|
||||
TARGET_BUILTIN(__nvvm_fmin_bf16, "yyy", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_ftz_bf16, "yyy", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_nan_bf16, "yyy", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_ftz_nan_bf16, "yyy", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_xorsign_abs_bf16, "yyy", "", AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmin_nan_xorsign_abs_bf16, "yyy", "",
|
||||
AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmin_bf16x2, "ZUiZUiZUi", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_nan_bf16x2, "ZUiZUiZUi", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_xorsign_abs_bf16x2, "ZUiZUiZUi", "",
|
||||
TARGET_BUILTIN(__nvvm_fmin_bf16x2, "V2yV2yV2y", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_ftz_bf16x2, "V2yV2yV2y", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_nan_bf16x2, "V2yV2yV2y", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_ftz_nan_bf16x2, "V2yV2yV2y", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmin_xorsign_abs_bf16x2, "V2yV2yV2y", "",
|
||||
AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmin_nan_xorsign_abs_bf16x2, "ZUiZUiZUi", "",
|
||||
TARGET_BUILTIN(__nvvm_fmin_nan_xorsign_abs_bf16x2, "V2yV2yV2y", "",
|
||||
AND(SM_86, PTX72))
|
||||
BUILTIN(__nvvm_fmin_f, "fff", "")
|
||||
BUILTIN(__nvvm_fmin_ftz_f, "fff", "")
|
||||
|
|
@ -186,16 +219,20 @@ TARGET_BUILTIN(__nvvm_fmax_nan_xorsign_abs_f16x2, "V2hV2hV2h", "",
|
|||
AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmax_ftz_nan_xorsign_abs_f16x2, "V2hV2hV2h", "",
|
||||
AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmax_bf16, "UsUsUs", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_nan_bf16, "UsUsUs", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_xorsign_abs_bf16, "UsUsUs", "", AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmax_nan_xorsign_abs_bf16, "UsUsUs", "",
|
||||
TARGET_BUILTIN(__nvvm_fmax_bf16, "yyy", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_ftz_bf16, "yyy", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_nan_bf16, "yyy", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_ftz_nan_bf16, "yyy", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_xorsign_abs_bf16, "yyy", "", AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmax_nan_xorsign_abs_bf16, "yyy", "",
|
||||
AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmax_bf16x2, "ZUiZUiZUi", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_nan_bf16x2, "ZUiZUiZUi", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_xorsign_abs_bf16x2, "ZUiZUiZUi", "",
|
||||
TARGET_BUILTIN(__nvvm_fmax_bf16x2, "V2yV2yV2y", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_ftz_bf16x2, "V2yV2yV2y", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_nan_bf16x2, "V2yV2yV2y", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_ftz_nan_bf16x2, "V2yV2yV2y", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fmax_xorsign_abs_bf16x2, "V2yV2yV2y", "",
|
||||
AND(SM_86, PTX72))
|
||||
TARGET_BUILTIN(__nvvm_fmax_nan_xorsign_abs_bf16x2, "ZUiZUiZUi", "",
|
||||
TARGET_BUILTIN(__nvvm_fmax_nan_xorsign_abs_bf16x2, "V2yV2yV2y", "",
|
||||
AND(SM_86, PTX72))
|
||||
BUILTIN(__nvvm_fmax_f, "fff", "")
|
||||
BUILTIN(__nvvm_fmax_ftz_f, "fff", "")
|
||||
|
|
@ -323,10 +360,10 @@ TARGET_BUILTIN(__nvvm_fma_rn_sat_f16x2, "V2hV2hV2hV2h", "", AND(SM_53, PTX42))
|
|||
TARGET_BUILTIN(__nvvm_fma_rn_ftz_sat_f16x2, "V2hV2hV2hV2h", "", AND(SM_53, PTX42))
|
||||
TARGET_BUILTIN(__nvvm_fma_rn_relu_f16x2, "V2hV2hV2hV2h", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fma_rn_ftz_relu_f16x2, "V2hV2hV2hV2h", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fma_rn_bf16, "UsUsUsUs", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fma_rn_relu_bf16, "UsUsUsUs", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fma_rn_bf16x2, "ZUiZUiZUiZUi", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fma_rn_relu_bf16x2, "ZUiZUiZUiZUi", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fma_rn_bf16, "yyyy", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fma_rn_relu_bf16, "yyyy", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fma_rn_bf16x2, "V2yV2yV2yV2y", "", AND(SM_80, PTX70))
|
||||
TARGET_BUILTIN(__nvvm_fma_rn_relu_bf16x2, "V2yV2yV2yV2y", "", AND(SM_80, PTX70))
|
||||
BUILTIN(__nvvm_fma_rn_ftz_f, "ffff", "")
|
||||
BUILTIN(__nvvm_fma_rn_f, "ffff", "")
|
||||
BUILTIN(__nvvm_fma_rz_ftz_f, "ffff", "")
|
||||
|
|
@ -514,20 +551,20 @@ BUILTIN(__nvvm_ull2d_rp, "dULLi", "")
|
|||
BUILTIN(__nvvm_f2h_rn_ftz, "Usf", "")
|
||||
BUILTIN(__nvvm_f2h_rn, "Usf", "")
|
||||
|
||||
TARGET_BUILTIN(__nvvm_ff2bf16x2_rn, "ZUiff", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_ff2bf16x2_rn_relu, "ZUiff", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_ff2bf16x2_rz, "ZUiff", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_ff2bf16x2_rz_relu, "ZUiff", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_ff2bf16x2_rn, "V2yff", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_ff2bf16x2_rn_relu, "V2yff", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_ff2bf16x2_rz, "V2yff", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_ff2bf16x2_rz_relu, "V2yff", "", AND(SM_80,PTX70))
|
||||
|
||||
TARGET_BUILTIN(__nvvm_ff2f16x2_rn, "V2hff", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_ff2f16x2_rn_relu, "V2hff", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_ff2f16x2_rz, "V2hff", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_ff2f16x2_rz_relu, "V2hff", "", AND(SM_80,PTX70))
|
||||
|
||||
TARGET_BUILTIN(__nvvm_f2bf16_rn, "ZUsf", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_f2bf16_rn_relu, "ZUsf", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_f2bf16_rz, "ZUsf", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_f2bf16_rz_relu, "ZUsf", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_f2bf16_rn, "yf", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_f2bf16_rn_relu, "yf", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_f2bf16_rz, "yf", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_f2bf16_rz_relu, "yf", "", AND(SM_80,PTX70))
|
||||
|
||||
TARGET_BUILTIN(__nvvm_f2tf32_rna, "ZUif", "", AND(SM_80,PTX70))
|
||||
|
||||
|
|
@ -553,6 +590,11 @@ TARGET_BUILTIN(__nvvm_bar_warp_sync, "vUi", "n", PTX60)
|
|||
TARGET_BUILTIN(__nvvm_barrier_sync, "vUi", "n", PTX60)
|
||||
TARGET_BUILTIN(__nvvm_barrier_sync_cnt, "vUiUi", "n", PTX60)
|
||||
|
||||
TARGET_BUILTIN(__nvvm_barrier_cluster_arrive, "v", "n", AND(SM_90,PTX78))
|
||||
TARGET_BUILTIN(__nvvm_barrier_cluster_arrive_relaxed, "v", "n", AND(SM_90,PTX80))
|
||||
TARGET_BUILTIN(__nvvm_barrier_cluster_wait, "v", "n", AND(SM_90,PTX78))
|
||||
TARGET_BUILTIN(__nvvm_fence_sc_cluster, "v", "n", AND(SM_90,PTX78))
|
||||
|
||||
// Shuffle
|
||||
|
||||
BUILTIN(__nvvm_shfl_down_i32, "iiii", "")
|
||||
|
|
@ -782,8 +824,50 @@ TARGET_BUILTIN(__nvvm_atom_sys_cas_gen_ll, "LLiLLiD*LLiLLi", "n", SM_60)
|
|||
BUILTIN(__nvvm_compiler_error, "vcC*4", "n")
|
||||
BUILTIN(__nvvm_compiler_warn, "vcC*4", "n")
|
||||
|
||||
// __ldg. This is not implemented as a builtin by nvcc.
|
||||
BUILTIN(__nvvm_ldu_c, "ccC*", "")
|
||||
BUILTIN(__nvvm_ldu_sc, "ScScC*", "")
|
||||
BUILTIN(__nvvm_ldu_s, "ssC*", "")
|
||||
BUILTIN(__nvvm_ldu_i, "iiC*", "")
|
||||
BUILTIN(__nvvm_ldu_l, "LiLiC*", "")
|
||||
BUILTIN(__nvvm_ldu_ll, "LLiLLiC*", "")
|
||||
|
||||
BUILTIN(__nvvm_ldu_uc, "UcUcC*", "")
|
||||
BUILTIN(__nvvm_ldu_us, "UsUsC*", "")
|
||||
BUILTIN(__nvvm_ldu_ui, "UiUiC*", "")
|
||||
BUILTIN(__nvvm_ldu_ul, "ULiULiC*", "")
|
||||
BUILTIN(__nvvm_ldu_ull, "ULLiULLiC*", "")
|
||||
|
||||
BUILTIN(__nvvm_ldu_h, "hhC*", "")
|
||||
BUILTIN(__nvvm_ldu_f, "ffC*", "")
|
||||
BUILTIN(__nvvm_ldu_d, "ddC*", "")
|
||||
|
||||
BUILTIN(__nvvm_ldu_c2, "E2cE2cC*", "")
|
||||
BUILTIN(__nvvm_ldu_sc2, "E2ScE2ScC*", "")
|
||||
BUILTIN(__nvvm_ldu_c4, "E4cE4cC*", "")
|
||||
BUILTIN(__nvvm_ldu_sc4, "E4ScE4ScC*", "")
|
||||
BUILTIN(__nvvm_ldu_s2, "E2sE2sC*", "")
|
||||
BUILTIN(__nvvm_ldu_s4, "E4sE4sC*", "")
|
||||
BUILTIN(__nvvm_ldu_i2, "E2iE2iC*", "")
|
||||
BUILTIN(__nvvm_ldu_i4, "E4iE4iC*", "")
|
||||
BUILTIN(__nvvm_ldu_l2, "E2LiE2LiC*", "")
|
||||
BUILTIN(__nvvm_ldu_ll2, "E2LLiE2LLiC*", "")
|
||||
|
||||
BUILTIN(__nvvm_ldu_uc2, "E2UcE2UcC*", "")
|
||||
BUILTIN(__nvvm_ldu_uc4, "E4UcE4UcC*", "")
|
||||
BUILTIN(__nvvm_ldu_us2, "E2UsE2UsC*", "")
|
||||
BUILTIN(__nvvm_ldu_us4, "E4UsE4UsC*", "")
|
||||
BUILTIN(__nvvm_ldu_ui2, "E2UiE2UiC*", "")
|
||||
BUILTIN(__nvvm_ldu_ui4, "E4UiE4UiC*", "")
|
||||
BUILTIN(__nvvm_ldu_ul2, "E2ULiE2ULiC*", "")
|
||||
BUILTIN(__nvvm_ldu_ull2, "E2ULLiE2ULLiC*", "")
|
||||
|
||||
BUILTIN(__nvvm_ldu_h2, "E2hE2hC*", "")
|
||||
BUILTIN(__nvvm_ldu_f2, "E2fE2fC*", "")
|
||||
BUILTIN(__nvvm_ldu_f4, "E4fE4fC*", "")
|
||||
BUILTIN(__nvvm_ldu_d2, "E2dE2dC*", "")
|
||||
|
||||
BUILTIN(__nvvm_ldg_c, "ccC*", "")
|
||||
BUILTIN(__nvvm_ldg_sc, "ScScC*", "")
|
||||
BUILTIN(__nvvm_ldg_s, "ssC*", "")
|
||||
BUILTIN(__nvvm_ldg_i, "iiC*", "")
|
||||
BUILTIN(__nvvm_ldg_l, "LiLiC*", "")
|
||||
|
|
@ -795,15 +879,19 @@ BUILTIN(__nvvm_ldg_ui, "UiUiC*", "")
|
|||
BUILTIN(__nvvm_ldg_ul, "ULiULiC*", "")
|
||||
BUILTIN(__nvvm_ldg_ull, "ULLiULLiC*", "")
|
||||
|
||||
BUILTIN(__nvvm_ldg_h, "hhC*", "")
|
||||
BUILTIN(__nvvm_ldg_f, "ffC*", "")
|
||||
BUILTIN(__nvvm_ldg_d, "ddC*", "")
|
||||
|
||||
BUILTIN(__nvvm_ldg_c2, "E2cE2cC*", "")
|
||||
BUILTIN(__nvvm_ldg_sc2, "E2ScE2ScC*", "")
|
||||
BUILTIN(__nvvm_ldg_c4, "E4cE4cC*", "")
|
||||
BUILTIN(__nvvm_ldg_sc4, "E4ScE4ScC*", "")
|
||||
BUILTIN(__nvvm_ldg_s2, "E2sE2sC*", "")
|
||||
BUILTIN(__nvvm_ldg_s4, "E4sE4sC*", "")
|
||||
BUILTIN(__nvvm_ldg_i2, "E2iE2iC*", "")
|
||||
BUILTIN(__nvvm_ldg_i4, "E4iE4iC*", "")
|
||||
BUILTIN(__nvvm_ldg_l2, "E2LiE2LiC*", "")
|
||||
BUILTIN(__nvvm_ldg_ll2, "E2LLiE2LLiC*", "")
|
||||
|
||||
BUILTIN(__nvvm_ldg_uc2, "E2UcE2UcC*", "")
|
||||
|
|
@ -812,8 +900,10 @@ BUILTIN(__nvvm_ldg_us2, "E2UsE2UsC*", "")
|
|||
BUILTIN(__nvvm_ldg_us4, "E4UsE4UsC*", "")
|
||||
BUILTIN(__nvvm_ldg_ui2, "E2UiE2UiC*", "")
|
||||
BUILTIN(__nvvm_ldg_ui4, "E4UiE4UiC*", "")
|
||||
BUILTIN(__nvvm_ldg_ul2, "E2ULiE2ULiC*", "")
|
||||
BUILTIN(__nvvm_ldg_ull2, "E2ULLiE2ULLiC*", "")
|
||||
|
||||
BUILTIN(__nvvm_ldg_h2, "E2hE2hC*", "")
|
||||
BUILTIN(__nvvm_ldg_f2, "E2fE2fC*", "")
|
||||
BUILTIN(__nvvm_ldg_f4, "E4fE4fC*", "")
|
||||
BUILTIN(__nvvm_ldg_d2, "E2dE2dC*", "")
|
||||
|
|
@ -823,6 +913,7 @@ BUILTIN(__nvvm_isspacep_const, "bvC*", "nc")
|
|||
BUILTIN(__nvvm_isspacep_global, "bvC*", "nc")
|
||||
BUILTIN(__nvvm_isspacep_local, "bvC*", "nc")
|
||||
BUILTIN(__nvvm_isspacep_shared, "bvC*", "nc")
|
||||
TARGET_BUILTIN(__nvvm_isspacep_shared_cluster,"bvC*", "nc", AND(SM_90,PTX78))
|
||||
|
||||
// Builtins to support WMMA instructions on sm_70
|
||||
TARGET_BUILTIN(__hmma_m16n16k16_ld_a, "vi*iC*UiIi", "", AND(SM_70,PTX60))
|
||||
|
|
@ -930,10 +1021,10 @@ TARGET_BUILTIN(__nvvm_cp_async_mbarrier_arrive_shared, "vWi*3", "", AND(SM_80,PT
|
|||
TARGET_BUILTIN(__nvvm_cp_async_mbarrier_arrive_noinc, "vWi*", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_cp_async_mbarrier_arrive_noinc_shared, "vWi*3", "", AND(SM_80,PTX70))
|
||||
|
||||
TARGET_BUILTIN(__nvvm_cp_async_ca_shared_global_4, "vv*3vC*1", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_cp_async_ca_shared_global_8, "vv*3vC*1", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_cp_async_ca_shared_global_16, "vv*3vC*1", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_cp_async_cg_shared_global_16, "vv*3vC*1", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_cp_async_ca_shared_global_4, "vv*3vC*1.", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_cp_async_ca_shared_global_8, "vv*3vC*1.", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_cp_async_ca_shared_global_16, "vv*3vC*1.", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_cp_async_cg_shared_global_16, "vv*3vC*1.", "", AND(SM_80,PTX70))
|
||||
|
||||
TARGET_BUILTIN(__nvvm_cp_async_commit_group, "v", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_cp_async_wait_group, "vIi", "", AND(SM_80,PTX70))
|
||||
|
|
@ -941,10 +1032,15 @@ TARGET_BUILTIN(__nvvm_cp_async_wait_all, "v", "", AND(SM_80,PTX70))
|
|||
|
||||
|
||||
// bf16, bf16x2 abs, neg
|
||||
TARGET_BUILTIN(__nvvm_abs_bf16, "UsUs", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_abs_bf16x2, "ZUiZUi", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_neg_bf16, "UsUs", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_neg_bf16x2, "ZUiZUi", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_abs_bf16, "yy", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_abs_bf16x2, "V2yV2y", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_neg_bf16, "yy", "", AND(SM_80,PTX70))
|
||||
TARGET_BUILTIN(__nvvm_neg_bf16x2, "V2yV2y", "", AND(SM_80,PTX70))
|
||||
|
||||
TARGET_BUILTIN(__nvvm_mapa, "v*v*i", "", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_mapa_shared_cluster, "v*3v*3i", "", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_getctarank, "iv*", "", AND(SM_90, PTX78))
|
||||
TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78))
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
|
|
@ -974,3 +1070,5 @@ TARGET_BUILTIN(__nvvm_neg_bf16x2, "ZUiZUi", "", AND(SM_80,PTX70))
|
|||
#pragma pop_macro("PTX76")
|
||||
#pragma pop_macro("PTX77")
|
||||
#pragma pop_macro("PTX78")
|
||||
#pragma pop_macro("PTX80")
|
||||
#pragma pop_macro("PTX81")
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -16,68 +16,78 @@
|
|||
#endif
|
||||
|
||||
// Zbb extension
|
||||
TARGET_BUILTIN(__builtin_riscv_orc_b_32, "ZiZi", "nc", "zbb")
|
||||
TARGET_BUILTIN(__builtin_riscv_orc_b_64, "WiWi", "nc", "zbb,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_clz_32, "ZiZi", "nc", "zbb")
|
||||
TARGET_BUILTIN(__builtin_riscv_clz_64, "WiWi", "nc", "zbb,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_ctz_32, "ZiZi", "nc", "zbb")
|
||||
TARGET_BUILTIN(__builtin_riscv_ctz_64, "WiWi", "nc", "zbb,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_orc_b_32, "UiUi", "nc", "zbb")
|
||||
TARGET_BUILTIN(__builtin_riscv_orc_b_64, "UWiUWi", "nc", "zbb,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_clz_32, "UiUi", "nc", "zbb|xtheadbb")
|
||||
TARGET_BUILTIN(__builtin_riscv_clz_64, "UiUWi", "nc", "zbb|xtheadbb,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_ctz_32, "UiUi", "nc", "zbb")
|
||||
TARGET_BUILTIN(__builtin_riscv_ctz_64, "UiUWi", "nc", "zbb,64bit")
|
||||
|
||||
// Zbc or Zbkc extension
|
||||
TARGET_BUILTIN(__builtin_riscv_clmul, "LiLiLi", "nc", "zbc|zbkc")
|
||||
TARGET_BUILTIN(__builtin_riscv_clmulh, "LiLiLi", "nc", "zbc|zbkc")
|
||||
TARGET_BUILTIN(__builtin_riscv_clmulr, "LiLiLi", "nc", "zbc")
|
||||
TARGET_BUILTIN(__builtin_riscv_clmul_32, "UiUiUi", "nc", "zbc|zbkc")
|
||||
TARGET_BUILTIN(__builtin_riscv_clmul_64, "UWiUWiUWi", "nc", "zbc|zbkc,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_clmulh_32, "UiUiUi", "nc", "zbc|zbkc,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_clmulh_64, "UWiUWiUWi", "nc", "zbc|zbkc,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_clmulr_32, "UiUiUi", "nc", "zbc,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_clmulr_64, "UWiUWiUWi", "nc", "zbc,64bit")
|
||||
|
||||
// Zbkx
|
||||
TARGET_BUILTIN(__builtin_riscv_xperm4, "LiLiLi", "nc", "zbkx")
|
||||
TARGET_BUILTIN(__builtin_riscv_xperm8, "LiLiLi", "nc", "zbkx")
|
||||
TARGET_BUILTIN(__builtin_riscv_xperm4_32, "UiUiUi", "nc", "zbkx,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_xperm4_64, "UWiUWiUWi", "nc", "zbkx,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_xperm8_32, "UiUiUi", "nc", "zbkx,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_xperm8_64, "UWiUWiUWi", "nc", "zbkx,64bit")
|
||||
|
||||
// Zbkb extension
|
||||
TARGET_BUILTIN(__builtin_riscv_brev8, "LiLi", "nc", "zbkb")
|
||||
TARGET_BUILTIN(__builtin_riscv_zip_32, "ZiZi", "nc", "zbkb,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_unzip_32, "ZiZi", "nc", "zbkb,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_brev8_32, "UiUi", "nc", "zbkb")
|
||||
TARGET_BUILTIN(__builtin_riscv_brev8_64, "UWiUWi", "nc", "zbkb,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_zip_32, "UiUi", "nc", "zbkb,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_unzip_32, "UiUi", "nc", "zbkb,32bit")
|
||||
|
||||
// Zknd extension
|
||||
TARGET_BUILTIN(__builtin_riscv_aes32dsi_32, "ZiZiZiIUc", "nc", "zknd,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes32dsmi_32, "ZiZiZiIUc", "nc", "zknd,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64ds_64, "WiWiWi", "nc", "zknd,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64dsm_64, "WiWiWi", "nc", "zknd,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64im_64, "WiWi", "nc", "zknd,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes32dsi, "UiUiUiIUi", "nc", "zknd,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes32dsmi, "UiUiUiIUi", "nc", "zknd,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64ds, "UWiUWiUWi", "nc", "zknd,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64dsm, "UWiUWiUWi", "nc", "zknd,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64im, "UWiUWi", "nc", "zknd,64bit")
|
||||
|
||||
// Zknd & zkne
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64ks1i_64, "WiWiIUi", "nc", "zknd|zkne,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64ks2_64, "WiWiWi", "nc", "zknd|zkne,64bit")
|
||||
// Zknd & Zkne
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64ks1i, "UWiUWiIUi", "nc", "zknd|zkne,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64ks2, "UWiUWiUWi", "nc", "zknd|zkne,64bit")
|
||||
|
||||
// Zkne extension
|
||||
TARGET_BUILTIN(__builtin_riscv_aes32esi_32, "ZiZiZiIUc", "nc", "zkne,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes32esmi_32, "ZiZiZiIUc", "nc", "zkne,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64es_64, "WiWiWi", "nc", "zkne,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64esm_64, "WiWiWi", "nc", "zkne,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes32esi, "UiUiUiIUi", "nc", "zkne,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes32esmi, "UiUiUiIUi", "nc", "zkne,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64es, "UWiUWiUWi", "nc", "zkne,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_aes64esm, "UWiUWiUWi", "nc", "zkne,64bit")
|
||||
|
||||
// Zknh extension
|
||||
TARGET_BUILTIN(__builtin_riscv_sha256sig0, "LiLi", "nc", "zknh")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha256sig1, "LiLi", "nc", "zknh")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha256sum0, "LiLi", "nc", "zknh")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha256sum1, "LiLi", "nc", "zknh")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha256sig0, "UiUi", "nc", "zknh")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha256sig1, "UiUi", "nc", "zknh")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha256sum0, "UiUi", "nc", "zknh")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha256sum1, "UiUi", "nc", "zknh")
|
||||
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig0h_32, "ZiZiZi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig0l_32, "ZiZiZi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig1h_32, "ZiZiZi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig1l_32, "ZiZiZi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sum0r_32, "ZiZiZi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sum1r_32, "ZiZiZi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig0_64, "WiWi", "nc", "zknh,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig1_64, "WiWi", "nc", "zknh,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sum0_64, "WiWi", "nc", "zknh,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sum1_64, "WiWi", "nc", "zknh,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig0h, "UiUiUi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig0l, "UiUiUi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig1h, "UiUiUi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig1l, "UiUiUi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sum0r, "UiUiUi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sum1r, "UiUiUi", "nc", "zknh,32bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig0, "UWiUWi", "nc", "zknh,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sig1, "UWiUWi", "nc", "zknh,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sum0, "UWiUWi", "nc", "zknh,64bit")
|
||||
TARGET_BUILTIN(__builtin_riscv_sha512sum1, "UWiUWi", "nc", "zknh,64bit")
|
||||
|
||||
// Zksed extension
|
||||
TARGET_BUILTIN(__builtin_riscv_sm4ed, "LiLiLiIUc", "nc", "zksed")
|
||||
TARGET_BUILTIN(__builtin_riscv_sm4ks, "LiLiLiIUc", "nc", "zksed")
|
||||
TARGET_BUILTIN(__builtin_riscv_sm4ed, "UiUiUiIUi", "nc", "zksed")
|
||||
TARGET_BUILTIN(__builtin_riscv_sm4ks, "UiUiUiIUi", "nc", "zksed")
|
||||
|
||||
// Zksh extension
|
||||
TARGET_BUILTIN(__builtin_riscv_sm3p0, "LiLi", "nc", "zksh")
|
||||
TARGET_BUILTIN(__builtin_riscv_sm3p1, "LiLi", "nc", "zksh")
|
||||
TARGET_BUILTIN(__builtin_riscv_sm3p0, "UiUi", "nc", "zksh")
|
||||
TARGET_BUILTIN(__builtin_riscv_sm3p1, "UiUi", "nc", "zksh")
|
||||
|
||||
// Zihintntl extension
|
||||
TARGET_BUILTIN(__builtin_riscv_ntl_load, "v.", "t", "experimental-zihintntl")
|
||||
TARGET_BUILTIN(__builtin_riscv_ntl_store, "v.", "t", "experimental-zihintntl")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#endif
|
||||
|
||||
#include "clang/Basic/riscv_vector_builtins.inc"
|
||||
#include "clang/Basic/riscv_sifive_vector_builtins.inc"
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
//===--- BuiltinsSME.def - SME Builtin function database --------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the SME-specific builtin function database. Users of
|
||||
// this file must define the BUILTIN macro to make use of this information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// The format of this database matches clang/Basic/Builtins.def.
|
||||
|
||||
#define GET_SME_BUILTINS
|
||||
#include "clang/Basic/arm_sme_builtins.inc"
|
||||
#undef GET_SME_BUILTINS
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
|
|
@ -161,7 +161,7 @@ TARGET_BUILTIN(__builtin_wasm_narrow_u_i16x8_i32x4, "V8UsV4iV4i", "nc", "simd128
|
|||
TARGET_BUILTIN(__builtin_wasm_trunc_sat_s_zero_f64x2_i32x4, "V4iV2d", "nc", "simd128")
|
||||
TARGET_BUILTIN(__builtin_wasm_trunc_sat_u_zero_f64x2_i32x4, "V4UiV2d", "nc", "simd128")
|
||||
|
||||
// Relaxed SIMD builtins (experimental)
|
||||
// Relaxed SIMD builtins
|
||||
TARGET_BUILTIN(__builtin_wasm_relaxed_madd_f32x4, "V4fV4fV4fV4f", "nc", "relaxed-simd")
|
||||
TARGET_BUILTIN(__builtin_wasm_relaxed_nmadd_f32x4, "V4fV4fV4fV4f", "nc", "relaxed-simd")
|
||||
TARGET_BUILTIN(__builtin_wasm_relaxed_madd_f64x2, "V2dV2dV2dV2d", "nc", "relaxed-simd")
|
||||
|
|
@ -190,5 +190,24 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_dot_i8x16_i7x16_s_i16x8, "V8sV16ScV16Sc",
|
|||
TARGET_BUILTIN(__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4, "V4iV16ScV16ScV4i", "nc", "relaxed-simd")
|
||||
TARGET_BUILTIN(__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4, "V4fV8UsV8UsV4f", "nc", "relaxed-simd")
|
||||
|
||||
// Reference Types builtins
|
||||
// Some builtins are custom type-checked - see 't' as part of the third argument,
|
||||
// in which case the argument spec (second argument) is unused.
|
||||
|
||||
TARGET_BUILTIN(__builtin_wasm_ref_null_extern, "i", "nct", "reference-types")
|
||||
|
||||
// A funcref represented as a function pointer with the funcref attribute
|
||||
// attached to the type, therefore SemaChecking will check for the right
|
||||
// return type.
|
||||
TARGET_BUILTIN(__builtin_wasm_ref_null_func, "i", "nct", "reference-types")
|
||||
|
||||
// Table builtins
|
||||
TARGET_BUILTIN(__builtin_wasm_table_set, "viii", "t", "reference-types")
|
||||
TARGET_BUILTIN(__builtin_wasm_table_get, "iii", "t", "reference-types")
|
||||
TARGET_BUILTIN(__builtin_wasm_table_size, "zi", "nt", "reference-types")
|
||||
TARGET_BUILTIN(__builtin_wasm_table_grow, "iiii", "nt", "reference-types")
|
||||
TARGET_BUILTIN(__builtin_wasm_table_fill, "viiii", "t", "reference-types")
|
||||
TARGET_BUILTIN(__builtin_wasm_table_copy, "viiiii", "t", "reference-types")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
|
|
|
|||
|
|
@ -2116,6 +2116,20 @@ TARGET_HEADER_BUILTIN(__readgsword, "UsUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES,
|
|||
TARGET_HEADER_BUILTIN(__readgsdword, "UNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(__readgsqword, "ULLiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
|
||||
// AVX-VNNI-INT16
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwsud128, "V4iV4iV4iV4i", "nV:128:", "avxvnniint16")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwsud256, "V8iV8iV8iV8i", "nV:256:", "avxvnniint16")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwsuds128, "V4iV4iV4iV4i", "nV:128:", "avxvnniint16")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwsuds256, "V8iV8iV8iV8i", "nV:256:", "avxvnniint16")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwusd128, "V4iV4iV4iV4i", "nV:128:", "avxvnniint16")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwusd256, "V8iV8iV8iV8i", "nV:256:", "avxvnniint16")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwusds128, "V4iV4iV4iV4i", "nV:128:", "avxvnniint16")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwusds256, "V8iV8iV8iV8i", "nV:256:", "avxvnniint16")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwuud128, "V4iV4iV4iV4i", "nV:128:", "avxvnniint16")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwuud256, "V8iV8iV8iV8i", "nV:256:", "avxvnniint16")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwuuds128, "V4iV4iV4iV4i", "nV:128:", "avxvnniint16")
|
||||
TARGET_BUILTIN(__builtin_ia32_vpdpwuuds256, "V8iV8iV8iV8i", "nV:256:", "avxvnniint16")
|
||||
|
||||
// AVX-NE-CONVERT
|
||||
TARGET_BUILTIN(__builtin_ia32_vbcstnebf162ps128, "V4fyC*", "nV:128:", "avxneconvert")
|
||||
TARGET_BUILTIN(__builtin_ia32_vbcstnebf162ps256, "V8fyC*", "nV:256:", "avxneconvert")
|
||||
|
|
@ -2132,6 +2146,11 @@ TARGET_BUILTIN(__builtin_ia32_vcvtneoph2ps256, "V8fV16xC*", "nV:256:", "avxnecon
|
|||
TARGET_BUILTIN(__builtin_ia32_vcvtneps2bf16128, "V8yV4f", "nV:128:", "avx512bf16,avx512vl|avxneconvert")
|
||||
TARGET_BUILTIN(__builtin_ia32_vcvtneps2bf16256, "V8yV8f", "nV:256:", "avx512bf16,avx512vl|avxneconvert")
|
||||
|
||||
// SHA512
|
||||
TARGET_BUILTIN(__builtin_ia32_vsha512msg1, "V4ULLiV4ULLiV2ULLi", "nV:256:", "sha512")
|
||||
TARGET_BUILTIN(__builtin_ia32_vsha512msg2, "V4ULLiV4ULLiV4ULLi", "nV:256:", "sha512")
|
||||
TARGET_BUILTIN(__builtin_ia32_vsha512rnds2, "V4ULLiV4ULLiV4ULLiV2ULLi", "nV:256:", "sha512")
|
||||
|
||||
TARGET_HEADER_BUILTIN(_InterlockedAnd64, "WiWiD*Wi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_InterlockedDecrement64, "WiWiD*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_InterlockedExchange64, "WiWiD*Wi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
|
|
@ -2141,6 +2160,17 @@ TARGET_HEADER_BUILTIN(_InterlockedIncrement64, "WiWiD*", "nh", INTRIN_H, ALL
|
|||
TARGET_HEADER_BUILTIN(_InterlockedOr64, "WiWiD*Wi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
TARGET_HEADER_BUILTIN(_InterlockedXor64, "WiWiD*Wi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
|
||||
|
||||
// SM3
|
||||
TARGET_BUILTIN(__builtin_ia32_vsm3msg1, "V4UiV4UiV4UiV4Ui", "nV:128:", "sm3")
|
||||
TARGET_BUILTIN(__builtin_ia32_vsm3msg2, "V4UiV4UiV4UiV4Ui", "nV:128:", "sm3")
|
||||
TARGET_BUILTIN(__builtin_ia32_vsm3rnds2, "V4UiV4UiV4UiV4UiIUi", "nV:128:", "sm3")
|
||||
|
||||
// SM4
|
||||
TARGET_BUILTIN(__builtin_ia32_vsm4key4128, "V4UiV4UiV4Ui", "nV:128:", "sm4")
|
||||
TARGET_BUILTIN(__builtin_ia32_vsm4key4256, "V8UiV8UiV8Ui", "nV:256:", "sm4")
|
||||
TARGET_BUILTIN(__builtin_ia32_vsm4rnds4128, "V4UiV4UiV4Ui", "nV:128:", "sm4")
|
||||
TARGET_BUILTIN(__builtin_ia32_vsm4rnds4256, "V8UiV8UiV8Ui", "nV:256:", "sm4")
|
||||
|
||||
#undef BUILTIN
|
||||
#undef TARGET_BUILTIN
|
||||
#undef TARGET_HEADER_BUILTIN
|
||||
|
|
|
|||
|
|
@ -117,6 +117,8 @@ TARGET_BUILTIN(__builtin_ia32_tilestored64_internal, "vUsUsv*zV256i", "n", "amx-
|
|||
TARGET_BUILTIN(__builtin_ia32_tilezero_internal, "V256iUsUs", "n", "amx-tile")
|
||||
TARGET_BUILTIN(__builtin_ia32_tdpbf16ps_internal, "V256iUsUsUsV256iV256iV256i", "n", "amx-bf16")
|
||||
TARGET_BUILTIN(__builtin_ia32_tdpfp16ps_internal, "V256iUsUsUsV256iV256iV256i", "n", "amx-fp16")
|
||||
TARGET_BUILTIN(__builtin_ia32_tcmmimfp16ps_internal, "V256iUsUsUsV256iV256iV256i", "n", "amx-complex")
|
||||
TARGET_BUILTIN(__builtin_ia32_tcmmrlfp16ps_internal, "V256iUsUsUsV256iV256iV256i", "n", "amx-complex")
|
||||
// AMX
|
||||
TARGET_BUILTIN(__builtin_ia32_tile_loadconfig, "vvC*", "n", "amx-tile")
|
||||
TARGET_BUILTIN(__builtin_ia32_tile_storeconfig, "vvC*", "n", "amx-tile")
|
||||
|
|
@ -134,6 +136,9 @@ TARGET_BUILTIN(__builtin_ia32_tdpbuud, "vIUcIUcIUc", "n", "amx-int8")
|
|||
TARGET_BUILTIN(__builtin_ia32_tdpbf16ps, "vIUcIUcIUc", "n", "amx-bf16")
|
||||
TARGET_BUILTIN(__builtin_ia32_ptwrite64, "vUOi", "n", "ptwrite")
|
||||
|
||||
TARGET_BUILTIN(__builtin_ia32_tcmmimfp16ps, "vIUcIUcIUc", "n", "amx-complex")
|
||||
TARGET_BUILTIN(__builtin_ia32_tcmmrlfp16ps, "vIUcIUcIUc", "n", "amx-complex")
|
||||
|
||||
TARGET_BUILTIN(__builtin_ia32_prefetchi, "vvC*Ui", "nc", "prefetchi")
|
||||
TARGET_BUILTIN(__builtin_ia32_cmpccxadd32, "Siv*SiSiIi", "n", "cmpccxadd")
|
||||
TARGET_BUILTIN(__builtin_ia32_cmpccxadd64, "SLLiv*SLLiSLLiIi", "n", "cmpccxadd")
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ CODEGENOPT(Dwarf64 , 1, 0) ///< -gdwarf64.
|
|||
CODEGENOPT(Dwarf32 , 1, 1) ///< -gdwarf32.
|
||||
CODEGENOPT(PreserveAsmComments, 1, 1) ///< -dA, -fno-preserve-as-comments.
|
||||
CODEGENOPT(AssumeSaneOperatorNew , 1, 1) ///< implicit __attribute__((malloc)) operator new
|
||||
CODEGENOPT(AssumeUniqueVTables , 1, 1) ///< Assume a class has only one vtable.
|
||||
CODEGENOPT(Autolink , 1, 1) ///< -fno-autolink
|
||||
CODEGENOPT(ObjCAutoRefCountExceptions , 1, 0) ///< Whether ARC should be EH-safe.
|
||||
CODEGENOPT(Backchain , 1, 0) ///< -mbackchain
|
||||
|
|
@ -52,6 +53,7 @@ CODEGENOPT(UniqueBasicBlockSectionNames, 1, 1) ///< Set for -funique-basic-block
|
|||
///< Produce unique section names with
|
||||
///< basic block sections.
|
||||
CODEGENOPT(EnableAIXExtendedAltivecABI, 1, 0) ///< Set for -mabi=vec-extabi. Enables the extended Altivec ABI on AIX.
|
||||
CODEGENOPT(XCOFFReadOnlyPointers, 1, 0) ///< Set for -mxcoff-roptr.
|
||||
ENUM_CODEGENOPT(FramePointer, FramePointerKind, 2, FramePointerKind::None) /// frame-pointer: all,non-leaf,none
|
||||
|
||||
CODEGENOPT(ClearASTBeforeBackend , 1, 0) ///< Free the AST before running backend code generation. Only works with -disable-free.
|
||||
|
|
@ -84,8 +86,6 @@ CODEGENOPT(EmitDeclMetadata , 1, 0) ///< Emit special metadata indicating what
|
|||
///< Only useful when running CodeGen as a
|
||||
///< subroutine.
|
||||
CODEGENOPT(EmitVersionIdentMetadata , 1, 1) ///< Emit compiler version metadata.
|
||||
CODEGENOPT(EmitGcovArcs , 1, 0) ///< Emit coverage data files, aka. GCDA.
|
||||
CODEGENOPT(EmitGcovNotes , 1, 0) ///< Emit coverage "notes" files, aka GCNO.
|
||||
CODEGENOPT(EmitOpenCLArgMetadata , 1, 0) ///< Emit OpenCL kernel arg metadata.
|
||||
CODEGENOPT(EmulatedTLS , 1, 0) ///< Set by default or -f[no-]emulated-tls.
|
||||
/// Embed Bitcode mode (off/all/bitcode/marker).
|
||||
|
|
@ -115,6 +115,9 @@ CODEGENOPT(StackSizeSection , 1, 0) ///< Set when -fstack-size-section is enabl
|
|||
CODEGENOPT(ForceDwarfFrameSection , 1, 0) ///< Set when -fforce-dwarf-frame is
|
||||
///< enabled.
|
||||
|
||||
///< Set when -femit-compact-unwind-non-canonical is enabled.
|
||||
CODEGENOPT(EmitCompactUnwindNonCanonical, 1, 0)
|
||||
|
||||
///< Set when -femit-dwarf-unwind is passed.
|
||||
ENUM_CODEGENOPT(EmitDwarfUnwind, llvm::EmitDwarfUnwindType, 2,
|
||||
llvm::EmitDwarfUnwindType::Default)
|
||||
|
|
@ -128,8 +131,8 @@ CODEGENOPT(XRayAlwaysEmitTypedEvents , 1, 0)
|
|||
///< Set when -fxray-ignore-loops is enabled.
|
||||
CODEGENOPT(XRayIgnoreLoops , 1, 0)
|
||||
|
||||
///< Set with -fno-xray-function-index to omit the index section.
|
||||
CODEGENOPT(XRayOmitFunctionIndex , 1, 0)
|
||||
///< Emit the XRay function index section.
|
||||
CODEGENOPT(XRayFunctionIndex , 1, 1)
|
||||
|
||||
|
||||
///< Set the minimum number of instructions in a function to determine selective
|
||||
|
|
@ -162,10 +165,12 @@ CODEGENOPT(PrepareForThinLTO , 1, 0) ///< Set when -flto=thin is enabled on the
|
|||
///< compile step.
|
||||
CODEGENOPT(LTOUnit, 1, 0) ///< Emit IR to support LTO unit features (CFI, whole
|
||||
///< program vtable opt).
|
||||
CODEGENOPT(FatLTO, 1, 0) ///< Set when -ffat-lto-objects is enabled.
|
||||
CODEGENOPT(EnableSplitLTOUnit, 1, 0) ///< Enable LTO unit splitting to support
|
||||
/// CFI and traditional whole program
|
||||
/// devirtualization that require whole
|
||||
/// program IR support.
|
||||
CODEGENOPT(UnifiedLTO, 1, 0) ///< Use the unified LTO pipeline.
|
||||
CODEGENOPT(IncrementalLinkerCompatible, 1, 0) ///< Emit an object file which can
|
||||
///< be used with an incremental
|
||||
///< linker.
|
||||
|
|
@ -257,6 +262,8 @@ CODEGENOPT(SanitizeMinimalRuntime, 1, 0) ///< Use "_minimal" sanitizer runtime f
|
|||
///< diagnostics.
|
||||
CODEGENOPT(SanitizeCfiICallGeneralizePointers, 1, 0) ///< Generalize pointer types in
|
||||
///< CFI icall function signatures
|
||||
CODEGENOPT(SanitizeCfiICallNormalizeIntegers, 1, 0) ///< Normalize integer types in
|
||||
///< CFI icall function signatures
|
||||
CODEGENOPT(SanitizeCfiCanonicalJumpTables, 1, 0) ///< Make jump table symbols canonical
|
||||
///< instead of creating a local jump table.
|
||||
CODEGENOPT(SanitizeCoverageType, 2, 0) ///< Type of sanitizer coverage
|
||||
|
|
@ -318,6 +325,8 @@ CODEGENOPT(UseRegisterSizedBitfieldAccess , 1, 0)
|
|||
|
||||
CODEGENOPT(VerifyModule , 1, 1) ///< Control whether the module should be run
|
||||
///< through the LLVM Verifier.
|
||||
CODEGENOPT(VerifyEach , 1, 1) ///< Control whether the LLVM verifier
|
||||
///< should run after every pass.
|
||||
|
||||
CODEGENOPT(StackRealignment , 1, 0) ///< Control whether to force stack
|
||||
///< realignment.
|
||||
|
|
@ -333,8 +342,8 @@ VALUE_CODEGENOPT(WarnStackSize , 32, UINT_MAX) ///< Set via -fwarn-stack-siz
|
|||
CODEGENOPT(NoStackArgProbe, 1, 0) ///< Set when -mno-stack-arg-probe is used
|
||||
CODEGENOPT(DebugStrictDwarf, 1, 1) ///< Whether or not to use strict DWARF info.
|
||||
|
||||
CODEGENOPT(EnableAssignmentTracking, 1,0) ///< Enable the Assignment Tracking
|
||||
///< debug info feature.
|
||||
/// Control the Assignment Tracking debug info feature.
|
||||
ENUM_CODEGENOPT(AssignmentTrackingMode, AssignmentTrackingOpts, 2, AssignmentTrackingOpts::Disabled)
|
||||
|
||||
CODEGENOPT(DebugColumnInfo, 1, 0) ///< Whether or not to use column information
|
||||
///< in debug info.
|
||||
|
|
@ -356,7 +365,7 @@ CODEGENOPT(DebugFwdTemplateParams, 1, 0) ///< Whether to emit complete
|
|||
///< template parameter descriptions in
|
||||
///< forward declarations (versus just
|
||||
///< including them in the name).
|
||||
ENUM_CODEGENOPT(DebugSimpleTemplateNames, codegenoptions::DebugTemplateNamesKind, 2, codegenoptions::DebugTemplateNamesKind::Full) ///< Whether to emit template parameters
|
||||
ENUM_CODEGENOPT(DebugSimpleTemplateNames, llvm::codegenoptions::DebugTemplateNamesKind, 2, llvm::codegenoptions::DebugTemplateNamesKind::Full) ///< Whether to emit template parameters
|
||||
///< in the textual names of template
|
||||
///< specializations.
|
||||
///< Implies DebugFwdTemplateNames to
|
||||
|
|
@ -386,7 +395,7 @@ VALUE_CODEGENOPT(SmallDataLimit, 32, 0)
|
|||
VALUE_CODEGENOPT(SSPBufferSize, 32, 0)
|
||||
|
||||
/// The kind of generated debug info.
|
||||
ENUM_CODEGENOPT(DebugInfo, codegenoptions::DebugInfoKind, 4, codegenoptions::NoDebugInfo)
|
||||
ENUM_CODEGENOPT(DebugInfo, llvm::codegenoptions::DebugInfoKind, 4, llvm::codegenoptions::NoDebugInfo)
|
||||
|
||||
/// Whether to generate macro debug info.
|
||||
CODEGENOPT(MacroDebugInfo, 1, 0)
|
||||
|
|
@ -470,6 +479,10 @@ CODEGENOPT(Addrsig, 1, 0)
|
|||
/// Whether to emit unused static constants.
|
||||
CODEGENOPT(KeepStaticConsts, 1, 0)
|
||||
|
||||
/// Whether to emit all variables that have a persistent storage duration,
|
||||
/// including global, static and thread local variables.
|
||||
CODEGENOPT(KeepPersistentStorageVariables, 1, 0)
|
||||
|
||||
/// Whether to follow the AAPCS enforcing at least one read before storing to a volatile bitfield
|
||||
CODEGENOPT(ForceAAPCSBitfieldLoad, 1, 0)
|
||||
|
||||
|
|
@ -497,9 +510,6 @@ CODEGENOPT(SkipRaxSetup, 1, 0)
|
|||
ENUM_CODEGENOPT(ZeroCallUsedRegs, llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind,
|
||||
5, llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::Skip)
|
||||
|
||||
/// Whether to use opaque pointers.
|
||||
CODEGENOPT(OpaquePointers, 1, 0)
|
||||
|
||||
/// Modify C++ ABI to returning `this` pointer from constructors and
|
||||
/// non-deleting destructors. (No effect on Microsoft ABI.)
|
||||
CODEGENOPT(CtorDtorReturnThis, 1, 0)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue