Merge llvm-project main llvmorg-19-init-18630-gf2ccf80136a0

This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and
openmp to llvm-project main llvmorg-19-init-18630-gf2ccf80136a0, the
last commit before the upstream release/19.x branch was created.

PR:		280562
MFC after:	1 month
This commit is contained in:
Dimitry Andric 2024-07-28 01:34:35 +02:00
commit 0fca6ea1d4
5782 changed files with 428434 additions and 220812 deletions

View file

@ -51,6 +51,483 @@
# xargs -n1 | sort | uniq -d;
# done
# 20241023: new clang import which bumps version from 18 to 19
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_builtin_vars.h
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_cmath.h
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_complex_builtins.h
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_device_functions.h
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_intrinsics.h
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_libdevice_declares.h
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_math.h
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_math_forward_declares.h
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/18/include/__clang_cuda_texture_intrinsics.h
OLD_FILES+=usr/lib/clang/18/include/__clang_hip_cmath.h
OLD_FILES+=usr/lib/clang/18/include/__clang_hip_libdevice_declares.h
OLD_FILES+=usr/lib/clang/18/include/__clang_hip_math.h
OLD_FILES+=usr/lib/clang/18/include/__clang_hip_runtime_wrapper.h
OLD_FILES+=usr/lib/clang/18/include/__clang_hip_stdlib.h
OLD_FILES+=usr/lib/clang/18/include/__stdarg___gnuc_va_list.h
OLD_FILES+=usr/lib/clang/18/include/__stdarg___va_copy.h
OLD_FILES+=usr/lib/clang/18/include/__stdarg_va_arg.h
OLD_FILES+=usr/lib/clang/18/include/__stdarg_va_copy.h
OLD_FILES+=usr/lib/clang/18/include/__stdarg_va_list.h
OLD_FILES+=usr/lib/clang/18/include/__stddef_max_align_t.h
OLD_FILES+=usr/lib/clang/18/include/__stddef_null.h
OLD_FILES+=usr/lib/clang/18/include/__stddef_nullptr_t.h
OLD_FILES+=usr/lib/clang/18/include/__stddef_offsetof.h
OLD_FILES+=usr/lib/clang/18/include/__stddef_ptrdiff_t.h
OLD_FILES+=usr/lib/clang/18/include/__stddef_rsize_t.h
OLD_FILES+=usr/lib/clang/18/include/__stddef_size_t.h
OLD_FILES+=usr/lib/clang/18/include/__stddef_unreachable.h
OLD_FILES+=usr/lib/clang/18/include/__stddef_wchar_t.h
OLD_FILES+=usr/lib/clang/18/include/__stddef_wint_t.h
OLD_FILES+=usr/lib/clang/18/include/__wmmintrin_aes.h
OLD_FILES+=usr/lib/clang/18/include/__wmmintrin_pclmul.h
OLD_FILES+=usr/lib/clang/18/include/adcintrin.h
OLD_FILES+=usr/lib/clang/18/include/adxintrin.h
OLD_FILES+=usr/lib/clang/18/include/altivec.h
OLD_FILES+=usr/lib/clang/18/include/ammintrin.h
OLD_FILES+=usr/lib/clang/18/include/amxcomplexintrin.h
OLD_FILES+=usr/lib/clang/18/include/amxfp16intrin.h
OLD_FILES+=usr/lib/clang/18/include/amxintrin.h
OLD_FILES+=usr/lib/clang/18/include/arm64intr.h
OLD_FILES+=usr/lib/clang/18/include/arm_acle.h
OLD_FILES+=usr/lib/clang/18/include/arm_bf16.h
OLD_FILES+=usr/lib/clang/18/include/arm_cde.h
OLD_FILES+=usr/lib/clang/18/include/arm_cmse.h
OLD_FILES+=usr/lib/clang/18/include/arm_fp16.h
OLD_FILES+=usr/lib/clang/18/include/arm_mve.h
OLD_FILES+=usr/lib/clang/18/include/arm_neon.h
OLD_FILES+=usr/lib/clang/18/include/arm_neon_sve_bridge.h
OLD_FILES+=usr/lib/clang/18/include/arm_sme_draft_spec_subject_to_change.h
OLD_FILES+=usr/lib/clang/18/include/arm_sve.h
OLD_FILES+=usr/lib/clang/18/include/arm_vector_types.h
OLD_FILES+=usr/lib/clang/18/include/armintr.h
OLD_FILES+=usr/lib/clang/18/include/avx2intrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512bf16intrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512bitalgintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512bwintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512cdintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512dqintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512erintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512fintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512fp16intrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512ifmaintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512ifmavlintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512pfintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vbmi2intrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vbmiintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vbmivlintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vlbf16intrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vlbitalgintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vlbwintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vlcdintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vldqintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vlfp16intrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vlintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vlvbmi2intrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vlvnniintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vlvp2intersectintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vnniintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vp2intersectintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vpopcntdqintrin.h
OLD_FILES+=usr/lib/clang/18/include/avx512vpopcntdqvlintrin.h
OLD_FILES+=usr/lib/clang/18/include/avxifmaintrin.h
OLD_FILES+=usr/lib/clang/18/include/avxintrin.h
OLD_FILES+=usr/lib/clang/18/include/avxneconvertintrin.h
OLD_FILES+=usr/lib/clang/18/include/avxvnniint16intrin.h
OLD_FILES+=usr/lib/clang/18/include/avxvnniint8intrin.h
OLD_FILES+=usr/lib/clang/18/include/avxvnniintrin.h
OLD_FILES+=usr/lib/clang/18/include/bmi2intrin.h
OLD_FILES+=usr/lib/clang/18/include/bmiintrin.h
OLD_FILES+=usr/lib/clang/18/include/builtins.h
OLD_FILES+=usr/lib/clang/18/include/cet.h
OLD_FILES+=usr/lib/clang/18/include/cetintrin.h
OLD_FILES+=usr/lib/clang/18/include/cldemoteintrin.h
OLD_FILES+=usr/lib/clang/18/include/clflushoptintrin.h
OLD_FILES+=usr/lib/clang/18/include/clwbintrin.h
OLD_FILES+=usr/lib/clang/18/include/clzerointrin.h
OLD_FILES+=usr/lib/clang/18/include/cmpccxaddintrin.h
OLD_FILES+=usr/lib/clang/18/include/cpuid.h
OLD_FILES+=usr/lib/clang/18/include/crc32intrin.h
OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/bits/basic_string.h
OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/bits/basic_string.tcc
OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/bits/shared_ptr_base.h
OLD_DIRS+=usr/lib/clang/18/include/cuda_wrappers/bits
OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/cmath
OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/18/include/cuda_wrappers/new
OLD_DIRS+=usr/lib/clang/18/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/18/include/emmintrin.h
OLD_FILES+=usr/lib/clang/18/include/enqcmdintrin.h
OLD_FILES+=usr/lib/clang/18/include/f16cintrin.h
OLD_FILES+=usr/lib/clang/18/include/float.h
OLD_FILES+=usr/lib/clang/18/include/fma4intrin.h
OLD_FILES+=usr/lib/clang/18/include/fmaintrin.h
OLD_FILES+=usr/lib/clang/18/include/fuzzer/FuzzedDataProvider.h
OLD_DIRS+=usr/lib/clang/18/include/fuzzer
OLD_FILES+=usr/lib/clang/18/include/fxsrintrin.h
OLD_FILES+=usr/lib/clang/18/include/gfniintrin.h
OLD_FILES+=usr/lib/clang/18/include/hexagon_circ_brev_intrinsics.h
OLD_FILES+=usr/lib/clang/18/include/hexagon_protos.h
OLD_FILES+=usr/lib/clang/18/include/hexagon_types.h
OLD_FILES+=usr/lib/clang/18/include/hlsl/hlsl_basic_types.h
OLD_FILES+=usr/lib/clang/18/include/hlsl/hlsl_intrinsics.h
OLD_DIRS+=usr/lib/clang/18/include/hlsl
OLD_FILES+=usr/lib/clang/18/include/hlsl.h
OLD_FILES+=usr/lib/clang/18/include/hresetintrin.h
OLD_FILES+=usr/lib/clang/18/include/htmintrin.h
OLD_FILES+=usr/lib/clang/18/include/htmxlintrin.h
OLD_FILES+=usr/lib/clang/18/include/hvx_hexagon_protos.h
OLD_FILES+=usr/lib/clang/18/include/ia32intrin.h
OLD_FILES+=usr/lib/clang/18/include/immintrin.h
OLD_FILES+=usr/lib/clang/18/include/intrin.h
OLD_FILES+=usr/lib/clang/18/include/inttypes.h
OLD_FILES+=usr/lib/clang/18/include/invpcidintrin.h
OLD_FILES+=usr/lib/clang/18/include/iso646.h
OLD_FILES+=usr/lib/clang/18/include/keylockerintrin.h
OLD_FILES+=usr/lib/clang/18/include/larchintrin.h
OLD_FILES+=usr/lib/clang/18/include/lasxintrin.h
OLD_FILES+=usr/lib/clang/18/include/limits.h
OLD_FILES+=usr/lib/clang/18/include/lsxintrin.h
OLD_FILES+=usr/lib/clang/18/include/lwpintrin.h
OLD_FILES+=usr/lib/clang/18/include/lzcntintrin.h
OLD_FILES+=usr/lib/clang/18/include/mm3dnow.h
OLD_FILES+=usr/lib/clang/18/include/mm_malloc.h
OLD_FILES+=usr/lib/clang/18/include/mmintrin.h
OLD_FILES+=usr/lib/clang/18/include/module.modulemap
OLD_FILES+=usr/lib/clang/18/include/movdirintrin.h
OLD_FILES+=usr/lib/clang/18/include/msa.h
OLD_FILES+=usr/lib/clang/18/include/mwaitxintrin.h
OLD_FILES+=usr/lib/clang/18/include/nmmintrin.h
OLD_FILES+=usr/lib/clang/18/include/omp-tools.h
OLD_FILES+=usr/lib/clang/18/include/omp.h
OLD_FILES+=usr/lib/clang/18/include/ompt.h
OLD_FILES+=usr/lib/clang/18/include/opencl-c-base.h
OLD_FILES+=usr/lib/clang/18/include/opencl-c.h
OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/__clang_openmp_device_functions.h
OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/cmath
OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/complex
OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/complex.h
OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/complex_cmath.h
OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/math.h
OLD_FILES+=usr/lib/clang/18/include/openmp_wrappers/new
OLD_DIRS+=usr/lib/clang/18/include/openmp_wrappers
OLD_FILES+=usr/lib/clang/18/include/orc_rt/c_api.h
OLD_DIRS+=usr/lib/clang/18/include/orc_rt
OLD_FILES+=usr/lib/clang/18/include/pconfigintrin.h
OLD_FILES+=usr/lib/clang/18/include/pkuintrin.h
OLD_FILES+=usr/lib/clang/18/include/pmmintrin.h
OLD_FILES+=usr/lib/clang/18/include/popcntintrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/bmi2intrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/bmiintrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/emmintrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/immintrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/mm_malloc.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/mmintrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/nmmintrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/pmmintrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/smmintrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/tmmintrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/x86gprintrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/x86intrin.h
OLD_FILES+=usr/lib/clang/18/include/ppc_wrappers/xmmintrin.h
OLD_DIRS+=usr/lib/clang/18/include/ppc_wrappers
OLD_FILES+=usr/lib/clang/18/include/prfchiintrin.h
OLD_FILES+=usr/lib/clang/18/include/prfchwintrin.h
OLD_FILES+=usr/lib/clang/18/include/profile/InstrProfData.inc
OLD_FILES+=usr/lib/clang/18/include/profile/MemProfData.inc
OLD_DIRS+=usr/lib/clang/18/include/profile
OLD_FILES+=usr/lib/clang/18/include/ptwriteintrin.h
OLD_FILES+=usr/lib/clang/18/include/raointintrin.h
OLD_FILES+=usr/lib/clang/18/include/rdpruintrin.h
OLD_FILES+=usr/lib/clang/18/include/rdseedintrin.h
OLD_FILES+=usr/lib/clang/18/include/riscv_bitmanip.h
OLD_FILES+=usr/lib/clang/18/include/riscv_crypto.h
OLD_FILES+=usr/lib/clang/18/include/riscv_ntlh.h
OLD_FILES+=usr/lib/clang/18/include/riscv_vector.h
OLD_FILES+=usr/lib/clang/18/include/rtmintrin.h
OLD_FILES+=usr/lib/clang/18/include/s390intrin.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/allocator_interface.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/asan_interface.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/common_interface_defs.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/coverage_interface.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/dfsan_interface.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/hwasan_interface.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/linux_syscall_hooks.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/lsan_interface.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/memprof_interface.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/msan_interface.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/netbsd_syscall_hooks.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/scudo_interface.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/tsan_interface.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/tsan_interface_atomic.h
OLD_FILES+=usr/lib/clang/18/include/sanitizer/ubsan_interface.h
OLD_DIRS+=usr/lib/clang/18/include/sanitizer
OLD_FILES+=usr/lib/clang/18/include/serializeintrin.h
OLD_FILES+=usr/lib/clang/18/include/sgxintrin.h
OLD_FILES+=usr/lib/clang/18/include/sha512intrin.h
OLD_FILES+=usr/lib/clang/18/include/shaintrin.h
OLD_FILES+=usr/lib/clang/18/include/sifive_vector.h
OLD_FILES+=usr/lib/clang/18/include/sm3intrin.h
OLD_FILES+=usr/lib/clang/18/include/sm4intrin.h
OLD_FILES+=usr/lib/clang/18/include/smmintrin.h
OLD_FILES+=usr/lib/clang/18/include/stdalign.h
OLD_FILES+=usr/lib/clang/18/include/stdarg.h
OLD_FILES+=usr/lib/clang/18/include/stdatomic.h
OLD_FILES+=usr/lib/clang/18/include/stdbool.h
OLD_FILES+=usr/lib/clang/18/include/stdckdint.h
OLD_FILES+=usr/lib/clang/18/include/stddef.h
OLD_FILES+=usr/lib/clang/18/include/stdint.h
OLD_FILES+=usr/lib/clang/18/include/stdnoreturn.h
OLD_FILES+=usr/lib/clang/18/include/tbmintrin.h
OLD_FILES+=usr/lib/clang/18/include/tgmath.h
OLD_FILES+=usr/lib/clang/18/include/tmmintrin.h
OLD_FILES+=usr/lib/clang/18/include/tsxldtrkintrin.h
OLD_FILES+=usr/lib/clang/18/include/uintrintrin.h
OLD_FILES+=usr/lib/clang/18/include/unwind.h
OLD_FILES+=usr/lib/clang/18/include/usermsrintrin.h
OLD_FILES+=usr/lib/clang/18/include/vadefs.h
OLD_FILES+=usr/lib/clang/18/include/vaesintrin.h
OLD_FILES+=usr/lib/clang/18/include/varargs.h
OLD_FILES+=usr/lib/clang/18/include/vecintrin.h
OLD_FILES+=usr/lib/clang/18/include/velintrin.h
OLD_FILES+=usr/lib/clang/18/include/velintrin_approx.h
OLD_FILES+=usr/lib/clang/18/include/velintrin_gen.h
OLD_FILES+=usr/lib/clang/18/include/vpclmulqdqintrin.h
OLD_FILES+=usr/lib/clang/18/include/waitpkgintrin.h
OLD_FILES+=usr/lib/clang/18/include/wasm_simd128.h
OLD_FILES+=usr/lib/clang/18/include/wbnoinvdintrin.h
OLD_FILES+=usr/lib/clang/18/include/wmmintrin.h
OLD_FILES+=usr/lib/clang/18/include/x86gprintrin.h
OLD_FILES+=usr/lib/clang/18/include/x86intrin.h
OLD_FILES+=usr/lib/clang/18/include/xmmintrin.h
OLD_FILES+=usr/lib/clang/18/include/xopintrin.h
OLD_FILES+=usr/lib/clang/18/include/xray/xray_interface.h
OLD_FILES+=usr/lib/clang/18/include/xray/xray_log_interface.h
OLD_FILES+=usr/lib/clang/18/include/xray/xray_records.h
OLD_DIRS+=usr/lib/clang/18/include/xray
OLD_FILES+=usr/lib/clang/18/include/xsavecintrin.h
OLD_FILES+=usr/lib/clang/18/include/xsaveintrin.h
OLD_FILES+=usr/lib/clang/18/include/xsaveoptintrin.h
OLD_FILES+=usr/lib/clang/18/include/xsavesintrin.h
OLD_FILES+=usr/lib/clang/18/include/xtestintrin.h
OLD_DIRS+=usr/lib/clang/18/include
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-aarch64.so
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-arm.so
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-armhf.so
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-i386.so
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-powerpc64.so
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-powerpc64le.so
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-riscv64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-preinit-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-riscv64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-riscv64.so
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan-x86_64.so
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-riscv64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.asan_static-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi_diag-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi_diag-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi_diag-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi_diag-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.cfi_diag-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.dd-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.dd-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_interceptors-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_no_main-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.fuzzer_no_main-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan_cxx-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan_cxx-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.msan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-powerpc.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-riscv64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.profile-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.safestack-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.safestack-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.safestack-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-riscv64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-riscv64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.stats_client-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan_cxx-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan_cxx-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.tsan_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-riscv64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_minimal-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-riscv64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-i386.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-riscv64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.ubsan_standalone_cxx-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-basic-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-basic-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-basic-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-basic-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-basic-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-fdr-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-fdr-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-fdr-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-fdr-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-fdr-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-profiling-aarch64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-profiling-arm.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-profiling-armhf.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-profiling-powerpc64le.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-profiling-x86_64.a
OLD_FILES+=usr/lib/clang/18/lib/freebsd/libclang_rt.xray-x86_64.a
OLD_DIRS+=usr/lib/clang/18/lib/freebsd
OLD_DIRS+=usr/lib/clang/18/lib
OLD_FILES+=usr/lib/clang/18/share/asan_ignorelist.txt
OLD_FILES+=usr/lib/clang/18/share/cfi_ignorelist.txt
OLD_FILES+=usr/lib/clang/18/share/msan_ignorelist.txt
OLD_DIRS+=usr/lib/clang/18/share
OLD_DIRS+=usr/lib/clang/18
# 20241023: new libc++ import which bumps version from 18 to 19
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_any_all_none_of.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backend.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backend.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/any_of.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/backend.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/fill.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/find_if.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/for_each.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/libdispatch.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/merge.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/serial.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/stable_sort.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/thread.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/transform.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends/transform_reduce.h
OLD_DIRS+=usr/include/c++/v1/__algorithm/pstl_backends/cpu_backends
OLD_DIRS+=usr/include/c++/v1/__algorithm/pstl_backends
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_copy.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_count.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_equal.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_fill.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_find.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_for_each.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_frontend_dispatch.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_generate.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_is_partitioned.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_merge.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_move.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_replace.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_rotate_copy.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_sort.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_stable_sort.h
OLD_FILES+=usr/include/c++/v1/__algorithm/pstl_transform.h
OLD_FILES+=usr/include/c++/v1/__availability
OLD_FILES+=usr/include/c++/v1/__format/format_fwd.h
OLD_FILES+=usr/include/c++/v1/__fwd/get.h
OLD_FILES+=usr/include/c++/v1/__fwd/hash.h
OLD_FILES+=usr/include/c++/v1/__numeric/pstl_reduce.h
OLD_FILES+=usr/include/c++/v1/__numeric/pstl_transform_reduce.h
OLD_FILES+=usr/include/c++/v1/__threading_support
OLD_FILES+=usr/include/c++/v1/__tuple/pair_like.h
OLD_FILES+=usr/include/c++/v1/__type_traits/apply_cv.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_copy_assignable.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_copy_constructible.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_default_constructible.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_member_function_pointer.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_member_object_pointer.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_move_assignable.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_move_constructible.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_nothrow_copy_assignable.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_nothrow_copy_constructible.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_nothrow_default_constructible.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_nothrow_move_assignable.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_nothrow_move_constructible.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_scoped_enum.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_trivially_copy_assignable.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_trivially_copy_constructible.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_trivially_default_constructible.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_trivially_move_assignable.h
OLD_FILES+=usr/include/c++/v1/__type_traits/is_trivially_move_constructible.h
OLD_FILES+=usr/include/c++/v1/__type_traits/operation_traits.h
OLD_FILES+=usr/include/c++/v1/experimental/__memory
# 20241014: move divapp to netpfil/common/
OLD_FILES+=usr/tests/sys/netpfil/pf/divapp

View file

@ -1,5 +1,3 @@
.arcconfig
.arclint
.ci/
.clang-format
.clang-tidy
@ -29,7 +27,11 @@ clang/examples/
clang/include/CMakeLists.txt
clang/include/clang/AST/CMakeLists.txt
clang/include/clang/Basic/CMakeLists.txt
clang/include/clang/Basic/Target/
clang/include/clang/Basic/Version.inc.in
clang/include/clang/CIR/CMakeLists.txt
clang/include/clang/CIR/Dialect/CMakeLists.txt
clang/include/clang/CIR/Dialect/IR/CMakeLists.txt
clang/include/clang/CMakeLists.txt
clang/include/clang/Config/
clang/include/clang/Driver/CMakeLists.txt
@ -52,6 +54,9 @@ clang/lib/Analysis/plugins/CheckerDependencyHandling/CMakeLists.txt
clang/lib/Analysis/plugins/CheckerOptionHandling/CMakeLists.txt
clang/lib/Analysis/plugins/SampleAnalyzer/CMakeLists.txt
clang/lib/Basic/CMakeLists.txt
clang/lib/CIR/CMakeLists.txt
clang/lib/CIR/Dialect/CMakeLists.txt
clang/lib/CIR/Dialect/IR/CMakeLists.txt
clang/lib/CMakeLists.txt
clang/lib/CodeGen/CMakeLists.txt
clang/lib/CodeGen/README.txt
@ -68,6 +73,7 @@ clang/lib/FrontendTool/CMakeLists.txt
clang/lib/Headers/CMakeLists.txt
clang/lib/Index/CMakeLists.txt
clang/lib/IndexSerialization/CMakeLists.txt
clang/lib/InstallAPI/CMakeLists.txt
clang/lib/Interpreter/CMakeLists.txt
clang/lib/Lex/CMakeLists.txt
clang/lib/Parse/CMakeLists.txt
@ -85,8 +91,6 @@ clang/lib/Tooling/ASTDiff/CMakeLists.txt
clang/lib/Tooling/CMakeLists.txt
clang/lib/Tooling/Core/CMakeLists.txt
clang/lib/Tooling/DependencyScanning/CMakeLists.txt
clang/lib/Tooling/DumpTool/CMakeLists.txt
clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
clang/lib/Tooling/Inclusions/CMakeLists.txt
clang/lib/Tooling/Inclusions/Stdlib/CMakeLists.txt
clang/lib/Tooling/Refactoring/CMakeLists.txt
@ -95,7 +99,7 @@ clang/lib/Tooling/Transformer/CMakeLists.txt
clang/runtime/
clang/test/
clang/tools/CMakeLists.txt
clang/tools/amdgpu-arch/CMakeLists.txt
clang/tools/amdgpu-arch/
clang/tools/apinotes-test/
clang/tools/arcmt-test/
clang/tools/c-arcmt-test/
@ -117,12 +121,14 @@ clang/tools/clang-format/git-clang-format.bat
clang/tools/clang-format-vs/
clang/tools/clang-fuzzer/
clang/tools/clang-import-test/
clang/tools/clang-installapi/
clang/tools/clang-linker-wrapper/
clang/tools/clang-nvlink-wrapper/
clang/tools/clang-offload-bundler/
clang/tools/clang-offload-packager/
clang/tools/clang-refactor/
clang/tools/clang-rename/
clang/tools/clang-repl/CMakeLists.txt
clang/tools/clang-repl/
clang/tools/clang-scan-deps/
clang/tools/clang-shlib/
clang/tools/diag-build/
@ -131,7 +137,7 @@ clang/tools/driver/CMakeLists.txt
clang/tools/driver/Info.plist.in
clang/tools/include-mapping/
clang/tools/libclang/
clang/tools/nvptx-arch/CMakeLists.txt
clang/tools/nvptx-arch/
clang/tools/scan-build/
clang/tools/scan-build-py/
clang/tools/scan-view/
@ -139,7 +145,6 @@ clang/unittests/
clang/utils/ABITest/
clang/utils/CIndex/
clang/utils/CaptureCmd
clang/utils/ClangDataFormat.py
clang/utils/ClangVisualizers/
clang/utils/CmpDriver
clang/utils/FindSpecRefs
@ -153,7 +158,6 @@ 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
@ -164,7 +168,6 @@ clang/utils/modfuzz.py
clang/utils/module-deps-to-rsp.py
clang/utils/perf-training/
clang/utils/token-delta.py
clang/utils/update_options_td_flags.py
clang/utils/valgrind/
clang/www/
clang-tools-extra/
@ -185,6 +188,8 @@ 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/ctx_profile/CMakeLists.txt
compiler-rt/lib/ctx_profile/tests/CMakeLists.txt
compiler-rt/lib/dfsan/.clang-format
compiler-rt/lib/dfsan/CMakeLists.txt
compiler-rt/lib/dfsan/scripts/
@ -211,11 +216,15 @@ compiler-rt/lib/memprof/tests/CMakeLists.txt
compiler-rt/lib/msan/.clang-format
compiler-rt/lib/msan/CMakeLists.txt
compiler-rt/lib/msan/tests/
compiler-rt/lib/nsan/CMakeLists.txt
compiler-rt/lib/nsan/tests/CMakeLists.txt
compiler-rt/lib/orc/CMakeLists.txt
compiler-rt/lib/orc/tests/CMakeLists.txt
compiler-rt/lib/orc/tests/tools/CMakeLists.txt
compiler-rt/lib/orc/tests/unit/CMakeLists.txt
compiler-rt/lib/profile/CMakeLists.txt
compiler-rt/lib/rtsan/CMakeLists.txt
compiler-rt/lib/rtsan/tests/CMakeLists.txt
compiler-rt/lib/safestack/.clang-format
compiler-rt/lib/safestack/CMakeLists.txt
compiler-rt/lib/sanitizer_common/.clang-format
@ -267,6 +276,7 @@ libcxx/include/__config_site.in
libcxx/include/__support/
libcxx/lib/
libcxx/modules/CMakeLists.txt
libcxx/modules/CMakeLists.txt.in
libcxx/modules/README.md
libcxx/src/CMakeLists.txt
libcxx/src/support/win32/
@ -309,9 +319,6 @@ lldb/docs/conf.py
lldb/docs/doxygen-mainpage.dox
lldb/docs/doxygen.cfg.in
lldb/docs/index.rst
lldb/docs/lldb-for-gdb-users.txt
lldb/docs/lldb-gdb-remote.txt
lldb/docs/lldb-platform-packets.txt
lldb/docs/resources/
lldb/docs/testsuite/
lldb/docs/use/
@ -483,7 +490,6 @@ lldb/source/Target/CMakeLists.txt
lldb/source/Utility/CMakeLists.txt
lldb/source/Version/CMakeLists.txt
lldb/test/
lldb/third_party/
lldb/tools/CMakeLists.txt
lldb/tools/argdumper/CMakeLists.txt
lldb/tools/darwin-debug/
@ -548,6 +554,8 @@ llvm/lib/CodeGen/GlobalISel/CMakeLists.txt
llvm/lib/CodeGen/MIRParser/CMakeLists.txt
llvm/lib/CodeGen/README.txt
llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt
llvm/lib/CodeGenData/CMakeLists.txt
llvm/lib/CodeGenTypes/CMakeLists.txt
llvm/lib/DWARFLinker/CMakeLists.txt
llvm/lib/DWARFLinker/Classic/CMakeLists.txt
llvm/lib/DWARFLinker/Parallel/CMakeLists.txt
@ -565,6 +573,7 @@ llvm/lib/Debuginfod/CMakeLists.txt
llvm/lib/Demangle/CMakeLists.txt
llvm/lib/ExecutionEngine/CMakeLists.txt
llvm/lib/ExecutionEngine/IntelJITEvents/CMakeLists.txt
llvm/lib/ExecutionEngine/IntelJITProfiling/CMakeLists.txt
llvm/lib/ExecutionEngine/Interpreter/CMakeLists.txt
llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
llvm/lib/ExecutionEngine/MCJIT/CMakeLists.txt
@ -604,9 +613,11 @@ llvm/lib/Passes/CMakeLists.txt
llvm/lib/ProfileData/CMakeLists.txt
llvm/lib/ProfileData/Coverage/CMakeLists.txt
llvm/lib/Remarks/CMakeLists.txt
llvm/lib/SandboxIR/CMakeLists.txt
llvm/lib/Support/BLAKE3/.clang-format
llvm/lib/Support/BLAKE3/CMakeLists.txt
llvm/lib/Support/CMakeLists.txt
llvm/lib/Support/rpmalloc/
llvm/lib/TableGen/CMakeLists.txt
llvm/lib/Target/AArch64/AsmParser/CMakeLists.txt
llvm/lib/Target/AArch64/CMakeLists.txt
@ -614,6 +625,7 @@ llvm/lib/Target/AArch64/Disassembler/CMakeLists.txt
llvm/lib/Target/AArch64/MCTargetDesc/CMakeLists.txt
llvm/lib/Target/AArch64/TargetInfo/CMakeLists.txt
llvm/lib/Target/AArch64/Utils/CMakeLists.txt
llvm/lib/Target/AArch64/peephole-sxtw.mir
llvm/lib/Target/AMDGPU/AsmParser/CMakeLists.txt
llvm/lib/Target/AMDGPU/CMakeLists.txt
llvm/lib/Target/AMDGPU/Disassembler/CMakeLists.txt
@ -703,6 +715,7 @@ llvm/lib/Target/RISCV/Disassembler/CMakeLists.txt
llvm/lib/Target/RISCV/MCA/CMakeLists.txt
llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
llvm/lib/Target/RISCV/TargetInfo/CMakeLists.txt
llvm/lib/Target/SPIRV/Analysis/CMakeLists.txt
llvm/lib/Target/SPIRV/CMakeLists.txt
llvm/lib/Target/SPIRV/MCTargetDesc/CMakeLists.txt
llvm/lib/Target/SPIRV/TargetInfo/CMakeLists.txt
@ -761,7 +774,6 @@ llvm/lib/Transforms/AggressiveInstCombine/CMakeLists.txt
llvm/lib/Transforms/CFGuard/CMakeLists.txt
llvm/lib/Transforms/CMakeLists.txt
llvm/lib/Transforms/Coroutines/CMakeLists.txt
llvm/lib/Transforms/Hello/
llvm/lib/Transforms/HipStdPar/CMakeLists.txt
llvm/lib/Transforms/IPO/CMakeLists.txt
llvm/lib/Transforms/InstCombine/CMakeLists.txt
@ -773,7 +785,6 @@ llvm/lib/Transforms/Vectorize/CMakeLists.txt
llvm/lib/WindowsDriver/CMakeLists.txt
llvm/lib/WindowsManifest/CMakeLists.txt
llvm/lib/XRay/CMakeLists.txt
llvm/llvm.spec.in
llvm/projects/
llvm/resources/
llvm/runtimes/
@ -794,6 +805,7 @@ llvm/tools/llvm-bcanalyzer/CMakeLists.txt
llvm/tools/llvm-c-test/
llvm/tools/llvm-cat/
llvm/tools/llvm-cfi-verify/
llvm/tools/llvm-cgdata/
llvm/tools/llvm-config/
llvm/tools/llvm-cov/CMakeLists.txt
llvm/tools/llvm-cvtres/
@ -866,6 +878,7 @@ llvm/tools/lto/
llvm/tools/obj2yaml/
llvm/tools/opt/CMakeLists.txt
llvm/tools/opt-viewer/
llvm/tools/reduce-chunk-list/
llvm/tools/remarks-shlib/
llvm/tools/sancov/
llvm/tools/sanstats/
@ -885,8 +898,9 @@ llvm/utils/LLVMVisualizers/
llvm/utils/Misc/
llvm/utils/PerfectShuffle/
llvm/utils/Reviewing/
llvm/utils/TableGen/Basic/CMakeLists.txt
llvm/utils/TableGen/CMakeLists.txt
llvm/utils/TableGen/GlobalISel/CMakeLists.txt
llvm/utils/TableGen/Common/CMakeLists.txt
llvm/utils/TableGen/README.md
llvm/utils/TableGen/jupyter/
llvm/utils/TableGen/tdtags
@ -908,6 +922,7 @@ llvm/utils/codegen-diff
llvm/utils/collect_and_build_with_pgo.py
llvm/utils/convert-constraint-log-to-z3.py
llvm/utils/count/
llvm/utils/count_running_jobs.py
llvm/utils/create_ladder_graph.py
llvm/utils/crosstool/
llvm/utils/demangle_tree.py
@ -956,8 +971,7 @@ llvm/utils/schedcover.py
llvm/utils/shuffle_fuzz.py
llvm/utils/shuffle_select_fuzz_tester.py
llvm/utils/sort_includes.py
llvm/utils/split-file/.clang-tidy
llvm/utils/split-file/CMakeLists.txt
llvm/utils/split-file/
llvm/utils/sysroot.py
llvm/utils/testgen/
llvm/utils/textmate/
@ -968,6 +982,7 @@ llvm/utils/update_cc_test_checks.py
llvm/utils/update_llc_test_checks.py
llvm/utils/update_mca_test_checks.py
llvm/utils/update_mir_test_checks.py
llvm/utils/update_test_body.py
llvm/utils/update_test_checks.py
llvm/utils/update_test_prefix.py
llvm/utils/valgrind/
@ -977,13 +992,13 @@ llvm/utils/wciia.py
llvm/utils/yaml-bench/
llvm-libgcc/
mlir/
offload/
openmp/.gitignore
openmp/CMakeLists.txt
openmp/README.rst
openmp/cmake/
openmp/docs/
openmp/libompd/
openmp/libomptarget/
openmp/runtime/.clang-format
openmp/runtime/.clang-tidy
openmp/runtime/CMakeLists.txt
@ -997,6 +1012,7 @@ openmp/runtime/tools/
openmp/tools/
polly/
pstl/
pyproject.toml
runtimes/
third-party/
utils/

View file

@ -1644,8 +1644,9 @@ enum CXCursorKind {
CXCursor_ObjCSelfExpr = 146,
/** OpenMP 5.0 [2.1.5, Array Section].
* OpenACC 3.3 [2.7.1, Data Specification for Data Clauses (Sub Arrays)]
*/
CXCursor_OMPArraySectionExpr = 147,
CXCursor_ArraySectionExpr = 147,
/** Represents an @available(...) check.
*/
@ -1675,7 +1676,7 @@ enum CXCursorKind {
CXCursor_ConceptSpecializationExpr = 153,
/**
* Expression that references a C++20 concept.
* Expression that references a C++20 requires expression.
*/
CXCursor_RequiresExpr = 154,
@ -1685,7 +1686,12 @@ enum CXCursorKind {
*/
CXCursor_CXXParenListInitExpr = 155,
CXCursor_LastExpr = CXCursor_CXXParenListInitExpr,
/**
* Represents a C++26 pack indexing expression.
*/
CXCursor_PackIndexingExpr = 156,
CXCursor_LastExpr = CXCursor_PackIndexingExpr,
/* Statements */
CXCursor_FirstStmt = 200,
@ -2140,7 +2146,23 @@ enum CXCursorKind {
*/
CXCursor_OMPScopeDirective = 306,
CXCursor_LastStmt = CXCursor_OMPScopeDirective,
/** OpenMP reverse directive.
*/
CXCursor_OMPReverseDirective = 307,
/** OpenMP interchange directive.
*/
CXCursor_OMPInterchangeDirective = 308,
/** OpenACC Compute Construct.
*/
CXCursor_OpenACCComputeConstruct = 320,
/** OpenACC Loop Construct.
*/
CXCursor_OpenACCLoopConstruct = 321,
CXCursor_LastStmt = CXCursor_OpenACCLoopConstruct,
/**
* Cursor that represents the translation unit itself.
@ -2981,6 +3003,8 @@ enum CXCallingConv {
CXCallingConv_SwiftAsync = 17,
CXCallingConv_AArch64SVEPCS = 18,
CXCallingConv_M68kRTD = 19,
CXCallingConv_PreserveNone = 20,
CXCallingConv_RISCVVectorCall = 21,
CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200
@ -3734,6 +3758,59 @@ enum CX_StorageClass {
CX_SC_Register
};
/**
* Represents a specific kind of binary operator which can appear at a cursor.
*/
enum CX_BinaryOperatorKind {
CX_BO_Invalid = 0,
CX_BO_PtrMemD = 1,
CX_BO_PtrMemI = 2,
CX_BO_Mul = 3,
CX_BO_Div = 4,
CX_BO_Rem = 5,
CX_BO_Add = 6,
CX_BO_Sub = 7,
CX_BO_Shl = 8,
CX_BO_Shr = 9,
CX_BO_Cmp = 10,
CX_BO_LT = 11,
CX_BO_GT = 12,
CX_BO_LE = 13,
CX_BO_GE = 14,
CX_BO_EQ = 15,
CX_BO_NE = 16,
CX_BO_And = 17,
CX_BO_Xor = 18,
CX_BO_Or = 19,
CX_BO_LAnd = 20,
CX_BO_LOr = 21,
CX_BO_Assign = 22,
CX_BO_MulAssign = 23,
CX_BO_DivAssign = 24,
CX_BO_RemAssign = 25,
CX_BO_AddAssign = 26,
CX_BO_SubAssign = 27,
CX_BO_ShlAssign = 28,
CX_BO_ShrAssign = 29,
CX_BO_AndAssign = 30,
CX_BO_XorAssign = 31,
CX_BO_OrAssign = 32,
CX_BO_Comma = 33,
CX_BO_LAST = CX_BO_Comma
};
/**
* \brief Returns the operator code for the binary operator.
*/
CINDEX_LINKAGE enum CX_BinaryOperatorKind
clang_Cursor_getBinaryOpcode(CXCursor C);
/**
* \brief Returns a string containing the spelling of the binary operator.
*/
CINDEX_LINKAGE CXString
clang_Cursor_getBinaryOpcodeStr(enum CX_BinaryOperatorKind Op);
/**
* Returns the storage class for a function or variable declaration.
*

View file

@ -9,7 +9,6 @@
#ifndef LLVM_CLANG_APINOTES_APINOTESMANAGER_H
#define LLVM_CLANG_APINOTES_APINOTESMANAGER_H
#include "clang/Basic/Module.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
@ -24,6 +23,7 @@ namespace clang {
class DirectoryEntry;
class FileEntry;
class LangOptions;
class Module;
class SourceManager;
namespace api_notes {

View file

@ -101,7 +101,7 @@ public:
/// \param Name The name of the class we're looking for.
///
/// \returns The information about the class, if known.
VersionedInfo<ObjCContextInfo> lookupObjCClassInfo(llvm::StringRef Name);
VersionedInfo<ContextInfo> lookupObjCClassInfo(llvm::StringRef Name);
/// Look for the context ID of the given Objective-C protocol.
///
@ -115,7 +115,7 @@ public:
/// \param Name The name of the protocol we're looking for.
///
/// \returns The information about the protocol, if known.
VersionedInfo<ObjCContextInfo> lookupObjCProtocolInfo(llvm::StringRef Name);
VersionedInfo<ContextInfo> lookupObjCProtocolInfo(llvm::StringRef Name);
/// Look for information regarding the given Objective-C property in
/// the given context.
@ -141,6 +141,16 @@ public:
ObjCSelectorRef Selector,
bool IsInstanceMethod);
/// Look for information regarding the given C++ method in the given C++ tag
/// context.
///
/// \param CtxID The ID that references the parent context, i.e. a C++ tag.
/// \param Name The name of the C++ method we're looking for.
///
/// \returns Information about the method, if known.
VersionedInfo<CXXMethodInfo> lookupCXXMethod(ContextID CtxID,
llvm::StringRef Name);
/// Look for information regarding the given global variable.
///
/// \param Name The name of the global variable.
@ -166,6 +176,17 @@ public:
/// \returns information about the enumerator, if known.
VersionedInfo<EnumConstantInfo> lookupEnumConstant(llvm::StringRef Name);
/// Look for the context ID of the given C++ tag.
///
/// \param Name The name of the tag we're looking for.
/// \param ParentCtx The context in which this tag is declared, e.g. a C++
/// namespace.
///
/// \returns The ID, if known.
std::optional<ContextID>
lookupTagID(llvm::StringRef Name,
std::optional<Context> ParentCtx = std::nullopt);
/// Look for information regarding the given tag
/// (struct/union/enum/C++ class).
///

View file

@ -5,7 +5,13 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines the \c APINotesWriter class that writes out source
// API notes data providing additional information about source code as
// a separate input, such as the non-nil/nilable annotations for
// method parameters.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_APINOTES_WRITER_H
#define LLVM_CLANG_APINOTES_WRITER_H
@ -20,11 +26,16 @@ namespace clang {
class FileEntry;
namespace api_notes {
/// A class that writes API notes data to a binary representation that can be
/// read by the \c APINotesReader.
class APINotesWriter {
class Implementation;
std::unique_ptr<Implementation> Implementation;
public:
/// Create a new API notes writer with the given module name and
/// (optional) source file.
APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF);
~APINotesWriter();
@ -42,10 +53,10 @@ public:
///
/// \returns the ID of the class, protocol, or namespace, which can be used to
/// add properties and methods to the class/protocol/namespace.
ContextID addObjCContext(std::optional<ContextID> ParentCtxID,
llvm::StringRef Name, ContextKind Kind,
const ObjCContextInfo &Info,
llvm::VersionTuple SwiftVersion);
ContextID addContext(std::optional<ContextID> ParentCtxID,
llvm::StringRef Name, ContextKind Kind,
const ContextInfo &Info,
llvm::VersionTuple SwiftVersion);
/// Add information about a specific Objective-C property.
///
@ -67,6 +78,14 @@ public:
bool IsInstanceMethod, const ObjCMethodInfo &Info,
llvm::VersionTuple SwiftVersion);
/// Add information about a specific C++ method.
///
/// \param CtxID The context in which this method resides, i.e. a C++ tag.
/// \param Name The name of the method.
/// \param Info Information about this method.
void addCXXMethod(ContextID CtxID, llvm::StringRef Name,
const CXXMethodInfo &Info, llvm::VersionTuple SwiftVersion);
/// Add information about a global variable.
///
/// \param Name The name of this global variable.

View file

@ -55,16 +55,20 @@ public:
std::string UnavailableMsg;
/// Whether this entity is marked unavailable.
LLVM_PREFERRED_TYPE(bool)
unsigned Unavailable : 1;
/// Whether this entity is marked unavailable in Swift.
LLVM_PREFERRED_TYPE(bool)
unsigned UnavailableInSwift : 1;
private:
/// Whether SwiftPrivate was specified.
LLVM_PREFERRED_TYPE(bool)
unsigned SwiftPrivateSpecified : 1;
/// Whether this entity is considered "private" to a Swift overlay.
LLVM_PREFERRED_TYPE(bool)
unsigned SwiftPrivate : 1;
public:
@ -188,25 +192,33 @@ inline bool operator!=(const CommonTypeInfo &LHS, const CommonTypeInfo &RHS) {
return !(LHS == RHS);
}
/// Describes API notes data for an Objective-C class or protocol.
class ObjCContextInfo : public CommonTypeInfo {
/// Describes API notes data for an Objective-C class or protocol or a C++
/// namespace.
class ContextInfo : public CommonTypeInfo {
/// Whether this class has a default nullability.
LLVM_PREFERRED_TYPE(bool)
unsigned HasDefaultNullability : 1;
/// The default nullability.
LLVM_PREFERRED_TYPE(NullabilityKind)
unsigned DefaultNullability : 2;
/// Whether this class has designated initializers recorded.
LLVM_PREFERRED_TYPE(bool)
unsigned HasDesignatedInits : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned SwiftImportAsNonGenericSpecified : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned SwiftImportAsNonGeneric : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned SwiftObjCMembersSpecified : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned SwiftObjCMembers : 1;
public:
ObjCContextInfo()
ContextInfo()
: HasDefaultNullability(0), DefaultNullability(0), HasDesignatedInits(0),
SwiftImportAsNonGenericSpecified(false), SwiftImportAsNonGeneric(false),
SwiftObjCMembersSpecified(false), SwiftObjCMembers(false) {}
@ -251,16 +263,9 @@ public:
SwiftObjCMembers = Value.value_or(false);
}
/// Strip off any information within the class information structure that is
/// module-local, such as 'audited' flags.
void stripModuleLocalInfo() {
HasDefaultNullability = false;
DefaultNullability = 0;
}
friend bool operator==(const ContextInfo &, const ContextInfo &);
friend bool operator==(const ObjCContextInfo &, const ObjCContextInfo &);
ObjCContextInfo &operator|=(const ObjCContextInfo &RHS) {
ContextInfo &operator|=(const ContextInfo &RHS) {
// Merge inherited info.
static_cast<CommonTypeInfo &>(*this) |= RHS;
@ -283,7 +288,7 @@ public:
LLVM_DUMP_METHOD void dump(llvm::raw_ostream &OS);
};
inline bool operator==(const ObjCContextInfo &LHS, const ObjCContextInfo &RHS) {
inline bool operator==(const ContextInfo &LHS, const ContextInfo &RHS) {
return static_cast<const CommonTypeInfo &>(LHS) == RHS &&
LHS.getDefaultNullability() == RHS.getDefaultNullability() &&
LHS.HasDesignatedInits == RHS.HasDesignatedInits &&
@ -291,17 +296,19 @@ inline bool operator==(const ObjCContextInfo &LHS, const ObjCContextInfo &RHS) {
LHS.getSwiftObjCMembers() == RHS.getSwiftObjCMembers();
}
inline bool operator!=(const ObjCContextInfo &LHS, const ObjCContextInfo &RHS) {
inline bool operator!=(const ContextInfo &LHS, const ContextInfo &RHS) {
return !(LHS == RHS);
}
/// API notes for a variable/property.
class VariableInfo : public CommonEntityInfo {
/// Whether this property has been audited for nullability.
LLVM_PREFERRED_TYPE(bool)
unsigned NullabilityAudited : 1;
/// The kind of nullability for this property. Only valid if the nullability
/// has been audited.
LLVM_PREFERRED_TYPE(NullabilityKind)
unsigned Nullable : 2;
/// The C type of the variable, as a string.
@ -352,7 +359,9 @@ inline bool operator!=(const VariableInfo &LHS, const VariableInfo &RHS) {
/// Describes API notes data for an Objective-C property.
class ObjCPropertyInfo : public VariableInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned SwiftImportAsAccessorsSpecified : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned SwiftImportAsAccessors : 1;
public:
@ -372,7 +381,7 @@ public:
friend bool operator==(const ObjCPropertyInfo &, const ObjCPropertyInfo &);
/// Merge class-wide information into the given property.
ObjCPropertyInfo &operator|=(const ObjCContextInfo &RHS) {
ObjCPropertyInfo &operator|=(const ContextInfo &RHS) {
static_cast<CommonEntityInfo &>(*this) |= RHS;
// Merge nullability.
@ -409,9 +418,11 @@ inline bool operator!=(const ObjCPropertyInfo &LHS,
/// Describes a function or method parameter.
class ParamInfo : public VariableInfo {
/// Whether noescape was specified.
LLVM_PREFERRED_TYPE(bool)
unsigned NoEscapeSpecified : 1;
/// Whether the this parameter has the 'noescape' attribute.
LLVM_PREFERRED_TYPE(bool)
unsigned NoEscape : 1;
/// A biased RetainCountConventionKind, where 0 means "unspecified".
@ -488,6 +499,7 @@ public:
// unknown nullability.
/// Whether the signature has been audited with respect to nullability.
LLVM_PREFERRED_TYPE(bool)
unsigned NullabilityAudited : 1;
/// Number of types whose nullability is encoded with the NullabilityPayload.
@ -597,16 +609,18 @@ inline bool operator!=(const FunctionInfo &LHS, const FunctionInfo &RHS) {
class ObjCMethodInfo : public FunctionInfo {
public:
/// Whether this is a designated initializer of its class.
LLVM_PREFERRED_TYPE(bool)
unsigned DesignatedInit : 1;
/// Whether this is a required initializer.
LLVM_PREFERRED_TYPE(bool)
unsigned RequiredInit : 1;
ObjCMethodInfo() : DesignatedInit(false), RequiredInit(false) {}
friend bool operator==(const ObjCMethodInfo &, const ObjCMethodInfo &);
ObjCMethodInfo &operator|=(const ObjCContextInfo &RHS) {
ObjCMethodInfo &operator|=(const ContextInfo &RHS) {
// Merge Nullability.
if (!NullabilityAudited) {
if (auto Nullable = RHS.getDefaultNullability()) {
@ -642,6 +656,12 @@ public:
GlobalFunctionInfo() {}
};
/// Describes API notes data for a C++ method.
class CXXMethodInfo : public FunctionInfo {
public:
CXXMethodInfo() {}
};
/// Describes API notes data for an enumerator.
class EnumConstantInfo : public CommonEntityInfo {
public:
@ -650,9 +670,16 @@ public:
/// Describes API notes data for a tag.
class TagInfo : public CommonTypeInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned HasFlagEnum : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsFlagEnum : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned SwiftCopyableSpecified : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned SwiftCopyable : 1;
public:
std::optional<std::string> SwiftImportAs;
std::optional<std::string> SwiftRetainOp;
@ -660,7 +687,9 @@ public:
std::optional<EnumExtensibilityKind> EnumExtensibility;
TagInfo() : HasFlagEnum(0), IsFlagEnum(0) {}
TagInfo()
: HasFlagEnum(0), IsFlagEnum(0), SwiftCopyableSpecified(false),
SwiftCopyable(false) {}
std::optional<bool> isFlagEnum() const {
if (HasFlagEnum)
@ -672,6 +701,15 @@ public:
IsFlagEnum = Value.value_or(false);
}
std::optional<bool> isSwiftCopyable() const {
return SwiftCopyableSpecified ? std::optional<bool>(SwiftCopyable)
: std::nullopt;
}
void setSwiftCopyable(std::optional<bool> Value) {
SwiftCopyableSpecified = Value.has_value();
SwiftCopyable = Value.value_or(false);
}
TagInfo &operator|=(const TagInfo &RHS) {
static_cast<CommonTypeInfo &>(*this) |= RHS;
@ -688,6 +726,9 @@ public:
if (!EnumExtensibility)
EnumExtensibility = RHS.EnumExtensibility;
if (!SwiftCopyableSpecified)
setSwiftCopyable(RHS.isSwiftCopyable());
return *this;
}
@ -702,6 +743,7 @@ inline bool operator==(const TagInfo &LHS, const TagInfo &RHS) {
LHS.SwiftRetainOp == RHS.SwiftRetainOp &&
LHS.SwiftReleaseOp == RHS.SwiftReleaseOp &&
LHS.isFlagEnum() == RHS.isFlagEnum() &&
LHS.isSwiftCopyable() == RHS.isSwiftCopyable() &&
LHS.EnumExtensibility == RHS.EnumExtensibility;
}
@ -753,6 +795,7 @@ enum class ContextKind : uint8_t {
ObjCClass = 0,
ObjCProtocol = 1,
Namespace = 2,
Tag = 3,
};
struct Context {

View file

@ -53,11 +53,10 @@ public:
bool IsSatisfied = false;
bool ContainsErrors = false;
/// \brief Pairs of unsatisfied atomic constraint expressions along with the
/// substituted constraint expr, if the template arguments could be
/// \brief The substituted constraint expr, if the template arguments could be
/// substituted into them, or a diagnostic if substitution resulted in an
/// invalid expression.
llvm::SmallVector<std::pair<const Expr *, Detail>, 4> Details;
llvm::SmallVector<Detail, 4> Details;
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &C) {
Profile(ID, C, ConstraintOwner, TemplateArgs);
@ -69,7 +68,7 @@ public:
bool HasSubstitutionFailure() {
for (const auto &Detail : Details)
if (Detail.second.dyn_cast<SubstitutionDiagnostic *>())
if (Detail.dyn_cast<SubstitutionDiagnostic *>())
return true;
return false;
}
@ -80,9 +79,7 @@ public:
/// substituted into them, or a diagnostic if substitution resulted in
/// an invalid expression.
using UnsatisfiedConstraintRecord =
std::pair<const Expr *,
llvm::PointerUnion<Expr *,
std::pair<SourceLocation, StringRef> *>>;
llvm::PointerUnion<Expr *, std::pair<SourceLocation, StringRef> *>;
/// \brief The result of a constraint satisfaction check, containing the
/// necessary information to diagnose an unsatisfied constraint.

View file

@ -23,6 +23,7 @@ namespace clang {
class ASTDeserializationListener; // layering violation because void* is ugly
class SemaConsumer; // layering violation required for safe SemaConsumer
class TagDecl;
class DeclaratorDecl;
class VarDecl;
class FunctionDecl;
class ImportDecl;
@ -105,7 +106,7 @@ public:
/// CompleteExternalDeclaration - Callback invoked at the end of a translation
/// unit to notify the consumer that the given external declaration should be
/// completed.
virtual void CompleteExternalDeclaration(VarDecl *D) {}
virtual void CompleteExternalDeclaration(DeclaratorDecl *D) {}
/// Callback invoked when an MSInheritanceAttr has been attached to a
/// CXXRecordDecl.

View file

@ -37,6 +37,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/TypeSize.h"
#include <optional>
@ -110,6 +111,9 @@ class VarTemplateDecl;
class VTableContextBase;
class XRayFunctionFilter;
/// A simple array of base specifiers.
typedef SmallVector<CXXBaseSpecifier *, 4> CXXCastPath;
namespace Builtin {
class Context;
@ -214,6 +218,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
DependentTypeOfExprTypes;
mutable llvm::ContextualFoldingSet<DependentDecltypeType, ASTContext &>
DependentDecltypeTypes;
mutable llvm::FoldingSet<PackIndexingType> DependentPackIndexingTypes;
mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
mutable llvm::FoldingSet<ObjCTypeParamType> ObjCTypeParamTypes;
mutable llvm::FoldingSet<SubstTemplateTypeParmType>
@ -247,6 +254,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
DependentBitIntTypes;
llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes;
mutable llvm::FoldingSet<CountAttributedType> CountAttributedTypes;
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage>
@ -255,6 +264,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
ASTContext&>
SubstTemplateTemplateParmPacks;
mutable llvm::ContextualFoldingSet<ArrayParameterType, ASTContext &>
ArrayParameterTypes;
/// The set of nested name specifiers.
///
/// This set is managed by the NestedNameSpecifier class.
@ -447,7 +459,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// initialization of another module).
struct PerModuleInitializers {
llvm::SmallVector<Decl*, 4> Initializers;
llvm::SmallVector<uint32_t, 4> LazyInitializers;
llvm::SmallVector<GlobalDeclID, 4> LazyInitializers;
void resolve(ASTContext &Ctx);
};
@ -456,6 +468,14 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// This is the top-level (C++20) Named module we are building.
Module *CurrentCXXNamedModule = nullptr;
/// Help structures to decide whether two `const Module *` belongs
/// to the same conceptual module to avoid the expensive to string comparison
/// if possible.
///
/// Not serialized intentionally.
llvm::StringMap<const Module *> PrimaryModuleNameMap;
llvm::DenseMap<const Module *, const Module *> SameModuleLookupSet;
static constexpr unsigned ConstantArrayTypesLog2InitSize = 8;
static constexpr unsigned GeneralTypesLog2InitSize = 9;
static constexpr unsigned FunctionProtoTypesLog2InitSize = 12;
@ -623,6 +643,9 @@ private:
/// address spaces (e.g. OpenCL/CUDA)
bool AddrSpaceMapMangling;
/// For performance, track whether any function effects are in use.
mutable bool AnyFunctionEffects = false;
const TargetInfo *Target = nullptr;
const TargetInfo *AuxTarget = nullptr;
clang::PrintingPolicy PrintingPolicy;
@ -715,6 +738,12 @@ public:
}
void Deallocate(void *Ptr) const {}
llvm::StringRef backupStr(llvm::StringRef S) const {
char *Buf = new (*this) char[S.size()];
std::copy(S.begin(), S.end(), Buf);
return llvm::StringRef(Buf, S.size());
}
/// Allocates a \c DeclListNode or returns one from the \c ListNodeFreeList
/// pool.
DeclListNode *AllocateDeclListNode(clang::NamedDecl *ND) {
@ -1051,7 +1080,7 @@ public:
/// or an ImportDecl nominating another module that has initializers.
void addModuleInitializer(Module *M, Decl *Init);
void addLazyModuleInitializers(Module *M, ArrayRef<uint32_t> IDs);
void addLazyModuleInitializers(Module *M, ArrayRef<GlobalDeclID> IDs);
/// Get the initializations to perform when importing a module, if any.
ArrayRef<Decl*> getModuleInitializers(Module *M);
@ -1062,6 +1091,12 @@ public:
/// Get module under construction, nullptr if this is not a C++20 module.
Module *getCurrentNamedModule() const { return CurrentCXXNamedModule; }
/// If the two module \p M1 and \p M2 are in the same module.
///
/// FIXME: The signature may be confusing since `clang::Module` means to
/// a module fragment or a module unit but not a C++20 module.
bool isInSameModule(const Module *M1, const Module *M2);
TranslationUnitDecl *getTranslationUnitDecl() const {
return TUDecl->getMostRecentDecl();
}
@ -1108,7 +1143,8 @@ public:
CanQualType BFloat16Ty;
CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
CanQualType VoidPtrTy, NullPtrTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnresolvedTemplateTy,
UnknownAnyTy;
CanQualType BuiltinFnTy;
CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
@ -1119,7 +1155,8 @@ public:
CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy;
CanQualType OCLQueueTy, OCLReserveIDTy;
CanQualType IncompleteMatrixIdxTy;
CanQualType OMPArraySectionTy, OMPArrayShapingTy, OMPIteratorTy;
CanQualType ArraySectionTy;
CanQualType OMPArrayShapingTy, OMPIteratorTy;
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
CanQualType Id##Ty;
#include "clang/Basic/OpenCLExtensionTypes.def"
@ -1134,6 +1171,8 @@ public:
#include "clang/Basic/RISCVVTypes.def"
#define WASM_TYPE(Name, Id, SingletonId) CanQualType SingletonId;
#include "clang/Basic/WebAssemblyReferenceTypes.def"
#define AMDGPU_TYPE(Name, Id, SingletonId) CanQualType SingletonId;
#include "clang/Basic/AMDGPUTypes.def"
// Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
mutable QualType AutoDeductTy; // Deduction against 'auto'.
@ -1160,6 +1199,12 @@ public:
/// in device compilation.
llvm::DenseSet<const FunctionDecl *> CUDAImplicitHostDeviceFunUsedByDevice;
/// For capturing lambdas with an explicit object parameter whose type is
/// derived from the lambda type, we need to perform derived-to-base
/// conversion so we can access the captures; the cast paths for that
/// are stored here.
llvm::DenseMap<const CXXMethodDecl *, CXXCastPath> LambdaCastPaths;
ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents,
SelectorTable &sels, Builtin::Context &builtins,
TranslationUnitKind TUKind);
@ -1242,6 +1287,14 @@ public:
/// space.
QualType removeAddrSpaceQualType(QualType T) const;
/// Return the "other" discriminator used for the pointer auth schema used for
/// vtable pointers in instances of the requested type.
uint16_t
getPointerAuthVTablePointerDiscriminator(const CXXRecordDecl *RD);
/// Return the "other" type-specific discriminator for the given type.
uint16_t getPointerAuthTypeDiscriminator(QualType T);
/// Apply Objective-C protocol qualifiers to the given type.
/// \param allowOnPointerType specifies if we can apply protocol
/// qualifiers on ObjCObjectPointerType. It can be set to true when
@ -1338,6 +1391,11 @@ public:
return CanQualType::CreateUnsafe(getPointerType((QualType) T));
}
QualType
getCountAttributedType(QualType T, Expr *CountExpr, bool CountInBytes,
bool OrNull,
ArrayRef<TypeCoupledDeclRefInfo> DependentDecls) const;
/// Return the uniqued reference to a type adjusted from the original
/// type to a new type.
QualType getAdjustedType(QualType Orig, QualType New) const;
@ -1357,6 +1415,10 @@ public:
/// type to the decayed type.
QualType getDecayedType(QualType Orig, QualType Decayed) const;
/// Return the uniqued reference to a specified array parameter type from the
/// original array type.
QualType getArrayParameterType(QualType Ty) const;
/// Return the uniqued reference to the atomic type for the specified
/// type.
QualType getAtomicType(QualType T) const;
@ -1713,6 +1775,11 @@ public:
/// C++11 decltype.
QualType getDecltypeType(Expr *e, QualType UnderlyingType) const;
QualType getPackIndexingType(QualType Pattern, Expr *IndexExpr,
bool FullySubstituted = false,
ArrayRef<QualType> Expansions = {},
int Index = -1) const;
/// Unary type transforms
QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
UnaryTransformType::UTTKind UKind) const;
@ -1738,6 +1805,13 @@ public:
QualType DeducedType,
bool IsDependent) const;
private:
QualType getDeducedTemplateSpecializationTypeInternal(TemplateName Template,
QualType DeducedType,
bool IsDependent,
QualType Canon) const;
public:
/// Return the unique reference to the type for the specified TagDecl
/// (struct/union/class/enum) decl.
QualType getTagDeclType(const TagDecl *Decl) const;
@ -2174,6 +2248,16 @@ public:
return getQualifiedType(type.getUnqualifiedType(), Qs);
}
/// \brief Return a type with the given __ptrauth qualifier.
QualType getPointerAuthType(QualType Ty, PointerAuthQualifier PointerAuth) {
assert(!Ty.getPointerAuth());
assert(PointerAuth);
Qualifiers Qs;
Qs.setPointerAuth(PointerAuth);
return getQualifiedType(Ty, Qs);
}
unsigned char getFixedPointScale(QualType Ty) const;
unsigned char getFixedPointIBits(QualType Ty) const;
llvm::FixedPointSemantics getFixedPointSemantics(QualType Ty) const;
@ -2405,12 +2489,18 @@ public:
unsigned getTargetDefaultAlignForAttributeAligned() const;
/// Return the alignment in bits that should be given to a
/// global variable with type \p T.
unsigned getAlignOfGlobalVar(QualType T) const;
/// global variable with type \p T. If \p VD is non-null it will be
/// considered specifically for the query.
unsigned getAlignOfGlobalVar(QualType T, const VarDecl *VD) const;
/// Return the alignment in characters that should be given to a
/// global variable with type \p T.
CharUnits getAlignOfGlobalVarInChars(QualType T) const;
/// global variable with type \p T. If \p VD is non-null it will be
/// considered specifically for the query.
CharUnits getAlignOfGlobalVarInChars(QualType T, const VarDecl *VD) const;
/// Return the minimum alignement as specified by the target. If \p VD is
/// non-null it may be used to identify external or weak variables.
unsigned getMinGlobalAlignOfVar(uint64_t Size, const VarDecl *VD) const;
/// Return a conservative estimate of the alignment of the specified
/// decl \p D.
@ -2571,7 +2661,11 @@ public:
///
/// \returns if this is an array type, the completely unqualified array type
/// that corresponds to it. Otherwise, returns T.getUnqualifiedType().
QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals);
QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals) const;
QualType getUnqualifiedArrayType(QualType T) const {
Qualifiers Quals;
return getUnqualifiedArrayType(T, Quals);
}
/// Determine whether the given types are equivalent after
/// cvr-qualifiers have been removed.
@ -2824,6 +2918,8 @@ public:
return AddrSpaceMapMangling || isTargetAddressSpace(AS);
}
bool hasAnyFunctionEffects() const { return AnyFunctionEffects; }
// Merges two exception specifications, such that the resulting
// exception spec is the union of both. For example, if either
// of them can throw something, the result can throw it as well.
@ -2967,6 +3063,10 @@ public:
// corresponding saturated type for a given fixed point type.
QualType getCorrespondingSaturatedType(QualType Ty) const;
// Per ISO N1169, this method accepts fixed point types and returns the
// corresponding non-saturated type for a given fixed point type.
QualType getCorrespondingUnsaturatedType(QualType Ty) const;
// This method accepts fixed point types and returns the corresponding signed
// type. Unlike getCorrespondingUnsignedType(), this only accepts unsigned
// fixed point types because there are unsigned integer types like bool and
@ -3150,9 +3250,6 @@ public:
/// valid feature names.
ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD) const;
std::vector<std::string>
filterFunctionTargetVersionAttrs(const TargetVersionAttr *TV) const;
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
const FunctionDecl *) const;
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
@ -3365,12 +3462,21 @@ public:
/// Whether a C++ static variable or CUDA/HIP kernel should be externalized.
bool shouldExternalize(const Decl *D) const;
/// Resolve the root record to be used to derive the vtable pointer
/// authentication policy for the specified record.
const CXXRecordDecl *
baseForVTableAuthentication(const CXXRecordDecl *ThisClass);
bool useAbbreviatedThunkName(GlobalDecl VirtualMethodDecl,
StringRef MangledName);
StringRef getCUIDHash() const;
private:
/// All OMPTraitInfo objects live in this collection, one per
/// `pragma omp [begin] declare variant` directive.
SmallVector<std::unique_ptr<OMPTraitInfo>, 4> OMPTraitInfoVector;
llvm::DenseMap<GlobalDecl, llvm::StringSet<>> ThunksToBeAbbreviated;
};
/// Insertion operator for diagnostics.
@ -3379,13 +3485,13 @@ const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
/// Utility function for constructing a nullary selector.
inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
const IdentifierInfo *II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(0, &II);
}
/// Utility function for constructing an unary selector.
inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) {
IdentifierInfo* II = &Ctx.Idents.get(name);
const IdentifierInfo *II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(1, &II);
}

View file

@ -27,6 +27,7 @@ namespace clang {
class FunctionTemplateDecl;
class Module;
class NamedDecl;
class NamespaceDecl;
class ObjCCategoryDecl;
class ObjCContainerDecl;
class ObjCInterfaceDecl;
@ -35,6 +36,7 @@ namespace clang {
class QualType;
class RecordDecl;
class TagDecl;
class TranslationUnitDecl;
class ValueDecl;
class VarDecl;
class VarTemplateDecl;
@ -147,6 +149,31 @@ public:
virtual void AddedAttributeToRecord(const Attr *Attr,
const RecordDecl *Record) {}
/// The parser find the named module declaration.
virtual void EnteringModulePurview() {}
/// An mangling number was added to a Decl
///
/// \param D The decl that got a mangling number
///
/// \param Number The mangling number that was added to the Decl
virtual void AddedManglingNumber(const Decl *D, unsigned Number) {}
/// An static local number was added to a Decl
///
/// \param D The decl that got a static local number
///
/// \param Number The static local number that was added to the Decl
virtual void AddedStaticLocalNumbers(const Decl *D, unsigned Number) {}
/// An anonymous namespace was added the translation unit decl
///
/// \param TU The translation unit decl that got a new anonymous namespace
///
/// \param AnonNamespace The anonymous namespace that was added
virtual void AddedAnonymousNamespace(const TranslationUnitDecl *TU,
NamespaceDecl *AnonNamespace) {}
// NOTE: If new methods are added they should also be added to
// MultiplexASTMutationListener.
};

View file

@ -23,7 +23,9 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TemplateArgumentVisitor.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/TypeVisitor.h"
#include "llvm/Support/SaveAndRestore.h"
namespace clang {
@ -48,8 +50,10 @@ struct {
void Visit(const Stmt *Node);
void Visit(const Type *T);
void Visit(QualType T);
void Visit(TypeLoc);
void Visit(const Decl *D);
void Visit(const CXXCtorInitializer *Init);
void Visit(const OpenACCClause *C);
void Visit(const OMPClause *C);
void Visit(const BlockDecl::Capture &C);
void Visit(const GenericSelectionExpr::ConstAssociation &A);
@ -64,6 +68,7 @@ class ASTNodeTraverser
public comments::ConstCommentVisitor<Derived, void,
const comments::FullComment *>,
public TypeVisitor<Derived>,
public TypeLocVisitor<Derived>,
public ConstAttrVisitor<Derived>,
public ConstTemplateArgumentVisitor<Derived> {
@ -71,6 +76,14 @@ class ASTNodeTraverser
/// not already been loaded.
bool Deserialize = false;
/// Tracks whether we should dump TypeLocs etc.
///
/// Detailed location information such as TypeLoc nodes is not usually
/// included in the dump (too verbose).
/// But when explicitly asked to dump a Loc node, we do so recursively,
/// including e.g. FunctionTypeLoc => ParmVarDecl => TypeLoc.
bool VisitLocs = false;
TraversalKind Traversal = TraversalKind::TK_AsIs;
NodeDelegateType &getNodeDelegate() {
@ -85,7 +98,7 @@ public:
void SetTraversalKind(TraversalKind TK) { Traversal = TK; }
TraversalKind GetTraversalKind() const { return Traversal; }
void Visit(const Decl *D) {
void Visit(const Decl *D, bool VisitLocs = false) {
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isImplicit())
return;
@ -94,7 +107,10 @@ public:
if (!D)
return;
ConstDeclVisitor<Derived>::Visit(D);
{
llvm::SaveAndRestore RestoreVisitLocs(this->VisitLocs, VisitLocs);
ConstDeclVisitor<Derived>::Visit(D);
}
for (const auto &A : D->attrs())
Visit(A);
@ -181,6 +197,17 @@ public:
});
}
void Visit(TypeLoc T) {
getNodeDelegate().AddChild([=] {
getNodeDelegate().Visit(T);
if (T.isNull())
return;
TypeLocVisitor<Derived>::Visit(T);
if (auto Inner = T.getNextTypeLoc())
Visit(Inner);
});
}
void Visit(const Attr *A) {
getNodeDelegate().AddChild([=] {
getNodeDelegate().Visit(A);
@ -213,6 +240,14 @@ public:
});
}
void Visit(const OpenACCClause *C) {
getNodeDelegate().AddChild([=] {
getNodeDelegate().Visit(C);
for (const auto *S : C->children())
Visit(S);
});
}
void Visit(const OMPClause *C) {
getNodeDelegate().AddChild([=] {
getNodeDelegate().Visit(C);
@ -286,6 +321,8 @@ public:
Visit(*QT);
else if (const auto *T = N.get<Type>())
Visit(T);
else if (const auto *TL = N.get<TypeLoc>())
Visit(*TL);
else if (const auto *C = N.get<CXXCtorInitializer>())
Visit(C);
else if (const auto *C = N.get<OMPClause>())
@ -346,7 +383,7 @@ public:
void VisitComplexType(const ComplexType *T) { Visit(T->getElementType()); }
void VisitLocInfoType(const LocInfoType *T) {
Visit(T->getTypeSourceInfo()->getType());
Visit(T->getTypeSourceInfo()->getTypeLoc());
}
void VisitPointerType(const PointerType *T) { Visit(T->getPointeeType()); }
void VisitBlockPointerType(const BlockPointerType *T) {
@ -385,6 +422,12 @@ public:
void VisitDecltypeType(const DecltypeType *T) {
Visit(T->getUnderlyingExpr());
}
void VisitPackIndexingType(const PackIndexingType *T) {
Visit(T->getPattern());
Visit(T->getIndexExpr());
}
void VisitUnaryTransformType(const UnaryTransformType *T) {
Visit(T->getBaseType());
}
@ -415,9 +458,55 @@ public:
if (!T->isSugared())
Visit(T->getPattern());
}
void VisitAutoType(const AutoType *T) {
for (const auto &Arg : T->getTypeConstraintArguments())
Visit(Arg);
}
// FIXME: ElaboratedType, DependentNameType,
// DependentTemplateSpecializationType, ObjCObjectType
// For TypeLocs, we automatically visit the inner type loc (pointee type etc).
// We must explicitly visit other lexically-nested nodes.
void VisitFunctionProtoTypeLoc(FunctionProtoTypeLoc TL) {
TypeLocVisitor<Derived>::VisitFunctionTypeLoc(TL);
for (const auto *Param : TL.getParams())
Visit(Param, /*VisitTypeLocs=*/true);
}
void VisitAutoTypeLoc(AutoTypeLoc TL) {
if (const auto *CR = TL.getConceptReference()) {
if (auto *Args = CR->getTemplateArgsAsWritten())
for (const auto &Arg : Args->arguments())
dumpTemplateArgumentLoc(Arg);
}
}
void VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) {
Visit(TL.getClassTInfo()->getTypeLoc());
}
void VisitVariableArrayTypeLoc(VariableArrayTypeLoc TL) {
Visit(TL.getSizeExpr());
}
void VisitDependentSizedArrayTypeLoc(DependentSizedArrayTypeLoc TL) {
Visit(TL.getSizeExpr());
}
void VisitDependentSizedExtVectorTypeLoc(DependentSizedExtVectorTypeLoc TL) {
Visit(cast<DependentSizedExtVectorType>(TL.getType())->getSizeExpr());
}
void VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) {
Visit(TL.getUnderlyingExpr());
}
void VisitDecltypeType(DecltypeType TL) {
Visit(TL.getUnderlyingExpr());
}
void VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL) {
for (unsigned I=0, N=TL.getNumArgs(); I < N; ++I)
dumpTemplateArgumentLoc(TL.getArgLoc(I));
}
void VisitDependentTemplateSpecializationTypeLoc(
DependentTemplateSpecializationTypeLoc TL) {
for (unsigned I=0, N=TL.getNumArgs(); I < N; ++I)
dumpTemplateArgumentLoc(TL.getArgLoc(I));
}
void VisitTypedefDecl(const TypedefDecl *D) { Visit(D->getUnderlyingType()); }
void VisitEnumConstantDecl(const EnumConstantDecl *D) {
@ -462,6 +551,8 @@ public:
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isCXXForRangeDecl())
return;
if (const auto *TSI = D->getTypeSourceInfo(); VisitLocs && TSI)
Visit(TSI->getTypeLoc());
if (D->hasInit())
Visit(D->getInit());
}
@ -604,7 +695,7 @@ public:
if (const auto *TC = D->getTypeConstraint())
Visit(TC->getImmediatelyDeclaredConstraint());
if (D->hasDefaultArgument())
Visit(D->getDefaultArgument(), SourceRange(),
Visit(D->getDefaultArgument().getArgument(), SourceRange(),
D->getDefaultArgStorage().getInheritedFrom(),
D->defaultArgumentWasInherited() ? "inherited from" : "previous");
}
@ -613,9 +704,9 @@ public:
if (const auto *E = D->getPlaceholderTypeConstraint())
Visit(E);
if (D->hasDefaultArgument())
Visit(D->getDefaultArgument(), SourceRange(),
D->getDefaultArgStorage().getInheritedFrom(),
D->defaultArgumentWasInherited() ? "inherited from" : "previous");
dumpTemplateArgumentLoc(
D->getDefaultArgument(), D->getDefaultArgStorage().getInheritedFrom(),
D->defaultArgumentWasInherited() ? "inherited from" : "previous");
}
void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) {
@ -717,6 +808,11 @@ public:
Visit(C);
}
void VisitOpenACCConstructStmt(const OpenACCConstructStmt *Node) {
for (const auto *C : Node->clauses())
Visit(C);
}
void VisitInitListExpr(const InitListExpr *ILE) {
if (auto *Filler = ILE->getArrayFiller()) {
Visit(Filler, "array_filler");
@ -748,6 +844,12 @@ public:
}
}
void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *E) {
if (E->hasExplicitTemplateArgs())
for (auto Arg : E->template_arguments())
Visit(Arg.getArgument());
}
void VisitRequiresExpr(const RequiresExpr *E) {
for (auto *D : E->getLocalParameters())
Visit(D);
@ -755,6 +857,12 @@ public:
Visit(R);
}
void VisitTypeTraitExpr(const TypeTraitExpr *E) {
// Argument types are not children of the TypeTraitExpr.
for (auto *A : E->getArgs())
Visit(A->getType());
}
void VisitLambdaExpr(const LambdaExpr *Node) {
if (Traversal == TK_IgnoreUnlessSpelledInSource) {
for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
@ -837,6 +945,14 @@ public:
Visit(TArg);
}
void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node) {
Visit(Node->getExpr());
}
void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node) {
Visit(Node->getExpr());
}
// Implements Visit methods for Attrs.
#include "clang/AST/AttrNodeTraverse.inc"
};

View file

@ -16,6 +16,7 @@
#include "clang/AST/ASTVector.h"
#include "clang/AST/DeclAccessPair.h"
#include "clang/AST/DeclID.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/Specifiers.h"
#include <cassert>
@ -56,6 +57,10 @@ public:
Decls.push_back(DeclAccessPair::make(D, AS), C);
}
void addLazyDecl(ASTContext &C, GlobalDeclID ID, AccessSpecifier AS) {
Decls.push_back(DeclAccessPair::makeLazy(ID.getRawValue(), AS), C);
}
/// Replaces the given declaration with the new one, once.
///
/// \return true if the set changed
@ -109,10 +114,10 @@ public:
void reserve(ASTContext &C, unsigned N) { Impl.reserve(C, N); }
void addLazyDecl(ASTContext &C, uintptr_t ID, AccessSpecifier AS) {
void addLazyDecl(ASTContext &C, GlobalDeclID ID, AccessSpecifier AS) {
assert(Impl.empty() || Impl.Decls.isLazy());
Impl.Decls.setLazy(true);
Impl.addDecl(C, reinterpret_cast<NamedDecl *>(ID << 2), AS);
Impl.addLazyDecl(C, ID, AS);
}
};

View file

@ -213,9 +213,9 @@ public:
}
Qualifiers readQualifiers() {
static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint32_t),
static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint64_t),
"update this if the value size changes");
uint32_t value = asImpl().readUInt32();
uint64_t value = asImpl().readUInt64();
return Qualifiers::fromOpaqueValue(value);
}
@ -244,6 +244,15 @@ public:
return FunctionProtoType::ExtParameterInfo::getFromOpaqueValue(value);
}
FunctionEffect readFunctionEffect() {
uint32_t value = asImpl().readUInt32();
return FunctionEffect::fromOpaqueInt32(value);
}
EffectConditionExpr readEffectConditionExpr() {
return EffectConditionExpr{asImpl().readExprRef()};
}
NestedNameSpecifier *readNestedNameSpecifier() {
auto &ctx = getASTContext();

View file

@ -196,9 +196,9 @@ public:
}
void writeQualifiers(Qualifiers value) {
static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint32_t),
static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint64_t),
"update this if the value size changes");
asImpl().writeUInt32(value.getAsOpaqueValue());
asImpl().writeUInt64(value.getAsOpaqueValue());
}
void writeExceptionSpecInfo(
@ -222,6 +222,14 @@ public:
asImpl().writeUInt32(epi.getOpaqueValue());
}
void writeFunctionEffect(FunctionEffect E) {
asImpl().writeUInt32(E.toOpaqueInt32());
}
void writeEffectConditionExpr(EffectConditionExpr CE) {
asImpl().writeExprRef(CE.getCondition());
}
void writeNestedNameSpecifier(NestedNameSpecifier *NNS) {
// Nested name specifiers usually aren't too long. I think that 8 would
// typically accommodate the vast majority.

View file

@ -14,6 +14,7 @@
#define LLVM_CLANG_AST_AVAILABILITY_H
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/VersionTuple.h"
@ -57,6 +58,68 @@ public:
bool isOtherPlatformSpec() const { return Version.empty(); }
};
class Decl;
/// Storage of availability attributes for a declaration.
struct AvailabilityInfo {
/// The domain is the platform for which this availability info applies to.
llvm::SmallString<32> Domain;
VersionTuple Introduced;
VersionTuple Deprecated;
VersionTuple Obsoleted;
bool Unavailable = false;
bool UnconditionallyDeprecated = false;
bool UnconditionallyUnavailable = false;
AvailabilityInfo() = default;
/// Determine if this AvailabilityInfo represents the default availability.
bool isDefault() const { return *this == AvailabilityInfo(); }
/// Check if the symbol has been obsoleted.
bool isObsoleted() const { return !Obsoleted.empty(); }
/// Check if the symbol is unavailable unconditionally or
/// on the active platform and os version.
bool isUnavailable() const {
return Unavailable || isUnconditionallyUnavailable();
}
/// Check if the symbol is unconditionally deprecated.
///
/// i.e. \code __attribute__((deprecated)) \endcode
bool isUnconditionallyDeprecated() const { return UnconditionallyDeprecated; }
/// Check if the symbol is unconditionally unavailable.
///
/// i.e. \code __attribute__((unavailable)) \endcode
bool isUnconditionallyUnavailable() const {
return UnconditionallyUnavailable;
}
AvailabilityInfo(StringRef Domain, VersionTuple I, VersionTuple D,
VersionTuple O, bool U, bool UD, bool UU)
: Domain(Domain), Introduced(I), Deprecated(D), Obsoleted(O),
Unavailable(U), UnconditionallyDeprecated(UD),
UnconditionallyUnavailable(UU) {}
friend bool operator==(const AvailabilityInfo &Lhs,
const AvailabilityInfo &Rhs);
public:
static AvailabilityInfo createFromDecl(const Decl *Decl);
};
inline bool operator==(const AvailabilityInfo &Lhs,
const AvailabilityInfo &Rhs) {
return std::tie(Lhs.Introduced, Lhs.Deprecated, Lhs.Obsoleted,
Lhs.Unavailable, Lhs.UnconditionallyDeprecated,
Lhs.UnconditionallyUnavailable) ==
std::tie(Rhs.Introduced, Rhs.Deprecated, Rhs.Obsoleted,
Rhs.Unavailable, Rhs.UnconditionallyDeprecated,
Rhs.UnconditionallyUnavailable);
}
} // end namespace clang
#endif

View file

@ -285,6 +285,9 @@ PLACEHOLDER_TYPE(Overload, OverloadTy)
// x->foo # if only contains non-static members
PLACEHOLDER_TYPE(BoundMember, BoundMemberTy)
// The type of an unresolved template. Used in UnresolvedLookupExpr.
PLACEHOLDER_TYPE(UnresolvedTemplate, UnresolvedTemplateTy)
// The type of an expression which refers to a pseudo-object,
// such as those introduced by Objective C's @property or
// VS.NET's __property declarations. A placeholder type. The
@ -320,7 +323,7 @@ PLACEHOLDER_TYPE(ARCUnbridgedCast, ARCUnbridgedCastTy)
PLACEHOLDER_TYPE(IncompleteMatrixIdx, IncompleteMatrixIdxTy)
// A placeholder type for OpenMP array sections.
PLACEHOLDER_TYPE(OMPArraySection, OMPArraySectionTy)
PLACEHOLDER_TYPE(ArraySection, ArraySectionTy)
// A placeholder type for OpenMP array shaping operation.
PLACEHOLDER_TYPE(OMPArrayShaping, OMPArrayShapingTy)

View file

@ -50,52 +50,69 @@ struct CommandInfo {
unsigned NumArgs : 4;
/// True if this command is a inline command (of any kind).
LLVM_PREFERRED_TYPE(bool)
unsigned IsInlineCommand : 1;
/// True if this command is a block command (of any kind).
LLVM_PREFERRED_TYPE(bool)
unsigned IsBlockCommand : 1;
/// True if this command is introducing a brief documentation
/// paragraph (\or an alias).
LLVM_PREFERRED_TYPE(bool)
unsigned IsBriefCommand : 1;
/// True if this command is \\returns or an alias.
LLVM_PREFERRED_TYPE(bool)
unsigned IsReturnsCommand : 1;
/// True if this command is introducing documentation for a function
/// parameter (\\param or an alias).
LLVM_PREFERRED_TYPE(bool)
unsigned IsParamCommand : 1;
/// True if this command is introducing documentation for
/// a template parameter (\\tparam or an alias).
LLVM_PREFERRED_TYPE(bool)
unsigned IsTParamCommand : 1;
/// True if this command is \\throws or an alias.
LLVM_PREFERRED_TYPE(bool)
unsigned IsThrowsCommand : 1;
/// True if this command is \\deprecated or an alias.
LLVM_PREFERRED_TYPE(bool)
unsigned IsDeprecatedCommand : 1;
/// True if this is a \\headerfile-like command.
LLVM_PREFERRED_TYPE(bool)
unsigned IsHeaderfileCommand : 1;
/// True if this is a \\par command.
LLVM_PREFERRED_TYPE(bool)
unsigned IsParCommand : 1;
/// True if we don't want to warn about this command being passed an empty
/// paragraph. Meaningful only for block commands.
LLVM_PREFERRED_TYPE(bool)
unsigned IsEmptyParagraphAllowed : 1;
/// True if this command is a verbatim-like block command.
///
/// A verbatim-like block command eats every character (except line starting
/// decorations) until matching end command is seen or comment end is hit.
LLVM_PREFERRED_TYPE(bool)
unsigned IsVerbatimBlockCommand : 1;
/// True if this command is an end command for a verbatim-like block.
LLVM_PREFERRED_TYPE(bool)
unsigned IsVerbatimBlockEndCommand : 1;
/// True if this command is a verbatim line command.
///
/// A verbatim-like line command eats everything until a newline is seen or
/// comment end is hit.
LLVM_PREFERRED_TYPE(bool)
unsigned IsVerbatimLineCommand : 1;
/// True if this command contains a declaration for the entity being
@ -105,20 +122,25 @@ struct CommandInfo {
/// \code
/// \fn void f(int a);
/// \endcode
LLVM_PREFERRED_TYPE(bool)
unsigned IsDeclarationCommand : 1;
/// True if verbatim-like line command is a function declaration.
LLVM_PREFERRED_TYPE(bool)
unsigned IsFunctionDeclarationCommand : 1;
/// True if block command is further describing a container API; such
/// as \@coclass, \@classdesign, etc.
LLVM_PREFERRED_TYPE(bool)
unsigned IsRecordLikeDetailCommand : 1;
/// True if block command is a container API; such as \@interface.
LLVM_PREFERRED_TYPE(bool)
unsigned IsRecordLikeDeclarationCommand : 1;
/// True if this command is unknown. This \c CommandInfo object was
/// created during parsing.
LLVM_PREFERRED_TYPE(bool)
unsigned IsUnknownCommand : 1;
};

View file

@ -18,6 +18,7 @@ class Command<string name> {
bit IsThrowsCommand = 0;
bit IsDeprecatedCommand = 0;
bit IsHeaderfileCommand = 0;
bit IsParCommand = 0;
bit IsEmptyParagraphAllowed = 0;
@ -132,9 +133,9 @@ def Tparam : BlockCommand<"tparam"> { let IsTParamCommand = 1; }
// HeaderDoc command for template parameter documentation.
def Templatefield : BlockCommand<"templatefield"> { let IsTParamCommand = 1; }
def Throws : BlockCommand<"throws"> { let IsThrowsCommand = 1; }
def Throw : BlockCommand<"throw"> { let IsThrowsCommand = 1; }
def Exception : BlockCommand<"exception"> { let IsThrowsCommand = 1; }
def Throws : BlockCommand<"throws"> { let IsThrowsCommand = 1; let NumArgs = 1; }
def Throw : BlockCommand<"throw"> { let IsThrowsCommand = 1; let NumArgs = 1; }
def Exception : BlockCommand<"exception"> { let IsThrowsCommand = 1; let NumArgs = 1;}
def Deprecated : BlockCommand<"deprecated"> {
let IsEmptyParagraphAllowed = 1;
@ -156,7 +157,7 @@ def Date : BlockCommand<"date">;
def Invariant : BlockCommand<"invariant">;
def Li : BlockCommand<"li">;
def Note : BlockCommand<"note">;
def Par : BlockCommand<"par">;
def Par : BlockCommand<"par"> { let IsParCommand = 1; let NumArgs = 1; }
def Post : BlockCommand<"post">;
def Pre : BlockCommand<"pre">;
def Remark : BlockCommand<"remark">;

View file

@ -100,6 +100,14 @@ public:
ArrayRef<Comment::Argument>
parseCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs);
/// Parse arguments for \throws command supported args are in form of class
/// or template.
ArrayRef<Comment::Argument>
parseThrowCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs);
ArrayRef<Comment::Argument>
parseParCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs);
BlockCommandComment *parseBlockCommand();
InlineCommandComment *parseInlineCommand();
@ -118,4 +126,3 @@ public:
} // end namespace clang
#endif

View file

@ -78,7 +78,7 @@ class ComparisonCategoryInfo {
friend class Sema;
public:
ComparisonCategoryInfo(const ASTContext &Ctx, CXXRecordDecl *RD,
ComparisonCategoryInfo(const ASTContext &Ctx, const CXXRecordDecl *RD,
ComparisonCategoryType Kind)
: Ctx(Ctx), Record(RD), Kind(Kind) {}

View file

@ -63,6 +63,7 @@ class ArrayTypeTraitExpr;
class ExpressionTraitExpr;
class CXXNoexceptExpr;
class PackExpansionExpr;
class PackIndexingExpr;
class SubstNonTypeTemplateParmExpr;
class CoroutineSuspendExpr;
class DependentCoawaitExpr;
@ -93,7 +94,7 @@ class DesignatedInitExpr;
class ParenListExpr;
class PseudoObjectExpr;
class AtomicExpr;
class OMPArraySectionExpr;
class ArraySectionExpr;
class OMPArrayShapingExpr;
class OMPIteratorExpr;
class ObjCArrayLiteral;
@ -150,6 +151,7 @@ ExprDependence computeDependence(ArrayTypeTraitExpr *E);
ExprDependence computeDependence(ExpressionTraitExpr *E);
ExprDependence computeDependence(CXXNoexceptExpr *E, CanThrowResult CT);
ExprDependence computeDependence(PackExpansionExpr *E);
ExprDependence computeDependence(PackIndexingExpr *E);
ExprDependence computeDependence(SubstNonTypeTemplateParmExpr *E);
ExprDependence computeDependence(CoroutineSuspendExpr *E);
ExprDependence computeDependence(DependentCoawaitExpr *E);
@ -187,7 +189,7 @@ ExprDependence computeDependence(ParenListExpr *E);
ExprDependence computeDependence(PseudoObjectExpr *E);
ExprDependence computeDependence(AtomicExpr *E);
ExprDependence computeDependence(OMPArraySectionExpr *E);
ExprDependence computeDependence(ArraySectionExpr *E);
ExprDependence computeDependence(OMPArrayShapingExpr *E);
ExprDependence computeDependence(OMPIteratorExpr *E);

View file

@ -120,7 +120,7 @@ public:
ASTContext &getASTContext() const { return Ctx; }
NamespaceDecl *getAnonymousNamespace() const { return AnonymousNamespace; }
void setAnonymousNamespace(NamespaceDecl *D) { AnonymousNamespace = D; }
void setAnonymousNamespace(NamespaceDecl *D);
static TranslationUnitDecl *Create(ASTContext &C);
@ -157,7 +157,7 @@ public:
SourceLocation CommentLoc,
PragmaMSCommentKind CommentKind,
StringRef Arg);
static PragmaCommentDecl *CreateDeserialized(ASTContext &C, unsigned ID,
static PragmaCommentDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned ArgSize);
PragmaMSCommentKind getCommentKind() const { return CommentKind; }
@ -192,7 +192,7 @@ public:
SourceLocation Loc, StringRef Name,
StringRef Value);
static PragmaDetectMismatchDecl *
CreateDeserialized(ASTContext &C, unsigned ID, unsigned NameValueSize);
CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NameValueSize);
StringRef getName() const { return getTrailingObjects<char>(); }
StringRef getValue() const { return getTrailingObjects<char>() + ValueStart; }
@ -518,7 +518,7 @@ public:
static LabelDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation IdentL, IdentifierInfo *II,
SourceLocation GnuLabelL);
static LabelDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static LabelDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
LabelStmt *getStmt() const { return TheStmt; }
void setStmt(LabelStmt *T) { TheStmt = T; }
@ -542,12 +542,9 @@ public:
};
/// Represent a C++ namespace.
class NamespaceDecl : public NamedDecl, public DeclContext,
public Redeclarable<NamespaceDecl>
{
enum Flags : unsigned { F_Inline = 1 << 0, F_Nested = 1 << 1 };
class NamespaceDecl : public NamedDecl,
public DeclContext,
public Redeclarable<NamespaceDecl> {
/// The starting location of the source range, pointing
/// to either the namespace or the inline keyword.
SourceLocation LocStart;
@ -555,12 +552,8 @@ class NamespaceDecl : public NamedDecl, public DeclContext,
/// The ending location of the source range.
SourceLocation RBraceLoc;
/// A pointer to either the anonymous namespace that lives just inside
/// this namespace or to the first namespace in the chain (the latter case
/// only when this is not the first in the chain), along with a
/// boolean value indicating whether this is an inline namespace.
llvm::PointerIntPair<NamespaceDecl *, 2, unsigned>
AnonOrFirstNamespaceAndFlags;
/// The unnamed namespace that inhabits this namespace, if any.
NamespaceDecl *AnonymousNamespace = nullptr;
NamespaceDecl(ASTContext &C, DeclContext *DC, bool Inline,
SourceLocation StartLoc, SourceLocation IdLoc,
@ -581,7 +574,7 @@ public:
IdentifierInfo *Id, NamespaceDecl *PrevDecl,
bool Nested);
static NamespaceDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static NamespaceDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
using redecl_range = redeclarable_base::redecl_range;
using redecl_iterator = redeclarable_base::redecl_iterator;
@ -607,35 +600,19 @@ public:
}
/// Returns true if this is an inline namespace declaration.
bool isInline() const {
return AnonOrFirstNamespaceAndFlags.getInt() & F_Inline;
}
bool isInline() const { return NamespaceDeclBits.IsInline; }
/// Set whether this is an inline namespace declaration.
void setInline(bool Inline) {
unsigned F = AnonOrFirstNamespaceAndFlags.getInt();
if (Inline)
AnonOrFirstNamespaceAndFlags.setInt(F | F_Inline);
else
AnonOrFirstNamespaceAndFlags.setInt(F & ~F_Inline);
}
void setInline(bool Inline) { NamespaceDeclBits.IsInline = Inline; }
/// Returns true if this is a nested namespace declaration.
/// \code
/// namespace outer::nested { }
/// \endcode
bool isNested() const {
return AnonOrFirstNamespaceAndFlags.getInt() & F_Nested;
}
bool isNested() const { return NamespaceDeclBits.IsNested; }
/// Set whether this is a nested namespace declaration.
void setNested(bool Nested) {
unsigned F = AnonOrFirstNamespaceAndFlags.getInt();
if (Nested)
AnonOrFirstNamespaceAndFlags.setInt(F | F_Nested);
else
AnonOrFirstNamespaceAndFlags.setInt(F & ~F_Nested);
}
void setNested(bool Nested) { NamespaceDeclBits.IsNested = Nested; }
/// Returns true if the inline qualifier for \c Name is redundant.
bool isRedundantInlineQualifierFor(DeclarationName Name) const {
@ -649,34 +626,18 @@ public:
std::distance(Y.begin(), Y.end());
}
/// Get the original (first) namespace declaration.
NamespaceDecl *getOriginalNamespace();
/// Get the original (first) namespace declaration.
const NamespaceDecl *getOriginalNamespace() const;
/// Return true if this declaration is an original (first) declaration
/// of the namespace. This is false for non-original (subsequent) namespace
/// declarations and anonymous namespaces.
bool isOriginalNamespace() const;
/// Retrieve the anonymous namespace nested inside this namespace,
/// if any.
/// Retrieve the anonymous namespace that inhabits this namespace, if any.
NamespaceDecl *getAnonymousNamespace() const {
return getOriginalNamespace()->AnonOrFirstNamespaceAndFlags.getPointer();
return getFirstDecl()->AnonymousNamespace;
}
void setAnonymousNamespace(NamespaceDecl *D) {
getOriginalNamespace()->AnonOrFirstNamespaceAndFlags.setPointer(D);
getFirstDecl()->AnonymousNamespace = D;
}
/// Retrieves the canonical declaration of this namespace.
NamespaceDecl *getCanonicalDecl() override {
return getOriginalNamespace();
}
const NamespaceDecl *getCanonicalDecl() const {
return getOriginalNamespace();
}
NamespaceDecl *getCanonicalDecl() override { return getFirstDecl(); }
const NamespaceDecl *getCanonicalDecl() const { return getFirstDecl(); }
SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange(LocStart, RBraceLoc);
@ -1100,6 +1061,9 @@ protected:
LLVM_PREFERRED_TYPE(bool)
unsigned EscapingByref : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsCXXCondDecl : 1;
};
union {
@ -1143,7 +1107,7 @@ public:
const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, StorageClass S);
static VarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static VarDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY;
@ -1589,6 +1553,15 @@ public:
NonParmVarDeclBits.EscapingByref = true;
}
bool isCXXCondDecl() const {
return isa<ParmVarDecl>(this) ? false : NonParmVarDeclBits.IsCXXCondDecl;
}
void setCXXCondDecl() {
assert(!isa<ParmVarDecl>(this));
NonParmVarDeclBits.IsCXXCondDecl = true;
}
/// Determines if this variable's alignment is dependent.
bool hasDependentAlignment() const;
@ -1716,10 +1689,10 @@ public:
static ImplicitParamDecl *Create(ASTContext &C, QualType T,
ImplicitParamKind ParamKind);
static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ImplicitParamDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc,
IdentifierInfo *Id, QualType Type,
const IdentifierInfo *Id, QualType Type,
ImplicitParamKind ParamKind)
: VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type,
/*TInfo=*/nullptr, SC_None) {
@ -1753,7 +1726,7 @@ public:
protected:
ParmVarDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
SourceLocation IdLoc, const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg)
: VarDecl(DK, C, DC, StartLoc, IdLoc, Id, T, TInfo, S) {
assert(ParmVarDeclBits.HasInheritedDefaultArg == false);
@ -1765,12 +1738,12 @@ protected:
public:
static ParmVarDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo,
StorageClass S, Expr *DefArg);
SourceLocation StartLoc, SourceLocation IdLoc,
const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, StorageClass S,
Expr *DefArg);
static ParmVarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ParmVarDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY;
@ -1981,21 +1954,35 @@ public:
};
/// Stashed information about a defaulted function definition whose body has
/// not yet been lazily generated.
class DefaultedFunctionInfo final
: llvm::TrailingObjects<DefaultedFunctionInfo, DeclAccessPair> {
/// Stashed information about a defaulted/deleted function body.
class DefaultedOrDeletedFunctionInfo final
: llvm::TrailingObjects<DefaultedOrDeletedFunctionInfo, DeclAccessPair,
StringLiteral *> {
friend TrailingObjects;
unsigned NumLookups;
bool HasDeletedMessage;
size_t numTrailingObjects(OverloadToken<DeclAccessPair>) const {
return NumLookups;
}
public:
static DefaultedFunctionInfo *Create(ASTContext &Context,
ArrayRef<DeclAccessPair> Lookups);
static DefaultedOrDeletedFunctionInfo *
Create(ASTContext &Context, ArrayRef<DeclAccessPair> Lookups,
StringLiteral *DeletedMessage = nullptr);
/// Get the unqualified lookup results that should be used in this
/// defaulted function definition.
ArrayRef<DeclAccessPair> getUnqualifiedLookups() const {
return {getTrailingObjects<DeclAccessPair>(), NumLookups};
}
StringLiteral *getDeletedMessage() const {
return HasDeletedMessage ? *getTrailingObjects<StringLiteral *>()
: nullptr;
}
void setDeletedMessage(StringLiteral *Message);
};
private:
@ -2005,12 +1992,12 @@ private:
ParmVarDecl **ParamInfo = nullptr;
/// The active member of this union is determined by
/// FunctionDeclBits.HasDefaultedFunctionInfo.
/// FunctionDeclBits.HasDefaultedOrDeletedInfo.
union {
/// The body of the function.
LazyDeclStmtPtr Body;
/// Information about a future defaulted function definition.
DefaultedFunctionInfo *DefaultedInfo;
DefaultedOrDeletedFunctionInfo *DefaultedOrDeletedInfo;
};
unsigned ODRHash;
@ -2070,13 +2057,12 @@ private:
///
/// \param PointOfInstantiation point at which the function template
/// specialization was first instantiated.
void setFunctionTemplateSpecialization(ASTContext &C,
FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
void *InsertPos,
TemplateSpecializationKind TSK,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation PointOfInstantiation);
void setFunctionTemplateSpecialization(
ASTContext &C, FunctionTemplateDecl *Template,
TemplateArgumentList *TemplateArgs, void *InsertPos,
TemplateSpecializationKind TSK,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation PointOfInstantiation);
/// Specify that this record is an instantiation of the
/// member function FD.
@ -2152,7 +2138,7 @@ public:
bool hasWrittenPrototype, ConstexprSpecKind ConstexprKind,
Expr *TrailingRequiresClause);
static FunctionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static FunctionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
DeclarationNameInfo getNameInfo() const {
return DeclarationNameInfo(getDeclName(), getLocation(), DNLoc);
@ -2163,6 +2149,8 @@ public:
void setRangeEnd(SourceLocation E) { EndRangeLoc = E; }
void setDeclarationNameLoc(DeclarationNameLoc L) { DNLoc = L; }
/// Returns the location of the ellipsis of a variadic function.
SourceLocation getEllipsisLoc() const {
const auto *FPT = getType()->getAs<FunctionProtoType>();
@ -2268,18 +2256,18 @@ public:
/// Returns whether this specific declaration of the function has a body.
bool doesThisDeclarationHaveABody() const {
return (!FunctionDeclBits.HasDefaultedFunctionInfo && Body) ||
return (!FunctionDeclBits.HasDefaultedOrDeletedInfo && Body) ||
isLateTemplateParsed();
}
void setBody(Stmt *B);
void setLazyBody(uint64_t Offset) {
FunctionDeclBits.HasDefaultedFunctionInfo = false;
FunctionDeclBits.HasDefaultedOrDeletedInfo = false;
Body = LazyDeclStmtPtr(Offset);
}
void setDefaultedFunctionInfo(DefaultedFunctionInfo *Info);
DefaultedFunctionInfo *getDefaultedFunctionInfo() const;
void setDefaultedOrDeletedInfo(DefaultedOrDeletedFunctionInfo *Info);
DefaultedOrDeletedFunctionInfo *getDefalutedOrDeletedInfo() const;
/// Whether this function is variadic.
bool isVariadic() const;
@ -2482,7 +2470,7 @@ public:
return FunctionDeclBits.IsDeleted && !isDefaulted();
}
void setDeletedAsWritten(bool D = true) { FunctionDeclBits.IsDeleted = D; }
void setDeletedAsWritten(bool D = true, StringLiteral *Message = nullptr);
/// Determines whether this function is "main", which is the
/// entry point into an executable program.
@ -2615,10 +2603,18 @@ public:
/// the target functionality.
bool isTargetMultiVersion() const;
/// True if this function is the default version of a multiversioned dispatch
/// function as a part of the target functionality.
bool isTargetMultiVersionDefault() const;
/// True if this function is a multiversioned dispatch function as a part of
/// the target-clones functionality.
bool isTargetClonesMultiVersion() const;
/// True if this function is a multiversioned dispatch function as a part of
/// the target-version functionality.
bool isTargetVersionMultiVersion() const;
/// \brief Get the associated-constraints of this function declaration.
/// Currently, this will either be a vector of size 1 containing the
/// trailing-requires-clause or an empty vector.
@ -2630,6 +2626,13 @@ public:
AC.push_back(TRC);
}
/// Get the message that indicates why this function was deleted.
StringLiteral *getDeletedMessage() const {
return FunctionDeclBits.HasDefaultedOrDeletedInfo
? DefaultedOrDeletedInfo->getDeletedMessage()
: nullptr;
}
void setPreviousDeclaration(FunctionDecl * PrevDecl);
FunctionDecl *getCanonicalDecl() override;
@ -2940,12 +2943,12 @@ public:
///
/// \param PointOfInstantiation point at which the function template
/// specialization was first instantiated.
void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs,
void *InsertPos,
TemplateSpecializationKind TSK = TSK_ImplicitInstantiation,
const TemplateArgumentListInfo *TemplateArgsAsWritten = nullptr,
SourceLocation PointOfInstantiation = SourceLocation()) {
void setFunctionTemplateSpecialization(
FunctionTemplateDecl *Template, TemplateArgumentList *TemplateArgs,
void *InsertPos,
TemplateSpecializationKind TSK = TSK_ImplicitInstantiation,
TemplateArgumentListInfo *TemplateArgsAsWritten = nullptr,
SourceLocation PointOfInstantiation = SourceLocation()) {
setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs,
InsertPos, TSK, TemplateArgsAsWritten,
PointOfInstantiation);
@ -3000,6 +3003,16 @@ public:
/// computed and stored.
unsigned getODRHash() const;
FunctionEffectsRef getFunctionEffects() const {
// Effects may differ between declarations, but they should be propagated
// from old to new on any redeclaration, so it suffices to look at
// getMostRecentDecl().
if (const auto *FPT =
getMostRecentDecl()->getType()->getAs<FunctionProtoType>())
return FPT->getFunctionEffects();
return {};
}
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
@ -3075,7 +3088,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable<FieldDecl> {
protected:
FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
SourceLocation IdLoc, const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
InClassInitStyle InitStyle)
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), BitField(false),
@ -3091,11 +3104,11 @@ public:
static FieldDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T,
const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
InClassInitStyle InitStyle);
static FieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static FieldDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
/// Returns the index of this field within its record,
/// as appropriate for passing to ASTRecordLayout::getFieldOffset.
@ -3108,7 +3121,7 @@ public:
bool isBitField() const { return BitField; }
/// Determines whether this is an unnamed bitfield.
bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); }
bool isUnnamedBitField() const { return isBitField() && !getDeclName(); }
/// Determines whether this field is a
/// representative for an anonymous struct or union. Such fields are
@ -3270,7 +3283,7 @@ public:
SourceLocation L, IdentifierInfo *Id,
QualType T, Expr *E,
const llvm::APSInt &V);
static EnumConstantDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static EnumConstantDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
const Expr *getInitExpr() const { return (const Expr*) Init; }
Expr *getInitExpr() { return (Expr*) Init; }
@ -3312,10 +3325,11 @@ public:
friend class ASTDeclReader;
static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
QualType T, llvm::MutableArrayRef<NamedDecl *> CH);
SourceLocation L, const IdentifierInfo *Id,
QualType T,
llvm::MutableArrayRef<NamedDecl *> CH);
static IndirectFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static IndirectFieldDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
using chain_iterator = ArrayRef<NamedDecl *>::const_iterator;
@ -3361,9 +3375,9 @@ class TypeDecl : public NamedDecl {
void anchor() override;
protected:
TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, const IdentifierInfo *Id,
SourceLocation StartL = SourceLocation())
: NamedDecl(DK, DC, L, Id), LocStart(StartL) {}
: NamedDecl(DK, DC, L, Id), LocStart(StartL) {}
public:
// Low-level accessor. If you just want the type defined by this node,
@ -3405,7 +3419,7 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable<TypedefNameDecl> {
protected:
TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, TypeSourceInfo *TInfo)
const IdentifierInfo *Id, TypeSourceInfo *TInfo)
: TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C),
MaybeModedTInfo(TInfo, 0) {}
@ -3492,14 +3506,15 @@ private:
/// type specifier.
class TypedefDecl : public TypedefNameDecl {
TypedefDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo)
SourceLocation IdLoc, const IdentifierInfo *Id,
TypeSourceInfo *TInfo)
: TypedefNameDecl(Typedef, C, DC, StartLoc, IdLoc, Id, TInfo) {}
public:
static TypedefDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, TypeSourceInfo *TInfo);
static TypedefDecl *CreateDeserialized(ASTContext &C, unsigned ID);
const IdentifierInfo *Id, TypeSourceInfo *TInfo);
static TypedefDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY;
@ -3515,15 +3530,16 @@ class TypeAliasDecl : public TypedefNameDecl {
TypeAliasTemplateDecl *Template;
TypeAliasDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo)
SourceLocation IdLoc, const IdentifierInfo *Id,
TypeSourceInfo *TInfo)
: TypedefNameDecl(TypeAlias, C, DC, StartLoc, IdLoc, Id, TInfo),
Template(nullptr) {}
public:
static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, TypeSourceInfo *TInfo);
static TypeAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID);
const IdentifierInfo *Id, TypeSourceInfo *TInfo);
static TypeAliasDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY;
@ -3933,7 +3949,7 @@ public:
IdentifierInfo *Id, EnumDecl *PrevDecl,
bool IsScoped, bool IsScopedUsingClassTag,
bool IsFixed);
static EnumDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static EnumDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
/// Overrides to provide correct range when there's an enum-base specifier
/// with forward declarations.
@ -4138,7 +4154,7 @@ public:
static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, RecordDecl* PrevDecl = nullptr);
static RecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
static RecordDecl *CreateDeserialized(const ASTContext &C, GlobalDeclID ID);
RecordDecl *getPreviousDecl() {
return cast_or_null<RecordDecl>(
@ -4389,7 +4405,7 @@ public:
StringLiteral *Str, SourceLocation AsmLoc,
SourceLocation RParenLoc);
static FileScopeAsmDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static FileScopeAsmDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceLocation getAsmLoc() const { return getLocation(); }
SourceLocation getRParenLoc() const { return RParenLoc; }
@ -4411,7 +4427,7 @@ public:
///
/// \note This is used in libInterpreter, clang -cc1 -fincremental-extensions
/// and in tools such as clang-repl.
class TopLevelStmtDecl : public Decl {
class TopLevelStmtDecl : public Decl, public DeclContext {
friend class ASTDeclReader;
friend class ASTDeclWriter;
@ -4419,26 +4435,30 @@ class TopLevelStmtDecl : public Decl {
bool IsSemiMissing = false;
TopLevelStmtDecl(DeclContext *DC, SourceLocation L, Stmt *S)
: Decl(TopLevelStmt, DC, L), Statement(S) {}
: Decl(TopLevelStmt, DC, L), DeclContext(TopLevelStmt), Statement(S) {}
virtual void anchor();
public:
static TopLevelStmtDecl *Create(ASTContext &C, Stmt *Statement);
static TopLevelStmtDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static TopLevelStmtDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
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;
}
void setStmt(Stmt *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; }
static DeclContext *castToDeclContext(const TopLevelStmtDecl *D) {
return static_cast<DeclContext *>(const_cast<TopLevelStmtDecl *>(D));
}
static TopLevelStmtDecl *castFromDeclContext(const DeclContext *DC) {
return static_cast<TopLevelStmtDecl *>(const_cast<DeclContext *>(DC));
}
};
/// Represents a block literal declaration, which is like an
@ -4515,7 +4535,7 @@ protected:
public:
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L);
static BlockDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static BlockDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceLocation getCaretLocation() const { return getLocation(); }
@ -4621,6 +4641,13 @@ public:
SourceRange getSourceRange() const override LLVM_READONLY;
FunctionEffectsRef getFunctionEffects() const {
if (const TypeSourceInfo *TSI = getSignatureAsWritten())
if (const auto *FPT = TSI->getType()->getAs<FunctionProtoType>())
return FPT->getFunctionEffects();
return {};
}
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Block; }
@ -4669,7 +4696,7 @@ public:
static CapturedDecl *Create(ASTContext &C, DeclContext *DC,
unsigned NumParams);
static CapturedDecl *CreateDeserialized(ASTContext &C, unsigned ID,
static CapturedDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned NumParams);
Stmt *getBody() const override;
@ -4803,7 +4830,7 @@ public:
SourceLocation EndLoc);
/// Create a new, deserialized module import declaration.
static ImportDecl *CreateDeserialized(ASTContext &C, unsigned ID,
static ImportDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned NumLocations);
/// Retrieve the module that was imported by the import declaration.
@ -4844,7 +4871,7 @@ private:
public:
static ExportDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation ExportLoc);
static ExportDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ExportDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceLocation getExportLoc() const { return getLocation(); }
SourceLocation getRBraceLoc() const { return RBraceLoc; }
@ -4883,7 +4910,7 @@ class EmptyDecl : public Decl {
public:
static EmptyDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L);
static EmptyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static EmptyDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Empty; }
@ -4909,7 +4936,7 @@ public:
bool CBuffer, SourceLocation KwLoc,
IdentifierInfo *ID, SourceLocation IDLoc,
SourceLocation LBrace);
static HLSLBufferDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static HLSLBufferDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange(getLocStart(), RBraceLoc);
@ -5001,6 +5028,11 @@ static constexpr StringRef getOpenMPVariantManglingSeparatorStr() {
return "$ompvariant";
}
/// Returns whether the given FunctionDecl has an __arm[_locally]_streaming
/// attribute.
bool IsArmStreamingFunction(const FunctionDecl *FD,
bool IncludeLocallyStreaming);
} // namespace clang
#endif // LLVM_CLANG_AST_DECL_H

View file

@ -19,6 +19,7 @@
#include "clang/Basic/Specifiers.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/Endian.h"
namespace clang {
@ -27,9 +28,17 @@ class NamedDecl;
/// A POD class for pairing a NamedDecl* with an access specifier.
/// Can be put into unions.
class DeclAccessPair {
uintptr_t Ptr; // we'd use llvm::PointerUnion, but it isn't trivial
/// Use the lower 2 bit to store AccessSpecifier. Use the higher
/// 61 bit to store the pointer to a NamedDecl or the DeclID to
/// a NamedDecl. If the 3rd bit is set, storing the DeclID, otherwise
/// storing the pointer.
llvm::support::detail::packed_endian_specific_integral<
uint64_t, llvm::endianness::native, alignof(void *)>
Ptr;
enum { Mask = 0x3 };
enum { ASMask = 0x3, Mask = 0x7 };
bool isDeclID() const { return (Ptr >> 2) & 0x1; }
public:
static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) {
@ -38,12 +47,22 @@ public:
return p;
}
static DeclAccessPair makeLazy(uint64_t ID, AccessSpecifier AS) {
DeclAccessPair p;
p.Ptr = (ID << 3) | (0x1 << 2) | uint64_t(AS);
return p;
}
uint64_t getDeclID() const {
assert(isDeclID());
return (~Mask & Ptr) >> 3;
}
NamedDecl *getDecl() const {
assert(!isDeclID());
return reinterpret_cast<NamedDecl*>(~Mask & Ptr);
}
AccessSpecifier getAccess() const {
return AccessSpecifier(Mask & Ptr);
}
AccessSpecifier getAccess() const { return AccessSpecifier(ASMask & Ptr); }
void setDecl(NamedDecl *D) {
set(D, getAccess());
@ -52,12 +71,18 @@ public:
set(getDecl(), AS);
}
void set(NamedDecl *D, AccessSpecifier AS) {
Ptr = uintptr_t(AS) | reinterpret_cast<uintptr_t>(D);
Ptr = uint64_t(AS) | reinterpret_cast<uint64_t>(D);
}
operator NamedDecl*() const { return getDecl(); }
NamedDecl *operator->() const { return getDecl(); }
};
// Make sure DeclAccessPair is pointer-aligned types.
static_assert(alignof(DeclAccessPair) == alignof(void *));
// Make sure DeclAccessPair is still POD.
static_assert(std::is_standard_layout_v<DeclAccessPair> &&
std::is_trivial_v<DeclAccessPair>);
}
#endif

View file

@ -15,6 +15,7 @@
#include "clang/AST/ASTDumperUtils.h"
#include "clang/AST/AttrIterator.h"
#include "clang/AST/DeclID.h"
#include "clang/AST/DeclarationName.h"
#include "clang/AST/SelectorLocationsKind.h"
#include "clang/Basic/IdentifierTable.h"
@ -358,7 +359,7 @@ protected:
/// \param Ctx The context in which we will allocate memory.
/// \param ID The global ID of the deserialized declaration.
/// \param Extra The amount of extra space to allocate after the object.
void *operator new(std::size_t Size, const ASTContext &Ctx, unsigned ID,
void *operator new(std::size_t Size, const ASTContext &Ctx, GlobalDeclID ID,
std::size_t Extra = 0);
/// Allocate memory for a non-deserialized declaration.
@ -669,19 +670,11 @@ public:
/// 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; }
/// Whether this declaration comes from explicit global module.
bool isFromExplicitGlobalModule() const;
/// Check if we should skip checking ODRHash for declaration \param D.
///
/// The existing ODRHash mechanism seems to be not stable enough and
/// the false positive ODR violation reports are annoying and we rarely see
/// true ODR violation reports. Also we learned that MSVC disabled ODR checks
/// for declarations in GMF. So we try to disable ODR checks in the GMF to
/// get better user experiences before we make the ODR violation checks stable
/// enough.
bool shouldSkipCheckingODR() const;
/// Whether this declaration comes from a named module.
bool isInNamedModule() const;
/// Return true if this declaration has an attribute which acts as
/// definition of the entity, such as 'alias' or 'ifunc'.
@ -711,10 +704,7 @@ public:
/// Set the owning module ID. This may only be called for
/// deserialized Decls.
void setOwningModuleID(unsigned ID) {
assert(isFromASTFile() && "Only works on a deserialized declaration");
*((unsigned*)this - 2) = ID;
}
void setOwningModuleID(unsigned ID);
public:
/// Determine the availability of the given declaration.
@ -787,19 +777,11 @@ public:
/// Retrieve the global declaration ID associated with this
/// declaration, which specifies where this Decl was loaded from.
unsigned getGlobalID() const {
if (isFromASTFile())
return *((const unsigned*)this - 1);
return 0;
}
GlobalDeclID getGlobalID() const;
/// Retrieve the global ID of the module that owns this particular
/// declaration.
unsigned getOwningModuleID() const {
if (isFromASTFile())
return *((const unsigned*)this - 2);
return 0;
}
unsigned getOwningModuleID() const;
private:
Module *getOwningModuleSlow() const;
@ -846,10 +828,7 @@ public:
/// Get the module that owns this declaration for linkage purposes.
/// 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.
Module *getOwningModuleForLinkage(bool IgnoreLinkage = false) const;
Module *getOwningModuleForLinkage() const;
/// Determine whether this declaration is definitely visible to name lookup,
/// independent of whether the owning module is visible.
@ -1508,6 +1487,27 @@ class DeclContext {
/// Number of bits in DeclContextBitfields.
enum { NumDeclContextBits = 13 };
/// Stores the bits used by NamespaceDecl.
/// If modified NumNamespaceDeclBits and the accessor
/// methods in NamespaceDecl should be updated appropriately.
class NamespaceDeclBitfields {
friend class NamespaceDecl;
/// For the bits in DeclContextBitfields
LLVM_PREFERRED_TYPE(DeclContextBitfields)
uint64_t : NumDeclContextBits;
/// True if this is an inline namespace.
LLVM_PREFERRED_TYPE(bool)
uint64_t IsInline : 1;
/// True if this is a nested-namespace-definition.
LLVM_PREFERRED_TYPE(bool)
uint64_t IsNested : 1;
};
/// Number of inherited and non-inherited bits in NamespaceDeclBitfields.
enum { NumNamespaceDeclBits = NumDeclContextBits + 2 };
/// Stores the bits used by TagDecl.
/// If modified NumTagDeclBits and the accessor
/// methods in TagDecl should be updated appropriately.
@ -1740,7 +1740,7 @@ class DeclContext {
LLVM_PREFERRED_TYPE(bool)
uint64_t IsExplicitlyDefaulted : 1;
LLVM_PREFERRED_TYPE(bool)
uint64_t HasDefaultedFunctionInfo : 1;
uint64_t HasDefaultedOrDeletedInfo : 1;
/// For member functions of complete types, whether this is an ineligible
/// special member function or an unselected destructor. See
@ -2006,6 +2006,7 @@ protected:
/// 8 bytes with static_asserts in the ctor of DeclContext.
union {
DeclContextBitfields DeclContextBits;
NamespaceDeclBitfields NamespaceDeclBits;
TagDeclBitfields TagDeclBits;
EnumDeclBitfields EnumDeclBits;
RecordDeclBitfields RecordDeclBits;
@ -2019,6 +2020,8 @@ protected:
static_assert(sizeof(DeclContextBitfields) <= 8,
"DeclContextBitfields is larger than 8 bytes!");
static_assert(sizeof(NamespaceDeclBitfields) <= 8,
"NamespaceDeclBitfields is larger than 8 bytes!");
static_assert(sizeof(TagDeclBitfields) <= 8,
"TagDeclBitfields is larger than 8 bytes!");
static_assert(sizeof(EnumDeclBitfields) <= 8,
@ -2130,6 +2133,7 @@ public:
case Decl::Block:
case Decl::Captured:
case Decl::ObjCMethod:
case Decl::TopLevelStmt:
return true;
default:
return getDeclKind() >= Decl::firstFunction &&
@ -2157,6 +2161,10 @@ public:
getDeclKind() <= Decl::lastRecord;
}
bool isRequiresExprBody() const {
return getDeclKind() == Decl::RequiresExprBody;
}
bool isNamespace() const { return getDeclKind() == Decl::Namespace; }
bool isStdNamespace() const;

View file

@ -120,7 +120,7 @@ public:
return new (C, DC) AccessSpecDecl(AS, DC, ASLoc, ColonLoc);
}
static AccessSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static AccessSpecDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@ -579,7 +579,8 @@ public:
TypeSourceInfo *Info, SourceLocation Loc,
unsigned DependencyKind, bool IsGeneric,
LambdaCaptureDefault CaptureDefault);
static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
static CXXRecordDecl *CreateDeserialized(const ASTContext &C,
GlobalDeclID ID);
bool isDynamicClass() const {
return data().Polymorphic || data().NumVBases != 0;
@ -1869,6 +1870,10 @@ public:
DL.MethodTyInfo = TS;
}
void setLambdaDependencyKind(unsigned Kind) {
getLambdaData().DependencyKind = Kind;
}
void setLambdaIsGeneric(bool IsGeneric) {
assert(DefinitionData && DefinitionData->IsLambda &&
"setting lambda property of non-lambda class");
@ -1976,7 +1981,8 @@ public:
CXXConstructorDecl *Ctor = nullptr,
DeductionCandidate Kind = DeductionCandidate::Normal);
static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
ExplicitSpecifier getExplicitSpecifier() { return ExplicitSpec; }
const ExplicitSpecifier getExplicitSpecifier() const { return ExplicitSpec; }
@ -2031,7 +2037,8 @@ public:
static RequiresExprBodyDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc);
static RequiresExprBodyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static RequiresExprBodyDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@ -2074,7 +2081,7 @@ public:
ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
Expr *TrailingRequiresClause = nullptr);
static CXXMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static CXXMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
bool isStatic() const;
bool isInstance() const { return !isStatic(); }
@ -2575,7 +2582,7 @@ public:
friend class ASTDeclWriter;
friend TrailingObjects;
static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID,
static CXXConstructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
uint64_t AllocKind);
static CXXConstructorDecl *
Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
@ -2818,7 +2825,7 @@ public:
bool UsesFPIntrin, bool isInline, bool isImplicitlyDeclared,
ConstexprSpecKind ConstexprKind,
Expr *TrailingRequiresClause = nullptr);
static CXXDestructorDecl *CreateDeserialized(ASTContext & C, unsigned ID);
static CXXDestructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
void setOperatorDelete(FunctionDecl *OD, Expr *ThisArg);
@ -2877,7 +2884,7 @@ public:
bool UsesFPIntrin, bool isInline, ExplicitSpecifier ES,
ConstexprSpecKind ConstexprKind, SourceLocation EndLocation,
Expr *TrailingRequiresClause = nullptr);
static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static CXXConversionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
ExplicitSpecifier getExplicitSpecifier() {
return getCanonicalDecl()->ExplicitSpec;
@ -2944,7 +2951,7 @@ public:
SourceLocation ExternLoc,
SourceLocation LangLoc,
LinkageSpecLanguageIDs Lang, bool HasBraces);
static LinkageSpecDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static LinkageSpecDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
/// Return the language specified by this linkage specification.
LinkageSpecLanguageIDs getLanguage() const {
@ -3092,7 +3099,7 @@ public:
SourceLocation IdentLoc,
NamedDecl *Nominated,
DeclContext *CommonAncestor);
static UsingDirectiveDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static UsingDirectiveDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY {
return SourceRange(UsingLoc, getLocation());
@ -3153,7 +3160,7 @@ public:
SourceLocation IdentLoc,
NamedDecl *Namespace);
static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
using redecl_range = redeclarable_base::redecl_range;
using redecl_iterator = redeclarable_base::redecl_iterator;
@ -3250,7 +3257,7 @@ public:
LifetimeExtendedTemporaryDecl(Temp, EDec, Mangling);
}
static LifetimeExtendedTemporaryDecl *CreateDeserialized(ASTContext &C,
unsigned ID) {
GlobalDeclID ID) {
return new (C, ID) LifetimeExtendedTemporaryDecl(EmptyShell{});
}
@ -3353,7 +3360,7 @@ public:
UsingShadowDecl(UsingShadow, C, DC, Loc, Name, Introducer, Target);
}
static UsingShadowDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static UsingShadowDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
using redecl_range = redeclarable_base::redecl_range;
using redecl_iterator = redeclarable_base::redecl_iterator;
@ -3562,7 +3569,7 @@ public:
const DeclarationNameInfo &NameInfo,
bool HasTypenameKeyword);
static UsingDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static UsingDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY;
@ -3641,7 +3648,7 @@ public:
UsingDecl *Using, NamedDecl *Target,
bool IsVirtual);
static ConstructorUsingShadowDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
GlobalDeclID ID);
/// Override the UsingShadowDecl's getIntroducer, returning the UsingDecl that
/// introduced this.
@ -3753,7 +3760,7 @@ public:
SourceLocation UsingL, SourceLocation EnumL,
SourceLocation NameL, TypeSourceInfo *EnumType);
static UsingEnumDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static UsingEnumDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY;
@ -3826,7 +3833,7 @@ public:
NamedDecl *InstantiatedFrom,
ArrayRef<NamedDecl *> UsingDecls);
static UsingPackDecl *CreateDeserialized(ASTContext &C, unsigned ID,
static UsingPackDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned NumExpansions);
SourceRange getSourceRange() const override LLVM_READONLY {
@ -3919,8 +3926,8 @@ public:
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo, SourceLocation EllipsisLoc);
static UnresolvedUsingValueDecl *
CreateDeserialized(ASTContext &C, unsigned ID);
static UnresolvedUsingValueDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY;
@ -4010,8 +4017,8 @@ public:
SourceLocation TargetNameLoc, DeclarationName TargetName,
SourceLocation EllipsisLoc);
static UnresolvedUsingTypenameDecl *
CreateDeserialized(ASTContext &C, unsigned ID);
static UnresolvedUsingTypenameDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
/// Retrieves the canonical declaration of this declaration.
UnresolvedUsingTypenameDecl *getCanonicalDecl() override {
@ -4041,7 +4048,7 @@ public:
SourceLocation Loc,
DeclarationName Name);
static UnresolvedUsingIfExistsDecl *CreateDeserialized(ASTContext &Ctx,
unsigned ID);
GlobalDeclID ID);
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) { return K == Decl::UnresolvedUsingIfExists; }
@ -4069,7 +4076,7 @@ public:
SourceLocation StaticAssertLoc,
Expr *AssertExpr, Expr *Message,
SourceLocation RParenLoc, bool Failed);
static StaticAssertDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static StaticAssertDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
Expr *getAssertExpr() { return AssertExprAndFailed.getPointer(); }
const Expr *getAssertExpr() const { return AssertExprAndFailed.getPointer(); }
@ -4116,7 +4123,7 @@ public:
static BindingDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation IdLoc, IdentifierInfo *Id);
static BindingDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static BindingDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
/// Get the expression to which this declaration is bound. This may be null
/// in two different cases: while parsing the initializer for the
@ -4185,7 +4192,7 @@ public:
QualType T, TypeSourceInfo *TInfo,
StorageClass S,
ArrayRef<BindingDecl *> Bindings);
static DecompositionDecl *CreateDeserialized(ASTContext &C, unsigned ID,
static DecompositionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned NumBindings);
ArrayRef<BindingDecl *> bindings() const {
@ -4242,7 +4249,7 @@ public:
SourceLocation L, DeclarationName N, QualType T,
TypeSourceInfo *TInfo, SourceLocation StartL,
IdentifierInfo *Getter, IdentifierInfo *Setter);
static MSPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static MSPropertyDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
static bool classof(const Decl *D) { return D->getKind() == MSProperty; }
@ -4296,7 +4303,7 @@ private:
MSGuidDecl(DeclContext *DC, QualType T, Parts P);
static MSGuidDecl *Create(const ASTContext &C, QualType T, Parts P);
static MSGuidDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static MSGuidDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
// Only ASTContext::getMSGuidDecl and deserialization create these.
friend class ASTContext;
@ -4349,7 +4356,7 @@ class UnnamedGlobalConstantDecl : public ValueDecl,
static UnnamedGlobalConstantDecl *Create(const ASTContext &C, QualType T,
const APValue &APVal);
static UnnamedGlobalConstantDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
GlobalDeclID ID);
// Only ASTContext::getUnnamedGlobalConstantDecl and deserialization create
// these.

View file

@ -42,11 +42,12 @@ class StoredDeclsList {
/// external declarations.
DeclsAndHasExternalTy Data;
template<typename Fn>
void erase_if(Fn ShouldErase) {
template <typename Fn> DeclListNode::Decls *erase_if(Fn ShouldErase) {
Decls List = Data.getPointer();
if (!List)
return;
return nullptr;
ASTContext &C = getASTContext();
DeclListNode::Decls NewHead = nullptr;
DeclListNode::Decls *NewLast = nullptr;
@ -79,6 +80,17 @@ class StoredDeclsList {
Data.setPointer(NewHead);
assert(llvm::none_of(getLookupResult(), ShouldErase) && "Still exists!");
if (!Data.getPointer())
// All declarations are erased.
return nullptr;
else if (NewHead.is<NamedDecl *>())
// The list only contains a declaration, the header itself.
return (DeclListNode::Decls *)&Data;
else {
assert(NewLast && NewLast->is<NamedDecl *>() && "Not the tail?");
return NewLast;
}
}
void erase(NamedDecl *ND) {
@ -160,12 +172,16 @@ public:
void replaceExternalDecls(ArrayRef<NamedDecl*> Decls) {
// Remove all declarations that are either external or are replaced with
// external declarations.
erase_if([Decls](NamedDecl *ND) {
// external declarations with higher visibilities.
DeclListNode::Decls *Tail = erase_if([Decls](NamedDecl *ND) {
if (ND->isFromASTFile())
return true;
// FIXME: Can we get rid of this loop completely?
for (NamedDecl *D : Decls)
if (D->declarationReplaces(ND, /*IsKnownNewer=*/false))
// Only replace the local declaration if the external declaration has
// higher visibilities.
if (D->getModuleOwnershipKind() <= ND->getModuleOwnershipKind() &&
D->declarationReplaces(ND, /*IsKnownNewer=*/false))
return true;
return false;
});
@ -185,27 +201,18 @@ public:
DeclsAsList = Node;
}
DeclListNode::Decls Head = Data.getPointer();
if (Head.isNull()) {
if (!Data.getPointer()) {
Data.setPointer(DeclsAsList);
return;
}
// Find the end of the existing list.
// FIXME: It would be possible to preserve information from erase_if to
// avoid this rescan looking for the end of the list.
DeclListNode::Decls *Tail = &Head;
while (DeclListNode *Node = Tail->dyn_cast<DeclListNode *>())
Tail = &Node->Rest;
// Append the Decls.
DeclListNode *Node = C.AllocateDeclListNode(Tail->get<NamedDecl *>());
Node->Rest = DeclsAsList;
*Tail = Node;
Data.setPointer(Head);
}
/// Return an array of all the decls that this list represents.
/// Return the list of all the decls.
DeclContext::lookup_result getLookupResult() const {
return DeclContext::lookup_result(Data.getPointer());
}

View file

@ -112,7 +112,7 @@ public:
Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_,
SourceLocation FriendL,
ArrayRef<TemplateParameterList *> FriendTypeTPLists = std::nullopt);
static FriendDecl *CreateDeserialized(ASTContext &C, unsigned ID,
static FriendDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned FriendTypeNumTPLists);
/// If this friend declaration names an (untemplated but possibly

View file

@ -0,0 +1,274 @@
//===--- DeclID.h - ID number for deserialized declarations ----*- 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 DeclID class family to describe the deserialized
// declarations. The DeclID is widely used in AST via LazyDeclPtr, or calls to
// `ExternalASTSource::getExternalDecl`. It will be helpful for type safety to
// require the use of `DeclID` to explicit.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_DECLID_H
#define LLVM_CLANG_AST_DECLID_H
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/iterator.h"
#include <climits>
namespace clang {
/// Predefined declaration IDs.
///
/// These declaration IDs correspond to predefined declarations in the AST
/// context, such as the NULL declaration ID. Such declarations are never
/// actually serialized, since they will be built by the AST context when
/// it is created.
enum PredefinedDeclIDs {
/// The NULL declaration.
PREDEF_DECL_NULL_ID = 0,
/// The translation unit.
PREDEF_DECL_TRANSLATION_UNIT_ID = 1,
/// The Objective-C 'id' type.
PREDEF_DECL_OBJC_ID_ID = 2,
/// The Objective-C 'SEL' type.
PREDEF_DECL_OBJC_SEL_ID = 3,
/// The Objective-C 'Class' type.
PREDEF_DECL_OBJC_CLASS_ID = 4,
/// The Objective-C 'Protocol' type.
PREDEF_DECL_OBJC_PROTOCOL_ID = 5,
/// The signed 128-bit integer type.
PREDEF_DECL_INT_128_ID = 6,
/// The unsigned 128-bit integer type.
PREDEF_DECL_UNSIGNED_INT_128_ID = 7,
/// The internal 'instancetype' typedef.
PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8,
/// The internal '__builtin_va_list' typedef.
PREDEF_DECL_BUILTIN_VA_LIST_ID = 9,
/// The internal '__va_list_tag' struct, if any.
PREDEF_DECL_VA_LIST_TAG = 10,
/// The internal '__builtin_ms_va_list' typedef.
PREDEF_DECL_BUILTIN_MS_VA_LIST_ID = 11,
/// The predeclared '_GUID' struct.
PREDEF_DECL_BUILTIN_MS_GUID_ID = 12,
/// The extern "C" context.
PREDEF_DECL_EXTERN_C_CONTEXT_ID = 13,
/// The internal '__make_integer_seq' template.
PREDEF_DECL_MAKE_INTEGER_SEQ_ID = 14,
/// The internal '__NSConstantString' typedef.
PREDEF_DECL_CF_CONSTANT_STRING_ID = 15,
/// The internal '__NSConstantString' tag type.
PREDEF_DECL_CF_CONSTANT_STRING_TAG_ID = 16,
/// The internal '__type_pack_element' template.
PREDEF_DECL_TYPE_PACK_ELEMENT_ID = 17,
};
/// The number of declaration IDs that are predefined.
///
/// For more information about predefined declarations, see the
/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
const unsigned int NUM_PREDEF_DECL_IDS = 18;
/// GlobalDeclID means DeclID in the current ASTContext and LocalDeclID means
/// DeclID specific to a certain ModuleFile. Specially, in ASTWriter, the
/// LocalDeclID to the ModuleFile been writting is equal to the GlobalDeclID.
/// Outside the serializer, all the DeclID been used should be GlobalDeclID.
/// We can translate a LocalDeclID to the GlobalDeclID by
/// `ASTReader::getGlobalDeclID()`.
class DeclIDBase {
public:
/// An ID number that refers to a declaration in an AST file.
///
/// The ID numbers of declarations are consecutive (in order of
/// discovery), with values below NUM_PREDEF_DECL_IDS being reserved.
/// At the start of a chain of precompiled headers, declaration ID 1 is
/// used for the translation unit declaration.
///
/// DeclID should only be used directly in serialization. All other users
/// should use LocalDeclID or GlobalDeclID.
using DeclID = uint64_t;
protected:
DeclIDBase() : ID(PREDEF_DECL_NULL_ID) {}
explicit DeclIDBase(DeclID ID) : ID(ID) {}
public:
DeclID getRawValue() const { return ID; }
explicit operator DeclID() const { return ID; }
explicit operator PredefinedDeclIDs() const { return (PredefinedDeclIDs)ID; }
bool isValid() const { return ID != PREDEF_DECL_NULL_ID; }
bool isInvalid() const { return ID == PREDEF_DECL_NULL_ID; }
unsigned getModuleFileIndex() const { return ID >> 32; }
unsigned getLocalDeclIndex() const;
// The DeclID may be compared with predefined decl ID.
friend bool operator==(const DeclIDBase &LHS, const DeclID &RHS) {
return LHS.ID == RHS;
}
friend bool operator!=(const DeclIDBase &LHS, const DeclID &RHS) {
return !operator==(LHS, RHS);
}
friend bool operator<(const DeclIDBase &LHS, const DeclID &RHS) {
return LHS.ID < RHS;
}
friend bool operator<=(const DeclIDBase &LHS, const DeclID &RHS) {
return LHS.ID <= RHS;
}
friend bool operator>(const DeclIDBase &LHS, const DeclID &RHS) {
return LHS.ID > RHS;
}
friend bool operator>=(const DeclIDBase &LHS, const DeclID &RHS) {
return LHS.ID >= RHS;
}
friend bool operator==(const DeclIDBase &LHS, const DeclIDBase &RHS) {
return LHS.ID == RHS.ID;
}
friend bool operator!=(const DeclIDBase &LHS, const DeclIDBase &RHS) {
return LHS.ID != RHS.ID;
}
// We may sort the decl ID.
friend bool operator<(const DeclIDBase &LHS, const DeclIDBase &RHS) {
return LHS.ID < RHS.ID;
}
friend bool operator>(const DeclIDBase &LHS, const DeclIDBase &RHS) {
return LHS.ID > RHS.ID;
}
friend bool operator<=(const DeclIDBase &LHS, const DeclIDBase &RHS) {
return LHS.ID <= RHS.ID;
}
friend bool operator>=(const DeclIDBase &LHS, const DeclIDBase &RHS) {
return LHS.ID >= RHS.ID;
}
protected:
DeclID ID;
};
class ASTWriter;
class ASTReader;
namespace serialization {
class ModuleFile;
} // namespace serialization
class LocalDeclID : public DeclIDBase {
using Base = DeclIDBase;
LocalDeclID(PredefinedDeclIDs ID) : Base(ID) {}
explicit LocalDeclID(DeclID ID) : Base(ID) {}
// Every Decl ID is a local decl ID to the module being writing in ASTWriter.
friend class ASTWriter;
friend class GlobalDeclID;
public:
LocalDeclID() : Base() {}
static LocalDeclID get(ASTReader &Reader, serialization::ModuleFile &MF,
DeclID ID);
static LocalDeclID get(ASTReader &Reader, serialization::ModuleFile &MF,
unsigned ModuleFileIndex, unsigned LocalDeclID);
LocalDeclID &operator++() {
++ID;
return *this;
}
LocalDeclID operator++(int) {
LocalDeclID Ret = *this;
++(*this);
return Ret;
}
};
class GlobalDeclID : public DeclIDBase {
using Base = DeclIDBase;
public:
GlobalDeclID() : Base() {}
explicit GlobalDeclID(DeclID ID) : Base(ID) {}
explicit GlobalDeclID(unsigned ModuleFileIndex, unsigned LocalID)
: Base((DeclID)ModuleFileIndex << 32 | (DeclID)LocalID) {}
// For DeclIDIterator<GlobalDeclID> to be able to convert a GlobalDeclID
// to a LocalDeclID.
explicit operator LocalDeclID() const { return LocalDeclID(this->ID); }
};
/// A helper iterator adaptor to convert the iterators to
/// `SmallVector<SomeDeclID>` to the iterators to `SmallVector<OtherDeclID>`.
template <class FromTy, class ToTy>
class DeclIDIterator
: public llvm::iterator_adaptor_base<DeclIDIterator<FromTy, ToTy>,
const FromTy *,
std::forward_iterator_tag, ToTy> {
public:
DeclIDIterator() : DeclIDIterator::iterator_adaptor_base(nullptr) {}
DeclIDIterator(const FromTy *ID)
: DeclIDIterator::iterator_adaptor_base(ID) {}
ToTy operator*() const { return ToTy(*this->I); }
bool operator==(const DeclIDIterator &RHS) const { return this->I == RHS.I; }
};
} // namespace clang
namespace llvm {
template <> struct DenseMapInfo<clang::GlobalDeclID> {
using GlobalDeclID = clang::GlobalDeclID;
using DeclID = GlobalDeclID::DeclID;
static GlobalDeclID getEmptyKey() {
return GlobalDeclID(DenseMapInfo<DeclID>::getEmptyKey());
}
static GlobalDeclID getTombstoneKey() {
return GlobalDeclID(DenseMapInfo<DeclID>::getTombstoneKey());
}
static unsigned getHashValue(const GlobalDeclID &Key) {
return DenseMapInfo<DeclID>::getHashValue(Key.getRawValue());
}
static bool isEqual(const GlobalDeclID &L, const GlobalDeclID &R) {
return L == R;
}
};
} // namespace llvm
#endif

View file

@ -236,7 +236,7 @@ public:
ObjCImplementationControl impControl = ObjCImplementationControl::None,
bool HasRelatedResultType = false);
static ObjCMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ObjCMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
ObjCMethodDecl *getCanonicalDecl() override;
const ObjCMethodDecl *getCanonicalDecl() const {
@ -614,7 +614,8 @@ public:
IdentifierInfo *name,
SourceLocation colonLoc,
TypeSourceInfo *boundInfo);
static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, unsigned ID);
static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx,
GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY;
@ -772,7 +773,7 @@ private:
// Synthesize ivar for this property
ObjCIvarDecl *PropertyIvarDecl = nullptr;
ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
ObjCPropertyDecl(DeclContext *DC, SourceLocation L, const IdentifierInfo *Id,
SourceLocation AtLocation, SourceLocation LParenLocation,
QualType T, TypeSourceInfo *TSI, PropertyControl propControl)
: NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation),
@ -782,12 +783,14 @@ private:
PropertyImplementation(propControl) {}
public:
static ObjCPropertyDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
SourceLocation AtLocation, SourceLocation LParenLocation, QualType T,
TypeSourceInfo *TSI, PropertyControl propControl = None);
static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, const IdentifierInfo *Id,
SourceLocation AtLocation,
SourceLocation LParenLocation, QualType T,
TypeSourceInfo *TSI,
PropertyControl propControl = None);
static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation L) { AtLoc = L; }
@ -952,7 +955,7 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
void anchor() override;
public:
ObjCContainerDecl(Kind DK, DeclContext *DC, IdentifierInfo *Id,
ObjCContainerDecl(Kind DK, DeclContext *DC, const IdentifierInfo *Id,
SourceLocation nameLoc, SourceLocation atStartLoc);
// Iterator access to instance/class properties.
@ -1240,7 +1243,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
llvm::PointerIntPair<DefinitionData *, 1, bool> Data;
ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
const IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
bool IsInternal);
@ -1271,15 +1274,14 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
}
public:
static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation atLoc,
IdentifierInfo *Id,
ObjCTypeParamList *typeParamList,
ObjCInterfaceDecl *PrevDecl,
SourceLocation ClassLoc = SourceLocation(),
bool isInternal = false);
static ObjCInterfaceDecl *
Create(const ASTContext &C, DeclContext *DC, SourceLocation atLoc,
const IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
ObjCInterfaceDecl *PrevDecl,
SourceLocation ClassLoc = SourceLocation(), bool isInternal = false);
static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C,
GlobalDeclID ID);
/// Retrieve the type parameters of this class.
///
@ -1338,7 +1340,8 @@ public:
ObjCImplementationDecl *getImplementation() const;
void setImplementation(ObjCImplementationDecl *ImplD);
ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const;
ObjCCategoryDecl *
FindCategoryDeclaration(const IdentifierInfo *CategoryId) const;
// Get the local instance/class method declared in a category.
ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const;
@ -1794,9 +1797,9 @@ public:
data().CategoryList = category;
}
ObjCPropertyDecl
*FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId,
ObjCPropertyQueryKind QueryKind) const;
ObjCPropertyDecl *
FindPropertyVisibleInPrimaryClass(const IdentifierInfo *PropertyId,
ObjCPropertyQueryKind QueryKind) const;
void collectPropertiesToImplement(PropertyMap &PM) const override;
@ -1954,8 +1957,8 @@ public:
private:
ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
SourceLocation IdLoc, const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
bool synthesized)
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
/*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
@ -1964,12 +1967,11 @@ private:
public:
static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo,
AccessControl ac, Expr *BW = nullptr,
bool synthesized=false);
const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, AccessControl ac,
Expr *BW = nullptr, bool synthesized = false);
static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ObjCIvarDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
/// Return the class interface that this ivar is logically contained
/// in; this is either the interface where the ivar was declared, or the
@ -2039,7 +2041,8 @@ public:
SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, Expr *BW);
static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@ -2142,7 +2145,7 @@ public:
SourceLocation atStartLoc,
ObjCProtocolDecl *PrevDecl);
static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
const ObjCProtocolList &getReferencedProtocols() const {
assert(hasDefinition() && "No definition available!");
@ -2343,7 +2346,7 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc = SourceLocation(),
SourceLocation IvarRBraceLoc = SourceLocation());
@ -2354,16 +2357,14 @@ public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation AtLoc,
SourceLocation ClassNameLoc,
SourceLocation CategoryNameLoc,
IdentifierInfo *Id,
ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc=SourceLocation(),
SourceLocation IvarRBraceLoc=SourceLocation());
static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ObjCCategoryDecl *
Create(ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc = SourceLocation(),
SourceLocation IvarRBraceLoc = SourceLocation());
static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
@ -2472,10 +2473,9 @@ class ObjCImplDecl : public ObjCContainerDecl {
void anchor() override;
protected:
ObjCImplDecl(Kind DK, DeclContext *DC,
ObjCInterfaceDecl *classInterface,
IdentifierInfo *Id,
SourceLocation nameLoc, SourceLocation atStartLoc)
ObjCImplDecl(Kind DK, DeclContext *DC, ObjCInterfaceDecl *classInterface,
const IdentifierInfo *Id, SourceLocation nameLoc,
SourceLocation atStartLoc)
: ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc),
ClassInterface(classInterface) {}
@ -2543,12 +2543,12 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
// Category name location
SourceLocation CategoryNameLoc;
ObjCCategoryImplDecl(DeclContext *DC, IdentifierInfo *Id,
ObjCCategoryImplDecl(DeclContext *DC, const IdentifierInfo *Id,
ObjCInterfaceDecl *classInterface,
SourceLocation nameLoc, SourceLocation atStartLoc,
SourceLocation CategoryNameLoc)
: ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id,
nameLoc, atStartLoc),
: ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id, nameLoc,
atStartLoc),
CategoryNameLoc(CategoryNameLoc) {}
void anchor() override;
@ -2557,13 +2557,12 @@ public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC,
IdentifierInfo *Id,
ObjCInterfaceDecl *classInterface,
SourceLocation nameLoc,
SourceLocation atStartLoc,
SourceLocation CategoryNameLoc);
static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ObjCCategoryImplDecl *
Create(ASTContext &C, DeclContext *DC, const IdentifierInfo *Id,
ObjCInterfaceDecl *classInterface, SourceLocation nameLoc,
SourceLocation atStartLoc, SourceLocation CategoryNameLoc);
static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
ObjCCategoryDecl *getCategoryDecl() const;
@ -2645,7 +2644,8 @@ public:
SourceLocation IvarLBraceLoc=SourceLocation(),
SourceLocation IvarRBraceLoc=SourceLocation());
static ObjCImplementationDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ObjCImplementationDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
/// init_iterator - Iterates through the ivar initializer list.
using init_iterator = CXXCtorInitializer **;
@ -2785,7 +2785,7 @@ public:
ObjCInterfaceDecl* aliasedClass);
static ObjCCompatibleAliasDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
GlobalDeclID ID);
const ObjCInterfaceDecl *getClassInterface() const { return AliasedClass; }
ObjCInterfaceDecl *getClassInterface() { return AliasedClass; }
@ -2856,7 +2856,8 @@ public:
ObjCIvarDecl *ivarDecl,
SourceLocation ivarLoc);
static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY;

View file

@ -1,4 +1,4 @@
//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-===//
//===- DeclOpenMP.h - Classes for representing OpenMP directives -*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@ -59,7 +59,7 @@ protected:
}
template <typename T, typename... Params>
static T *createEmptyDirective(const ASTContext &C, unsigned ID,
static T *createEmptyDirective(const ASTContext &C, GlobalDeclID ID,
unsigned NumClauses, unsigned NumChildren,
Params &&... P) {
auto *Inst = new (C, ID, size(NumClauses, NumChildren))
@ -133,7 +133,7 @@ public:
SourceLocation L,
ArrayRef<Expr *> VL);
static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
unsigned ID, unsigned N);
GlobalDeclID ID, unsigned N);
typedef MutableArrayRef<Expr *>::iterator varlist_iterator;
typedef ArrayRef<const Expr *>::iterator varlist_const_iterator;
@ -214,7 +214,7 @@ public:
QualType T, OMPDeclareReductionDecl *PrevDeclInScope);
/// Create deserialized declare reduction node.
static OMPDeclareReductionDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
GlobalDeclID ID);
/// Get combiner expression of the declare reduction construct.
Expr *getCombiner() { return Combiner; }
@ -318,8 +318,8 @@ public:
ArrayRef<OMPClause *> Clauses,
OMPDeclareMapperDecl *PrevDeclInScope);
/// Creates deserialized declare mapper node.
static OMPDeclareMapperDecl *CreateDeserialized(ASTContext &C, unsigned ID,
unsigned N);
static OMPDeclareMapperDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID, unsigned N);
using clauselist_iterator = MutableArrayRef<OMPClause *>::iterator;
using clauselist_const_iterator = ArrayRef<const OMPClause *>::iterator;
@ -397,7 +397,8 @@ public:
IdentifierInfo *Id, QualType T,
SourceLocation StartLoc);
static OMPCapturedExprDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static OMPCapturedExprDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY;
@ -427,7 +428,7 @@ public:
static OMPRequiresDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, ArrayRef<OMPClause *> CL);
/// Create deserialized requires node.
static OMPRequiresDecl *CreateDeserialized(ASTContext &C, unsigned ID,
static OMPRequiresDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned N);
using clauselist_iterator = MutableArrayRef<OMPClause *>::iterator;
@ -495,7 +496,7 @@ public:
static OMPAllocateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, ArrayRef<Expr *> VL,
ArrayRef<OMPClause *> CL);
static OMPAllocateDecl *CreateDeserialized(ASTContext &C, unsigned ID,
static OMPAllocateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned NVars, unsigned NClauses);
typedef MutableArrayRef<Expr *>::iterator varlist_iterator;

View file

@ -134,6 +134,7 @@ public:
const_iterator end() const { return begin() + NumParams; }
unsigned size() const { return NumParams; }
bool empty() const { return NumParams == 0; }
ArrayRef<NamedDecl *> asArray() { return llvm::ArrayRef(begin(), end()); }
ArrayRef<const NamedDecl*> asArray() const {
@ -241,9 +242,6 @@ public:
/// A template argument list.
class TemplateArgumentList final
: private llvm::TrailingObjects<TemplateArgumentList, TemplateArgument> {
/// The template argument list.
const TemplateArgument *Arguments;
/// The number of template arguments in this template
/// argument list.
unsigned NumArguments;
@ -258,30 +256,11 @@ public:
TemplateArgumentList(const TemplateArgumentList &) = delete;
TemplateArgumentList &operator=(const TemplateArgumentList &) = delete;
/// Type used to indicate that the template argument list itself is a
/// stack object. It does not own its template arguments.
enum OnStackType { OnStack };
/// Create a new template argument list that copies the given set of
/// template arguments.
static TemplateArgumentList *CreateCopy(ASTContext &Context,
ArrayRef<TemplateArgument> Args);
/// Construct a new, temporary template argument list on the stack.
///
/// The template argument list does not own the template arguments
/// provided.
explicit TemplateArgumentList(OnStackType, ArrayRef<TemplateArgument> Args)
: Arguments(Args.data()), NumArguments(Args.size()) {}
/// Produces a shallow copy of the given template argument list.
///
/// This operation assumes that the input argument list outlives it.
/// This takes the list as a pointer to avoid looking like a copy
/// constructor, since this really isn't safe to use that way.
explicit TemplateArgumentList(const TemplateArgumentList *Other)
: Arguments(Other->data()), NumArguments(Other->size()) {}
/// Retrieve the template argument at a given index.
const TemplateArgument &get(unsigned Idx) const {
assert(Idx < NumArguments && "Invalid template argument index");
@ -301,7 +280,9 @@ public:
unsigned size() const { return NumArguments; }
/// Retrieve a pointer to the template argument list.
const TemplateArgument *data() const { return Arguments; }
const TemplateArgument *data() const {
return getTrailingObjects<TemplateArgument>();
}
};
void *allocateDefaultArgStorageChain(const ASTContext &C);
@ -497,7 +478,7 @@ class FunctionTemplateSpecializationInfo final
public:
/// The template arguments used to produce the function template
/// specialization from the function template.
const TemplateArgumentList *TemplateArguments;
TemplateArgumentList *TemplateArguments;
/// The template arguments as written in the sources, if provided.
/// FIXME: Normally null; tail-allocate this.
@ -510,7 +491,7 @@ public:
private:
FunctionTemplateSpecializationInfo(
FunctionDecl *FD, FunctionTemplateDecl *Template,
TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs,
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation POI, MemberSpecializationInfo *MSInfo)
: Function(FD, MSInfo ? true : false), Template(Template, TSK - 1),
@ -530,8 +511,7 @@ public:
static FunctionTemplateSpecializationInfo *
Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
TemplateSpecializationKind TSK,
const TemplateArgumentList *TemplateArgs,
TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
const TemplateArgumentListInfo *TemplateArgsAsWritten,
SourceLocation POI, MemberSpecializationInfo *MSInfo);
@ -816,7 +796,7 @@ protected:
///
/// The first value in the array is the number of specializations/partial
/// specializations that follow.
uint32_t *LazySpecializations = nullptr;
GlobalDeclID *LazySpecializations = nullptr;
/// The set of "injected" template arguments used within this
/// template.
@ -1106,7 +1086,8 @@ public:
NamedDecl *Decl);
/// Create an empty function template node.
static FunctionTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static FunctionTemplateDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@ -1204,7 +1185,7 @@ class TemplateTypeParmDecl final : public TypeDecl,
/// The default template argument, if any.
using DefArgStorage =
DefaultArgStorage<TemplateTypeParmDecl, TypeSourceInfo *>;
DefaultArgStorage<TemplateTypeParmDecl, TemplateArgumentLoc *>;
DefArgStorage DefaultArgument;
TemplateTypeParmDecl(DeclContext *DC, SourceLocation KeyLoc,
@ -1223,9 +1204,9 @@ public:
bool Typename, bool ParameterPack, bool HasTypeConstraint = false,
std::optional<unsigned> NumExpanded = std::nullopt);
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
unsigned ID);
GlobalDeclID ID);
static TemplateTypeParmDecl *CreateDeserialized(const ASTContext &C,
unsigned ID,
GlobalDeclID ID,
bool HasTypeConstraint);
/// Whether this template type parameter was declared with
@ -1244,13 +1225,9 @@ public:
bool hasDefaultArgument() const { return DefaultArgument.isSet(); }
/// Retrieve the default argument, if any.
QualType getDefaultArgument() const {
return DefaultArgument.get()->getType();
}
/// Retrieves the default argument's source information, if any.
TypeSourceInfo *getDefaultArgumentInfo() const {
return DefaultArgument.get();
const TemplateArgumentLoc &getDefaultArgument() const {
static const TemplateArgumentLoc NoneLoc;
return DefaultArgument.isSet() ? *DefaultArgument.get() : NoneLoc;
}
/// Retrieves the location of the default argument declaration.
@ -1263,9 +1240,8 @@ public:
}
/// Set the default argument for this template parameter.
void setDefaultArgument(TypeSourceInfo *DefArg) {
DefaultArgument.set(DefArg);
}
void setDefaultArgument(const ASTContext &C,
const TemplateArgumentLoc &DefArg);
/// Set that this default argument was inherited from another
/// parameter.
@ -1384,7 +1360,8 @@ class NonTypeTemplateParmDecl final
/// The default template argument, if any, and whether or not
/// it was inherited.
using DefArgStorage = DefaultArgStorage<NonTypeTemplateParmDecl, Expr *>;
using DefArgStorage =
DefaultArgStorage<NonTypeTemplateParmDecl, TemplateArgumentLoc *>;
DefArgStorage DefaultArgument;
// FIXME: Collapse this into TemplateParamPosition; or, just move depth/index
@ -1408,14 +1385,14 @@ class NonTypeTemplateParmDecl final
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, unsigned D, unsigned P,
IdentifierInfo *Id, QualType T,
const IdentifierInfo *Id, QualType T,
bool ParameterPack, TypeSourceInfo *TInfo)
: DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc),
TemplateParmPosition(D, P), ParameterPack(ParameterPack) {}
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, unsigned D, unsigned P,
IdentifierInfo *Id, QualType T,
const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo,
ArrayRef<QualType> ExpandedTypes,
ArrayRef<TypeSourceInfo *> ExpandedTInfos);
@ -1423,20 +1400,19 @@ class NonTypeTemplateParmDecl final
public:
static NonTypeTemplateParmDecl *
Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id,
QualType T, bool ParameterPack, TypeSourceInfo *TInfo);
static NonTypeTemplateParmDecl *
Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes,
ArrayRef<TypeSourceInfo *> ExpandedTInfos);
static NonTypeTemplateParmDecl *
CreateDeserialized(ASTContext &C, GlobalDeclID ID, bool HasTypeConstraint);
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID,
bool HasTypeConstraint);
static NonTypeTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID,
GlobalDeclID ID,
unsigned NumExpandedTypes,
bool HasTypeConstraint);
@ -1455,7 +1431,10 @@ public:
bool hasDefaultArgument() const { return DefaultArgument.isSet(); }
/// Retrieve the default argument, if any.
Expr *getDefaultArgument() const { return DefaultArgument.get(); }
const TemplateArgumentLoc &getDefaultArgument() const {
static const TemplateArgumentLoc NoneLoc;
return DefaultArgument.isSet() ? *DefaultArgument.get() : NoneLoc;
}
/// Retrieve the location of the default argument, if any.
SourceLocation getDefaultArgumentLoc() const;
@ -1469,7 +1448,8 @@ public:
/// Set the default argument for this template parameter, and
/// whether that default argument was inherited from another
/// declaration.
void setDefaultArgument(Expr *DefArg) { DefaultArgument.set(DefArg); }
void setDefaultArgument(const ASTContext &C,
const TemplateArgumentLoc &DefArg);
void setInheritedDefaultArgument(const ASTContext &C,
NonTypeTemplateParmDecl *Parm) {
DefaultArgument.setInherited(C, Parm);
@ -1600,26 +1580,36 @@ class TemplateTemplateParmDecl final
DefaultArgStorage<TemplateTemplateParmDecl, TemplateArgumentLoc *>;
DefArgStorage DefaultArgument;
/// Whether this template template parameter was declaration with
/// the 'typename' keyword.
///
/// If false, it was declared with the 'class' keyword.
LLVM_PREFERRED_TYPE(bool)
unsigned Typename : 1;
/// Whether this parameter is a parameter pack.
bool ParameterPack;
LLVM_PREFERRED_TYPE(bool)
unsigned ParameterPack : 1;
/// Whether this template template parameter is an "expanded"
/// parameter pack, meaning that it is a pack expansion and we
/// already know the set of template parameters that expansion expands to.
bool ExpandedParameterPack = false;
LLVM_PREFERRED_TYPE(bool)
unsigned ExpandedParameterPack : 1;
/// The number of parameters in an expanded parameter pack.
unsigned NumExpandedParams = 0;
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
unsigned D, unsigned P, bool ParameterPack,
IdentifierInfo *Id, TemplateParameterList *Params)
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
unsigned P, bool ParameterPack, IdentifierInfo *Id,
bool Typename, TemplateParameterList *Params)
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
TemplateParmPosition(D, P), ParameterPack(ParameterPack) {}
TemplateParmPosition(D, P), Typename(Typename),
ParameterPack(ParameterPack), ExpandedParameterPack(false) {}
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
unsigned D, unsigned P,
IdentifierInfo *Id, TemplateParameterList *Params,
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
unsigned P, IdentifierInfo *Id, bool Typename,
TemplateParameterList *Params,
ArrayRef<TemplateParameterList *> Expansions);
void anchor() override;
@ -1632,20 +1622,18 @@ public:
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D,
unsigned P, bool ParameterPack,
IdentifierInfo *Id,
IdentifierInfo *Id, bool Typename,
TemplateParameterList *Params);
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D,
unsigned P,
IdentifierInfo *Id,
TemplateParameterList *Params,
ArrayRef<TemplateParameterList *> Expansions);
static TemplateTemplateParmDecl *
Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
unsigned P, IdentifierInfo *Id, bool Typename,
TemplateParameterList *Params,
ArrayRef<TemplateParameterList *> Expansions);
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned NumExpansions);
GlobalDeclID ID);
static TemplateTemplateParmDecl *
CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NumExpansions);
using TemplateParmPosition::getDepth;
using TemplateParmPosition::setDepth;
@ -1653,6 +1641,14 @@ public:
using TemplateParmPosition::setPosition;
using TemplateParmPosition::getIndex;
/// Whether this template template parameter was declared with
/// the 'typename' keyword.
bool wasDeclaredWithTypename() const { return Typename; }
/// Set whether this template template parameter was declared with
/// the 'typename' or 'class' keyword.
void setDeclaredWithTypename(bool withTypename) { Typename = withTypename; }
/// Whether this template template parameter is a template
/// parameter pack.
///
@ -1779,6 +1775,25 @@ public:
BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
};
/// Provides information about an explicit instantiation of a variable or class
/// template.
struct ExplicitInstantiationInfo {
/// The template arguments as written..
const ASTTemplateArgumentListInfo *TemplateArgsAsWritten = nullptr;
/// The location of the extern keyword.
SourceLocation ExternKeywordLoc;
/// The location of the template keyword.
SourceLocation TemplateKeywordLoc;
ExplicitInstantiationInfo() = default;
};
using SpecializationOrInstantiationInfo =
llvm::PointerUnion<const ASTTemplateArgumentListInfo *,
ExplicitInstantiationInfo *>;
/// Represents a class template specialization, which refers to
/// a class template with a given set of template arguments.
///
@ -1792,8 +1807,8 @@ public:
/// template<>
/// class array<bool> { }; // class template specialization array<bool>
/// \endcode
class ClassTemplateSpecializationDecl
: public CXXRecordDecl, public llvm::FoldingSetNode {
class ClassTemplateSpecializationDecl : public CXXRecordDecl,
public llvm::FoldingSetNode {
/// Structure that stores information about a class template
/// specialization that was instantiated from a class template partial
/// specialization.
@ -1811,23 +1826,9 @@ class ClassTemplateSpecializationDecl
llvm::PointerUnion<ClassTemplateDecl *, SpecializedPartialSpecialization *>
SpecializedTemplate;
/// Further info for explicit template specialization/instantiation.
struct ExplicitSpecializationInfo {
/// The type-as-written.
TypeSourceInfo *TypeAsWritten = nullptr;
/// The location of the extern keyword.
SourceLocation ExternLoc;
/// The location of the template keyword.
SourceLocation TemplateKeywordLoc;
ExplicitSpecializationInfo() = default;
};
/// Further info for explicit template specialization/instantiation.
/// Does not apply to implicit specializations.
ExplicitSpecializationInfo *ExplicitInfo = nullptr;
SpecializationOrInstantiationInfo ExplicitInfo = nullptr;
/// The template arguments used to describe this specialization.
const TemplateArgumentList *TemplateArgs;
@ -1859,8 +1860,8 @@ public:
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
ClassTemplateSpecializationDecl *PrevDecl);
static ClassTemplateSpecializationDecl *
CreateDeserialized(ASTContext &C, unsigned ID);
static ClassTemplateSpecializationDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy,
bool Qualified) const override;
@ -2004,44 +2005,49 @@ public:
SpecializedTemplate = TemplDecl;
}
/// Sets the type of this specialization as it was written by
/// the user. This will be a class template specialization type.
void setTypeAsWritten(TypeSourceInfo *T) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->TypeAsWritten = T;
/// Retrieve the template argument list as written in the sources,
/// if any.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->TemplateArgsAsWritten;
return ExplicitInfo.get<const ASTTemplateArgumentListInfo *>();
}
/// Gets the type of this specialization as it was written by
/// the user, if it was so written.
TypeSourceInfo *getTypeAsWritten() const {
return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr;
/// Set the template argument list as written in the sources.
void
setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
Info->TemplateArgsAsWritten = ArgsWritten;
else
ExplicitInfo = ArgsWritten;
}
/// Set the template argument list as written in the sources.
void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
setTemplateArgsAsWritten(
ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
}
/// Gets the location of the extern keyword, if present.
SourceLocation getExternLoc() const {
return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation();
SourceLocation getExternKeywordLoc() const {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->ExternKeywordLoc;
return SourceLocation();
}
/// Sets the location of the extern keyword.
void setExternLoc(SourceLocation Loc) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->ExternLoc = Loc;
}
/// Sets the location of the template keyword.
void setTemplateKeywordLoc(SourceLocation Loc) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->TemplateKeywordLoc = Loc;
}
void setExternKeywordLoc(SourceLocation Loc);
/// Gets the location of the template keyword, if present.
SourceLocation getTemplateKeywordLoc() const {
return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->TemplateKeywordLoc;
return SourceLocation();
}
/// Sets the location of the template keyword.
void setTemplateKeywordLoc(SourceLocation Loc);
SourceRange getSourceRange() const override LLVM_READONLY;
void Profile(llvm::FoldingSetNodeID &ID) const {
@ -2069,10 +2075,6 @@ class ClassTemplatePartialSpecializationDecl
/// The list of template parameters
TemplateParameterList* TemplateParams = nullptr;
/// The source info for the template arguments as written.
/// FIXME: redundant with TypeAsWritten?
const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
/// The class template partial specialization from which this
/// class template partial specialization was instantiated.
///
@ -2081,15 +2083,11 @@ class ClassTemplatePartialSpecializationDecl
llvm::PointerIntPair<ClassTemplatePartialSpecializationDecl *, 1, bool>
InstantiatedFromMember;
ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
DeclContext *DC,
SourceLocation StartLoc,
SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
const ASTTemplateArgumentListInfo *ArgsAsWritten,
ClassTemplatePartialSpecializationDecl *PrevDecl);
ClassTemplatePartialSpecializationDecl(
ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate, ArrayRef<TemplateArgument> Args,
ClassTemplatePartialSpecializationDecl *PrevDecl);
ClassTemplatePartialSpecializationDecl(ASTContext &C)
: ClassTemplateSpecializationDecl(C, ClassTemplatePartialSpecialization),
@ -2104,15 +2102,12 @@ public:
static ClassTemplatePartialSpecializationDecl *
Create(ASTContext &Context, TagKind TK, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
TemplateParameterList *Params,
ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args,
const TemplateArgumentListInfo &ArgInfos,
QualType CanonInjectedType,
TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate,
ArrayRef<TemplateArgument> Args, QualType CanonInjectedType,
ClassTemplatePartialSpecializationDecl *PrevDecl);
static ClassTemplatePartialSpecializationDecl *
CreateDeserialized(ASTContext &C, unsigned ID);
CreateDeserialized(ASTContext &C, GlobalDeclID ID);
ClassTemplatePartialSpecializationDecl *getMostRecentDecl() {
return cast<ClassTemplatePartialSpecializationDecl>(
@ -2139,11 +2134,6 @@ public:
return TemplateParams->hasAssociatedConstraints();
}
/// Get the template arguments as written.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten;
}
/// Retrieve the member class template partial specialization from
/// which this particular class template partial specialization was
/// instantiated.
@ -2196,7 +2186,7 @@ public:
/// template<> template<typename T>
/// struct X<int>::Inner<T*> { /* ... */ };
/// \endcode
bool isMemberSpecialization() {
bool isMemberSpecialization() const {
const auto *First =
cast<ClassTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getInt();
@ -2219,6 +2209,8 @@ public:
->getInjectedSpecializationType();
}
SourceRange getSourceRange() const override LLVM_READONLY;
void Profile(llvm::FoldingSetNodeID &ID) const {
Profile(ID, getTemplateArgs().asArray(), getTemplateParameters(),
getASTContext());
@ -2308,7 +2300,7 @@ public:
NamedDecl *Decl);
/// Create an empty class template node.
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ClassTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
/// Return the specialization with the provided arguments if it exists,
/// otherwise return the insertion point.
@ -2474,7 +2466,7 @@ public:
MutableArrayRef<TemplateParameterList *> Params, FriendUnion Friend,
SourceLocation FriendLoc);
static FriendTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static FriendTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
/// If this friend declaration names a templated type (or
/// a dependent member type of a templated type), return that
@ -2575,7 +2567,8 @@ public:
NamedDecl *Decl);
/// Create an empty alias template node.
static TypeAliasTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static TypeAliasTemplateDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
// Implement isa/cast/dyncast support
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@ -2615,27 +2608,12 @@ class VarTemplateSpecializationDecl : public VarDecl,
llvm::PointerUnion<VarTemplateDecl *, SpecializedPartialSpecialization *>
SpecializedTemplate;
/// Further info for explicit template specialization/instantiation.
struct ExplicitSpecializationInfo {
/// The type-as-written.
TypeSourceInfo *TypeAsWritten = nullptr;
/// The location of the extern keyword.
SourceLocation ExternLoc;
/// The location of the template keyword.
SourceLocation TemplateKeywordLoc;
ExplicitSpecializationInfo() = default;
};
/// Further info for explicit template specialization/instantiation.
/// Does not apply to implicit specializations.
ExplicitSpecializationInfo *ExplicitInfo = nullptr;
SpecializationOrInstantiationInfo ExplicitInfo = nullptr;
/// The template arguments used to describe this specialization.
const TemplateArgumentList *TemplateArgs;
const ASTTemplateArgumentListInfo *TemplateArgsInfo = nullptr;
/// The point where this template was instantiated (if any).
SourceLocation PointOfInstantiation;
@ -2672,7 +2650,7 @@ public:
TypeSourceInfo *TInfo, StorageClass S,
ArrayRef<TemplateArgument> Args);
static VarTemplateSpecializationDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
GlobalDeclID ID);
void getNameForDiagnostic(raw_ostream &OS, const PrintingPolicy &Policy,
bool Qualified) const override;
@ -2689,14 +2667,6 @@ public:
/// specialization.
const TemplateArgumentList &getTemplateArgs() const { return *TemplateArgs; }
// TODO: Always set this when creating the new specialization?
void setTemplateArgsInfo(const TemplateArgumentListInfo &ArgsInfo);
void setTemplateArgsInfo(const ASTTemplateArgumentListInfo *ArgsInfo);
const ASTTemplateArgumentListInfo *getTemplateArgsInfo() const {
return TemplateArgsInfo;
}
/// Determine the kind of specialization that this
/// declaration represents.
TemplateSpecializationKind getSpecializationKind() const {
@ -2800,44 +2770,49 @@ public:
SpecializedTemplate = TemplDecl;
}
/// Sets the type of this specialization as it was written by
/// the user.
void setTypeAsWritten(TypeSourceInfo *T) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->TypeAsWritten = T;
/// Retrieve the template argument list as written in the sources,
/// if any.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->TemplateArgsAsWritten;
return ExplicitInfo.get<const ASTTemplateArgumentListInfo *>();
}
/// Gets the type of this specialization as it was written by
/// the user, if it was so written.
TypeSourceInfo *getTypeAsWritten() const {
return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr;
/// Set the template argument list as written in the sources.
void
setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
Info->TemplateArgsAsWritten = ArgsWritten;
else
ExplicitInfo = ArgsWritten;
}
/// Set the template argument list as written in the sources.
void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
setTemplateArgsAsWritten(
ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
}
/// Gets the location of the extern keyword, if present.
SourceLocation getExternLoc() const {
return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation();
SourceLocation getExternKeywordLoc() const {
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->ExternKeywordLoc;
return SourceLocation();
}
/// Sets the location of the extern keyword.
void setExternLoc(SourceLocation Loc) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->ExternLoc = Loc;
}
/// Sets the location of the template keyword.
void setTemplateKeywordLoc(SourceLocation Loc) {
if (!ExplicitInfo)
ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
ExplicitInfo->TemplateKeywordLoc = Loc;
}
void setExternKeywordLoc(SourceLocation Loc);
/// Gets the location of the template keyword, if present.
SourceLocation getTemplateKeywordLoc() const {
return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
if (auto *Info = ExplicitInfo.dyn_cast<ExplicitInstantiationInfo *>())
return Info->TemplateKeywordLoc;
return SourceLocation();
}
/// Sets the location of the template keyword.
void setTemplateKeywordLoc(SourceLocation Loc);
SourceRange getSourceRange() const override LLVM_READONLY;
void Profile(llvm::FoldingSetNodeID &ID) const {
@ -2865,10 +2840,6 @@ class VarTemplatePartialSpecializationDecl
/// The list of template parameters
TemplateParameterList *TemplateParams = nullptr;
/// The source info for the template arguments as written.
/// FIXME: redundant with TypeAsWritten?
const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
/// The variable template partial specialization from which this
/// variable template partial specialization was instantiated.
///
@ -2881,8 +2852,7 @@ class VarTemplatePartialSpecializationDecl
ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
StorageClass S, ArrayRef<TemplateArgument> Args,
const ASTTemplateArgumentListInfo *ArgInfos);
StorageClass S, ArrayRef<TemplateArgument> Args);
VarTemplatePartialSpecializationDecl(ASTContext &Context)
: VarTemplateSpecializationDecl(VarTemplatePartialSpecialization,
@ -2899,11 +2869,11 @@ public:
Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, TemplateParameterList *Params,
VarTemplateDecl *SpecializedTemplate, QualType T,
TypeSourceInfo *TInfo, StorageClass S, ArrayRef<TemplateArgument> Args,
const TemplateArgumentListInfo &ArgInfos);
TypeSourceInfo *TInfo, StorageClass S,
ArrayRef<TemplateArgument> Args);
static VarTemplatePartialSpecializationDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
static VarTemplatePartialSpecializationDecl *
CreateDeserialized(ASTContext &C, GlobalDeclID ID);
VarTemplatePartialSpecializationDecl *getMostRecentDecl() {
return cast<VarTemplatePartialSpecializationDecl>(
@ -2916,11 +2886,6 @@ public:
return TemplateParams;
}
/// Get the template arguments as written.
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten;
}
/// \brief All associated constraints of this partial specialization,
/// including the requires clause and any constraints derived from
/// constrained-parameters.
@ -2983,7 +2948,7 @@ public:
/// template<> template<typename T>
/// U* X<int>::Inner<T*> = (T*)(0) + 1;
/// \endcode
bool isMemberSpecialization() {
bool isMemberSpecialization() const {
const auto *First =
cast<VarTemplatePartialSpecializationDecl>(getFirstDecl());
return First->InstantiatedFromMember.getInt();
@ -3080,7 +3045,7 @@ public:
VarDecl *Decl);
/// Create an empty variable template node.
static VarTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static VarTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
/// Return the specialization with the provided arguments if it exists,
/// otherwise return the insertion point.
@ -3185,7 +3150,7 @@ public:
SourceLocation L, DeclarationName Name,
TemplateParameterList *Params,
Expr *ConstraintExpr);
static ConceptDecl *CreateDeserialized(ASTContext &C, unsigned ID);
static ConceptDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
Expr *getConstraintExpr() const {
return ConstraintExpr;
@ -3234,7 +3199,7 @@ public:
Create(const ASTContext &C, DeclContext *DC, SourceLocation SL,
ArrayRef<TemplateArgument> ConvertedArgs);
static ImplicitConceptSpecializationDecl *
CreateDeserialized(const ASTContext &C, unsigned ID,
CreateDeserialized(const ASTContext &C, GlobalDeclID ID,
unsigned NumTemplateArgs);
ArrayRef<TemplateArgument> getTemplateArguments() const {
@ -3277,7 +3242,7 @@ private:
static TemplateParamObjectDecl *Create(const ASTContext &C, QualType T,
const APValue &V);
static TemplateParamObjectDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
GlobalDeclID ID);
/// Only ASTContext::getTemplateParamObjectDecl and deserialization
/// create these.

View file

@ -82,7 +82,7 @@ struct SubobjectAdjustment {
union {
struct DTB DerivedToBase;
FieldDecl *Field;
const FieldDecl *Field;
struct P Ptr;
};
@ -93,8 +93,7 @@ struct SubobjectAdjustment {
DerivedToBase.DerivedClass = DerivedClass;
}
SubobjectAdjustment(FieldDecl *Field)
: Kind(FieldAdjustment) {
SubobjectAdjustment(const FieldDecl *Field) : Kind(FieldAdjustment) {
this->Field = Field;
}
@ -154,6 +153,12 @@ public:
TR = t;
}
/// If this expression is an enumeration constant, return the
/// enumeration type under which said constant was declared.
/// Otherwise return the expression's type.
/// Note this effectively circumvents the weak typing of C's enum constants
QualType getEnumCoercedType(const ASTContext &Ctx) const;
ExprDependence getDependence() const {
return static_cast<ExprDependence>(ExprBits.Dependent);
}
@ -379,7 +384,7 @@ public:
bool isRValue() const { return Kind >= CL_XValue; }
bool isModifiable() const { return getModifiable() == CM_Modifiable; }
/// Create a simple, modifiably lvalue
/// Create a simple, modifiable lvalue
static Classification makeSimpleLValue() {
return Classification(CL_LValue, CM_Modifiable);
}
@ -472,6 +477,13 @@ public:
/// bit-fields, but it will return null for a conditional bit-field.
FieldDecl *getSourceBitField();
/// If this expression refers to an enum constant, retrieve its declaration
EnumConstantDecl *getEnumConstantDecl();
const EnumConstantDecl *getEnumConstantDecl() const {
return const_cast<Expr *>(this)->getEnumConstantDecl();
}
const FieldDecl *getSourceBitField() const {
return const_cast<Expr*>(this)->getSourceBitField();
}
@ -775,6 +787,11 @@ public:
const Expr *PtrExpression, ASTContext &Ctx,
EvalResult &Status) const;
/// If the current Expr can be evaluated to a pointer to a null-terminated
/// constant string, return the constant string (without the terminating
/// null).
std::optional<std::string> tryEvaluateString(ASTContext &Ctx) const;
/// Enumeration used to describe the kind of Null pointer constant
/// returned from \c isNullPointerConstant().
enum NullPointerConstantKind {
@ -1275,7 +1292,7 @@ class DeclRefExpr final
DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, ValueDecl *D,
bool RefersToEnlosingVariableOrCapture,
bool RefersToEnclosingVariableOrCapture,
const DeclarationNameInfo &NameInfo, NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs, QualType T,
ExprValueKind VK, NonOdrUseReason NOUR);
@ -1641,14 +1658,14 @@ public:
}
/// Get a raw enumeration value representing the floating-point semantics of
/// this literal (32-bit IEEE, x87, ...), suitable for serialisation.
/// this literal (32-bit IEEE, x87, ...), suitable for serialization.
llvm::APFloatBase::Semantics getRawSemantics() const {
return static_cast<llvm::APFloatBase::Semantics>(
FloatingLiteralBits.Semantics);
}
/// Set the raw enumeration value representing the floating-point semantics of
/// this literal (32-bit IEEE, x87, ...), suitable for serialisation.
/// this literal (32-bit IEEE, x87, ...), suitable for serialization.
void setRawSemantics(llvm::APFloatBase::Semantics Sem) {
FloatingLiteralBits.Semantics = Sem;
}
@ -1863,6 +1880,17 @@ public:
llvm_unreachable("Unsupported character width!");
}
// Get code unit but preserve sign info.
int64_t getCodeUnitS(size_t I, uint64_t BitWidth) const {
int64_t V = getCodeUnit(I);
if (isOrdinary() || isWide()) {
unsigned Width = getCharByteWidth() * BitWidth;
llvm::APInt AInt(Width, (uint64_t)V);
V = AInt.getSExtValue();
}
return V;
}
unsigned getByteLength() const { return getCharByteWidth() * getLength(); }
unsigned getLength() const { return *getTrailingObjects<unsigned>(); }
unsigned getCharByteWidth() const { return StringLiteralBits.CharByteWidth; }
@ -2022,7 +2050,8 @@ public:
}
static std::string ComputeName(PredefinedIdentKind IK,
const Decl *CurrentDecl);
const Decl *CurrentDecl,
bool ForceElaboratedPrinting = false);
SourceLocation getBeginLoc() const { return getLocation(); }
SourceLocation getEndLoc() const { return getLocation(); }
@ -2101,7 +2130,7 @@ public:
static std::string ComputeName(ASTContext &Context, QualType Ty);
};
/// ParenExpr - This represents a parethesized expression, e.g. "(1)". This
/// ParenExpr - This represents a parenthesized expression, e.g. "(1)". This
/// AST node is only formed if full location information is requested.
class ParenExpr : public Expr {
SourceLocation L, R;
@ -2217,7 +2246,7 @@ 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
/// Get the FP contractibility status of this operator. Only meaningful for
/// operations on floating point types.
bool isFPContractableWithinStatement(const LangOptions &LO) const {
return getFPFeaturesInEffect(LO).allowFPContractWithinStatement();
@ -2304,6 +2333,11 @@ public:
return getTrailingFPFeatures();
}
/// Get the store FPOptionsOverride or default if not stored.
FPOptionsOverride getStoredFPFeaturesOrDefault() const {
return hasStoredFPFeatures() ? getStoredFPFeatures() : FPOptionsOverride();
}
protected:
/// Set FPFeatures in trailing storage, used by Serialization & ASTImporter.
void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; }
@ -3067,6 +3101,11 @@ public:
*getTrailingFPFeatures() = F;
}
/// Get the store FPOptionsOverride or default if not stored.
FPOptionsOverride getStoredFPFeaturesOrDefault() const {
return hasStoredFPFeatures() ? getStoredFPFeatures() : FPOptionsOverride();
}
/// Get the FP features status of this operator. Only meaningful for
/// operations on floating point types.
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const {
@ -3139,23 +3178,12 @@ public:
}
};
/// Extra data stored in some MemberExpr objects.
struct MemberExprNameQualifier {
/// The nested-name-specifier that qualifies the name, including
/// source-location information.
NestedNameSpecifierLoc QualifierLoc;
/// The DeclAccessPair through which the MemberDecl was found due to
/// name qualifiers.
DeclAccessPair FoundDecl;
};
/// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F.
///
class MemberExpr final
: public Expr,
private llvm::TrailingObjects<MemberExpr, MemberExprNameQualifier,
ASTTemplateKWAndArgsInfo,
private llvm::TrailingObjects<MemberExpr, NestedNameSpecifierLoc,
DeclAccessPair, ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc> {
friend class ASTReader;
friend class ASTStmtReader;
@ -3177,26 +3205,30 @@ class MemberExpr final
/// MemberLoc - This is the location of the member name.
SourceLocation MemberLoc;
size_t numTrailingObjects(OverloadToken<MemberExprNameQualifier>) const {
return hasQualifierOrFoundDecl();
size_t numTrailingObjects(OverloadToken<NestedNameSpecifierLoc>) const {
return hasQualifier();
}
size_t numTrailingObjects(OverloadToken<DeclAccessPair>) const {
return hasFoundDecl();
}
size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
return hasTemplateKWAndArgsInfo();
}
bool hasQualifierOrFoundDecl() const {
return MemberExprBits.HasQualifierOrFoundDecl;
}
bool hasFoundDecl() const { return MemberExprBits.HasFoundDecl; }
bool hasTemplateKWAndArgsInfo() const {
return MemberExprBits.HasTemplateKWAndArgsInfo;
}
MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
ValueDecl *MemberDecl, const DeclarationNameInfo &NameInfo,
QualType T, ExprValueKind VK, ExprObjectKind OK,
NonOdrUseReason NOUR);
NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
ValueDecl *MemberDecl, DeclAccessPair FoundDecl,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs, QualType T,
ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR);
MemberExpr(EmptyShell Empty)
: Expr(MemberExprClass, Empty), Base(), MemberDecl() {}
@ -3240,24 +3272,24 @@ public:
/// Retrieves the declaration found by lookup.
DeclAccessPair getFoundDecl() const {
if (!hasQualifierOrFoundDecl())
if (!hasFoundDecl())
return DeclAccessPair::make(getMemberDecl(),
getMemberDecl()->getAccess());
return getTrailingObjects<MemberExprNameQualifier>()->FoundDecl;
return *getTrailingObjects<DeclAccessPair>();
}
/// Determines whether this member expression actually had
/// a C++ nested-name-specifier prior to the name of the member, e.g.,
/// x->Base::foo.
bool hasQualifier() const { return getQualifier() != nullptr; }
bool hasQualifier() const { return MemberExprBits.HasQualifier; }
/// If the member name was qualified, retrieves the
/// nested-name-specifier that precedes the member name, with source-location
/// information.
NestedNameSpecifierLoc getQualifierLoc() const {
if (!hasQualifierOrFoundDecl())
if (!hasQualifier())
return NestedNameSpecifierLoc();
return getTrailingObjects<MemberExprNameQualifier>()->QualifierLoc;
return *getTrailingObjects<NestedNameSpecifierLoc>();
}
/// If the member name was qualified, retrieves the
@ -3538,6 +3570,18 @@ public:
path_const_iterator path_begin() const { return path_buffer(); }
path_const_iterator path_end() const { return path_buffer() + path_size(); }
/// Path through the class hierarchy taken by casts between base and derived
/// classes (see implementation of `CastConsistency()` for a full list of
/// cast kinds that have a path).
///
/// For each derived-to-base edge in the path, the path contains a
/// `CXXBaseSpecifier` for the base class of that edge; the entries are
/// ordered from derived class to base class.
///
/// For example, given classes `Base`, `Intermediate : public Base` and
/// `Derived : public Intermediate`, the path for a cast from `Derived *` to
/// `Base *` contains two entries: One for `Intermediate`, and one for `Base`,
/// in that order.
llvm::iterator_range<path_iterator> path() {
return llvm::make_range(path_begin(), path_end());
}
@ -3558,6 +3602,11 @@ public:
return *getTrailingFPFeatures();
}
/// Get the store FPOptionsOverride or default if not stored.
FPOptionsOverride getStoredFPFeaturesOrDefault() const {
return hasStoredFPFeatures() ? getStoredFPFeatures() : FPOptionsOverride();
}
/// Get the FP features status of this operation. Only meaningful for
/// operations on floating point types.
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const {
@ -4004,6 +4053,10 @@ public:
assert(BinaryOperatorBits.HasFPFeatures);
*getTrailingFPFeatures() = F;
}
/// Get the store FPOptionsOverride or default if not stored.
FPOptionsOverride getStoredFPFeaturesOrDefault() const {
return hasStoredFPFeatures() ? getStoredFPFeatures() : FPOptionsOverride();
}
/// Get the FP features status of this operator. Only meaningful for
/// operations on floating point types.
@ -4020,7 +4073,7 @@ public:
return FPOptionsOverride();
}
/// Get the FP contractability status of this operator. Only meaningful for
/// Get the FP contractibility status of this operator. Only meaningful for
/// operations on floating point types.
bool isFPContractableWithinStatement(const LangOptions &LO) const {
return getFPFeaturesInEffect(LO).allowFPContractWithinStatement();
@ -4261,7 +4314,7 @@ public:
}
/// getFalseExpr - Return the subexpression which will be
/// evaluated if the condnition evaluates to false; this is
/// evaluated if the condition evaluates to false; this is
/// defined in terms of the opaque value.
Expr *getFalseExpr() const {
return cast<Expr>(SubExprs[RHS]);
@ -4770,6 +4823,164 @@ private:
friend class ASTStmtReader;
};
/// Stores data related to a single #embed directive.
struct EmbedDataStorage {
StringLiteral *BinaryData;
size_t getDataElementCount() const { return BinaryData->getByteLength(); }
};
/// Represents a reference to #emded data. By default, this references the whole
/// range. Otherwise it represents a subrange of data imported by #embed
/// directive. Needed to handle nested initializer lists with #embed directives.
/// Example:
/// struct S {
/// int x, y;
/// };
///
/// struct T {
/// int x[2];
/// struct S s
/// };
///
/// struct T t[] = {
/// #embed "data" // data contains 10 elements;
/// };
///
/// The resulting semantic form of initializer list will contain (EE stands
/// for EmbedExpr):
/// { {EE(first two data elements), {EE(3rd element), EE(4th element) }},
/// { {EE(5th and 6th element), {EE(7th element), EE(8th element) }},
/// { {EE(9th and 10th element), { zeroinitializer }}}
///
/// EmbedExpr inside of a semantic initializer list and referencing more than
/// one element can only appear for arrays of scalars.
class EmbedExpr final : public Expr {
SourceLocation EmbedKeywordLoc;
IntegerLiteral *FakeChildNode = nullptr;
const ASTContext *Ctx = nullptr;
EmbedDataStorage *Data;
unsigned Begin = 0;
unsigned NumOfElements;
public:
EmbedExpr(const ASTContext &Ctx, SourceLocation Loc, EmbedDataStorage *Data,
unsigned Begin, unsigned NumOfElements);
explicit EmbedExpr(EmptyShell Empty) : Expr(SourceLocExprClass, Empty) {}
SourceLocation getLocation() const { return EmbedKeywordLoc; }
SourceLocation getBeginLoc() const { return EmbedKeywordLoc; }
SourceLocation getEndLoc() const { return EmbedKeywordLoc; }
StringLiteral *getDataStringLiteral() const { return Data->BinaryData; }
EmbedDataStorage *getData() const { return Data; }
unsigned getStartingElementPos() const { return Begin; }
size_t getDataElementCount() const { return NumOfElements; }
// Allows accessing every byte of EmbedExpr data and iterating over it.
// An Iterator knows the EmbedExpr that it refers to, and an offset value
// within the data.
// Dereferencing an Iterator results in construction of IntegerLiteral AST
// node filled with byte of data of the corresponding EmbedExpr within offset
// that the Iterator currently has.
template <bool Const>
class ChildElementIter
: public llvm::iterator_facade_base<
ChildElementIter<Const>, std::random_access_iterator_tag,
std::conditional_t<Const, const IntegerLiteral *,
IntegerLiteral *>> {
friend class EmbedExpr;
EmbedExpr *EExpr = nullptr;
unsigned long long CurOffset = ULLONG_MAX;
using BaseTy = typename ChildElementIter::iterator_facade_base;
ChildElementIter(EmbedExpr *E) : EExpr(E) {
if (E)
CurOffset = E->getStartingElementPos();
}
public:
ChildElementIter() : CurOffset(ULLONG_MAX) {}
typename BaseTy::reference operator*() const {
assert(EExpr && CurOffset != ULLONG_MAX &&
"trying to dereference an invalid iterator");
IntegerLiteral *N = EExpr->FakeChildNode;
StringRef DataRef = EExpr->Data->BinaryData->getBytes();
N->setValue(*EExpr->Ctx,
llvm::APInt(N->getValue().getBitWidth(), DataRef[CurOffset],
N->getType()->isSignedIntegerType()));
// We want to return a reference to the fake child node in the
// EmbedExpr, not the local variable N.
return const_cast<typename BaseTy::reference>(EExpr->FakeChildNode);
}
typename BaseTy::pointer operator->() const { return **this; }
using BaseTy::operator++;
ChildElementIter &operator++() {
assert(EExpr && "trying to increment an invalid iterator");
assert(CurOffset != ULLONG_MAX &&
"Already at the end of what we can iterate over");
if (++CurOffset >=
EExpr->getDataElementCount() + EExpr->getStartingElementPos()) {
CurOffset = ULLONG_MAX;
EExpr = nullptr;
}
return *this;
}
bool operator==(ChildElementIter Other) const {
return (EExpr == Other.EExpr && CurOffset == Other.CurOffset);
}
}; // class ChildElementIter
public:
using fake_child_range = llvm::iterator_range<ChildElementIter<false>>;
using const_fake_child_range = llvm::iterator_range<ChildElementIter<true>>;
fake_child_range underlying_data_elements() {
return fake_child_range(ChildElementIter<false>(this),
ChildElementIter<false>());
}
const_fake_child_range underlying_data_elements() const {
return const_fake_child_range(
ChildElementIter<true>(const_cast<EmbedExpr *>(this)),
ChildElementIter<true>());
}
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == EmbedExprClass;
}
ChildElementIter<false> begin() { return ChildElementIter<false>(this); }
ChildElementIter<true> begin() const {
return ChildElementIter<true>(const_cast<EmbedExpr *>(this));
}
template <typename Call, typename... Targs>
bool doForEachDataElement(Call &&C, unsigned &StartingIndexInArray,
Targs &&...Fargs) const {
for (auto It : underlying_data_elements()) {
if (!std::invoke(std::forward<Call>(C), const_cast<IntegerLiteral *>(It),
StartingIndexInArray, std::forward<Targs>(Fargs)...))
return false;
StartingIndexInArray++;
}
return true;
}
private:
friend class ASTStmtReader;
};
/// Describes an C or C++ initializer list.
///
/// InitListExpr describes an initializer list, which can be used to
@ -5811,7 +6022,7 @@ class GenericSelectionExpr final
// if *It1 and *It2 are bound to the same objects.
// An alternative design approach was discussed during review;
// store an Association object inside the iterator, and return a reference
// to it when dereferenced. This idea was discarded beacuse of nasty
// to it when dereferenced. This idea was discarded because of nasty
// lifetime issues:
// AssociationIterator It = ...;
// const Association &Assoc = *It++; // Oops, Assoc is dangling.
@ -5820,7 +6031,7 @@ class GenericSelectionExpr final
std::conditional_t<Const, const Stmt *const *, Stmt **>;
using TSIPtrPtrTy = std::conditional_t<Const, const TypeSourceInfo *const *,
TypeSourceInfo **>;
StmtPtrPtrTy E; // = nullptr; FIXME: Once support for gcc 4.8 is dropped.
StmtPtrPtrTy E = nullptr;
TSIPtrPtrTy TSI; // Kept in sync with E.
unsigned Offset = 0, SelectedOffset = 0;
AssociationIteratorTy(StmtPtrPtrTy E, TSIPtrPtrTy TSI, unsigned Offset,
@ -6410,7 +6621,7 @@ public:
enum AtomicOp {
#define BUILTIN(ID, TYPE, ATTRS)
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) AO ## ID,
#include "clang/Basic/Builtins.def"
#include "clang/Basic/Builtins.inc"
// Avoid trailing comma
BI_First = 0
};
@ -6476,7 +6687,7 @@ public:
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
case AO##ID: \
return #ID;
#include "clang/Basic/Builtins.def"
#include "clang/Basic/Builtins.inc"
}
llvm_unreachable("not an atomic operator?");
}
@ -6505,8 +6716,8 @@ public:
}
bool isOpenCL() const {
return getOp() >= AO__opencl_atomic_init &&
getOp() <= AO__opencl_atomic_fetch_max;
return getOp() >= AO__opencl_atomic_compare_exchange_strong &&
getOp() <= AO__opencl_atomic_store;
}
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
@ -6531,11 +6742,14 @@ public:
/// \return empty atomic scope model if the atomic op code does not have
/// scope operand.
static std::unique_ptr<AtomicScopeModel> getScopeModel(AtomicOp Op) {
if (Op >= AO__opencl_atomic_load && Op <= AO__opencl_atomic_fetch_max)
// FIXME: Allow grouping of builtins to be able to only check >= and <=
if (Op >= AO__opencl_atomic_compare_exchange_strong &&
Op <= AO__opencl_atomic_store && Op != AO__opencl_atomic_init)
return AtomicScopeModel::create(AtomicScopeModelKind::OpenCL);
else if (Op >= AO__hip_atomic_load && Op <= AO__hip_atomic_fetch_max)
if (Op >= AO__hip_atomic_compare_exchange_strong &&
Op <= AO__hip_atomic_store)
return AtomicScopeModel::create(AtomicScopeModelKind::HIP);
else if (Op >= AO__scoped_atomic_load && Op <= AO__scoped_atomic_fetch_max)
if (Op >= AO__scoped_atomic_add_fetch && Op <= AO__scoped_atomic_xor_fetch)
return AtomicScopeModel::create(AtomicScopeModelKind::Generic);
return AtomicScopeModel::create(AtomicScopeModelKind::None);
}
@ -6578,6 +6792,275 @@ public:
};
/// This class represents BOTH the OpenMP Array Section and OpenACC 'subarray',
/// with a boolean differentiator.
/// OpenMP 5.0 [2.1.5, Array Sections].
/// To specify an array section in an OpenMP construct, array subscript
/// expressions are extended with the following syntax:
/// \code
/// [ lower-bound : length : stride ]
/// [ lower-bound : length : ]
/// [ lower-bound : length ]
/// [ lower-bound : : stride ]
/// [ lower-bound : : ]
/// [ lower-bound : ]
/// [ : length : stride ]
/// [ : length : ]
/// [ : length ]
/// [ : : stride ]
/// [ : : ]
/// [ : ]
/// \endcode
/// The array section must be a subset of the original array.
/// Array sections are allowed on multidimensional arrays. Base language array
/// subscript expressions can be used to specify length-one dimensions of
/// multidimensional array sections.
/// Each of the lower-bound, length, and stride expressions if specified must be
/// an integral type expressions of the base language. When evaluated
/// they represent a set of integer values as follows:
/// \code
/// { lower-bound, lower-bound + stride, lower-bound + 2 * stride,... ,
/// lower-bound + ((length - 1) * stride) }
/// \endcode
/// The lower-bound and length must evaluate to non-negative integers.
/// The stride must evaluate to a positive integer.
/// When the size of the array dimension is not known, the length must be
/// specified explicitly.
/// When the stride is absent it defaults to 1.
/// When the length is absent it defaults to ⌈(size lower-bound)/stride⌉,
/// where size is the size of the array dimension. When the lower-bound is
/// absent it defaults to 0.
///
///
/// OpenACC 3.3 [2.7.1 Data Specification in Data Clauses]
/// In C and C++, a subarray is an array name followed by an extended array
/// range specification in brackets, with start and length, such as
///
/// AA[2:n]
///
/// If the lower bound is missing, zero is used. If the length is missing and
/// the array has known size, the size of the array is used; otherwise the
/// length is required. The subarray AA[2:n] means elements AA[2], AA[3], . . .
/// , AA[2+n-1]. In C and C++, a two dimensional array may be declared in at
/// least four ways:
///
/// -Statically-sized array: float AA[100][200];
/// -Pointer to statically sized rows: typedef float row[200]; row* BB;
/// -Statically-sized array of pointers: float* CC[200];
/// -Pointer to pointers: float** DD;
///
/// Each dimension may be statically sized, or a pointer to dynamically
/// allocated memory. Each of these may be included in a data clause using
/// subarray notation to specify a rectangular array:
///
/// -AA[2:n][0:200]
/// -BB[2:n][0:m]
/// -CC[2:n][0:m]
/// -DD[2:n][0:m]
///
/// Multidimensional rectangular subarrays in C and C++ may be specified for any
/// array with any combination of statically-sized or dynamically-allocated
/// dimensions. For statically sized dimensions, all dimensions except the first
/// must specify the whole extent to preserve the contiguous data restriction,
/// discussed below. For dynamically allocated dimensions, the implementation
/// will allocate pointers in device memory corresponding to the pointers in
/// local memory and will fill in those pointers as appropriate.
///
/// In Fortran, a subarray is an array name followed by a comma-separated list
/// of range specifications in parentheses, with lower and upper bound
/// subscripts, such as
///
/// arr(1:high,low:100)
///
/// If either the lower or upper bounds are missing, the declared or allocated
/// bounds of the array, if known, are used. All dimensions except the last must
/// specify the whole extent, to preserve the contiguous data restriction,
/// discussed below.
///
/// Restrictions
///
/// -In Fortran, the upper bound for the last dimension of an assumed-size dummy
/// array must be specified.
///
/// -In C and C++, the length for dynamically allocated dimensions of an array
/// must be explicitly specified.
///
/// -In C and C++, modifying pointers in pointer arrays during the data
/// lifetime, either on the host or on the device, may result in undefined
/// behavior.
///
/// -If a subarray appears in a data clause, the implementation may choose to
/// allocate memory for only that subarray on the accelerator.
///
/// -In Fortran, array pointers may appear, but pointer association is not
/// preserved in device memory.
///
/// -Any array or subarray in a data clause, including Fortran array pointers,
/// must be a contiguous section of memory, except for dynamic multidimensional
/// C arrays.
///
/// -In C and C++, if a variable or array of composite type appears, all the
/// data members of the struct or class are allocated and copied, as
/// appropriate. If a composite member is a pointer type, the data addressed by
/// that pointer are not implicitly copied.
///
/// -In Fortran, if a variable or array of composite type appears, all the
/// members of that derived type are allocated and copied, as appropriate. If
/// any member has the allocatable or pointer attribute, the data accessed
/// through that member are not copied.
///
/// -If an expression is used in a subscript or subarray expression in a clause
/// on a data construct, the same value is used when copying data at the end of
/// the data region, even if the values of variables in the expression change
/// during the data region.
class ArraySectionExpr : public Expr {
friend class ASTStmtReader;
friend class ASTStmtWriter;
public:
enum ArraySectionType { OMPArraySection, OpenACCArraySection };
private:
enum {
BASE,
LOWER_BOUND,
LENGTH,
STRIDE,
END_EXPR,
OPENACC_END_EXPR = STRIDE
};
ArraySectionType ASType = OMPArraySection;
Stmt *SubExprs[END_EXPR] = {nullptr};
SourceLocation ColonLocFirst;
SourceLocation ColonLocSecond;
SourceLocation RBracketLoc;
public:
// Constructor for OMP array sections, which include a 'stride'.
ArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, Expr *Stride,
QualType Type, ExprValueKind VK, ExprObjectKind OK,
SourceLocation ColonLocFirst, SourceLocation ColonLocSecond,
SourceLocation RBracketLoc)
: Expr(ArraySectionExprClass, Type, VK, OK), ASType(OMPArraySection),
ColonLocFirst(ColonLocFirst), ColonLocSecond(ColonLocSecond),
RBracketLoc(RBracketLoc) {
setBase(Base);
setLowerBound(LowerBound);
setLength(Length);
setStride(Stride);
setDependence(computeDependence(this));
}
// Constructor for OpenACC sub-arrays, which do not permit a 'stride'.
ArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, QualType Type,
ExprValueKind VK, ExprObjectKind OK, SourceLocation ColonLoc,
SourceLocation RBracketLoc)
: Expr(ArraySectionExprClass, Type, VK, OK), ASType(OpenACCArraySection),
ColonLocFirst(ColonLoc), RBracketLoc(RBracketLoc) {
setBase(Base);
setLowerBound(LowerBound);
setLength(Length);
setDependence(computeDependence(this));
}
/// Create an empty array section expression.
explicit ArraySectionExpr(EmptyShell Shell)
: Expr(ArraySectionExprClass, Shell) {}
/// Return original type of the base expression for array section.
static QualType getBaseOriginalType(const Expr *Base);
static bool classof(const Stmt *T) {
return T->getStmtClass() == ArraySectionExprClass;
}
bool isOMPArraySection() const { return ASType == OMPArraySection; }
bool isOpenACCArraySection() const { return ASType == OpenACCArraySection; }
/// Get base of the array section.
Expr *getBase() { return cast<Expr>(SubExprs[BASE]); }
const Expr *getBase() const { return cast<Expr>(SubExprs[BASE]); }
/// Get lower bound of array section.
Expr *getLowerBound() { return cast_or_null<Expr>(SubExprs[LOWER_BOUND]); }
const Expr *getLowerBound() const {
return cast_or_null<Expr>(SubExprs[LOWER_BOUND]);
}
/// Get length of array section.
Expr *getLength() { return cast_or_null<Expr>(SubExprs[LENGTH]); }
const Expr *getLength() const { return cast_or_null<Expr>(SubExprs[LENGTH]); }
/// Get stride of array section.
Expr *getStride() {
assert(ASType != OpenACCArraySection &&
"Stride not valid in OpenACC subarrays");
return cast_or_null<Expr>(SubExprs[STRIDE]);
}
const Expr *getStride() const {
assert(ASType != OpenACCArraySection &&
"Stride not valid in OpenACC subarrays");
return cast_or_null<Expr>(SubExprs[STRIDE]);
}
SourceLocation getBeginLoc() const LLVM_READONLY {
return getBase()->getBeginLoc();
}
SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; }
SourceLocation getColonLocFirst() const { return ColonLocFirst; }
SourceLocation getColonLocSecond() const {
assert(ASType != OpenACCArraySection &&
"second colon for stride not valid in OpenACC subarrays");
return ColonLocSecond;
}
SourceLocation getRBracketLoc() const { return RBracketLoc; }
SourceLocation getExprLoc() const LLVM_READONLY {
return getBase()->getExprLoc();
}
child_range children() {
return child_range(
&SubExprs[BASE],
&SubExprs[ASType == OMPArraySection ? END_EXPR : OPENACC_END_EXPR]);
}
const_child_range children() const {
return const_child_range(
&SubExprs[BASE],
&SubExprs[ASType == OMPArraySection ? END_EXPR : OPENACC_END_EXPR]);
}
private:
/// Set base of the array section.
void setBase(Expr *E) { SubExprs[BASE] = E; }
/// Set lower bound of the array section.
void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; }
/// Set length of the array section.
void setLength(Expr *E) { SubExprs[LENGTH] = E; }
/// Set length of the array section.
void setStride(Expr *E) {
assert(ASType != OpenACCArraySection &&
"Stride not valid in OpenACC subarrays");
SubExprs[STRIDE] = E;
}
void setColonLocFirst(SourceLocation L) { ColonLocFirst = L; }
void setColonLocSecond(SourceLocation L) {
assert(ASType != OpenACCArraySection &&
"second colon for stride not valid in OpenACC subarrays");
ColonLocSecond = L;
}
void setRBracketLoc(SourceLocation L) { RBracketLoc = L; }
};
/// Frontend produces RecoveryExprs on semantic errors that prevent creating
/// other well-formed expressions. E.g. when type-checking of a binary operator
/// fails, we cannot produce a BinaryOperator expression. Instead, we can choose

View file

@ -919,6 +919,10 @@ public:
reinterpret_cast<Stmt **>(&const_cast<CXXTypeidExpr *>(this)->Operand);
return const_child_range(begin, begin + 1);
}
/// Whether this is of a form like "typeid(*ptr)" that can throw a
/// std::bad_typeid if a pointer is a null pointer ([expr.typeid]p2)
bool hasNullCheck() const;
};
/// A member reference to an MSPropertyDecl.
@ -1149,6 +1153,7 @@ class CXXThisExpr : public Expr {
CXXThisExpr(SourceLocation L, QualType Ty, bool IsImplicit, ExprValueKind VK)
: Expr(CXXThisExprClass, Ty, VK, OK_Ordinary) {
CXXThisExprBits.IsImplicit = IsImplicit;
CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = false;
CXXThisExprBits.Loc = L;
setDependence(computeDependence(this));
}
@ -1170,6 +1175,15 @@ public:
bool isImplicit() const { return CXXThisExprBits.IsImplicit; }
void setImplicit(bool I) { CXXThisExprBits.IsImplicit = I; }
bool isCapturedByCopyInLambdaWithExplicitObjectParameter() const {
return CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter;
}
void setCapturedByCopyInLambdaWithExplicitObjectParameter(bool Set) {
CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = Set;
setDependence(computeDependence(this));
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXThisExprClass;
}
@ -1472,6 +1486,8 @@ public:
/// const S &s_ref = S(); // Requires a CXXBindTemporaryExpr.
/// }
/// \endcode
///
/// Destructor might be null if destructor declaration is not valid.
class CXXBindTemporaryExpr : public Expr {
CXXTemporary *Temp = nullptr;
Stmt *SubExpr = nullptr;
@ -2549,7 +2565,7 @@ public:
class PseudoDestructorTypeStorage {
/// Either the type source information or the name of the type, if
/// it couldn't be resolved due to type-dependence.
llvm::PointerUnion<TypeSourceInfo *, IdentifierInfo *> Type;
llvm::PointerUnion<TypeSourceInfo *, const IdentifierInfo *> Type;
/// The starting source location of the pseudo-destructor type.
SourceLocation Location;
@ -2557,7 +2573,7 @@ class PseudoDestructorTypeStorage {
public:
PseudoDestructorTypeStorage() = default;
PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc)
PseudoDestructorTypeStorage(const IdentifierInfo *II, SourceLocation Loc)
: Type(II), Location(Loc) {}
PseudoDestructorTypeStorage(TypeSourceInfo *Info);
@ -2566,8 +2582,8 @@ public:
return Type.dyn_cast<TypeSourceInfo *>();
}
IdentifierInfo *getIdentifier() const {
return Type.dyn_cast<IdentifierInfo *>();
const IdentifierInfo *getIdentifier() const {
return Type.dyn_cast<const IdentifierInfo *>();
}
SourceLocation getLocation() const { return Location; }
@ -2698,7 +2714,7 @@ public:
/// In a dependent pseudo-destructor expression for which we do not
/// have full type information on the destroyed type, provides the name
/// of the destroyed type.
IdentifierInfo *getDestroyedTypeIdentifier() const {
const IdentifierInfo *getDestroyedTypeIdentifier() const {
return DestroyedType.getIdentifier();
}
@ -3013,9 +3029,10 @@ protected:
public:
struct FindResult {
OverloadExpr *Expression;
bool IsAddressOfOperand;
bool HasFormOfMemberPointer;
OverloadExpr *Expression = nullptr;
bool IsAddressOfOperand = false;
bool IsAddressOfOperandWithParen = false;
bool HasFormOfMemberPointer = false;
};
/// Finds the overloaded expression in the given expression \p E of
@ -3027,6 +3044,7 @@ public:
assert(E->getType()->isSpecificBuiltinType(BuiltinType::Overload));
FindResult Result;
bool HasParen = isa<ParenExpr>(E);
E = E->IgnoreParens();
if (isa<UnaryOperator>(E)) {
@ -3036,10 +3054,9 @@ public:
Result.HasFormOfMemberPointer = (E == Ovl && Ovl->getQualifier());
Result.IsAddressOfOperand = true;
Result.IsAddressOfOperandWithParen = HasParen;
Result.Expression = Ovl;
} else {
Result.HasFormOfMemberPointer = false;
Result.IsAddressOfOperand = false;
Result.Expression = cast<OverloadExpr>(E);
}
@ -3151,8 +3168,30 @@ public:
/// This arises in several ways:
/// * we might be waiting for argument-dependent lookup;
/// * the name might resolve to an overloaded function;
/// * the name might resolve to a non-function template; for example, in the
/// following snippet, the return expression of the member function
/// 'foo()' might remain unresolved until instantiation:
///
/// \code
/// struct P {
/// template <class T> using I = T;
/// };
///
/// struct Q {
/// template <class T> int foo() {
/// return T::template I<int>;
/// }
/// };
/// \endcode
///
/// ...which is distinct from modeling function overloads, and therefore we use
/// a different builtin type 'UnresolvedTemplate' to avoid confusion. This is
/// done in Sema::BuildTemplateIdExpr.
///
/// and eventually:
/// * the lookup might have included a function template.
/// * the unresolved template gets transformed in an instantiation or gets
/// diagnosed for its direct use.
///
/// These never include UnresolvedUsingValueDecls, which are always class
/// members and therefore appear only in UnresolvedMemberLookupExprs.
@ -3188,7 +3227,6 @@ class UnresolvedLookupExpr final
NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo, bool RequiresADL,
bool Overloaded,
const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
bool KnownDependent);
@ -3208,8 +3246,9 @@ public:
static UnresolvedLookupExpr *
Create(const ASTContext &Context, CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo, bool RequiresADL, bool Overloaded,
UnresolvedSetIterator Begin, UnresolvedSetIterator End);
const DeclarationNameInfo &NameInfo, bool RequiresADL,
UnresolvedSetIterator Begin, UnresolvedSetIterator End,
bool KnownDependent);
// After canonicalization, there may be dependent template arguments in
// CanonicalConverted But none of Args is dependent. When any of
@ -3230,9 +3269,6 @@ public:
/// argument-dependent lookup.
bool requiresADL() const { return UnresolvedLookupExprBits.RequiresADL; }
/// True if this lookup is overloaded.
bool isOverloaded() const { return UnresolvedLookupExprBits.Overloaded; }
/// Gets the 'naming class' (in the sense of C++0x
/// [class.access.base]p5) of the lookup. This is the scope
/// that was looked in to find these results.
@ -4331,6 +4367,116 @@ public:
}
};
class PackIndexingExpr final
: public Expr,
private llvm::TrailingObjects<PackIndexingExpr, Expr *> {
friend class ASTStmtReader;
friend class ASTStmtWriter;
friend TrailingObjects;
SourceLocation EllipsisLoc;
// The location of the closing bracket
SourceLocation RSquareLoc;
// The pack being indexed, followed by the index
Stmt *SubExprs[2];
// The size of the trailing expressions.
unsigned TransformedExpressions : 31;
LLVM_PREFERRED_TYPE(bool)
unsigned ExpandedToEmptyPack : 1;
PackIndexingExpr(QualType Type, SourceLocation EllipsisLoc,
SourceLocation RSquareLoc, Expr *PackIdExpr, Expr *IndexExpr,
ArrayRef<Expr *> SubstitutedExprs = {},
bool ExpandedToEmptyPack = false)
: Expr(PackIndexingExprClass, Type, VK_LValue, OK_Ordinary),
EllipsisLoc(EllipsisLoc), RSquareLoc(RSquareLoc),
SubExprs{PackIdExpr, IndexExpr},
TransformedExpressions(SubstitutedExprs.size()),
ExpandedToEmptyPack(ExpandedToEmptyPack) {
auto *Exprs = getTrailingObjects<Expr *>();
std::uninitialized_copy(SubstitutedExprs.begin(), SubstitutedExprs.end(),
Exprs);
setDependence(computeDependence(this));
if (!isInstantiationDependent())
setValueKind(getSelectedExpr()->getValueKind());
}
/// Create an empty expression.
PackIndexingExpr(EmptyShell Empty) : Expr(PackIndexingExprClass, Empty) {}
unsigned numTrailingObjects(OverloadToken<Expr *>) const {
return TransformedExpressions;
}
public:
static PackIndexingExpr *Create(ASTContext &Context,
SourceLocation EllipsisLoc,
SourceLocation RSquareLoc, Expr *PackIdExpr,
Expr *IndexExpr, std::optional<int64_t> Index,
ArrayRef<Expr *> SubstitutedExprs = {},
bool ExpandedToEmptyPack = false);
static PackIndexingExpr *CreateDeserialized(ASTContext &Context,
unsigned NumTransformedExprs);
/// Determine if the expression was expanded to empty.
bool expandsToEmptyPack() const { return ExpandedToEmptyPack; }
/// Determine the location of the 'sizeof' keyword.
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
/// Determine the location of the parameter pack.
SourceLocation getPackLoc() const { return SubExprs[0]->getBeginLoc(); }
/// Determine the location of the right parenthesis.
SourceLocation getRSquareLoc() const { return RSquareLoc; }
SourceLocation getBeginLoc() const LLVM_READONLY { return getPackLoc(); }
SourceLocation getEndLoc() const LLVM_READONLY { return RSquareLoc; }
Expr *getPackIdExpression() const { return cast<Expr>(SubExprs[0]); }
NamedDecl *getPackDecl() const;
Expr *getIndexExpr() const { return cast<Expr>(SubExprs[1]); }
std::optional<unsigned> getSelectedIndex() const {
if (isInstantiationDependent())
return std::nullopt;
ConstantExpr *CE = cast<ConstantExpr>(getIndexExpr());
auto Index = CE->getResultAsAPSInt();
assert(Index.isNonNegative() && "Invalid index");
return static_cast<unsigned>(Index.getExtValue());
}
Expr *getSelectedExpr() const {
std::optional<unsigned> Index = getSelectedIndex();
assert(Index && "extracting the indexed expression of a dependant pack");
return getTrailingObjects<Expr *>()[*Index];
}
/// Return the trailing expressions, regardless of the expansion.
ArrayRef<Expr *> getExpressions() const {
return {getTrailingObjects<Expr *>(), TransformedExpressions};
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == PackIndexingExprClass;
}
// Iterators
child_range children() { return child_range(SubExprs, SubExprs + 2); }
const_child_range children() const {
return const_child_range(SubExprs, SubExprs + 2);
}
};
/// Represents a reference to a non-type template parameter
/// that has been substituted with a template argument.
class SubstNonTypeTemplateParmExpr : public Expr {
@ -4939,6 +5085,9 @@ class CoroutineSuspendExpr : public Expr {
OpaqueValueExpr *OpaqueValue = nullptr;
public:
// These types correspond to the three C++ 'await_suspend' return variants
enum class SuspendReturnType { SuspendVoid, SuspendBool, SuspendHandle };
CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, Expr *Operand,
Expr *Common, Expr *Ready, Expr *Suspend, Expr *Resume,
OpaqueValueExpr *OpaqueValue)
@ -4998,6 +5147,24 @@ public:
return static_cast<Expr *>(SubExprs[SubExpr::Operand]);
}
SuspendReturnType getSuspendReturnType() const {
auto *SuspendExpr = getSuspendExpr();
assert(SuspendExpr);
auto SuspendType = SuspendExpr->getType();
if (SuspendType->isVoidType())
return SuspendReturnType::SuspendVoid;
if (SuspendType->isBooleanType())
return SuspendReturnType::SuspendBool;
// Void pointer is the type of handle.address(), which is returned
// from the await suspend wrapper so that the temporary coroutine handle
// value won't go to the frame by mistake
assert(SuspendType->isVoidPointerType());
return SuspendReturnType::SuspendHandle;
}
SourceLocation getKeywordLoc() const { return KeywordLoc; }
SourceLocation getBeginLoc() const LLVM_READONLY { return KeywordLoc; }

View file

@ -17,130 +17,6 @@
#include "clang/AST/Expr.h"
namespace clang {
/// OpenMP 5.0 [2.1.5, Array Sections].
/// To specify an array section in an OpenMP construct, array subscript
/// expressions are extended with the following syntax:
/// \code
/// [ lower-bound : length : stride ]
/// [ lower-bound : length : ]
/// [ lower-bound : length ]
/// [ lower-bound : : stride ]
/// [ lower-bound : : ]
/// [ lower-bound : ]
/// [ : length : stride ]
/// [ : length : ]
/// [ : length ]
/// [ : : stride ]
/// [ : : ]
/// [ : ]
/// \endcode
/// The array section must be a subset of the original array.
/// Array sections are allowed on multidimensional arrays. Base language array
/// subscript expressions can be used to specify length-one dimensions of
/// multidimensional array sections.
/// Each of the lower-bound, length, and stride expressions if specified must be
/// an integral type expressions of the base language. When evaluated
/// they represent a set of integer values as follows:
/// \code
/// { lower-bound, lower-bound + stride, lower-bound + 2 * stride,... ,
/// lower-bound + ((length - 1) * stride) }
/// \endcode
/// The lower-bound and length must evaluate to non-negative integers.
/// The stride must evaluate to a positive integer.
/// When the size of the array dimension is not known, the length must be
/// specified explicitly.
/// When the stride is absent it defaults to 1.
/// When the length is absent it defaults to ⌈(size lower-bound)/stride⌉,
/// where size is the size of the array dimension. When the lower-bound is
/// absent it defaults to 0.
class OMPArraySectionExpr : public Expr {
enum { BASE, LOWER_BOUND, LENGTH, STRIDE, END_EXPR };
Stmt *SubExprs[END_EXPR];
SourceLocation ColonLocFirst;
SourceLocation ColonLocSecond;
SourceLocation RBracketLoc;
public:
OMPArraySectionExpr(Expr *Base, Expr *LowerBound, Expr *Length, Expr *Stride,
QualType Type, ExprValueKind VK, ExprObjectKind OK,
SourceLocation ColonLocFirst,
SourceLocation ColonLocSecond, SourceLocation RBracketLoc)
: Expr(OMPArraySectionExprClass, Type, VK, OK),
ColonLocFirst(ColonLocFirst), ColonLocSecond(ColonLocSecond),
RBracketLoc(RBracketLoc) {
SubExprs[BASE] = Base;
SubExprs[LOWER_BOUND] = LowerBound;
SubExprs[LENGTH] = Length;
SubExprs[STRIDE] = Stride;
setDependence(computeDependence(this));
}
/// Create an empty array section expression.
explicit OMPArraySectionExpr(EmptyShell Shell)
: Expr(OMPArraySectionExprClass, Shell) {}
/// An array section can be written only as Base[LowerBound:Length].
/// Get base of the array section.
Expr *getBase() { return cast<Expr>(SubExprs[BASE]); }
const Expr *getBase() const { return cast<Expr>(SubExprs[BASE]); }
/// Set base of the array section.
void setBase(Expr *E) { SubExprs[BASE] = E; }
/// Return original type of the base expression for array section.
static QualType getBaseOriginalType(const Expr *Base);
/// Get lower bound of array section.
Expr *getLowerBound() { return cast_or_null<Expr>(SubExprs[LOWER_BOUND]); }
const Expr *getLowerBound() const {
return cast_or_null<Expr>(SubExprs[LOWER_BOUND]);
}
/// Set lower bound of the array section.
void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; }
/// Get length of array section.
Expr *getLength() { return cast_or_null<Expr>(SubExprs[LENGTH]); }
const Expr *getLength() const { return cast_or_null<Expr>(SubExprs[LENGTH]); }
/// Set length of the array section.
void setLength(Expr *E) { SubExprs[LENGTH] = E; }
/// Get stride of array section.
Expr *getStride() { return cast_or_null<Expr>(SubExprs[STRIDE]); }
const Expr *getStride() const { return cast_or_null<Expr>(SubExprs[STRIDE]); }
/// Set length of the array section.
void setStride(Expr *E) { SubExprs[STRIDE] = E; }
SourceLocation getBeginLoc() const LLVM_READONLY {
return getBase()->getBeginLoc();
}
SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; }
SourceLocation getColonLocFirst() const { return ColonLocFirst; }
void setColonLocFirst(SourceLocation L) { ColonLocFirst = L; }
SourceLocation getColonLocSecond() const { return ColonLocSecond; }
void setColonLocSecond(SourceLocation L) { ColonLocSecond = L; }
SourceLocation getRBracketLoc() const { return RBracketLoc; }
void setRBracketLoc(SourceLocation L) { RBracketLoc = L; }
SourceLocation getExprLoc() const LLVM_READONLY {
return getBase()->getExprLoc();
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPArraySectionExprClass;
}
child_range children() {
return child_range(&SubExprs[BASE], &SubExprs[END_EXPR]);
}
const_child_range children() const {
return const_child_range(&SubExprs[BASE], &SubExprs[END_EXPR]);
}
};
/// An explicit cast in C or a C-style cast in C++, which uses the syntax
/// ([s1][s2]...[sn])expr. For example: @c ([3][3])f.
class OMPArrayShapingExpr final

View file

@ -99,7 +99,7 @@ public:
/// passes back decl sets as VisibleDeclaration objects.
///
/// The default implementation of this method is a no-op.
virtual Decl *GetExternalDecl(uint32_t ID);
virtual Decl *GetExternalDecl(GlobalDeclID ID);
/// Resolve a selector ID into a selector.
///
@ -138,7 +138,7 @@ public:
virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
/// Update an out-of-date identifier.
virtual void updateOutOfDateIdentifier(IdentifierInfo &II) {}
virtual void updateOutOfDateIdentifier(const IdentifierInfo &II) {}
/// Find all declarations with the given name in the given context,
/// and add them to the context by calling SetExternalVisibleDeclsForName
@ -375,7 +375,7 @@ public:
if (isOffset()) {
assert(Source &&
"Cannot deserialize a lazy pointer without an AST source");
Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1));
Ptr = reinterpret_cast<uint64_t>((Source->*Get)(OffsT(Ptr >> 1)));
}
return reinterpret_cast<T*>(Ptr);
}
@ -579,7 +579,7 @@ using LazyDeclStmtPtr =
/// A lazy pointer to a declaration.
using LazyDeclPtr =
LazyOffsetPtr<Decl, uint32_t, &ExternalASTSource::GetExternalDecl>;
LazyOffsetPtr<Decl, GlobalDeclID, &ExternalASTSource::GetExternalDecl>;
/// A lazy pointer to a set of CXXCtorInitializers.
using LazyCXXCtorInitializersPtr =

View file

@ -171,6 +171,14 @@ public:
ZArg, // MS extension
// ISO/IEC TR 18037 (fixed-point) specific specifiers.
kArg, // %k for signed accum types
KArg, // %K for unsigned accum types
rArg, // %r for signed fract types
RArg, // %R for unsigned fract types
FixedPointArgBeg = kArg,
FixedPointArgEnd = RArg,
// Objective-C specific specifiers.
ObjCObjArg, // '@'
ObjCBeg = ObjCObjArg,
@ -237,6 +245,9 @@ public:
bool isDoubleArg() const {
return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
}
bool isFixedPointArg() const {
return kind >= FixedPointArgBeg && kind <= FixedPointArgEnd;
}
const char *toString() const;
@ -273,6 +284,8 @@ public:
/// The conversion specifier and the argument type are disallowed by the C
/// standard, but are in practice harmless. For instance, "%p" and int*.
NoMatchPedantic,
/// The conversion specifier and the argument type have different sign.
NoMatchSignedness,
/// The conversion specifier and the argument type are compatible, but still
/// seems likely to be an error. For instance, "%hd" and _Bool.
NoMatchTypeConfusion,

View file

@ -145,6 +145,10 @@ public:
LHS.MultiVersionIndex == RHS.MultiVersionIndex;
}
bool operator!=(const GlobalDecl &Other) const {
return !(*this == Other);
}
void *getAsOpaquePtr() const { return Value.getOpaqueValue(); }
explicit operator bool() const { return getAsOpaquePtr(); }

View file

@ -197,16 +197,19 @@ public:
void Visit(const Type *T);
void Visit(QualType T);
void Visit(const Decl *D);
void Visit(TypeLoc TL);
void Visit(const comments::Comment *C, const comments::FullComment *FC);
void Visit(const TemplateArgument &TA, SourceRange R = {},
const Decl *From = nullptr, StringRef Label = {});
void Visit(const CXXCtorInitializer *Init);
void Visit(const OpenACCClause *C);
void Visit(const OMPClause *C);
void Visit(const BlockDecl::Capture &C);
void Visit(const GenericSelectionExpr::ConstAssociation &A);
void Visit(const concepts::Requirement *R);
void Visit(const APValue &Value, QualType Ty);
void Visit(const ConceptReference *);
void VisitAliasAttr(const AliasAttr *AA);
void VisitCleanupAttr(const CleanupAttr *CA);
@ -307,6 +310,8 @@ public:
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE);
void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *ME);
void VisitRequiresExpr(const RequiresExpr *RE);
void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node);
void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node);
void VisitObjCEncodeExpr(const ObjCEncodeExpr *OEE);
void VisitObjCMessageExpr(const ObjCMessageExpr *OME);

View file

@ -130,15 +130,15 @@ public:
// FIXME: consider replacing raw_ostream & with something like SmallString &.
void mangleName(GlobalDecl GD, raw_ostream &);
virtual void mangleCXXName(GlobalDecl GD, raw_ostream &) = 0;
virtual void mangleThunk(const CXXMethodDecl *MD,
const ThunkInfo &Thunk,
raw_ostream &) = 0;
virtual void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk,
bool ElideOverrideInfo, raw_ostream &) = 0;
virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type,
const ThisAdjustment &ThisAdjustment,
raw_ostream &) = 0;
const ThunkInfo &Thunk,
bool ElideOverrideInfo, raw_ostream &) = 0;
virtual void mangleReferenceTemporary(const VarDecl *D,
unsigned ManglingNumber,
raw_ostream &) = 0;
virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0;
virtual void mangleCXXRTTI(QualType T, raw_ostream &) = 0;
virtual void mangleCXXRTTIName(QualType T, raw_ostream &,
bool NormalizeIntegers = false) = 0;
@ -192,7 +192,6 @@ public:
bool IsAux = false)
: MangleContext(C, D, MK_Itanium, IsAux) {}
virtual void mangleCXXVTable(const CXXRecordDecl *RD, raw_ostream &) = 0;
virtual void mangleCXXVTT(const CXXRecordDecl *RD, raw_ostream &) = 0;
virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset,
const CXXRecordDecl *Type,

View file

@ -124,7 +124,7 @@ public:
/// cannot be resolved.
static NestedNameSpecifier *Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
IdentifierInfo *II);
const IdentifierInfo *II);
/// Builds a nested name specifier that names a namespace.
static NestedNameSpecifier *Create(const ASTContext &Context,
@ -134,7 +134,7 @@ public:
/// Builds a nested name specifier that names a namespace alias.
static NestedNameSpecifier *Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
NamespaceAliasDecl *Alias);
const NamespaceAliasDecl *Alias);
/// Builds a nested name specifier that names a type.
static NestedNameSpecifier *Create(const ASTContext &Context,
@ -148,7 +148,7 @@ public:
/// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent
/// type.
static NestedNameSpecifier *Create(const ASTContext &Context,
IdentifierInfo *II);
const IdentifierInfo *II);
/// Returns the nested name specifier representing the global
/// scope.
@ -266,7 +266,7 @@ public:
explicit operator bool() const { return Qualifier; }
/// Evaluates true when this nested-name-specifier location is
/// empty.
/// non-empty.
bool hasQualifier() const { return Qualifier; }
/// Retrieve the nested-name-specifier to which this instance

View file

@ -0,0 +1,917 @@
//===- OpenACCClause.h - Classes for OpenACC clauses ------------*- 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
//
//===----------------------------------------------------------------------===//
//
// \file
// This file defines OpenACC AST classes for clauses.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_OPENACCCLAUSE_H
#define LLVM_CLANG_AST_OPENACCCLAUSE_H
#include "clang/AST/ASTContext.h"
#include "clang/AST/StmtIterator.h"
#include "clang/Basic/OpenACCKinds.h"
#include <utility>
namespace clang {
/// This is the base type for all OpenACC Clauses.
class OpenACCClause {
OpenACCClauseKind Kind;
SourceRange Location;
protected:
OpenACCClause(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation EndLoc)
: Kind(K), Location(BeginLoc, EndLoc) {
assert(!BeginLoc.isInvalid() && !EndLoc.isInvalid() &&
"Begin and end location must be valid for OpenACCClause");
}
public:
OpenACCClauseKind getClauseKind() const { return Kind; }
SourceLocation getBeginLoc() const { return Location.getBegin(); }
SourceLocation getEndLoc() const { return Location.getEnd(); }
static bool classof(const OpenACCClause *) { return false; }
using child_iterator = StmtIterator;
using const_child_iterator = ConstStmtIterator;
using child_range = llvm::iterator_range<child_iterator>;
using const_child_range = llvm::iterator_range<const_child_iterator>;
child_range children();
const_child_range children() const {
auto Children = const_cast<OpenACCClause *>(this)->children();
return const_child_range(Children.begin(), Children.end());
}
virtual ~OpenACCClause() = default;
};
// Represents the 'auto' clause.
class OpenACCAutoClause : public OpenACCClause {
protected:
OpenACCAutoClause(SourceLocation BeginLoc, SourceLocation EndLoc)
: OpenACCClause(OpenACCClauseKind::Auto, BeginLoc, EndLoc) {}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Auto;
}
static OpenACCAutoClause *
Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc);
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
};
// Represents the 'independent' clause.
class OpenACCIndependentClause : public OpenACCClause {
protected:
OpenACCIndependentClause(SourceLocation BeginLoc, SourceLocation EndLoc)
: OpenACCClause(OpenACCClauseKind::Independent, BeginLoc, EndLoc) {}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Independent;
}
static OpenACCIndependentClause *
Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc);
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
};
// Represents the 'seq' clause.
class OpenACCSeqClause : public OpenACCClause {
protected:
OpenACCSeqClause(SourceLocation BeginLoc, SourceLocation EndLoc)
: OpenACCClause(OpenACCClauseKind::Seq, BeginLoc, EndLoc) {}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Seq;
}
static OpenACCSeqClause *
Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc);
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
};
// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so
// this provides a basic, do-nothing implementation. We still need to add this
// type to the visitors/etc, as well as get it to take its proper arguments.
class OpenACCGangClause : public OpenACCClause {
protected:
OpenACCGangClause(SourceLocation BeginLoc, SourceLocation EndLoc)
: OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) {
llvm_unreachable("Not yet implemented");
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Gang;
}
static OpenACCGangClause *
Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc);
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
};
// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so
// this provides a basic, do-nothing implementation. We still need to add this
// type to the visitors/etc, as well as get it to take its proper arguments.
class OpenACCVectorClause : public OpenACCClause {
protected:
OpenACCVectorClause(SourceLocation BeginLoc, SourceLocation EndLoc)
: OpenACCClause(OpenACCClauseKind::Vector, BeginLoc, EndLoc) {
llvm_unreachable("Not yet implemented");
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Gang;
}
static OpenACCVectorClause *
Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc);
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
};
// Not yet implemented, but the type name is necessary for 'seq' diagnostics, so
// this provides a basic, do-nothing implementation. We still need to add this
// type to the visitors/etc, as well as get it to take its proper arguments.
class OpenACCWorkerClause : public OpenACCClause {
protected:
OpenACCWorkerClause(SourceLocation BeginLoc, SourceLocation EndLoc)
: OpenACCClause(OpenACCClauseKind::Gang, BeginLoc, EndLoc) {
llvm_unreachable("Not yet implemented");
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Gang;
}
static OpenACCWorkerClause *
Create(const ASTContext &Ctx, SourceLocation BeginLoc, SourceLocation EndLoc);
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
};
/// Represents a clause that has a list of parameters.
class OpenACCClauseWithParams : public OpenACCClause {
/// Location of the '('.
SourceLocation LParenLoc;
protected:
OpenACCClauseWithParams(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, SourceLocation EndLoc)
: OpenACCClause(K, BeginLoc, EndLoc), LParenLoc(LParenLoc) {}
public:
static bool classof(const OpenACCClause *C);
SourceLocation getLParenLoc() const { return LParenLoc; }
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
};
using DeviceTypeArgument = std::pair<IdentifierInfo *, SourceLocation>;
/// A 'device_type' or 'dtype' clause, takes a list of either an 'asterisk' or
/// an identifier. The 'asterisk' means 'the rest'.
class OpenACCDeviceTypeClause final
: public OpenACCClauseWithParams,
public llvm::TrailingObjects<OpenACCDeviceTypeClause,
DeviceTypeArgument> {
// Data stored in trailing objects as IdentifierInfo* /SourceLocation pairs. A
// nullptr IdentifierInfo* represents an asterisk.
unsigned NumArchs;
OpenACCDeviceTypeClause(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc,
ArrayRef<DeviceTypeArgument> Archs,
SourceLocation EndLoc)
: OpenACCClauseWithParams(K, BeginLoc, LParenLoc, EndLoc),
NumArchs(Archs.size()) {
assert(
(K == OpenACCClauseKind::DeviceType || K == OpenACCClauseKind::DType) &&
"Invalid clause kind for device-type");
assert(!llvm::any_of(Archs, [](const DeviceTypeArgument &Arg) {
return Arg.second.isInvalid();
}) && "Invalid SourceLocation for an argument");
assert(
(Archs.size() == 1 || !llvm::any_of(Archs,
[](const DeviceTypeArgument &Arg) {
return Arg.first == nullptr;
})) &&
"Only a single asterisk version is permitted, and must be the "
"only one");
std::uninitialized_copy(Archs.begin(), Archs.end(),
getTrailingObjects<DeviceTypeArgument>());
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::DType ||
C->getClauseKind() == OpenACCClauseKind::DeviceType;
}
bool hasAsterisk() const {
return getArchitectures().size() > 0 &&
getArchitectures()[0].first == nullptr;
}
ArrayRef<DeviceTypeArgument> getArchitectures() const {
return ArrayRef<DeviceTypeArgument>(
getTrailingObjects<DeviceTypeArgument>(), NumArchs);
}
static OpenACCDeviceTypeClause *
Create(const ASTContext &C, OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, ArrayRef<DeviceTypeArgument> Archs,
SourceLocation EndLoc);
};
/// A 'default' clause, has the optional 'none' or 'present' argument.
class OpenACCDefaultClause : public OpenACCClauseWithParams {
friend class ASTReaderStmt;
friend class ASTWriterStmt;
OpenACCDefaultClauseKind DefaultClauseKind;
protected:
OpenACCDefaultClause(OpenACCDefaultClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, SourceLocation EndLoc)
: OpenACCClauseWithParams(OpenACCClauseKind::Default, BeginLoc, LParenLoc,
EndLoc),
DefaultClauseKind(K) {
assert((DefaultClauseKind == OpenACCDefaultClauseKind::None ||
DefaultClauseKind == OpenACCDefaultClauseKind::Present) &&
"Invalid Clause Kind");
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Default;
}
OpenACCDefaultClauseKind getDefaultClauseKind() const {
return DefaultClauseKind;
}
static OpenACCDefaultClause *Create(const ASTContext &C,
OpenACCDefaultClauseKind K,
SourceLocation BeginLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
};
/// Represents one of the handful of classes that has an optional/required
/// 'condition' expression as an argument.
class OpenACCClauseWithCondition : public OpenACCClauseWithParams {
Expr *ConditionExpr = nullptr;
protected:
OpenACCClauseWithCondition(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *ConditionExpr,
SourceLocation EndLoc)
: OpenACCClauseWithParams(K, BeginLoc, LParenLoc, EndLoc),
ConditionExpr(ConditionExpr) {}
public:
static bool classof(const OpenACCClause *C);
bool hasConditionExpr() const { return ConditionExpr; }
const Expr *getConditionExpr() const { return ConditionExpr; }
Expr *getConditionExpr() { return ConditionExpr; }
child_range children() {
if (ConditionExpr)
return child_range(reinterpret_cast<Stmt **>(&ConditionExpr),
reinterpret_cast<Stmt **>(&ConditionExpr + 1));
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
if (ConditionExpr)
return const_child_range(
reinterpret_cast<Stmt *const *>(&ConditionExpr),
reinterpret_cast<Stmt *const *>(&ConditionExpr + 1));
return const_child_range(const_child_iterator(), const_child_iterator());
}
};
/// An 'if' clause, which has a required condition expression.
class OpenACCIfClause : public OpenACCClauseWithCondition {
protected:
OpenACCIfClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *ConditionExpr, SourceLocation EndLoc);
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::If;
}
static OpenACCIfClause *Create(const ASTContext &C, SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *ConditionExpr,
SourceLocation EndLoc);
};
/// A 'self' clause, which has an optional condition expression.
class OpenACCSelfClause : public OpenACCClauseWithCondition {
OpenACCSelfClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *ConditionExpr, SourceLocation EndLoc);
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Self;
}
static OpenACCSelfClause *Create(const ASTContext &C, SourceLocation BeginLoc,
SourceLocation LParenLoc,
Expr *ConditionExpr, SourceLocation EndLoc);
};
/// Represents a clause that has one or more expressions associated with it.
class OpenACCClauseWithExprs : public OpenACCClauseWithParams {
MutableArrayRef<Expr *> Exprs;
protected:
OpenACCClauseWithExprs(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, SourceLocation EndLoc)
: OpenACCClauseWithParams(K, BeginLoc, LParenLoc, EndLoc) {}
/// Used only for initialization, the leaf class can initialize this to
/// trailing storage.
void setExprs(MutableArrayRef<Expr *> NewExprs) {
assert(Exprs.empty() && "Cannot change Exprs list");
Exprs = NewExprs;
}
/// Gets the entire list of expressions, but leave it to the
/// individual clauses to expose this how they'd like.
llvm::ArrayRef<Expr *> getExprs() const { return Exprs; }
public:
static bool classof(const OpenACCClause *C);
child_range children() {
return child_range(reinterpret_cast<Stmt **>(Exprs.begin()),
reinterpret_cast<Stmt **>(Exprs.end()));
}
const_child_range children() const {
child_range Children =
const_cast<OpenACCClauseWithExprs *>(this)->children();
return const_child_range(Children.begin(), Children.end());
}
};
// Represents the 'devnum' and expressions lists for the 'wait' clause.
class OpenACCWaitClause final
: public OpenACCClauseWithExprs,
public llvm::TrailingObjects<OpenACCWaitClause, Expr *> {
SourceLocation QueuesLoc;
OpenACCWaitClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *DevNumExpr, SourceLocation QueuesLoc,
ArrayRef<Expr *> QueueIdExprs, SourceLocation EndLoc)
: OpenACCClauseWithExprs(OpenACCClauseKind::Wait, BeginLoc, LParenLoc,
EndLoc),
QueuesLoc(QueuesLoc) {
// The first element of the trailing storage is always the devnum expr,
// whether it is used or not.
std::uninitialized_copy(&DevNumExpr, &DevNumExpr + 1,
getTrailingObjects<Expr *>());
std::uninitialized_copy(QueueIdExprs.begin(), QueueIdExprs.end(),
getTrailingObjects<Expr *>() + 1);
setExprs(
MutableArrayRef(getTrailingObjects<Expr *>(), QueueIdExprs.size() + 1));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Wait;
}
static OpenACCWaitClause *Create(const ASTContext &C, SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *DevNumExpr,
SourceLocation QueuesLoc,
ArrayRef<Expr *> QueueIdExprs,
SourceLocation EndLoc);
bool hasQueuesTag() const { return !QueuesLoc.isInvalid(); }
SourceLocation getQueuesLoc() const { return QueuesLoc; }
bool hasDevNumExpr() const { return getExprs()[0]; }
Expr *getDevNumExpr() const { return getExprs()[0]; }
llvm::ArrayRef<Expr *> getQueueIdExprs() {
return OpenACCClauseWithExprs::getExprs().drop_front();
}
llvm::ArrayRef<Expr *> getQueueIdExprs() const {
return OpenACCClauseWithExprs::getExprs().drop_front();
}
};
class OpenACCNumGangsClause final
: public OpenACCClauseWithExprs,
public llvm::TrailingObjects<OpenACCNumGangsClause, Expr *> {
OpenACCNumGangsClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> IntExprs, SourceLocation EndLoc)
: OpenACCClauseWithExprs(OpenACCClauseKind::NumGangs, BeginLoc, LParenLoc,
EndLoc) {
std::uninitialized_copy(IntExprs.begin(), IntExprs.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), IntExprs.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::NumGangs;
}
static OpenACCNumGangsClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> IntExprs, SourceLocation EndLoc);
llvm::ArrayRef<Expr *> getIntExprs() {
return OpenACCClauseWithExprs::getExprs();
}
llvm::ArrayRef<Expr *> getIntExprs() const {
return OpenACCClauseWithExprs::getExprs();
}
};
/// Represents one of a handful of clauses that have a single integer
/// expression.
class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithExprs {
Expr *IntExpr;
protected:
OpenACCClauseWithSingleIntExpr(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *IntExpr,
SourceLocation EndLoc)
: OpenACCClauseWithExprs(K, BeginLoc, LParenLoc, EndLoc),
IntExpr(IntExpr) {
if (IntExpr)
setExprs(MutableArrayRef<Expr *>{&this->IntExpr, 1});
}
public:
static bool classof(const OpenACCClause *C);
bool hasIntExpr() const { return !getExprs().empty(); }
const Expr *getIntExpr() const {
return hasIntExpr() ? getExprs()[0] : nullptr;
}
Expr *getIntExpr() { return hasIntExpr() ? getExprs()[0] : nullptr; };
};
class OpenACCNumWorkersClause : public OpenACCClauseWithSingleIntExpr {
OpenACCNumWorkersClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *IntExpr, SourceLocation EndLoc);
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::NumWorkers;
}
static OpenACCNumWorkersClause *Create(const ASTContext &C,
SourceLocation BeginLoc,
SourceLocation LParenLoc,
Expr *IntExpr, SourceLocation EndLoc);
};
class OpenACCVectorLengthClause : public OpenACCClauseWithSingleIntExpr {
OpenACCVectorLengthClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *IntExpr, SourceLocation EndLoc);
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::VectorLength;
}
static OpenACCVectorLengthClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *IntExpr, SourceLocation EndLoc);
};
class OpenACCAsyncClause : public OpenACCClauseWithSingleIntExpr {
OpenACCAsyncClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
Expr *IntExpr, SourceLocation EndLoc);
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Async;
}
static OpenACCAsyncClause *Create(const ASTContext &C,
SourceLocation BeginLoc,
SourceLocation LParenLoc, Expr *IntExpr,
SourceLocation EndLoc);
};
/// Represents a clause with one or more 'var' objects, represented as an expr,
/// as its arguments. Var-list is expected to be stored in trailing storage.
/// For now, we're just storing the original expression in its entirety, unlike
/// OMP which has to do a bunch of work to create a private.
class OpenACCClauseWithVarList : public OpenACCClauseWithExprs {
protected:
OpenACCClauseWithVarList(OpenACCClauseKind K, SourceLocation BeginLoc,
SourceLocation LParenLoc, SourceLocation EndLoc)
: OpenACCClauseWithExprs(K, BeginLoc, LParenLoc, EndLoc) {}
public:
static bool classof(const OpenACCClause *C);
ArrayRef<Expr *> getVarList() { return getExprs(); }
ArrayRef<Expr *> getVarList() const { return getExprs(); }
};
class OpenACCPrivateClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCPrivateClause, Expr *> {
OpenACCPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::Private, BeginLoc,
LParenLoc, EndLoc) {
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Private;
}
static OpenACCPrivateClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};
class OpenACCFirstPrivateClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCFirstPrivateClause, Expr *> {
OpenACCFirstPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::FirstPrivate, BeginLoc,
LParenLoc, EndLoc) {
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::FirstPrivate;
}
static OpenACCFirstPrivateClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};
class OpenACCDevicePtrClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCDevicePtrClause, Expr *> {
OpenACCDevicePtrClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::DevicePtr, BeginLoc,
LParenLoc, EndLoc) {
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::DevicePtr;
}
static OpenACCDevicePtrClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};
class OpenACCAttachClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCAttachClause, Expr *> {
OpenACCAttachClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::Attach, BeginLoc, LParenLoc,
EndLoc) {
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Attach;
}
static OpenACCAttachClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};
class OpenACCNoCreateClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCNoCreateClause, Expr *> {
OpenACCNoCreateClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::NoCreate, BeginLoc,
LParenLoc, EndLoc) {
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::NoCreate;
}
static OpenACCNoCreateClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};
class OpenACCPresentClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCPresentClause, Expr *> {
OpenACCPresentClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::Present, BeginLoc,
LParenLoc, EndLoc) {
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Present;
}
static OpenACCPresentClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};
class OpenACCCopyClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCCopyClause, Expr *> {
OpenACCCopyClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc,
SourceLocation LParenLoc, ArrayRef<Expr *> VarList,
SourceLocation EndLoc)
: OpenACCClauseWithVarList(Spelling, BeginLoc, LParenLoc, EndLoc) {
assert((Spelling == OpenACCClauseKind::Copy ||
Spelling == OpenACCClauseKind::PCopy ||
Spelling == OpenACCClauseKind::PresentOrCopy) &&
"Invalid clause kind for copy-clause");
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Copy ||
C->getClauseKind() == OpenACCClauseKind::PCopy ||
C->getClauseKind() == OpenACCClauseKind::PresentOrCopy;
}
static OpenACCCopyClause *
Create(const ASTContext &C, OpenACCClauseKind Spelling,
SourceLocation BeginLoc, SourceLocation LParenLoc,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};
class OpenACCCopyInClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCCopyInClause, Expr *> {
bool IsReadOnly;
OpenACCCopyInClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc,
SourceLocation LParenLoc, bool IsReadOnly,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(Spelling, BeginLoc, LParenLoc, EndLoc),
IsReadOnly(IsReadOnly) {
assert((Spelling == OpenACCClauseKind::CopyIn ||
Spelling == OpenACCClauseKind::PCopyIn ||
Spelling == OpenACCClauseKind::PresentOrCopyIn) &&
"Invalid clause kind for copyin-clause");
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::CopyIn ||
C->getClauseKind() == OpenACCClauseKind::PCopyIn ||
C->getClauseKind() == OpenACCClauseKind::PresentOrCopyIn;
}
bool isReadOnly() const { return IsReadOnly; }
static OpenACCCopyInClause *
Create(const ASTContext &C, OpenACCClauseKind Spelling,
SourceLocation BeginLoc, SourceLocation LParenLoc, bool IsReadOnly,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};
class OpenACCCopyOutClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCCopyOutClause, Expr *> {
bool IsZero;
OpenACCCopyOutClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc,
SourceLocation LParenLoc, bool IsZero,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(Spelling, BeginLoc, LParenLoc, EndLoc),
IsZero(IsZero) {
assert((Spelling == OpenACCClauseKind::CopyOut ||
Spelling == OpenACCClauseKind::PCopyOut ||
Spelling == OpenACCClauseKind::PresentOrCopyOut) &&
"Invalid clause kind for copyout-clause");
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::CopyOut ||
C->getClauseKind() == OpenACCClauseKind::PCopyOut ||
C->getClauseKind() == OpenACCClauseKind::PresentOrCopyOut;
}
bool isZero() const { return IsZero; }
static OpenACCCopyOutClause *
Create(const ASTContext &C, OpenACCClauseKind Spelling,
SourceLocation BeginLoc, SourceLocation LParenLoc, bool IsZero,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};
class OpenACCCreateClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCCreateClause, Expr *> {
bool IsZero;
OpenACCCreateClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc,
SourceLocation LParenLoc, bool IsZero,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(Spelling, BeginLoc, LParenLoc, EndLoc),
IsZero(IsZero) {
assert((Spelling == OpenACCClauseKind::Create ||
Spelling == OpenACCClauseKind::PCreate ||
Spelling == OpenACCClauseKind::PresentOrCreate) &&
"Invalid clause kind for create-clause");
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Create ||
C->getClauseKind() == OpenACCClauseKind::PCreate ||
C->getClauseKind() == OpenACCClauseKind::PresentOrCreate;
}
bool isZero() const { return IsZero; }
static OpenACCCreateClause *
Create(const ASTContext &C, OpenACCClauseKind Spelling,
SourceLocation BeginLoc, SourceLocation LParenLoc, bool IsZero,
ArrayRef<Expr *> VarList, SourceLocation EndLoc);
};
class OpenACCReductionClause final
: public OpenACCClauseWithVarList,
public llvm::TrailingObjects<OpenACCReductionClause, Expr *> {
OpenACCReductionOperator Op;
OpenACCReductionClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
OpenACCReductionOperator Operator,
ArrayRef<Expr *> VarList, SourceLocation EndLoc)
: OpenACCClauseWithVarList(OpenACCClauseKind::Reduction, BeginLoc,
LParenLoc, EndLoc),
Op(Operator) {
std::uninitialized_copy(VarList.begin(), VarList.end(),
getTrailingObjects<Expr *>());
setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), VarList.size()));
}
public:
static bool classof(const OpenACCClause *C) {
return C->getClauseKind() == OpenACCClauseKind::Reduction;
}
static OpenACCReductionClause *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
OpenACCReductionOperator Operator, ArrayRef<Expr *> VarList,
SourceLocation EndLoc);
OpenACCReductionOperator getReductionOp() const { return Op; }
};
template <class Impl> class OpenACCClauseVisitor {
Impl &getDerived() { return static_cast<Impl &>(*this); }
public:
void VisitClauseList(ArrayRef<const OpenACCClause *> List) {
for (const OpenACCClause *Clause : List)
Visit(Clause);
}
void Visit(const OpenACCClause *C) {
if (!C)
return;
switch (C->getClauseKind()) {
#define VISIT_CLAUSE(CLAUSE_NAME) \
case OpenACCClauseKind::CLAUSE_NAME: \
Visit##CLAUSE_NAME##Clause(*cast<OpenACC##CLAUSE_NAME##Clause>(C)); \
return;
#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME, DEPRECATED) \
case OpenACCClauseKind::ALIAS_NAME: \
Visit##CLAUSE_NAME##Clause(*cast<OpenACC##CLAUSE_NAME##Clause>(C)); \
return;
#include "clang/Basic/OpenACCClauses.def"
default:
llvm_unreachable("Clause visitor not yet implemented");
}
llvm_unreachable("Invalid Clause kind");
}
#define VISIT_CLAUSE(CLAUSE_NAME) \
void Visit##CLAUSE_NAME##Clause( \
const OpenACC##CLAUSE_NAME##Clause &Clause) { \
return getDerived().Visit##CLAUSE_NAME##Clause(Clause); \
}
#include "clang/Basic/OpenACCClauses.def"
};
class OpenACCClausePrinter final
: public OpenACCClauseVisitor<OpenACCClausePrinter> {
raw_ostream &OS;
const PrintingPolicy &Policy;
void printExpr(const Expr *E);
public:
void VisitClauseList(ArrayRef<const OpenACCClause *> List) {
for (const OpenACCClause *Clause : List) {
Visit(Clause);
if (Clause != List.back())
OS << ' ';
}
}
OpenACCClausePrinter(raw_ostream &OS, const PrintingPolicy &Policy)
: OS(OS), Policy(Policy) {}
#define VISIT_CLAUSE(CLAUSE_NAME) \
void Visit##CLAUSE_NAME##Clause(const OpenACC##CLAUSE_NAME##Clause &Clause);
#include "clang/Basic/OpenACCClauses.def"
};
} // namespace clang
#endif // LLVM_CLANG_AST_OPENACCCLAUSE_H

View file

@ -2513,6 +2513,46 @@ public:
}
};
/// This represents 'weak' clause in the '#pragma omp atomic'
/// directives.
///
/// \code
/// #pragma omp atomic compare weak
/// \endcode
/// In this example directive '#pragma omp atomic' has 'weak' clause.
class OMPWeakClause final : public OMPClause {
public:
/// Build 'weak' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
OMPWeakClause(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPClause(llvm::omp::OMPC_weak, StartLoc, EndLoc) {}
/// Build an empty clause.
OMPWeakClause()
: OMPClause(llvm::omp::OMPC_weak, SourceLocation(), SourceLocation()) {}
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
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_weak;
}
};
/// This represents 'fail' clause in the '#pragma omp atomic'
/// directive.
///

View file

@ -361,6 +361,12 @@ CAST_OPERATION(AddressSpaceConversion)
// Convert an integer initializer to an OpenCL sampler.
CAST_OPERATION(IntToOCLSampler)
// Truncate a vector type by dropping elements from the end (HLSL only).
CAST_OPERATION(HLSLVectorTruncation)
// Non-decaying array RValue cast (HLSL only).
CAST_OPERATION(HLSLArrayRValue)
//===- Binary Operations -------------------------------------------------===//
// Operators listed in order of precedence.
// Note that additions to this should also update the StmtVisitor class,

View file

@ -1,4 +1,4 @@
//===- ParentMapContext.h - Map of parents using DynTypedNode -------*- C++ -*-===//
//===- ParentMapContext.h - Map of parents using DynTypedNode ---*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.

View file

@ -77,7 +77,7 @@ struct PrintingPolicy {
PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true),
UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false),
CleanUglifiedParameters(false), EntireContentsOfLargeArray(true),
UseEnumerators(true) {}
UseEnumerators(true), UseHLSLTypes(LO.HLSL) {}
/// Adjust this printing policy for cases where it's known that we're
/// printing C++ code (for instance, if AST dumping reaches a C++-only
@ -342,6 +342,11 @@ struct PrintingPolicy {
LLVM_PREFERRED_TYPE(bool)
unsigned UseEnumerators : 1;
/// Whether or not we're printing known HLSL code and should print HLSL
/// sugared types when possible.
LLVM_PREFERRED_TYPE(bool)
unsigned UseHLSLTypes : 1;
/// Callbacks to use to allow the behavior of printing to be customized.
const PrintingCallbacks *Callbacks = nullptr;
};

View file

@ -117,6 +117,8 @@ def ExtParameterInfo : PropertyType<"FunctionProtoType::ExtParameterInfo">;
def FixedPointSemantics : PropertyType<"llvm::FixedPointSemantics"> {
let PassByReference = 1;
}
def FunctionEffect : PropertyType<"FunctionEffect">;
def EffectConditionExpr : PropertyType<"EffectConditionExpr">;
def Identifier : RefPropertyType<"IdentifierInfo"> { let ConstWhenWriting = 1; }
def LValuePathEntry : PropertyType<"APValue::LValuePathEntry">;
def LValuePathSerializationHelper :
@ -143,6 +145,7 @@ def UInt32 : CountPropertyType<"uint32_t">;
def UInt64 : CountPropertyType<"uint64_t">;
def UnaryTypeTransformKind : EnumPropertyType<"UnaryTransformType::UTTKind">;
def VectorKind : EnumPropertyType<"VectorKind">;
def TypeCoupledDeclRefInfo : PropertyType;
def ExceptionSpecInfo : PropertyType<"FunctionProtoType::ExceptionSpecInfo"> {
let BufferElementTypes = [ QualType ];

View file

@ -175,17 +175,22 @@ private:
mutable StringRef RawText;
mutable const char *BriefText = nullptr;
mutable bool RawTextValid : 1; ///< True if RawText is valid
mutable bool BriefTextValid : 1; ///< True if BriefText is valid
LLVM_PREFERRED_TYPE(bool)
mutable unsigned RawTextValid : 1;
LLVM_PREFERRED_TYPE(bool)
mutable unsigned BriefTextValid : 1;
LLVM_PREFERRED_TYPE(CommentKind)
unsigned Kind : 3;
/// True if comment is attached to a declaration in ASTContext.
bool IsAttached : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsAttached : 1;
bool IsTrailingComment : 1;
bool IsAlmostTrailingComment : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsTrailingComment : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IsAlmostTrailingComment : 1;
/// Constructor for AST deserialization.
RawComment(SourceRange SR, CommentKind K, bool IsTrailingComment,

View file

@ -30,10 +30,12 @@
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/LambdaCapture.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/OpenACCClause.h"
#include "clang/AST/OpenMPClause.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
@ -505,6 +507,11 @@ private:
bool VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *Node);
bool PostVisitStmt(Stmt *S);
bool TraverseOpenACCConstructStmt(OpenACCConstructStmt *S);
bool
TraverseOpenACCAssociatedStmtConstruct(OpenACCAssociatedStmtConstruct *S);
bool VisitOpenACCClauseList(ArrayRef<const OpenACCClause *>);
bool VisitOpenACCClause(const OpenACCClause *);
};
template <typename Derived>
@ -731,13 +738,27 @@ bool RecursiveASTVisitor<Derived>::TraverseDecl(Decl *D) {
// As a syntax visitor, by default we want to ignore declarations for
// implicit declarations (ones not typed explicitly by the user).
if (!getDerived().shouldVisitImplicitCode() && D->isImplicit()) {
// For an implicit template type parameter, its type constraints are not
// implicit and are not represented anywhere else. We still need to visit
// them.
if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(D))
return TraverseTemplateTypeParamDeclConstraints(TTPD);
return true;
if (!getDerived().shouldVisitImplicitCode()) {
if (D->isImplicit()) {
// For an implicit template type parameter, its type constraints are not
// implicit and are not represented anywhere else. We still need to visit
// them.
if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(D))
return TraverseTemplateTypeParamDeclConstraints(TTPD);
return true;
}
// Deduction guides for alias templates are always synthesized, so they
// should not be traversed unless shouldVisitImplicitCode() returns true.
//
// It's important to note that checking the implicit bit is not efficient
// for the alias case. For deduction guides synthesized from explicit
// user-defined deduction guides, we must maintain the explicit bit to
// ensure correct overload resolution.
if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
if (llvm::isa_and_present<TypeAliasTemplateDecl>(
FTD->getDeclName().getCXXDeductionGuideTemplate()))
return true;
}
switch (D->getKind()) {
@ -834,10 +855,14 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo(
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateName(TemplateName Template) {
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName())
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
TRY_TO(TraverseNestedNameSpecifier(DTN->getQualifier()));
else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName())
TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier()));
} else if (QualifiedTemplateName *QTN =
Template.getAsQualifiedTemplateName()) {
if (QTN->getQualifier()) {
TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier()));
}
}
return true;
}
@ -989,6 +1014,12 @@ DEF_TRAVERSE_TYPE(ConstantArrayType, {
TRY_TO(TraverseStmt(const_cast<Expr*>(T->getSizeExpr())));
})
DEF_TRAVERSE_TYPE(ArrayParameterType, {
TRY_TO(TraverseType(T->getElementType()));
if (T->getSizeExpr())
TRY_TO(TraverseStmt(const_cast<Expr *>(T->getSizeExpr())));
})
DEF_TRAVERSE_TYPE(IncompleteArrayType,
{ TRY_TO(TraverseType(T->getElementType())); })
@ -1065,6 +1096,11 @@ DEF_TRAVERSE_TYPE(TypeOfType, { TRY_TO(TraverseType(T->getUnmodifiedType())); })
DEF_TRAVERSE_TYPE(DecltypeType,
{ TRY_TO(TraverseStmt(T->getUnderlyingExpr())); })
DEF_TRAVERSE_TYPE(PackIndexingType, {
TRY_TO(TraverseType(T->getPattern()));
TRY_TO(TraverseStmt(T->getIndexExpr()));
})
DEF_TRAVERSE_TYPE(UnaryTransformType, {
TRY_TO(TraverseType(T->getBaseType()));
TRY_TO(TraverseType(T->getUnderlyingType()));
@ -1101,6 +1137,12 @@ DEF_TRAVERSE_TYPE(InjectedClassNameType, {})
DEF_TRAVERSE_TYPE(AttributedType,
{ TRY_TO(TraverseType(T->getModifiedType())); })
DEF_TRAVERSE_TYPE(CountAttributedType, {
if (T->getCountExpr())
TRY_TO(TraverseStmt(T->getCountExpr()));
TRY_TO(TraverseType(T->desugar()));
})
DEF_TRAVERSE_TYPE(BTFTagAttributedType,
{ TRY_TO(TraverseType(T->getWrappedType())); })
@ -1245,6 +1287,11 @@ DEF_TRAVERSE_TYPELOC(ConstantArrayType, {
TRY_TO(TraverseArrayTypeLocHelper(TL));
})
DEF_TRAVERSE_TYPELOC(ArrayParameterType, {
TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
TRY_TO(TraverseArrayTypeLocHelper(TL));
})
DEF_TRAVERSE_TYPELOC(IncompleteArrayType, {
TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
TRY_TO(TraverseArrayTypeLocHelper(TL));
@ -1343,6 +1390,11 @@ DEF_TRAVERSE_TYPELOC(DecltypeType, {
TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr()));
})
DEF_TRAVERSE_TYPELOC(PackIndexingType, {
TRY_TO(TraverseType(TL.getPattern()));
TRY_TO(TraverseStmt(TL.getTypePtr()->getIndexExpr()));
})
DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
})
@ -1387,6 +1439,9 @@ DEF_TRAVERSE_TYPELOC(MacroQualifiedType,
DEF_TRAVERSE_TYPELOC(AttributedType,
{ TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); })
DEF_TRAVERSE_TYPELOC(CountAttributedType,
{ TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })
DEF_TRAVERSE_TYPELOC(BTFTagAttributedType,
{ TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); })
@ -1911,7 +1966,7 @@ DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
TRY_TO(TraverseTemplateTypeParamDeclConstraints(D));
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc()));
TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument()));
})
DEF_TRAVERSE_DECL(TypedefDecl, {
@ -1995,6 +2050,15 @@ DEF_TRAVERSE_DECL(RecordDecl, { TRY_TO(TraverseRecordHelper(D)); })
DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
const TemplateArgumentLoc *TAL, unsigned Count) {
for (unsigned I = 0; I < Count; ++I) {
TRY_TO(TraverseTemplateArgumentLoc(TAL[I]));
}
return true;
}
#define DEF_TRAVERSE_TMPL_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, { \
/* For implicit instantiations ("set<int> x;"), we don't want to \
@ -2004,9 +2068,12 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
TemplateSpecializationType). For explicit instantiations \
("template set<int>;"), we do need a callback, since this \
is the only callback that's made for this instantiation. \
We use getTypeAsWritten() to distinguish. */ \
if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \
We use getTemplateArgsAsWritten() to distinguish. */ \
if (const auto *ArgsWritten = D->getTemplateArgsAsWritten()) { \
/* The args that remains unspecialized. */ \
TRY_TO(TraverseTemplateArgumentLocsHelper( \
ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs)); \
} \
\
if (getDerived().shouldVisitTemplateInstantiations() || \
D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { \
@ -2026,15 +2093,6 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
DEF_TRAVERSE_TMPL_SPEC_DECL(Class, CXXRecord)
DEF_TRAVERSE_TMPL_SPEC_DECL(Var, Var)
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateArgumentLocsHelper(
const TemplateArgumentLoc *TAL, unsigned Count) {
for (unsigned I = 0; I < Count; ++I) {
TRY_TO(TraverseTemplateArgumentLoc(TAL[I]));
}
return true;
}
#define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \
/* The partial specialization. */ \
@ -2268,7 +2326,7 @@ DEF_TRAVERSE_DECL(NonTypeTemplateParmDecl, {
// A non-type template parameter, e.g. "S" in template<int S> class Foo ...
TRY_TO(TraverseDeclaratorHelper(D));
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
TRY_TO(TraverseStmt(D->getDefaultArgument()));
TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument()));
})
DEF_TRAVERSE_DECL(ParmVarDecl, {
@ -2705,7 +2763,7 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, {})
DEF_TRAVERSE_STMT(AddrLabelExpr, {})
DEF_TRAVERSE_STMT(ArraySubscriptExpr, {})
DEF_TRAVERSE_STMT(MatrixSubscriptExpr, {})
DEF_TRAVERSE_STMT(OMPArraySectionExpr, {})
DEF_TRAVERSE_STMT(ArraySectionExpr, {})
DEF_TRAVERSE_STMT(OMPArrayShapingExpr, {})
DEF_TRAVERSE_STMT(OMPIteratorExpr, {})
@ -2806,6 +2864,11 @@ DEF_TRAVERSE_STMT(ShuffleVectorExpr, {})
DEF_TRAVERSE_STMT(ConvertVectorExpr, {})
DEF_TRAVERSE_STMT(StmtExpr, {})
DEF_TRAVERSE_STMT(SourceLocExpr, {})
DEF_TRAVERSE_STMT(EmbedExpr, {
for (IntegerLiteral *IL : S->underlying_data_elements()) {
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(IL);
}
})
DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
@ -2854,6 +2917,7 @@ DEF_TRAVERSE_STMT(CompoundAssignOperator, {})
DEF_TRAVERSE_STMT(CXXNoexceptExpr, {})
DEF_TRAVERSE_STMT(PackExpansionExpr, {})
DEF_TRAVERSE_STMT(SizeOfPackExpr, {})
DEF_TRAVERSE_STMT(PackIndexingExpr, {})
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {})
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
@ -2968,6 +3032,12 @@ DEF_TRAVERSE_STMT(OMPTileDirective,
DEF_TRAVERSE_STMT(OMPUnrollDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
DEF_TRAVERSE_STMT(OMPReverseDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
DEF_TRAVERSE_STMT(OMPInterchangeDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
DEF_TRAVERSE_STMT(OMPForDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
@ -3425,6 +3495,11 @@ bool RecursiveASTVisitor<Derived>::VisitOMPRelaxedClause(OMPRelaxedClause *) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPWeakClause(OMPWeakClause *) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPThreadsClause(OMPThreadsClause *) {
return true;
@ -3894,6 +3969,51 @@ bool RecursiveASTVisitor<Derived>::VisitOMPXBareClause(OMPXBareClause *C) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseOpenACCConstructStmt(
OpenACCConstructStmt *C) {
TRY_TO(VisitOpenACCClauseList(C->clauses()));
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseOpenACCAssociatedStmtConstruct(
OpenACCAssociatedStmtConstruct *S) {
TRY_TO(TraverseOpenACCConstructStmt(S));
TRY_TO(TraverseStmt(S->getAssociatedStmt()));
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOpenACCClause(const OpenACCClause *C) {
for (const Stmt *Child : C->children())
TRY_TO(TraverseStmt(const_cast<Stmt *>(Child)));
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOpenACCClauseList(
ArrayRef<const OpenACCClause *> Clauses) {
for (const auto *C : Clauses)
TRY_TO(VisitOpenACCClause(C));
// if (const auto *WithCond = dyn_cast<OopenACCClauseWithCondition>(C);
// WithCond && WIthCond->hasConditionExpr()) {
// TRY_TO(TraverseStmt(WithCond->getConditionExpr());
// } else if (const auto *
// }
// OpenACCClauseWithCondition::getConditionExpr/hasConditionExpr
//OpenACCClauseWithExprs::children (might be null?)
// TODO OpenACC: When we have Clauses with expressions, we should visit them
// here.
return true;
}
DEF_TRAVERSE_STMT(OpenACCComputeConstruct,
{ TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })
DEF_TRAVERSE_STMT(OpenACCLoopConstruct,
{ TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })
// 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

View file

@ -281,10 +281,10 @@ public:
return tmp;
}
friend bool operator==(redecl_iterator x, redecl_iterator y) {
friend bool operator==(const redecl_iterator &x, const redecl_iterator &y) {
return x.Current == y.Current;
}
friend bool operator!=(redecl_iterator x, redecl_iterator y) {
friend bool operator!=(const redecl_iterator &x, const redecl_iterator &y) {
return x.Current != y.Current;
}
};

View file

@ -460,10 +460,10 @@ protected:
unsigned : NumExprBits;
static_assert(
llvm::APFloat::S_MaxSemantics < 16,
"Too many Semantics enum values to fit in bitfield of size 4");
llvm::APFloat::S_MaxSemantics < 32,
"Too many Semantics enum values to fit in bitfield of size 5");
LLVM_PREFERRED_TYPE(llvm::APFloat::Semantics)
unsigned Semantics : 4; // Provides semantics for APFloat construction
unsigned Semantics : 5; // Provides semantics for APFloat construction
LLVM_PREFERRED_TYPE(bool)
unsigned IsExact : 1;
};
@ -583,11 +583,13 @@ protected:
unsigned IsArrow : 1;
/// True if this member expression used a nested-name-specifier to
/// refer to the member, e.g., "x->Base::f", or found its member via
/// a using declaration. When true, a MemberExprNameQualifier
/// structure is allocated immediately after the MemberExpr.
/// refer to the member, e.g., "x->Base::f".
LLVM_PREFERRED_TYPE(bool)
unsigned HasQualifierOrFoundDecl : 1;
unsigned HasQualifier : 1;
// True if this member expression found its member via a using declaration.
LLVM_PREFERRED_TYPE(bool)
unsigned HasFoundDecl : 1;
/// True if this member expression specified a template keyword
/// and/or a template argument list explicitly, e.g., x->f<int>,
@ -782,6 +784,11 @@ protected:
LLVM_PREFERRED_TYPE(bool)
unsigned IsImplicit : 1;
/// Whether there is a lambda with an explicit object parameter that
/// captures this "this" by copy.
LLVM_PREFERRED_TYPE(bool)
unsigned CapturedByCopyInLambdaWithExplicitObjectParameter : 1;
/// The location of the "this".
SourceLocation Loc;
};
@ -1060,11 +1067,6 @@ protected:
/// argument-dependent lookup if this is the operand of a function call.
LLVM_PREFERRED_TYPE(bool)
unsigned RequiresADL : 1;
/// True if these lookup results are overloaded. This is pretty trivially
/// rederivable if we urgently need to kill this field.
LLVM_PREFERRED_TYPE(bool)
unsigned Overloaded : 1;
};
static_assert(sizeof(UnresolvedLookupExprBitfields) <= 4,
"UnresolvedLookupExprBitfields must be <= than 4 bytes to"
@ -1656,6 +1658,11 @@ public:
return *getTrailingObjects<FPOptionsOverride>();
}
/// Get the store FPOptionsOverride or default if not stored.
FPOptionsOverride getStoredFPFeaturesOrDefault() const {
return hasStoredFPFeatures() ? getStoredFPFeatures() : FPOptionsOverride();
}
using body_iterator = Stmt **;
using body_range = llvm::iterator_range<body_iterator>;

View file

@ -177,7 +177,8 @@ class ObjCAtTryStmt final
unsigned NumCatchStmts : 16;
// Whether this statement has a \@finally statement.
bool HasFinally : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned HasFinally : 1;
/// Retrieve the statements that are stored after this \@try statement.
///

View file

@ -0,0 +1,256 @@
//===- StmtOpenACC.h - Classes for OpenACC directives ----------*- 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
//
//===----------------------------------------------------------------------===//
/// \file
/// This file defines OpenACC AST classes for statement-level contructs.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_AST_STMTOPENACC_H
#define LLVM_CLANG_AST_STMTOPENACC_H
#include "clang/AST/OpenACCClause.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/OpenACCKinds.h"
#include "clang/Basic/SourceLocation.h"
#include <memory>
namespace clang {
/// This is the base class for an OpenACC statement-level construct, other
/// construct types are expected to inherit from this.
class OpenACCConstructStmt : public Stmt {
friend class ASTStmtWriter;
friend class ASTStmtReader;
/// The directive kind. Each implementation of this interface should handle
/// specific kinds.
OpenACCDirectiveKind Kind = OpenACCDirectiveKind::Invalid;
/// The location of the directive statement, from the '#' to the last token of
/// the directive.
SourceRange Range;
/// The location of the directive name.
SourceLocation DirectiveLoc;
/// The list of clauses. This is stored here as an ArrayRef, as this is the
/// most convienient place to access the list, however the list itself should
/// be stored in leaf nodes, likely in trailing-storage.
MutableArrayRef<const OpenACCClause *> Clauses;
protected:
OpenACCConstructStmt(StmtClass SC, OpenACCDirectiveKind K,
SourceLocation Start, SourceLocation DirectiveLoc,
SourceLocation End)
: Stmt(SC), Kind(K), Range(Start, End), DirectiveLoc(DirectiveLoc) {}
// Used only for initialization, the leaf class can initialize this to
// trailing storage.
void setClauseList(MutableArrayRef<const OpenACCClause *> NewClauses) {
assert(Clauses.empty() && "Cannot change clause list");
Clauses = NewClauses;
}
public:
OpenACCDirectiveKind getDirectiveKind() const { return Kind; }
static bool classof(const Stmt *S) {
return S->getStmtClass() >= firstOpenACCConstructStmtConstant &&
S->getStmtClass() <= lastOpenACCConstructStmtConstant;
}
SourceLocation getBeginLoc() const { return Range.getBegin(); }
SourceLocation getEndLoc() const { return Range.getEnd(); }
SourceLocation getDirectiveLoc() const { return DirectiveLoc; }
ArrayRef<const OpenACCClause *> clauses() const { return Clauses; }
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_cast<OpenACCConstructStmt *>(this)->children();
}
};
/// This is a base class for any OpenACC statement-level constructs that have an
/// associated statement. This class is not intended to be instantiated, but is
/// a convenient place to hold the associated statement.
class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt {
friend class ASTStmtWriter;
friend class ASTStmtReader;
template <typename Derived> friend class RecursiveASTVisitor;
Stmt *AssociatedStmt = nullptr;
protected:
OpenACCAssociatedStmtConstruct(StmtClass SC, OpenACCDirectiveKind K,
SourceLocation Start,
SourceLocation DirectiveLoc,
SourceLocation End, Stmt *AssocStmt)
: OpenACCConstructStmt(SC, K, Start, DirectiveLoc, End),
AssociatedStmt(AssocStmt) {}
void setAssociatedStmt(Stmt *S) { AssociatedStmt = S; }
Stmt *getAssociatedStmt() { return AssociatedStmt; }
const Stmt *getAssociatedStmt() const {
return const_cast<OpenACCAssociatedStmtConstruct *>(this)
->getAssociatedStmt();
}
public:
static bool classof(const Stmt *T) {
return false;
}
child_range children() {
if (getAssociatedStmt())
return child_range(&AssociatedStmt, &AssociatedStmt + 1);
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_cast<OpenACCAssociatedStmtConstruct *>(this)->children();
}
};
class OpenACCLoopConstruct;
/// This class represents a compute construct, representing a 'Kind' of
/// `parallel', 'serial', or 'kernel'. These constructs are associated with a
/// 'structured block', defined as:
///
/// in C or C++, an executable statement, possibly compound, with a single
/// entry at the top and a single exit at the bottom
///
/// At the moment there is no real motivation to have a different AST node for
/// those three, as they are semantically identical, and have only minor
/// differences in the permitted list of clauses, which can be differentiated by
/// the 'Kind'.
class OpenACCComputeConstruct final
: public OpenACCAssociatedStmtConstruct,
public llvm::TrailingObjects<OpenACCComputeConstruct,
const OpenACCClause *> {
friend class ASTStmtWriter;
friend class ASTStmtReader;
friend class ASTContext;
OpenACCComputeConstruct(unsigned NumClauses)
: OpenACCAssociatedStmtConstruct(
OpenACCComputeConstructClass, OpenACCDirectiveKind::Invalid,
SourceLocation{}, SourceLocation{}, SourceLocation{},
/*AssociatedStmt=*/nullptr) {
// We cannot send the TrailingObjects storage to the base class (which holds
// a reference to the data) until it is constructed, so we have to set it
// separately here.
std::uninitialized_value_construct(
getTrailingObjects<const OpenACCClause *>(),
getTrailingObjects<const OpenACCClause *>() + NumClauses);
setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
NumClauses));
}
OpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation Start,
SourceLocation DirectiveLoc, SourceLocation End,
ArrayRef<const OpenACCClause *> Clauses,
Stmt *StructuredBlock)
: OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, K, Start,
DirectiveLoc, End, StructuredBlock) {
assert(isOpenACCComputeDirectiveKind(K) &&
"Only parallel, serial, and kernels constructs should be "
"represented by this type");
// Initialize the trailing storage.
std::uninitialized_copy(Clauses.begin(), Clauses.end(),
getTrailingObjects<const OpenACCClause *>());
setClauseList(MutableArrayRef(getTrailingObjects<const OpenACCClause *>(),
Clauses.size()));
}
void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
// Serialization helper function that searches the structured block for 'loop'
// constructs that should be associated with this, and sets their parent
// compute construct to this one. This isn't necessary normally, since we have
// the ability to record the state during parsing.
void findAndSetChildLoops();
public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == OpenACCComputeConstructClass;
}
static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C,
unsigned NumClauses);
static OpenACCComputeConstruct *
Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc,
SourceLocation DirectiveLoc, SourceLocation EndLoc,
ArrayRef<const OpenACCClause *> Clauses, Stmt *StructuredBlock,
ArrayRef<OpenACCLoopConstruct *> AssociatedLoopConstructs);
Stmt *getStructuredBlock() { return getAssociatedStmt(); }
const Stmt *getStructuredBlock() const {
return const_cast<OpenACCComputeConstruct *>(this)->getStructuredBlock();
}
};
/// This class represents a 'loop' construct. The 'loop' construct applies to a
/// 'for' loop (or range-for loop), and is optionally associated with a Compute
/// Construct.
class OpenACCLoopConstruct final
: public OpenACCAssociatedStmtConstruct,
public llvm::TrailingObjects<OpenACCLoopConstruct,
const OpenACCClause *> {
// The compute construct this loop is associated with, or nullptr if this is
// an orphaned loop construct, or if it hasn't been set yet. Because we
// construct the directives at the end of their statement, the 'parent'
// construct is not yet available at the time of construction, so this needs
// to be set 'later'.
const OpenACCComputeConstruct *ParentComputeConstruct = nullptr;
friend class ASTStmtWriter;
friend class ASTStmtReader;
friend class ASTContext;
friend class OpenACCComputeConstruct;
OpenACCLoopConstruct(unsigned NumClauses);
OpenACCLoopConstruct(SourceLocation Start, SourceLocation DirLoc,
SourceLocation End,
ArrayRef<const OpenACCClause *> Clauses, Stmt *Loop);
void setLoop(Stmt *Loop);
void setParentComputeConstruct(OpenACCComputeConstruct *CC) {
assert(!ParentComputeConstruct && "Parent already set?");
ParentComputeConstruct = CC;
}
public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == OpenACCLoopConstructClass;
}
static OpenACCLoopConstruct *CreateEmpty(const ASTContext &C,
unsigned NumClauses);
static OpenACCLoopConstruct *
Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation DirLoc,
SourceLocation EndLoc, ArrayRef<const OpenACCClause *> Clauses,
Stmt *Loop);
Stmt *getLoop() { return getAssociatedStmt(); }
const Stmt *getLoop() const {
return const_cast<OpenACCLoopConstruct *>(this)->getLoop();
}
/// OpenACC 3.3 2.9:
/// An orphaned loop construct is a loop construct that is not lexically
/// enclosed within a compute construct. The parent compute construct of a
/// loop construct is the nearest compute construct that lexically contains
/// the loop construct.
bool isOrphanedLoopConstruct() const {
return ParentComputeConstruct == nullptr;
}
const OpenACCComputeConstruct *getParentComputeConstruct() const {
return ParentComputeConstruct;
}
};
} // namespace clang
#endif // LLVM_CLANG_AST_STMTOPENACC_H

View file

@ -1007,8 +1007,9 @@ public:
Stmt *getPreInits() const;
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPTileDirectiveClass ||
T->getStmtClass() == OMPUnrollDirectiveClass;
Stmt::StmtClass C = T->getStmtClass();
return C == OMPTileDirectiveClass || C == OMPUnrollDirectiveClass ||
C == OMPReverseDirectiveClass || C == OMPInterchangeDirectiveClass;
}
};
@ -2974,6 +2975,7 @@ class OMPAtomicDirective : public OMPExecutableDirective {
/// This field is 1 for the first form of the expression and 0 for the
/// second. Required for correct codegen of non-associative operations (like
/// << or >>).
LLVM_PREFERRED_TYPE(bool)
uint8_t IsXLHSInRHSPart : 1;
/// Used for 'atomic update' or 'atomic capture' constructs. They may
/// have atomic expressions of forms:
@ -2983,9 +2985,11 @@ class OMPAtomicDirective : public OMPExecutableDirective {
/// \endcode
/// This field is 1 for the first(postfix) form of the expression and 0
/// otherwise.
LLVM_PREFERRED_TYPE(bool)
uint8_t IsPostfixUpdate : 1;
/// 1 if 'v' is updated only when the condition is false (compare capture
/// only).
LLVM_PREFERRED_TYPE(bool)
uint8_t IsFailOnly : 1;
} Flags;
@ -5708,6 +5712,144 @@ public:
}
};
/// Represents the '#pragma omp reverse' loop transformation directive.
///
/// \code
/// #pragma omp reverse
/// for (int i = 0; i < n; ++i)
/// ...
/// \endcode
class OMPReverseDirective final : public OMPLoopTransformationDirective {
friend class ASTStmtReader;
friend class OMPExecutableDirective;
/// Offsets of child members.
enum {
PreInitsOffset = 0,
TransformedStmtOffset,
};
explicit OMPReverseDirective(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPLoopTransformationDirective(OMPReverseDirectiveClass,
llvm::omp::OMPD_reverse, StartLoc,
EndLoc, 1) {}
void setPreInits(Stmt *PreInits) {
Data->getChildren()[PreInitsOffset] = PreInits;
}
void setTransformedStmt(Stmt *S) {
Data->getChildren()[TransformedStmtOffset] = S;
}
public:
/// Create a new AST node representation for '#pragma omp reverse'.
///
/// \param C Context of the AST.
/// \param StartLoc Location of the introducer (e.g. the 'omp' token).
/// \param EndLoc Location of the directive's end (e.g. the tok::eod).
/// \param AssociatedStmt The outermost associated loop.
/// \param TransformedStmt The loop nest after tiling, or nullptr in
/// dependent contexts.
/// \param PreInits Helper preinits statements for the loop nest.
static OMPReverseDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
Stmt *AssociatedStmt, Stmt *TransformedStmt, Stmt *PreInits);
/// Build an empty '#pragma omp reverse' AST node for deserialization.
///
/// \param C Context of the AST.
/// \param NumClauses Number of clauses to allocate.
static OMPReverseDirective *CreateEmpty(const ASTContext &C);
/// Gets/sets the associated loops after the transformation, i.e. after
/// de-sugaring.
Stmt *getTransformedStmt() const {
return Data->getChildren()[TransformedStmtOffset];
}
/// Return preinits statement.
Stmt *getPreInits() const { return Data->getChildren()[PreInitsOffset]; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPReverseDirectiveClass;
}
};
/// Represents the '#pragma omp interchange' loop transformation directive.
///
/// \code{c}
/// #pragma omp interchange
/// for (int i = 0; i < m; ++i)
/// for (int j = 0; j < n; ++j)
/// ..
/// \endcode
class OMPInterchangeDirective final : public OMPLoopTransformationDirective {
friend class ASTStmtReader;
friend class OMPExecutableDirective;
/// Offsets of child members.
enum {
PreInitsOffset = 0,
TransformedStmtOffset,
};
explicit OMPInterchangeDirective(SourceLocation StartLoc,
SourceLocation EndLoc, unsigned NumLoops)
: OMPLoopTransformationDirective(OMPInterchangeDirectiveClass,
llvm::omp::OMPD_interchange, StartLoc,
EndLoc, NumLoops) {
setNumGeneratedLoops(3 * NumLoops);
}
void setPreInits(Stmt *PreInits) {
Data->getChildren()[PreInitsOffset] = PreInits;
}
void setTransformedStmt(Stmt *S) {
Data->getChildren()[TransformedStmtOffset] = S;
}
public:
/// Create a new AST node representation for '#pragma omp interchange'.
///
/// \param C Context of the AST.
/// \param StartLoc Location of the introducer (e.g. the 'omp' token).
/// \param EndLoc Location of the directive's end (e.g. the tok::eod).
/// \param Clauses The directive's clauses.
/// \param NumLoops Number of affected loops
/// (number of items in the 'permutation' clause if present).
/// \param AssociatedStmt The outermost associated loop.
/// \param TransformedStmt The loop nest after tiling, or nullptr in
/// dependent contexts.
/// \param PreInits Helper preinits statements for the loop nest.
static OMPInterchangeDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, unsigned NumLoops, Stmt *AssociatedStmt,
Stmt *TransformedStmt, Stmt *PreInits);
/// Build an empty '#pragma omp interchange' AST node for deserialization.
///
/// \param C Context of the AST.
/// \param NumClauses Number of clauses to allocate.
/// \param NumLoops Number of associated loops to allocate.
static OMPInterchangeDirective *
CreateEmpty(const ASTContext &C, unsigned NumClauses, unsigned NumLoops);
/// Gets the associated loops after the transformation. This is the de-sugared
/// replacement or nullptr in dependent contexts.
Stmt *getTransformedStmt() const {
return Data->getChildren()[TransformedStmtOffset];
}
/// Return preinits statement.
Stmt *getPreInits() const { return Data->getChildren()[PreInitsOffset]; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPInterchangeDirectiveClass;
}
};
/// This represents '#pragma omp scan' directive.
///
/// \code
@ -6106,6 +6248,8 @@ public:
class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
friend class ASTStmtReader;
friend class OMPExecutableDirective;
/// true if loop directive's associated loop can be a parallel for.
bool CanBeParallelFor = false;
/// Build directive with the given start and end location.
///
/// \param StartLoc Starting location of the directive kind.
@ -6128,6 +6272,9 @@ class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
llvm::omp::OMPD_target_teams_loop, SourceLocation(),
SourceLocation(), CollapsedNum) {}
/// Set whether associated loop can be a parallel for.
void setCanBeParallelFor(bool ParFor) { CanBeParallelFor = ParFor; }
public:
/// Creates directive with a list of \p Clauses.
///
@ -6142,7 +6289,7 @@ public:
static OMPTargetTeamsGenericLoopDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt, const HelperExprs &Exprs);
Stmt *AssociatedStmt, const HelperExprs &Exprs, bool CanBeParallelFor);
/// Creates an empty directive with the place
/// for \a NumClauses clauses.
@ -6156,6 +6303,10 @@ public:
unsigned CollapsedNum,
EmptyShell);
/// Return true if current loop directive's associated loop can be a
/// parallel for.
bool canBeParallelFor() const { return CanBeParallelFor; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPTargetTeamsGenericLoopDirectiveClass;
}

View file

@ -13,13 +13,14 @@
#ifndef LLVM_CLANG_AST_STMTVISITOR_H
#define LLVM_CLANG_AST_STMTVISITOR_H
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/STLExtras.h"

View file

@ -459,7 +459,7 @@ public:
bool IncludeType) const;
/// Debugging aid that dumps the template argument.
void dump(raw_ostream &Out) const;
void dump(raw_ostream &Out, const ASTContext &Context) const;
/// Debugging aid that dumps the template argument to standard error.
void dump() const;

View file

@ -198,7 +198,8 @@ public:
///
/// Here, "apply" is treated as a template name within the typename
/// specifier in the typedef. "apply" is a nested template, and can
/// only be understood in the context of
/// only be understood in the context of a template instantiation,
/// hence is represented as a dependent template name.
class TemplateName {
// NameDecl is either a TemplateDecl or a UsingShadowDecl depending on the
// NameKind.
@ -314,11 +315,6 @@ public:
TemplateName getUnderlying() const;
/// Get the template name to substitute when this template name is used as a
/// template template argument. This refers to the most recent declaration of
/// the template, including any default template arguments.
TemplateName getNameToSubstitute() const;
TemplateNameDependence getDependence() const;
/// Determines whether this is a dependent template name.
@ -332,7 +328,7 @@ public:
/// unexpanded parameter pack (for C++0x variadic templates).
bool containsUnexpandedParameterPack() const;
enum class Qualified { None, AsWritten, Fully };
enum class Qualified { None, AsWritten };
/// Print the template name.
///
/// \param OS the output stream to which the template name will be
@ -345,13 +341,15 @@ public:
Qualified Qual = Qualified::AsWritten) const;
/// Debugging aid that dumps the template name.
void dump(raw_ostream &OS) const;
void dump(raw_ostream &OS, const ASTContext &Context) const;
/// Debugging aid that dumps the template name to standard
/// error.
void dump() const;
void Profile(llvm::FoldingSetNodeID &ID);
void Profile(llvm::FoldingSetNodeID &ID) {
ID.AddPointer(Storage.getOpaqueValue());
}
/// Retrieve the template name as a void pointer.
void *getAsVoidPointer() const { return Storage.getOpaqueValue(); }
@ -360,6 +358,10 @@ public:
static TemplateName getFromVoidPointer(void *Ptr) {
return TemplateName(Ptr);
}
/// Structural equality.
bool operator==(TemplateName Other) const { return Storage == Other.Storage; }
bool operator!=(TemplateName Other) const { return !operator==(Other); }
};
/// Insertion operator for diagnostics. This allows sending TemplateName's
@ -417,17 +419,18 @@ inline TemplateName TemplateName::getUnderlying() const {
return *this;
}
/// Represents a template name that was expressed as a
/// qualified name.
/// Represents a template name as written in source code.
///
/// This kind of template name refers to a template name that was
/// This kind of template name may refer to a template name that was
/// preceded by a nested name specifier, e.g., \c std::vector. Here,
/// the nested name specifier is "std::" and the template name is the
/// declaration for "vector". The QualifiedTemplateName class is only
/// used to provide "sugar" for template names that were expressed
/// with a qualified name, and has no semantic meaning. In this
/// manner, it is to TemplateName what ElaboratedType is to Type,
/// providing extra syntactic sugar for downstream clients.
/// declaration for "vector". It may also have been written with the
/// 'template' keyword. The QualifiedTemplateName class is only
/// used to provide "sugar" for template names, so that they can
/// be differentiated from canonical template names. and has no
/// semantic meaning. In this manner, it is to TemplateName what
/// ElaboratedType is to Type, providing extra syntactic sugar
/// for downstream clients.
class QualifiedTemplateName : public llvm::FoldingSetNode {
friend class ASTContext;

View file

@ -24,6 +24,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TemplateArgumentVisitor.h"
#include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/TypeVisitor.h"
namespace clang {
@ -132,6 +133,7 @@ class TextNodeDumper
public ConstTemplateArgumentVisitor<TextNodeDumper>,
public ConstStmtVisitor<TextNodeDumper>,
public TypeVisitor<TextNodeDumper>,
public TypeLocVisitor<TextNodeDumper>,
public ConstDeclVisitor<TextNodeDumper> {
raw_ostream &OS;
const bool ShowColors;
@ -179,12 +181,16 @@ public:
void Visit(QualType T);
void Visit(TypeLoc);
void Visit(const Decl *D);
void Visit(const CXXCtorInitializer *Init);
void Visit(const OMPClause *C);
void Visit(const OpenACCClause *C);
void Visit(const BlockDecl::Capture &C);
void Visit(const GenericSelectionExpr::ConstAssociation &A);
@ -207,6 +213,9 @@ public:
void dumpTemplateSpecializationKind(TemplateSpecializationKind TSK);
void dumpNestedNameSpecifier(const NestedNameSpecifier *NNS);
void dumpConceptReference(const ConceptReference *R);
void dumpTemplateArgument(const TemplateArgument &TA);
void dumpBareTemplateName(TemplateName TN);
void dumpTemplateName(TemplateName TN, StringRef Label = {});
void dumpDeclRef(const Decl *D, StringRef Label = {});
@ -291,6 +300,8 @@ public:
void VisitTypeTraitExpr(const TypeTraitExpr *Node);
void VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *Node);
void VisitExpressionTraitExpr(const ExpressionTraitExpr *Node);
void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node);
void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node);
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node);
void VisitExprWithCleanups(const ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
@ -337,6 +348,8 @@ public:
void VisitObjCInterfaceType(const ObjCInterfaceType *T);
void VisitPackExpansionType(const PackExpansionType *T);
void VisitTypeLoc(TypeLoc TL);
void VisitLabelDecl(const LabelDecl *D);
void VisitTypedefDecl(const TypedefDecl *D);
void VisitEnumDecl(const EnumDecl *D);
@ -344,6 +357,7 @@ public:
void VisitEnumConstantDecl(const EnumConstantDecl *D);
void VisitIndirectFieldDecl(const IndirectFieldDecl *D);
void VisitFunctionDecl(const FunctionDecl *D);
void VisitCXXDeductionGuideDecl(const CXXDeductionGuideDecl *D);
void VisitFieldDecl(const FieldDecl *D);
void VisitVarDecl(const VarDecl *D);
void VisitBindingDecl(const BindingDecl *D);
@ -393,6 +407,9 @@ public:
void
VisitLifetimeExtendedTemporaryDecl(const LifetimeExtendedTemporaryDecl *D);
void VisitHLSLBufferDecl(const HLSLBufferDecl *D);
void VisitOpenACCConstructStmt(const OpenACCConstructStmt *S);
void VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S);
void VisitEmbedExpr(const EmbedExpr *S);
};
} // namespace clang

File diff suppressed because it is too large Load diff

View file

@ -189,6 +189,9 @@ public:
/// pointer types, but not through decltype or typedefs.
AutoTypeLoc getContainedAutoTypeLoc() const;
/// Get the SourceLocation of the template keyword (if any).
SourceLocation getTemplateKeywordLoc() const;
/// Initializes this to state that every location in this
/// type is the given location.
///
@ -229,6 +232,9 @@ public:
/// __nullable, or __null_unspecifier), if there is one.
SourceLocation findNullabilityLoc() const;
void dump() const;
void dump(llvm::raw_ostream &, const ASTContext &) const;
private:
static bool isKind(const TypeLoc&) {
return true;
@ -884,6 +890,10 @@ public:
return getInnerTypeLoc();
}
TypeLoc getEquivalentTypeLoc() const {
return TypeLoc(getTypePtr()->getEquivalentType(), getNonLocalData());
}
/// The type attribute.
const Attr *getAttr() const {
return getLocalData()->TypeAttr;
@ -1110,6 +1120,32 @@ public:
}
};
struct BoundsAttributedLocInfo {};
class BoundsAttributedTypeLoc
: public ConcreteTypeLoc<UnqualTypeLoc, BoundsAttributedTypeLoc,
BoundsAttributedType, BoundsAttributedLocInfo> {
public:
TypeLoc getInnerLoc() const { return getInnerTypeLoc(); }
QualType getInnerType() const { return getTypePtr()->desugar(); }
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
// nothing to do
}
// LocalData is empty and TypeLocBuilder doesn't handle DataSize 1.
unsigned getLocalDataSize() const { return 0; }
};
class CountAttributedTypeLoc final
: public InheritingConcreteTypeLoc<BoundsAttributedTypeLoc,
CountAttributedTypeLoc,
CountAttributedType> {
public:
Expr *getCountExpr() const { return getTypePtr()->getCountExpr(); }
bool isCountInBytes() const { return getTypePtr()->isCountInBytes(); }
bool isOrNull() const { return getTypePtr()->isOrNull(); }
SourceRange getLocalSourceRange() const;
};
struct MacroQualifiedLocInfo {
SourceLocation ExpansionLoc;
};
@ -1575,6 +1611,11 @@ class ConstantArrayTypeLoc :
ConstantArrayType> {
};
/// Wrapper for source info for array parameter types.
class ArrayParameterTypeLoc
: public InheritingConcreteTypeLoc<
ConstantArrayTypeLoc, ArrayParameterTypeLoc, ArrayParameterType> {};
class IncompleteArrayTypeLoc :
public InheritingConcreteTypeLoc<ArrayTypeLoc,
IncompleteArrayTypeLoc,
@ -1684,7 +1725,7 @@ public:
}
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
setTemplateKeywordLoc(Loc);
setTemplateKeywordLoc(SourceLocation());
setTemplateNameLoc(Loc);
setLAngleLoc(Loc);
setRAngleLoc(Loc);
@ -2055,6 +2096,34 @@ public:
}
};
struct PackIndexingTypeLocInfo {
SourceLocation EllipsisLoc;
};
class PackIndexingTypeLoc
: public ConcreteTypeLoc<UnqualTypeLoc, PackIndexingTypeLoc,
PackIndexingType, PackIndexingTypeLocInfo> {
public:
Expr *getIndexExpr() const { return getTypePtr()->getIndexExpr(); }
QualType getPattern() const { return getTypePtr()->getPattern(); }
SourceLocation getEllipsisLoc() const { return getLocalData()->EllipsisLoc; }
void setEllipsisLoc(SourceLocation Loc) { getLocalData()->EllipsisLoc = Loc; }
void initializeLocal(ASTContext &Context, SourceLocation Loc) {
setEllipsisLoc(Loc);
}
TypeLoc getPatternLoc() const { return getInnerTypeLoc(); }
QualType getInnerType() const { return this->getTypePtr()->getPattern(); }
SourceRange getLocalSourceRange() const {
return SourceRange(getEllipsisLoc(), getEllipsisLoc());
}
};
struct UnaryTransformTypeLocInfo {
// FIXME: While there's only one unary transform right now, future ones may
// need different representations

View file

@ -25,6 +25,25 @@ let Class = PointerType in {
def : Creator<[{ return ctx.getPointerType(pointeeType); }]>;
}
let Class = CountAttributedType in {
def : Property<"WrappedTy", QualType> {
let Read = [{ node->desugar() }];
}
def : Property<"CountExpr", ExprRef> {
let Read = [{ node->getCountExpr() }];
}
def : Property<"CountInBytes", Bool> {
let Read = [{ node->isCountInBytes() }];
}
def : Property<"OrNull", Bool> {
let Read = [{ node->isOrNull() }];
}
def : Property<"CoupledDecls", Array<TypeCoupledDeclRefInfo>> {
let Read = [{ node->getCoupledDecls() }];
}
def : Creator<[{ return ctx.getCountAttributedType(WrappedTy, CountExpr, CountInBytes, OrNull, CoupledDecls); }]>;
}
let Class = AdjustedType in {
def : Property<"originalType", QualType> {
let Read = [{ node->getOriginalType() }];
@ -117,6 +136,13 @@ let Class = ConstantArrayType in {
}]>;
}
let Class = ArrayParameterType in {
def : Creator<[{ return ctx.getAdjustedParameterType(
ctx.getConstantArrayType(elementType,sizeValue,
size,sizeModifier,
indexQualifiers.getCVRQualifiers())); }]>;
}
let Class = IncompleteArrayType in {
def : Creator<[{
return ctx.getIncompleteArrayType(elementType, sizeModifier,
@ -326,6 +352,12 @@ let Class = FunctionProtoType in {
def : Property<"AArch64SMEAttributes", UInt32> {
let Read = [{ node->getAArch64SMEAttributes() }];
}
def : Property<"functionEffects", Array<FunctionEffect>> {
let Read = [{ node->getFunctionEffectsWithoutConditions() }];
}
def : Property<"functionEffectConds", Array<EffectConditionExpr>> {
let Read = [{ node->getFunctionEffectConditions() }];
}
def : Creator<[{
auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm,
@ -342,6 +374,7 @@ let Class = FunctionProtoType in {
epi.ExtParameterInfos =
extParameterInfo.empty() ? nullptr : extParameterInfo.data();
epi.AArch64SMEAttributes = AArch64SMEAttributes;
epi.FunctionEffects = FunctionEffectsRef::create(functionEffects, functionEffectConds);
return ctx.getFunctionType(returnType, parameters, epi);
}]>;
}
@ -433,6 +466,20 @@ let Class = DecltypeType in {
}]>;
}
let Class = PackIndexingType in {
def : Property<"pattern", QualType> {
let Read = [{ node->getPattern() }];
}
def : Property<"indexExpression", ExprRef> {
let Read = [{ node->getIndexExpr() }];
}
def : Creator<[{
return ctx.getPackIndexingType(pattern, indexExpression);
}]>;
}
let Class = UnaryTransformType in {
def : Property<"baseType", QualType> {
let Read = [{ node->getBaseType() }];
@ -821,6 +868,10 @@ let Class = BuiltinType in {
case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/Basic/WebAssemblyReferenceTypes.def"
#define AMDGPU_TYPE(NAME, ID, SINGLETON_ID) \
case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/Basic/AMDGPUTypes.def"
#define BUILTIN_TYPE(ID, SINGLETON_ID) \
case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/AST/BuiltinTypes.def"

View file

@ -47,6 +47,7 @@ public:
// temporaries with defaulted ctors are not zero initialized.
UnresolvedSetIterator() : iterator_adaptor_base(nullptr) {}
uint64_t getDeclID() const { return I->getDeclID(); }
NamedDecl *getDecl() const { return I->getDecl(); }
void setDecl(NamedDecl *ND) const { return I->setDecl(ND); }
AccessSpecifier getAccess() const { return I->getAccess(); }

View file

@ -92,7 +92,7 @@ class VTTBuilder {
using AddressPointsMapTy = llvm::DenseMap<BaseSubobject, uint64_t>;
/// The sub-VTT indices for the bases of the most derived class.
llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndicies;
llvm::DenseMap<BaseSubobject, uint64_t> SubVTTIndices;
/// The secondary virtual pointer indices of all subobjects of
/// the most derived class.
@ -148,8 +148,8 @@ public:
}
/// Returns a reference to the sub-VTT indices.
const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndicies() const {
return SubVTTIndicies;
const llvm::DenseMap<BaseSubobject, uint64_t> &getSubVTTIndices() const {
return SubVTTIndices;
}
/// Returns a reference to the secondary virtual pointer indices.

View file

@ -361,6 +361,10 @@ public:
};
class ItaniumVTableContext : public VTableContextBase {
public:
typedef llvm::DenseMap<const CXXMethodDecl *, const CXXMethodDecl *>
OriginalMethodMapTy;
private:
/// Contains the index (relative to the vtable address point)
@ -384,6 +388,10 @@ private:
VirtualBaseClassOffsetOffsetsMapTy;
VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets;
/// Map from a virtual method to the nearest method in the primary base class
/// chain that it overrides.
OriginalMethodMapTy OriginalMethodMap;
void computeVTableRelatedInformation(const CXXRecordDecl *RD) override;
public:
@ -425,6 +433,27 @@ public:
CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *VBase);
/// Return the method that added the v-table slot that will be used to call
/// the given method.
///
/// In the Itanium ABI, where overrides always cause methods to be added to
/// the primary v-table if they're not already there, this will be the first
/// declaration in the primary base class chain for which the return type
/// adjustment is trivial.
GlobalDecl findOriginalMethod(GlobalDecl GD);
const CXXMethodDecl *findOriginalMethodInMap(const CXXMethodDecl *MD) const;
void setOriginalMethod(const CXXMethodDecl *Key, const CXXMethodDecl *Val) {
OriginalMethodMap[Key] = Val;
}
/// This method is reserved for the implementation and shouldn't be used
/// directly.
const OriginalMethodMapTy &getOriginalMethodMap() {
return OriginalMethodMap;
}
static bool classof(const VTableContextBase *VT) {
return !VT->isMicrosoft();
}

View file

@ -764,9 +764,9 @@ AST_POLYMORPHIC_MATCHER(isImplicit,
return Node.isImplicit();
}
/// Matches classTemplateSpecializations, templateSpecializationType and
/// functionDecl that have at least one TemplateArgument matching the given
/// InnerMatcher.
/// Matches templateSpecializationTypes, class template specializations,
/// variable template specializations, and function template specializations
/// that have at least one TemplateArgument matching the given InnerMatcher.
///
/// Given
/// \code
@ -788,8 +788,8 @@ AST_POLYMORPHIC_MATCHER(isImplicit,
AST_POLYMORPHIC_MATCHER_P(
hasAnyTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
TemplateSpecializationType,
FunctionDecl),
VarTemplateSpecializationDecl, FunctionDecl,
TemplateSpecializationType),
internal::Matcher<TemplateArgument>, InnerMatcher) {
ArrayRef<TemplateArgument> List =
internal::getTemplateSpecializationArgs(Node);
@ -1047,8 +1047,9 @@ AST_MATCHER(Expr, isTypeDependent) { return Node.isTypeDependent(); }
/// expr(isValueDependent()) matches return Size
AST_MATCHER(Expr, isValueDependent) { return Node.isValueDependent(); }
/// Matches classTemplateSpecializations, templateSpecializationType and
/// functionDecl where the n'th TemplateArgument matches the given InnerMatcher.
/// Matches templateSpecializationType, class template specializations,
/// variable template specializations, and function template specializations
/// where the n'th TemplateArgument matches the given InnerMatcher.
///
/// Given
/// \code
@ -1068,8 +1069,8 @@ AST_MATCHER(Expr, isValueDependent) { return Node.isValueDependent(); }
AST_POLYMORPHIC_MATCHER_P2(
hasTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
TemplateSpecializationType,
FunctionDecl),
VarTemplateSpecializationDecl, FunctionDecl,
TemplateSpecializationType),
unsigned, N, internal::Matcher<TemplateArgument>, InnerMatcher) {
ArrayRef<TemplateArgument> List =
internal::getTemplateSpecializationArgs(Node);
@ -4066,7 +4067,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
/// Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
/// Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
/// Matcher<CXXUnresolvedConstructExpr>,
/// Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
/// Matcher<CompoundLiteralExpr>,
/// Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
/// Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
/// Matcher<TypedefNameDecl>
@ -4075,9 +4076,8 @@ AST_POLYMORPHIC_MATCHER_P(
AST_POLYMORPHIC_SUPPORTED_TYPES(
BlockDecl, CXXBaseSpecifier, CXXCtorInitializer, CXXFunctionalCastExpr,
CXXNewExpr, CXXTemporaryObjectExpr, CXXUnresolvedConstructExpr,
ClassTemplateSpecializationDecl, CompoundLiteralExpr, DeclaratorDecl,
ExplicitCastExpr, ObjCPropertyDecl, TemplateArgumentLoc,
TypedefNameDecl),
CompoundLiteralExpr, DeclaratorDecl, ExplicitCastExpr, ObjCPropertyDecl,
TemplateArgumentLoc, TypedefNameDecl),
internal::Matcher<TypeLoc>, Inner) {
TypeSourceInfo *source = internal::GetTypeSourceInfo(Node);
if (source == nullptr) {
@ -4580,8 +4580,7 @@ AST_POLYMORPHIC_MATCHER_P2(hasArgument,
/// return (args * ... * 1);
/// }
/// \endcode
AST_MATCHER_P(CXXFoldExpr, hasFoldInit, ast_matchers::internal::Matcher<Expr>,
InnerMacher) {
AST_MATCHER_P(CXXFoldExpr, hasFoldInit, internal::Matcher<Expr>, InnerMacher) {
const auto *const Init = Node.getInit();
return Init && InnerMacher.matches(*Init, Finder, Builder);
}
@ -4603,8 +4602,7 @@ AST_MATCHER_P(CXXFoldExpr, hasFoldInit, ast_matchers::internal::Matcher<Expr>,
/// return (args * ... * 1);
/// }
/// \endcode
AST_MATCHER_P(CXXFoldExpr, hasPattern, ast_matchers::internal::Matcher<Expr>,
InnerMacher) {
AST_MATCHER_P(CXXFoldExpr, hasPattern, internal::Matcher<Expr>, InnerMacher) {
const Expr *const Pattern = Node.getPattern();
return Pattern && InnerMacher.matches(*Pattern, Finder, Builder);
}
@ -4685,8 +4683,8 @@ AST_MATCHER(CXXFoldExpr, isBinaryFold) { return Node.getInit() != nullptr; }
/// \code
/// int x{y}.
/// \endcode
AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N,
ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
AST_MATCHER_P2(InitListExpr, hasInit, unsigned, N, internal::Matcher<Expr>,
InnerMatcher) {
return N < Node.getNumInits() &&
InnerMatcher.matches(*Node.getInit(N), Finder, Builder);
}
@ -4963,6 +4961,8 @@ AST_MATCHER_P(LambdaExpr, hasAnyCapture, internal::Matcher<LambdaCapture>,
/// capturesVar(hasName("x")) matches `x` and `x = 1`.
AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher<ValueDecl>,
InnerMatcher) {
if (!Node.capturesVariable())
return false;
auto *capturedVar = Node.getCapturedVar();
return capturedVar && InnerMatcher.matches(*capturedVar, Finder, Builder);
}
@ -5034,6 +5034,25 @@ AST_POLYMORPHIC_MATCHER_P2(hasParameter,
&& InnerMatcher.matches(*Node.parameters()[N], Finder, Builder));
}
/// Matches if the given method declaration declares a member function with an
/// explicit object parameter.
///
/// Given
/// \code
/// struct A {
/// int operator-(this A, int);
/// void fun(this A &&self);
/// static int operator()(int);
/// int operator+(int);
/// };
/// \endcode
///
/// cxxMethodDecl(isExplicitObjectMemberFunction()) matches the first two
/// methods but not the last two.
AST_MATCHER(CXXMethodDecl, isExplicitObjectMemberFunction) {
return Node.isExplicitObjectMemberFunction();
}
/// Matches all arguments and their respective ParmVarDecl.
///
/// Given
@ -5062,10 +5081,12 @@ AST_POLYMORPHIC_MATCHER_P2(forEachArgumentWithParam,
// argument of the method which should not be matched against a parameter, so
// we skip over it here.
BoundNodesTreeBuilder Matches;
unsigned ArgIndex = cxxOperatorCallExpr(callee(cxxMethodDecl()))
.matches(Node, Finder, &Matches)
? 1
: 0;
unsigned ArgIndex =
cxxOperatorCallExpr(
callee(cxxMethodDecl(unless(isExplicitObjectMemberFunction()))))
.matches(Node, Finder, &Matches)
? 1
: 0;
int ParamIndex = 0;
bool Matched = false;
for (; ArgIndex < Node.getNumArgs(); ++ArgIndex) {
@ -5123,11 +5144,12 @@ AST_POLYMORPHIC_MATCHER_P2(forEachArgumentWithParamType,
// argument of the method which should not be matched against a parameter, so
// we skip over it here.
BoundNodesTreeBuilder Matches;
unsigned ArgIndex = cxxOperatorCallExpr(callee(cxxMethodDecl()))
.matches(Node, Finder, &Matches)
? 1
: 0;
unsigned ArgIndex =
cxxOperatorCallExpr(
callee(cxxMethodDecl(unless(isExplicitObjectMemberFunction()))))
.matches(Node, Finder, &Matches)
? 1
: 0;
const FunctionProtoType *FProto = nullptr;
if (const auto *Call = dyn_cast<CallExpr>(&Node)) {
@ -5282,9 +5304,10 @@ AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
return Node.getNumParams() == N;
}
/// Matches classTemplateSpecialization, templateSpecializationType and
/// functionDecl nodes where the template argument matches the inner matcher.
/// This matcher may produce multiple matches.
/// Matches templateSpecializationType, class template specialization,
/// variable template specialization, and function template specialization
/// nodes where the template argument matches the inner matcher. This matcher
/// may produce multiple matches.
///
/// Given
/// \code
@ -5308,8 +5331,9 @@ AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
AST_POLYMORPHIC_MATCHER_P(
forEachTemplateArgument,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
TemplateSpecializationType, FunctionDecl),
clang::ast_matchers::internal::Matcher<TemplateArgument>, InnerMatcher) {
VarTemplateSpecializationDecl, FunctionDecl,
TemplateSpecializationType),
internal::Matcher<TemplateArgument>, InnerMatcher) {
ArrayRef<TemplateArgument> TemplateArgs =
clang::ast_matchers::internal::getTemplateSpecializationArgs(Node);
clang::ast_matchers::internal::BoundNodesTreeBuilder Result;
@ -6883,8 +6907,10 @@ extern const internal::VariadicDynCastAllOfMatcher<
TypeLoc, TemplateSpecializationTypeLoc>
templateSpecializationTypeLoc;
/// Matches template specialization `TypeLoc`s that have at least one
/// `TemplateArgumentLoc` matching the given `InnerMatcher`.
/// Matches template specialization `TypeLoc`s, class template specializations,
/// variable template specializations, and function template specializations
/// that have at least one `TemplateArgumentLoc` matching the given
/// `InnerMatcher`.
///
/// Given
/// \code
@ -6894,20 +6920,21 @@ extern const internal::VariadicDynCastAllOfMatcher<
/// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
/// hasTypeLoc(loc(asString("int")))))))
/// matches `A<int> a`.
AST_MATCHER_P(TemplateSpecializationTypeLoc, hasAnyTemplateArgumentLoc,
internal::Matcher<TemplateArgumentLoc>, InnerMatcher) {
for (unsigned Index = 0, N = Node.getNumArgs(); Index < N; ++Index) {
clang::ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
if (InnerMatcher.matches(Node.getArgLoc(Index), Finder, &Result)) {
*Builder = std::move(Result);
return true;
}
}
AST_POLYMORPHIC_MATCHER_P(
hasAnyTemplateArgumentLoc,
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
VarTemplateSpecializationDecl, FunctionDecl,
DeclRefExpr, TemplateSpecializationTypeLoc),
internal::Matcher<TemplateArgumentLoc>, InnerMatcher) {
auto Args = internal::getTemplateArgsWritten(Node);
return matchesFirstInRange(InnerMatcher, Args.begin(), Args.end(), Finder,
Builder) != Args.end();
return false;
}
/// Matches template specialization `TypeLoc`s where the n'th
/// `TemplateArgumentLoc` matches the given `InnerMatcher`.
/// Matches template specialization `TypeLoc`s, class template specializations,
/// variable template specializations, and function template specializations
/// where the n'th `TemplateArgumentLoc` matches the given `InnerMatcher`.
///
/// Given
/// \code
@ -6920,10 +6947,13 @@ AST_MATCHER_P(TemplateSpecializationTypeLoc, hasAnyTemplateArgumentLoc,
/// matches `A<double, int> b`, but not `A<int, double> c`.
AST_POLYMORPHIC_MATCHER_P2(
hasTemplateArgumentLoc,
AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr, TemplateSpecializationTypeLoc),
AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
VarTemplateSpecializationDecl, FunctionDecl,
DeclRefExpr, TemplateSpecializationTypeLoc),
unsigned, Index, internal::Matcher<TemplateArgumentLoc>, InnerMatcher) {
return internal::MatchTemplateArgLocAt(Node, Index, InnerMatcher, Finder,
Builder);
auto Args = internal::getTemplateArgsWritten(Node);
return Index < Args.size() &&
InnerMatcher.matches(Args[Index], Finder, Builder);
}
/// Matches C or C++ elaborated `TypeLoc`s.
@ -8341,20 +8371,28 @@ AST_MATCHER_P(Stmt, forCallable, internal::Matcher<Decl>, InnerMatcher) {
const auto &CurNode = Stack.back();
Stack.pop_back();
if (const auto *FuncDeclNode = CurNode.get<FunctionDecl>()) {
if (InnerMatcher.matches(*FuncDeclNode, Finder, Builder)) {
BoundNodesTreeBuilder B = *Builder;
if (InnerMatcher.matches(*FuncDeclNode, Finder, &B)) {
*Builder = std::move(B);
return true;
}
} else if (const auto *LambdaExprNode = CurNode.get<LambdaExpr>()) {
BoundNodesTreeBuilder B = *Builder;
if (InnerMatcher.matches(*LambdaExprNode->getCallOperator(), Finder,
Builder)) {
&B)) {
*Builder = std::move(B);
return true;
}
} else if (const auto *ObjCMethodDeclNode = CurNode.get<ObjCMethodDecl>()) {
if (InnerMatcher.matches(*ObjCMethodDeclNode, Finder, Builder)) {
BoundNodesTreeBuilder B = *Builder;
if (InnerMatcher.matches(*ObjCMethodDeclNode, Finder, &B)) {
*Builder = std::move(B);
return true;
}
} else if (const auto *BlockDeclNode = CurNode.get<BlockDecl>()) {
if (InnerMatcher.matches(*BlockDeclNode, Finder, Builder)) {
BoundNodesTreeBuilder B = *Builder;
if (InnerMatcher.matches(*BlockDeclNode, Finder, &B)) {
*Builder = std::move(B);
return true;
}
} else {
@ -8525,8 +8563,8 @@ AST_MATCHER(FunctionDecl, hasTrailingReturn) {
///
/// ``varDecl(hasInitializer(ignoringElidableConstructorCall(callExpr())))``
/// matches ``H D = G()`` in C++11 through C++17 (and beyond).
AST_MATCHER_P(Expr, ignoringElidableConstructorCall,
ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
AST_MATCHER_P(Expr, ignoringElidableConstructorCall, internal::Matcher<Expr>,
InnerMatcher) {
// E tracks the node that we are examining.
const Expr *E = &Node;
// If present, remove an outer `ExprWithCleanups` corresponding to the

View file

@ -186,10 +186,6 @@ inline TypeSourceInfo *GetTypeSourceInfo(const BlockDecl &Node) {
inline TypeSourceInfo *GetTypeSourceInfo(const CXXNewExpr &Node) {
return Node.getAllocatedTypeSourceInfo();
}
inline TypeSourceInfo *
GetTypeSourceInfo(const ClassTemplateSpecializationDecl &Node) {
return Node.getTypeAsWritten();
}
/// Unifies obtaining the FunctionProtoType pointer from both
/// FunctionProtoType and FunctionDecl nodes..
@ -1939,6 +1935,11 @@ getTemplateSpecializationArgs(const ClassTemplateSpecializationDecl &D) {
return D.getTemplateArgs().asArray();
}
inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const VarTemplateSpecializationDecl &D) {
return D.getTemplateArgs().asArray();
}
inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const TemplateSpecializationType &T) {
return T.template_arguments();
@ -1948,7 +1949,46 @@ inline ArrayRef<TemplateArgument>
getTemplateSpecializationArgs(const FunctionDecl &FD) {
if (const auto* TemplateArgs = FD.getTemplateSpecializationArgs())
return TemplateArgs->asArray();
return ArrayRef<TemplateArgument>();
return std::nullopt;
}
inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const ClassTemplateSpecializationDecl &D) {
if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
return Args->arguments();
return std::nullopt;
}
inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const VarTemplateSpecializationDecl &D) {
if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
return Args->arguments();
return std::nullopt;
}
inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const FunctionDecl &FD) {
if (const auto *Args = FD.getTemplateSpecializationArgsAsWritten())
return Args->arguments();
return std::nullopt;
}
inline ArrayRef<TemplateArgumentLoc>
getTemplateArgsWritten(const DeclRefExpr &DRE) {
if (const auto *Args = DRE.getTemplateArgs())
return {Args, DRE.getNumTemplateArgs()};
return std::nullopt;
}
inline SmallVector<TemplateArgumentLoc>
getTemplateArgsWritten(const TemplateSpecializationTypeLoc &T) {
SmallVector<TemplateArgumentLoc> Args;
if (!T.isNull()) {
Args.reserve(T.getNumArgs());
for (unsigned I = 0; I < T.getNumArgs(); ++I)
Args.emplace_back(T.getArgLoc(I));
}
return Args;
}
struct NotEqualsBoundNodePredicate {

View file

@ -8,11 +8,9 @@
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
#define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
#include <type_traits>
#include "clang/AST/AST.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "llvm/ADT/DenseMap.h"
#include <memory>
namespace clang {
@ -21,14 +19,74 @@ class FunctionParmMutationAnalyzer;
/// Analyzes whether any mutative operations are applied to an expression within
/// a given statement.
class ExprMutationAnalyzer {
friend class FunctionParmMutationAnalyzer;
public:
struct Memoized {
using ResultMap = llvm::DenseMap<const Expr *, const Stmt *>;
using FunctionParaAnalyzerMap =
llvm::SmallDenseMap<const FunctionDecl *,
std::unique_ptr<FunctionParmMutationAnalyzer>>;
ResultMap Results;
ResultMap PointeeResults;
FunctionParaAnalyzerMap FuncParmAnalyzer;
void clear() {
Results.clear();
PointeeResults.clear();
FuncParmAnalyzer.clear();
}
};
struct Analyzer {
Analyzer(const Stmt &Stm, ASTContext &Context, Memoized &Memorized)
: Stm(Stm), Context(Context), Memorized(Memorized) {}
const Stmt *findMutation(const Expr *Exp);
const Stmt *findMutation(const Decl *Dec);
const Stmt *findPointeeMutation(const Expr *Exp);
const Stmt *findPointeeMutation(const Decl *Dec);
static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm,
ASTContext &Context);
private:
using MutationFinder = const Stmt *(Analyzer::*)(const Expr *);
const Stmt *findMutationMemoized(const Expr *Exp,
llvm::ArrayRef<MutationFinder> Finders,
Memoized::ResultMap &MemoizedResults);
const Stmt *tryEachDeclRef(const Decl *Dec, MutationFinder Finder);
bool isUnevaluated(const Expr *Exp);
const Stmt *findExprMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *findDeclMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *
findExprPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *
findDeclPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *findDirectMutation(const Expr *Exp);
const Stmt *findMemberMutation(const Expr *Exp);
const Stmt *findArrayElementMutation(const Expr *Exp);
const Stmt *findCastMutation(const Expr *Exp);
const Stmt *findRangeLoopMutation(const Expr *Exp);
const Stmt *findReferenceMutation(const Expr *Exp);
const Stmt *findFunctionArgMutation(const Expr *Exp);
const Stmt &Stm;
ASTContext &Context;
Memoized &Memorized;
};
ExprMutationAnalyzer(const Stmt &Stm, ASTContext &Context)
: Stm(Stm), Context(Context) {}
: Memorized(), A(Stm, Context, Memorized) {}
bool isMutated(const Expr *Exp) { return findMutation(Exp) != nullptr; }
bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; }
const Stmt *findMutation(const Expr *Exp);
const Stmt *findMutation(const Decl *Dec);
const Stmt *findMutation(const Expr *Exp) { return A.findMutation(Exp); }
const Stmt *findMutation(const Decl *Dec) { return A.findMutation(Dec); }
bool isPointeeMutated(const Expr *Exp) {
return findPointeeMutation(Exp) != nullptr;
@ -36,51 +94,40 @@ public:
bool isPointeeMutated(const Decl *Dec) {
return findPointeeMutation(Dec) != nullptr;
}
const Stmt *findPointeeMutation(const Expr *Exp);
const Stmt *findPointeeMutation(const Decl *Dec);
const Stmt *findPointeeMutation(const Expr *Exp) {
return A.findPointeeMutation(Exp);
}
const Stmt *findPointeeMutation(const Decl *Dec) {
return A.findPointeeMutation(Dec);
}
static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm,
ASTContext &Context);
ASTContext &Context) {
return Analyzer::isUnevaluated(Smt, Stm, Context);
}
private:
using MutationFinder = const Stmt *(ExprMutationAnalyzer::*)(const Expr *);
using ResultMap = llvm::DenseMap<const Expr *, const Stmt *>;
const Stmt *findMutationMemoized(const Expr *Exp,
llvm::ArrayRef<MutationFinder> Finders,
ResultMap &MemoizedResults);
const Stmt *tryEachDeclRef(const Decl *Dec, MutationFinder Finder);
bool isUnevaluated(const Expr *Exp);
const Stmt *findExprMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *findDeclMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *
findExprPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *
findDeclPointeeMutation(ArrayRef<ast_matchers::BoundNodes> Matches);
const Stmt *findDirectMutation(const Expr *Exp);
const Stmt *findMemberMutation(const Expr *Exp);
const Stmt *findArrayElementMutation(const Expr *Exp);
const Stmt *findCastMutation(const Expr *Exp);
const Stmt *findRangeLoopMutation(const Expr *Exp);
const Stmt *findReferenceMutation(const Expr *Exp);
const Stmt *findFunctionArgMutation(const Expr *Exp);
const Stmt &Stm;
ASTContext &Context;
llvm::DenseMap<const FunctionDecl *,
std::unique_ptr<FunctionParmMutationAnalyzer>>
FuncParmAnalyzer;
ResultMap Results;
ResultMap PointeeResults;
Memoized Memorized;
Analyzer A;
};
// A convenient wrapper around ExprMutationAnalyzer for analyzing function
// params.
class FunctionParmMutationAnalyzer {
public:
FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context);
static FunctionParmMutationAnalyzer *
getFunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context,
ExprMutationAnalyzer::Memoized &Memorized) {
auto it = Memorized.FuncParmAnalyzer.find(&Func);
if (it == Memorized.FuncParmAnalyzer.end())
it =
Memorized.FuncParmAnalyzer
.try_emplace(&Func, std::unique_ptr<FunctionParmMutationAnalyzer>(
new FunctionParmMutationAnalyzer(
Func, Context, Memorized)))
.first;
return it->getSecond().get();
}
bool isMutated(const ParmVarDecl *Parm) {
return findMutation(Parm) != nullptr;
@ -88,8 +135,11 @@ public:
const Stmt *findMutation(const ParmVarDecl *Parm);
private:
ExprMutationAnalyzer BodyAnalyzer;
ExprMutationAnalyzer::Analyzer BodyAnalyzer;
llvm::DenseMap<const ParmVarDecl *, const Stmt *> Results;
FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context,
ExprMutationAnalyzer::Memoized &Memorized);
};
} // namespace clang

View file

@ -70,7 +70,41 @@ public:
};
private:
using po_iterator = llvm::po_iterator<const CFG *, CFGBlockSet, true>;
// The CFG orders the blocks of loop bodies before those of loop successors
// (both numerically, and in the successor order of the loop condition
// block). So, RPO necessarily reverses that order, placing the loop successor
// *before* the loop body. For many analyses, particularly those that converge
// to a fixpoint, this results in potentially significant extra work because
// loop successors will necessarily need to be reconsidered once the algorithm
// has reached a fixpoint on the loop body.
//
// This definition of CFG graph traits reverses the order of children, so that
// loop bodies will come first in an RPO.
struct CFGLoopBodyFirstTraits {
using NodeRef = const ::clang::CFGBlock *;
using ChildIteratorType = ::clang::CFGBlock::const_succ_reverse_iterator;
static ChildIteratorType child_begin(NodeRef N) { return N->succ_rbegin(); }
static ChildIteratorType child_end(NodeRef N) { return N->succ_rend(); }
using nodes_iterator = ::clang::CFG::const_iterator;
static NodeRef getEntryNode(const ::clang::CFG *F) {
return &F->getEntry();
}
static nodes_iterator nodes_begin(const ::clang::CFG *F) {
return F->nodes_begin();
}
static nodes_iterator nodes_end(const ::clang::CFG *F) {
return F->nodes_end();
}
static unsigned size(const ::clang::CFG *F) { return F->size(); }
};
using po_iterator =
llvm::po_iterator<const CFG *, CFGBlockSet, true, CFGLoopBodyFirstTraits>;
std::vector<const CFGBlock *> Blocks;
using BlockOrderTy = llvm::DenseMap<const CFGBlock *, unsigned>;

View file

@ -330,9 +330,9 @@ public:
bool shouldIgnore() const { return sexpr() == nullptr; }
bool isInvalid() const { return sexpr() && isa<til::Undefined>(sexpr()); }
bool isInvalid() const { return isa_and_nonnull<til::Undefined>(sexpr()); }
bool isUniversal() const { return sexpr() && isa<til::Wildcard>(sexpr()); }
bool isUniversal() const { return isa_and_nonnull<til::Wildcard>(sexpr()); }
};
// Translate clang::Expr to til::SExpr.
@ -527,8 +527,10 @@ private:
BlockInfo *CurrentBlockInfo = nullptr;
};
#ifndef NDEBUG
// Dump an SCFG to llvm::errs().
void printSCFG(CFGWalker &Walker);
#endif // NDEBUG
} // namespace threadSafety
} // namespace clang

View file

@ -16,6 +16,7 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/Support/Debug.h"
namespace clang {
@ -41,6 +42,43 @@ public:
virtual VarGrpRef getGroupOfParms() const =0;
};
// FixitStrategy is a map from variables to the way we plan to emit fixes for
// these variables. It is figured out gradually by trying different fixes
// for different variables depending on gadgets in which these variables
// participate.
class FixitStrategy {
public:
enum class Kind {
Wontfix, // We don't plan to emit a fixit for this variable.
Span, // We recommend replacing the variable with std::span.
Iterator, // We recommend replacing the variable with std::span::iterator.
Array, // We recommend replacing the variable with std::array.
Vector // We recommend replacing the variable with std::vector.
};
private:
using MapTy = llvm::DenseMap<const VarDecl *, Kind>;
MapTy Map;
public:
FixitStrategy() = default;
FixitStrategy(const FixitStrategy &) = delete; // Let's avoid copies.
FixitStrategy &operator=(const FixitStrategy &) = delete;
FixitStrategy(FixitStrategy &&) = default;
FixitStrategy &operator=(FixitStrategy &&) = default;
void set(const VarDecl *VD, Kind K) { Map[VD] = K; }
Kind lookup(const VarDecl *VD) const {
auto I = Map.find(VD);
if (I == Map.end())
return Kind::Wontfix;
return I->second;
}
};
/// The interface that lets the caller handle unsafe buffer usage analysis
/// results by overriding this class's handle... methods.
class UnsafeBufferUsageHandler {
@ -68,15 +106,22 @@ public:
virtual void handleUnsafeOperation(const Stmt *Operation,
bool IsRelatedToDecl, ASTContext &Ctx) = 0;
/// Invoked when an unsafe operation with a std container is found.
virtual void handleUnsafeOperationInContainer(const Stmt *Operation,
bool IsRelatedToDecl,
ASTContext &Ctx) = 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.
///
/// `D` is the declaration of the callable under analysis that owns `Variable`
/// and all of its group mates.
virtual void handleUnsafeVariableGroup(const VarDecl *Variable,
const VariableGroupsManager &VarGrpMgr,
FixItList &&Fixes, const Decl *D) = 0;
virtual void
handleUnsafeVariableGroup(const VarDecl *Variable,
const VariableGroupsManager &VarGrpMgr,
FixItList &&Fixes, const Decl *D,
const FixitStrategy &VarTargetTypes) = 0;
#ifndef NDEBUG
public:
@ -98,9 +143,14 @@ public:
#endif
public:
/// Returns a reference to the `Preprocessor`:
/// \return true iff buffer safety is opt-out at `Loc`; false otherwise.
virtual bool isSafeBufferOptOut(const SourceLocation &Loc) const = 0;
/// \return true iff unsafe uses in containers should NOT be reported at
/// `Loc`; false otherwise.
virtual bool
ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const = 0;
virtual std::string
getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
StringRef WSSuffix = "") const = 0;

View file

@ -18,6 +18,12 @@
#define WARNING_GADGET(name) GADGET(name)
#endif
/// A `WARNING_GADGET` subset, where the code pattern of each gadget
/// corresponds uses of a (possibly hardened) contatiner (e.g., `std::span`).
#ifndef WARNING_CONTAINER_GADGET
#define WARNING_CONTAINER_GADGET(name) WARNING_GADGET(name)
#endif
/// Safe gadgets correspond to code patterns that aren't unsafe but need to be
/// properly recognized in order to emit correct warnings and fixes over unsafe
/// gadgets.
@ -30,7 +36,9 @@ WARNING_GADGET(Decrement)
WARNING_GADGET(ArraySubscript)
WARNING_GADGET(PointerArithmetic)
WARNING_GADGET(UnsafeBufferUsageAttr)
WARNING_GADGET(UnsafeBufferUsageCtorAttr)
WARNING_GADGET(DataInvocation)
WARNING_CONTAINER_GADGET(SpanTwoParamConstructor) // Uses of `std::span(arg0, arg1)`
FIXABLE_GADGET(ULCArraySubscript) // `DRE[any]` in an Unspecified Lvalue Context
FIXABLE_GADGET(DerefSimplePtrArithFixable)
FIXABLE_GADGET(PointerDereference)
@ -38,9 +46,11 @@ FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified Poin
FIXABLE_GADGET(UPCStandalonePointer)
FIXABLE_GADGET(UPCPreIncrement) // '++Ptr' in an Unspecified Pointer Context
FIXABLE_GADGET(UUCAddAssign) // 'Ptr += n' in an Unspecified Untyped Context
FIXABLE_GADGET(PointerAssignment)
FIXABLE_GADGET(PtrToPtrAssignment)
FIXABLE_GADGET(CArrayToPtrAssignment)
FIXABLE_GADGET(PointerInit)
#undef FIXABLE_GADGET
#undef WARNING_GADGET
#undef WARNING_CONTAINER_GADGET
#undef GADGET

View file

@ -879,6 +879,7 @@ private:
///
/// Optimization Note: This bit could be profitably folded with Terminator's
/// storage if the memory usage of CFGBlock becomes an issue.
LLVM_PREFERRED_TYPE(bool)
unsigned HasNoReturnElement : 1;
/// The parent CFG that owns this CFGBlock.
@ -1007,7 +1008,9 @@ public:
class FilterOptions {
public:
LLVM_PREFERRED_TYPE(bool)
unsigned IgnoreNullPredecessors : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IgnoreDefaultsWithCoveredEnums : 1;
FilterOptions()

View file

@ -0,0 +1,156 @@
//===-- ASTOps.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 AST nodes that are used in flow-sensitive analysis.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/FlowSensitive/StorageLocation.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
namespace clang {
namespace dataflow {
/// 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
/// exist.
///
/// * `ParenExpr` - The CFG takes the operator precedence into account, but
/// otherwise omits the node afterwards.
///
/// * `ExprWithCleanups` - The CFG will generate the appropriate calls to
/// destructors and then omit the node.
///
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.
FieldSet getObjectFields(QualType Type);
/// Returns whether `Fields` and `FieldLocs` contain the same fields.
bool containsSameFields(const FieldSet &Fields,
const RecordStorageLocation::FieldToLoc &FieldLocs);
/// Helper class for initialization of a record with an `InitListExpr`.
/// `InitListExpr::inits()` contains the initializers for both the base classes
/// and the fields of the record; this helper class separates these out into two
/// different lists. In addition, it deals with special cases associated with
/// unions.
class RecordInitListHelper {
public:
// `InitList` must have record type.
RecordInitListHelper(const InitListExpr *InitList);
RecordInitListHelper(const CXXParenListInitExpr *ParenInitList);
// Base classes with their associated initializer expressions.
ArrayRef<std::pair<const CXXBaseSpecifier *, Expr *>> base_inits() const {
return BaseInits;
}
// Fields with their associated initializer expressions.
ArrayRef<std::pair<const FieldDecl *, Expr *>> field_inits() const {
return FieldInits;
}
private:
RecordInitListHelper(QualType Ty, std::vector<const FieldDecl *> Fields,
ArrayRef<Expr *> Inits);
SmallVector<std::pair<const CXXBaseSpecifier *, Expr *>> BaseInits;
SmallVector<std::pair<const FieldDecl *, Expr *>> FieldInits;
// We potentially synthesize an `ImplicitValueInitExpr` for unions. It's a
// member variable because we store a pointer to it in `FieldInits`.
std::optional<ImplicitValueInitExpr> ImplicitValueInitForUnion;
};
/// Specialization of `RecursiveASTVisitor` that visits those nodes that are
/// relevant to the dataflow analysis; generally, these are the ones that also
/// appear in the CFG.
/// To start the traversal, call `TraverseStmt()` on the statement or body of
/// the function to analyze. Don't call `TraverseDecl()` on the function itself;
/// this won't work as `TraverseDecl()` contains code to avoid traversing nested
/// functions.
template <class Derived>
class AnalysisASTVisitor : public RecursiveASTVisitor<Derived> {
public:
bool shouldVisitImplicitCode() { return true; }
bool shouldVisitLambdaBody() const { return false; }
bool TraverseDecl(Decl *D) {
// Don't traverse nested record or function declarations.
// - We won't be analyzing code contained in these anyway
// - We don't model fields that are used only in these nested declaration,
// so trying to propagate a result object to initializers of such fields
// would cause an error.
if (isa_and_nonnull<RecordDecl>(D) || isa_and_nonnull<FunctionDecl>(D))
return true;
return RecursiveASTVisitor<Derived>::TraverseDecl(D);
}
// Don't traverse expressions in unevaluated contexts, as we don't model
// fields that are only used in these.
// Note: The operand of the `noexcept` operator is an unevaluated operand, but
// nevertheless it appears in the Clang CFG, so we don't exclude it here.
bool TraverseDecltypeTypeLoc(DecltypeTypeLoc) { return true; }
bool TraverseTypeOfExprTypeLoc(TypeOfExprTypeLoc) { return true; }
bool TraverseCXXTypeidExpr(CXXTypeidExpr *TIE) {
if (TIE->isPotentiallyEvaluated())
return RecursiveASTVisitor<Derived>::TraverseCXXTypeidExpr(TIE);
return true;
}
bool TraverseUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *) {
return true;
}
bool TraverseBindingDecl(BindingDecl *BD) {
// `RecursiveASTVisitor` doesn't traverse holding variables for
// `BindingDecl`s by itself, so we need to tell it to.
if (VarDecl *HoldingVar = BD->getHoldingVar())
TraverseDecl(HoldingVar);
return RecursiveASTVisitor<Derived>::TraverseBindingDecl(BD);
}
};
/// A collection of several types of declarations, all referenced from the same
/// function.
struct ReferencedDecls {
/// Non-static member variables.
FieldSet Fields;
/// All variables with static storage duration, notably including static
/// member variables and static variables declared within a function.
llvm::DenseSet<const VarDecl *> Globals;
/// Free functions and member functions which are referenced (but not
/// necessarily called).
llvm::DenseSet<const FunctionDecl *> Functions;
};
/// Returns declarations that are declared in or referenced from `FD`.
ReferencedDecls getReferencedDecls(const FunctionDecl &FD);
/// Returns declarations that are declared in or referenced from `S`.
ReferencedDecls getReferencedDecls(const Stmt &S);
} // namespace dataflow
} // namespace clang
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ASTOPS_H

View file

@ -0,0 +1,96 @@
//===-- AdornedCFG.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
//
//===----------------------------------------------------------------------===//
//
// This file defines an AdornedCFG class that is used by dataflow analyses that
// run over Control-Flow Graphs (CFGs).
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ADORNEDCFG_H
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ADORNEDCFG_H
#include "clang/AST/ASTContext.h"
#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>
#include <utility>
namespace clang {
namespace dataflow {
/// Holds CFG with additional information derived from it that is needed to
/// perform dataflow analysis.
class AdornedCFG {
public:
/// Builds an `AdornedCFG` from a `FunctionDecl`.
/// `Func.doesThisDeclarationHaveABody()` must be true, and
/// `Func.isTemplated()` must be false.
static llvm::Expected<AdornedCFG> build(const FunctionDecl &Func);
/// Builds an `AdornedCFG` from an AST node. `D` is the function in which
/// `S` resides. `D.isTemplated()` must be false.
static llvm::Expected<AdornedCFG> build(const Decl &D, Stmt &S,
ASTContext &C);
/// Returns the `Decl` containing the statement used to construct the CFG, if
/// available.
const Decl &getDecl() const { return ContainingDecl; }
/// Returns the CFG that is stored in this context.
const CFG &getCFG() const { return *Cfg; }
/// Returns a mapping from statements to basic blocks that contain them.
const llvm::DenseMap<const Stmt *, const CFGBlock *> &getStmtToBlock() const {
return StmtToBlock;
}
/// Returns whether `B` is reachable from the entry block.
bool isBlockReachable(const CFGBlock &B) const {
return BlockReachable[B.getBlockID()];
}
/// Returns whether `B` contains an expression that is consumed in a
/// different block than `B` (i.e. the parent of the expression is in a
/// different block).
/// This happens if there is control flow within a full-expression (triggered
/// by `&&`, `||`, or the conditional operator). Note that the operands of
/// these operators are not the only expressions that can be consumed in a
/// different block. For example, in the function call
/// `f(&i, cond() ? 1 : 0)`, `&i` is in a different block than the `CallExpr`.
bool containsExprConsumedInDifferentBlock(const CFGBlock &B) const {
return ContainsExprConsumedInDifferentBlock.contains(&B);
}
private:
AdornedCFG(
const Decl &D, std::unique_ptr<CFG> Cfg,
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock,
llvm::BitVector BlockReachable,
llvm::DenseSet<const CFGBlock *> ContainsExprConsumedInDifferentBlock)
: ContainingDecl(D), Cfg(std::move(Cfg)),
StmtToBlock(std::move(StmtToBlock)),
BlockReachable(std::move(BlockReachable)),
ContainsExprConsumedInDifferentBlock(
std::move(ContainsExprConsumedInDifferentBlock)) {}
/// 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;
llvm::DenseSet<const CFGBlock *> ContainsExprConsumedInDifferentBlock;
};
} // namespace dataflow
} // namespace clang
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ADORNEDCFG_H

View file

@ -0,0 +1,179 @@
//===- CNFFormula.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
//
//===----------------------------------------------------------------------===//
//
// A representation of a boolean formula in 3-CNF.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CNFFORMULA_H
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CNFFORMULA_H
#include <cstdint>
#include <vector>
#include "clang/Analysis/FlowSensitive/Formula.h"
namespace clang {
namespace dataflow {
/// Boolean variables are represented as positive integers.
using Variable = uint32_t;
/// A null boolean variable is used as a placeholder in various data structures
/// and algorithms.
constexpr Variable NullVar = 0;
/// Literals are represented as positive integers. Specifically, for a boolean
/// variable `V` that is represented as the positive integer `I`, the positive
/// literal `V` is represented as the integer `2*I` and the negative literal
/// `!V` is represented as the integer `2*I+1`.
using Literal = uint32_t;
/// A null literal is used as a placeholder in various data structures and
/// algorithms.
constexpr Literal NullLit = 0;
/// Clause identifiers are represented as positive integers.
using ClauseID = uint32_t;
/// A null clause identifier is used as a placeholder in various data structures
/// and algorithms.
constexpr ClauseID NullClause = 0;
/// Returns the positive literal `V`.
inline constexpr Literal posLit(Variable V) { return 2 * V; }
/// Returns the negative literal `!V`.
inline constexpr Literal negLit(Variable V) { return 2 * V + 1; }
/// Returns whether `L` is a positive literal.
inline constexpr bool isPosLit(Literal L) { return 0 == (L & 1); }
/// Returns whether `L` is a negative literal.
inline constexpr bool isNegLit(Literal L) { return 1 == (L & 1); }
/// Returns the negated literal `!L`.
inline constexpr Literal notLit(Literal L) { return L ^ 1; }
/// Returns the variable of `L`.
inline constexpr Variable var(Literal L) { return L >> 1; }
/// A boolean formula in 3-CNF (conjunctive normal form with at most 3 literals
/// per clause).
class CNFFormula {
/// `LargestVar` is equal to the largest positive integer that represents a
/// variable in the formula.
const Variable LargestVar;
/// Literals of all clauses in the formula.
///
/// The element at index 0 stands for the literal in the null clause. It is
/// set to 0 and isn't used. Literals of clauses in the formula start from the
/// element at index 1.
///
/// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of
/// `Clauses` will be `[0, L1, L2, L2, L3, L4]`.
std::vector<Literal> Clauses;
/// Start indices of clauses of the formula in `Clauses`.
///
/// The element at index 0 stands for the start index of the null clause. It
/// is set to 0 and isn't used. Start indices of clauses in the formula start
/// from the element at index 1.
///
/// For example, for the formula `(L1 v L2) ^ (L2 v L3 v L4)` the elements of
/// `ClauseStarts` will be `[0, 1, 3]`. Note that the literals of the first
/// clause always start at index 1. The start index for the literals of the
/// second clause depends on the size of the first clause and so on.
std::vector<size_t> ClauseStarts;
/// Indicates that we already know the formula is unsatisfiable.
/// During construction, we catch simple cases of conflicting unit-clauses.
bool KnownContradictory;
public:
explicit CNFFormula(Variable LargestVar);
/// Adds the `L1 v ... v Ln` clause to the formula.
/// Requirements:
///
/// `Li` must not be `NullLit`.
///
/// All literals in the input that are not `NullLit` must be distinct.
void addClause(ArrayRef<Literal> lits);
/// Returns whether the formula is known to be contradictory.
/// This is the case if any of the clauses is empty.
bool knownContradictory() const { return KnownContradictory; }
/// Returns the largest variable in the formula.
Variable largestVar() const { return LargestVar; }
/// Returns the number of clauses in the formula.
/// Valid clause IDs are in the range [1, `numClauses()`].
ClauseID numClauses() const { return ClauseStarts.size() - 1; }
/// Returns the number of literals in clause `C`.
size_t clauseSize(ClauseID C) const {
return C == ClauseStarts.size() - 1 ? Clauses.size() - ClauseStarts[C]
: ClauseStarts[C + 1] - ClauseStarts[C];
}
/// Returns the literals of clause `C`.
/// If `knownContradictory()` is false, each clause has at least one literal.
llvm::ArrayRef<Literal> clauseLiterals(ClauseID C) const {
size_t S = clauseSize(C);
if (S == 0)
return llvm::ArrayRef<Literal>();
return llvm::ArrayRef<Literal>(&Clauses[ClauseStarts[C]], S);
}
/// An iterator over all literals of all clauses in the formula.
/// The iterator allows mutation of the literal through the `*` operator.
/// This is to support solvers that mutate the formula during solving.
class Iterator {
friend class CNFFormula;
CNFFormula *CNF;
size_t Idx;
Iterator(CNFFormula *CNF, size_t Idx) : CNF(CNF), Idx(Idx) {}
public:
Iterator(const Iterator &) = default;
Iterator &operator=(const Iterator &) = default;
Iterator &operator++() {
++Idx;
assert(Idx < CNF->Clauses.size() && "Iterator out of bounds");
return *this;
}
Iterator next() const {
Iterator I = *this;
++I;
return I;
}
Literal &operator*() const { return CNF->Clauses[Idx]; }
};
friend class Iterator;
/// Returns an iterator to the first literal of clause `C`.
Iterator startOfClause(ClauseID C) { return Iterator(this, ClauseStarts[C]); }
};
/// Converts the conjunction of `Vals` into a formula in conjunctive normal
/// form where each clause has at least one and at most three literals.
/// `Atomics` is populated with a mapping from `Variables` to the corresponding
/// `Atom`s for atomic booleans in the input formulas.
CNFFormula buildCNF(const llvm::ArrayRef<const Formula *> &Formulas,
llvm::DenseMap<Variable, Atom> &Atomics);
} // namespace dataflow
} // namespace clang
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CNFFORMULA_H

View file

@ -1,79 +0,0 @@
//===-- ControlFlowContext.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
//
//===----------------------------------------------------------------------===//
//
// This file defines a ControlFlowContext class that is used by dataflow
// analyses that run over Control-Flow Graphs (CFGs).
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H
#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H
#include "clang/AST/ASTContext.h"
#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>
#include <utility>
namespace clang {
namespace dataflow {
/// Holds CFG and other derived context that is needed to perform dataflow
/// analysis.
class ControlFlowContext {
public:
/// Builds a ControlFlowContext from a `FunctionDecl`.
/// `Func.doesThisDeclarationHaveABody()` 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. `D.isTemplated()` must be false.
static llvm::Expected<ControlFlowContext> build(const Decl &D, Stmt &S,
ASTContext &C);
/// Returns the `Decl` containing the statement used to construct the CFG, if
/// available.
const Decl &getDecl() const { return ContainingDecl; }
/// Returns the CFG that is stored in this context.
const CFG &getCFG() const { return *Cfg; }
/// Returns a mapping from statements to basic blocks that contain them.
const llvm::DenseMap<const Stmt *, const CFGBlock *> &getStmtToBlock() const {
return StmtToBlock;
}
/// Returns whether `B` is reachable from the entry block.
bool isBlockReachable(const CFGBlock &B) const {
return BlockReachable[B.getBlockID()];
}
private:
ControlFlowContext(const Decl &D, std::unique_ptr<CFG> Cfg,
llvm::DenseMap<const Stmt *, const CFGBlock *> StmtToBlock,
llvm::BitVector BlockReachable)
: ContainingDecl(D), Cfg(std::move(Cfg)),
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
} // namespace clang
#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H

View file

@ -22,7 +22,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
#include "clang/Analysis/FlowSensitive/AdornedCFG.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/MatchSwitch.h"
@ -54,10 +54,9 @@ namespace dataflow {
/// Environment &Env)` - applies the analysis transfer
/// function for a given edge from a CFG block of a conditional statement.
///
/// `Derived` can optionally override the following members:
/// * `bool merge(QualType, const Value &, const Value &, Value &,
/// Environment &)` - joins distinct values. This could be a strict
/// lattice join or a more general widening operation.
/// `Derived` can optionally override the virtual functions in the
/// `Environment::ValueModel` interface (which is an indirect base class of
/// this class).
///
/// `LatticeT` is a bounded join-semilattice that is used by `Derived` and must
/// provide the following public members:
@ -179,13 +178,50 @@ template <typename LatticeT> struct DataflowAnalysisState {
Environment Env;
};
/// A callback to be called with the state before or after visiting a CFG
/// element.
template <typename AnalysisT>
using CFGEltCallback = std::function<void(
const CFGElement &,
const DataflowAnalysisState<typename AnalysisT::Lattice> &)>;
/// A pair of callbacks to be called with the state before and after visiting a
/// CFG element.
/// Either or both of the callbacks may be null.
template <typename AnalysisT> struct CFGEltCallbacks {
CFGEltCallback<AnalysisT> Before;
CFGEltCallback<AnalysisT> After;
};
/// A callback for performing diagnosis on a CFG element, called with the state
/// before or after visiting that CFG element. Returns a list of diagnostics
/// to emit (if any).
template <typename AnalysisT, typename Diagnostic>
using DiagnosisCallback = llvm::function_ref<llvm::SmallVector<Diagnostic>(
const CFGElement &, ASTContext &,
const TransferStateForDiagnostics<typename AnalysisT::Lattice> &)>;
/// A pair of callbacks for performing diagnosis on a CFG element, called with
/// the state before and after visiting that CFG element.
/// Either or both of the callbacks may be null.
template <typename AnalysisT, typename Diagnostic> struct DiagnosisCallbacks {
DiagnosisCallback<AnalysisT, Diagnostic> Before;
DiagnosisCallback<AnalysisT, Diagnostic> After;
};
/// Default for the maximum number of SAT solver iterations during analysis.
inline constexpr std::int64_t kDefaultMaxSATIterations = 1'000'000'000;
/// Default for the maximum number of block visits during analysis.
inline constexpr std::int32_t kDefaultMaxBlockVisits = 20'000;
/// Performs dataflow analysis and returns a mapping from basic block IDs to
/// dataflow analysis states that model the respective basic blocks. The
/// returned vector, if any, will have the same size as the number of CFG
/// blocks, with indices corresponding to basic block IDs. Returns an error if
/// the dataflow analysis cannot be performed successfully. Otherwise, calls
/// `PostVisitCFG` on each CFG element with the final analysis results at that
/// program point.
/// `PostAnalysisCallbacks` on each CFG element with the final analysis results
/// before and after that program point.
///
/// `MaxBlockVisits` caps the number of block visits during analysis. See
/// `runTypeErasedDataflowAnalysis` for a full description. The default value is
@ -195,31 +231,40 @@ template <typename LatticeT> struct DataflowAnalysisState {
template <typename AnalysisT>
llvm::Expected<std::vector<
std::optional<DataflowAnalysisState<typename AnalysisT::Lattice>>>>
runDataflowAnalysis(
const ControlFlowContext &CFCtx, AnalysisT &Analysis,
const Environment &InitEnv,
std::function<void(const CFGElement &, const DataflowAnalysisState<
typename AnalysisT::Lattice> &)>
PostVisitCFG = nullptr,
std::int32_t MaxBlockVisits = 20'000) {
std::function<void(const CFGElement &,
const TypeErasedDataflowAnalysisState &)>
PostVisitCFGClosure = nullptr;
if (PostVisitCFG) {
PostVisitCFGClosure = [&PostVisitCFG](
const CFGElement &Element,
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.fork()});
};
runDataflowAnalysis(const AdornedCFG &ACFG, AnalysisT &Analysis,
const Environment &InitEnv,
CFGEltCallbacks<AnalysisT> PostAnalysisCallbacks,
std::int32_t MaxBlockVisits = kDefaultMaxBlockVisits) {
CFGEltCallbacksTypeErased TypeErasedCallbacks;
if (PostAnalysisCallbacks.Before) {
TypeErasedCallbacks.Before =
[&PostAnalysisCallbacks](const CFGElement &Element,
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 `CFGEltCallback` only gets a const reference anyway.
PostAnalysisCallbacks.Before(
Element, DataflowAnalysisState<typename AnalysisT::Lattice>{
*Lattice, State.Env.fork()});
};
}
if (PostAnalysisCallbacks.After) {
TypeErasedCallbacks.After =
[&PostAnalysisCallbacks](const CFGElement &Element,
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 `CFGEltCallback` only gets a const reference anyway.
PostAnalysisCallbacks.After(
Element, DataflowAnalysisState<typename AnalysisT::Lattice>{
*Lattice, State.Env.fork()});
};
}
auto TypeErasedBlockStates = runTypeErasedDataflowAnalysis(
CFCtx, Analysis, InitEnv, PostVisitCFGClosure, MaxBlockVisits);
ACFG, Analysis, InitEnv, TypeErasedCallbacks, MaxBlockVisits);
if (!TypeErasedBlockStates)
return TypeErasedBlockStates.takeError();
@ -241,6 +286,22 @@ runDataflowAnalysis(
return std::move(BlockStates);
}
/// Overload that takes only one post-analysis callback, which is run on the
/// state after visiting the `CFGElement`. This is provided for backwards
/// compatibility; new callers should call the overload taking `CFGEltCallbacks`
/// instead.
template <typename AnalysisT>
llvm::Expected<std::vector<
std::optional<DataflowAnalysisState<typename AnalysisT::Lattice>>>>
runDataflowAnalysis(
const AdornedCFG &ACFG, AnalysisT &Analysis, const Environment &InitEnv,
CFGEltCallback<AnalysisT> PostAnalysisCallbackAfterElt = nullptr,
std::int32_t MaxBlockVisits = kDefaultMaxBlockVisits) {
return runDataflowAnalysis(ACFG, Analysis, InitEnv,
{nullptr, PostAnalysisCallbackAfterElt},
MaxBlockVisits);
}
// Create an analysis class that is derived from `DataflowAnalysis`. This is an
// SFINAE adapter that allows us to call two different variants of constructor
// (either with or without the optional `Environment` parameter).
@ -273,40 +334,52 @@ auto createAnalysis(ASTContext &ASTCtx, Environment &Env)
/// `runDataflowAnalysis` for a full description and explanation of the default
/// value.
template <typename AnalysisT, typename Diagnostic>
llvm::Expected<llvm::SmallVector<Diagnostic>> diagnoseFunction(
const FunctionDecl &FuncDecl, ASTContext &ASTCtx,
llvm::function_ref<llvm::SmallVector<Diagnostic>(
const CFGElement &, ASTContext &,
const TransferStateForDiagnostics<typename AnalysisT::Lattice> &)>
Diagnoser,
std::int64_t MaxSATIterations = 1'000'000'000,
std::int32_t MaxBlockVisits = 20'000) {
llvm::Expected<ControlFlowContext> Context =
ControlFlowContext::build(FuncDecl);
llvm::Expected<llvm::SmallVector<Diagnostic>>
diagnoseFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx,
DiagnosisCallbacks<AnalysisT, Diagnostic> Diagnoser,
std::int64_t MaxSATIterations = kDefaultMaxSATIterations,
std::int32_t MaxBlockVisits = kDefaultMaxBlockVisits) {
llvm::Expected<AdornedCFG> Context = AdornedCFG::build(FuncDecl);
if (!Context)
return Context.takeError();
auto OwnedSolver = std::make_unique<WatchedLiteralsSolver>(MaxSATIterations);
const WatchedLiteralsSolver *Solver = OwnedSolver.get();
DataflowAnalysisContext AnalysisContext(std::move(OwnedSolver));
auto Solver = std::make_unique<WatchedLiteralsSolver>(MaxSATIterations);
DataflowAnalysisContext AnalysisContext(*Solver);
Environment Env(AnalysisContext, FuncDecl);
AnalysisT Analysis = createAnalysis<AnalysisT>(ASTCtx, Env);
llvm::SmallVector<Diagnostic> Diagnostics;
CFGEltCallbacksTypeErased PostAnalysisCallbacks;
if (Diagnoser.Before) {
PostAnalysisCallbacks.Before =
[&ASTCtx, &Diagnoser,
&Diagnostics](const CFGElement &Elt,
const TypeErasedDataflowAnalysisState &State) mutable {
auto EltDiagnostics = Diagnoser.Before(
Elt, ASTCtx,
TransferStateForDiagnostics<typename AnalysisT::Lattice>(
llvm::any_cast<const typename AnalysisT::Lattice &>(
State.Lattice.Value),
State.Env));
llvm::move(EltDiagnostics, std::back_inserter(Diagnostics));
};
}
if (Diagnoser.After) {
PostAnalysisCallbacks.After =
[&ASTCtx, &Diagnoser,
&Diagnostics](const CFGElement &Elt,
const TypeErasedDataflowAnalysisState &State) mutable {
auto EltDiagnostics = Diagnoser.After(
Elt, ASTCtx,
TransferStateForDiagnostics<typename AnalysisT::Lattice>(
llvm::any_cast<const typename AnalysisT::Lattice &>(
State.Lattice.Value),
State.Env));
llvm::move(EltDiagnostics, std::back_inserter(Diagnostics));
};
}
if (llvm::Error Err =
runTypeErasedDataflowAnalysis(
*Context, Analysis, Env,
[&ASTCtx, &Diagnoser, &Diagnostics](
const CFGElement &Elt,
const TypeErasedDataflowAnalysisState &State) mutable {
auto EltDiagnostics = Diagnoser(
Elt, ASTCtx,
TransferStateForDiagnostics<typename AnalysisT::Lattice>(
llvm::any_cast<const typename AnalysisT::Lattice &>(
State.Lattice.Value),
State.Env));
llvm::move(EltDiagnostics, std::back_inserter(Diagnostics));
},
MaxBlockVisits)
runTypeErasedDataflowAnalysis(*Context, Analysis, Env,
PostAnalysisCallbacks, MaxBlockVisits)
.takeError())
return std::move(Err);
@ -317,6 +390,21 @@ llvm::Expected<llvm::SmallVector<Diagnostic>> diagnoseFunction(
return Diagnostics;
}
/// Overload that takes only one diagnosis callback, which is run on the state
/// after visiting the `CFGElement`. This is provided for backwards
/// compatibility; new callers should call the overload taking
/// `DiagnosisCallbacks` instead.
template <typename AnalysisT, typename Diagnostic>
llvm::Expected<llvm::SmallVector<Diagnostic>>
diagnoseFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx,
DiagnosisCallback<AnalysisT, Diagnostic> Diagnoser,
std::int64_t MaxSATIterations = kDefaultMaxSATIterations,
std::int32_t MaxBlockVisits = kDefaultMaxBlockVisits) {
DiagnosisCallbacks<AnalysisT, Diagnostic> Callbacks = {nullptr, Diagnoser};
return diagnoseFunction(FuncDecl, ASTCtx, Callbacks, MaxSATIterations,
MaxBlockVisits);
}
/// Abstract base class for dataflow "models": reusable analysis components that
/// model a particular aspect of program semantics in the `Environment`. For
/// example, a model may capture a type and its related functions.

View file

@ -18,8 +18,9 @@
#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/TypeOrdering.h"
#include "clang/Analysis/FlowSensitive/ASTOps.h"
#include "clang/Analysis/FlowSensitive/AdornedCFG.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"
@ -30,38 +31,11 @@
#include <cassert>
#include <memory>
#include <optional>
#include <type_traits>
#include <utility>
#include <vector>
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
/// exist.
///
/// * `ParenExpr` - The CFG takes the operator precedence into account, but
/// otherwise omits the node afterwards.
///
/// * `ExprWithCleanups` - The CFG will generate the appropriate calls to
/// destructors and then omit the node.
///
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.
FieldSet getObjectFields(QualType Type);
/// Returns whether `Fields` and `FieldLocs` contain the same fields.
bool containsSameFields(const FieldSet &Fields,
const RecordStorageLocation::FieldToLoc &FieldLocs);
struct ContextSensitiveOptions {
/// The maximum depth to analyze. A value of zero is equivalent to disabling
/// context-sensitive analysis entirely.
@ -93,13 +67,27 @@ public:
DataflowAnalysisContext(std::unique_ptr<Solver> S,
Options Opts = Options{
/*ContextSensitiveOpts=*/std::nullopt,
/*Logger=*/nullptr});
/*Logger=*/nullptr})
: DataflowAnalysisContext(*S, std::move(S), Opts) {}
/// Constructs a dataflow analysis context.
///
/// Requirements:
///
/// `S` must outlive the `DataflowAnalysisContext`.
DataflowAnalysisContext(Solver &S, Options Opts = Options{
/*ContextSensitiveOpts=*/std::nullopt,
/*Logger=*/nullptr})
: DataflowAnalysisContext(S, nullptr, Opts) {}
~DataflowAnalysisContext();
/// Sets a callback that returns the names and types of the synthetic fields
/// to add to a `RecordStorageLocation` of a given type.
/// Typically, this is called from the constructor of a `DataflowAnalysis`
///
/// The field types returned by the callback may not have reference type.
///
/// To maintain the invariant that all `RecordStorageLocation`s of a given
/// type have the same fields:
/// * The callback must always return the same result for a given type
@ -181,9 +169,9 @@ public:
LLVM_DUMP_METHOD void dumpFlowCondition(Atom Token,
llvm::raw_ostream &OS = llvm::dbgs());
/// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise,
/// Returns the `AdornedCFG` registered for `F`, if any. Otherwise,
/// returns null.
const ControlFlowContext *getControlFlowContext(const FunctionDecl *F);
const AdornedCFG *getAdornedCFG(const FunctionDecl *F);
const Options &getOptions() { return Opts; }
@ -205,8 +193,17 @@ public:
/// type.
llvm::StringMap<QualType> getSyntheticFields(QualType Type) {
assert(Type->isRecordType());
if (SyntheticFieldCallback)
return SyntheticFieldCallback(Type);
if (SyntheticFieldCallback) {
llvm::StringMap<QualType> Result = SyntheticFieldCallback(Type);
// Synthetic fields are not allowed to have reference type.
assert([&Result] {
for (const auto &Entry : Result)
if (Entry.getValue()->isReferenceType())
return false;
return true;
}());
return Result;
}
return {};
}
@ -224,6 +221,13 @@ private:
using DenseMapInfo::isEqual;
};
/// `S` is the solver to use. `OwnedSolver` may be:
/// * Null (in which case `S` is non-onwed and must outlive this object), or
/// * Non-null (in which case it must refer to `S`, and the
/// `DataflowAnalysisContext will take ownership of `OwnedSolver`).
DataflowAnalysisContext(Solver &S, std::unique_ptr<Solver> &&OwnedSolver,
Options Opts);
// Extends the set of modeled field declarations.
void addModeledFields(const FieldSet &Fields);
@ -247,7 +251,8 @@ private:
Solver::Result::Status::Unsatisfiable;
}
std::unique_ptr<Solver> S;
Solver &S;
std::unique_ptr<Solver> OwnedSolver;
std::unique_ptr<Arena> A;
// Maps from program declarations and statements to storage locations that are
@ -285,7 +290,7 @@ private:
llvm::DenseMap<Atom, const Formula *> FlowConditionConstraints;
const Formula *Invariant = nullptr;
llvm::DenseMap<const FunctionDecl *, ControlFlowContext> FunctionContexts;
llvm::DenseMap<const FunctionDecl *, AdornedCFG> FunctionContexts;
// Fields modeled by environments covered by this context.
FieldSet ModeledFields;

View file

@ -19,7 +19,7 @@
#include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
#include "clang/Analysis/FlowSensitive/ASTOps.h"
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/Formula.h"
@ -31,9 +31,11 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
namespace clang {
namespace dataflow {
@ -45,6 +47,15 @@ enum class ComparisonResult {
Unknown,
};
/// The result of a `widen` operation.
struct WidenResult {
/// Non-null pointer to a potentially widened version of the input value.
Value *V;
/// Whether `V` represents a "change" (that is, a different value) with
/// respect to the previous value in the sequence.
LatticeEffect Effect;
};
/// Holds the state of the program (store and heap) at a given program point.
///
/// WARNING: Symbolic values that are created by the environment for static
@ -76,16 +87,13 @@ public:
virtual ComparisonResult compare(QualType Type, const Value &Val1,
const Environment &Env1, const Value &Val2,
const Environment &Env2) {
// FIXME: Consider adding QualType to RecordValue and removing the Type
// FIXME: Consider adding `QualType` to `Value` and removing the `Type`
// argument here.
return ComparisonResult::Unknown;
}
/// Modifies `MergedVal` to approximate both `Val1` and `Val2`. This could
/// be a strict lattice join or a more general widening operation.
///
/// If this function returns true, `MergedVal` will be assigned to a storage
/// location of type `Type` in `MergedEnv`.
/// Modifies `JoinedVal` to approximate both `Val1` and `Val2`. This should
/// obey the properties of a lattice join.
///
/// `Env1` and `Env2` can be used to query child values and path condition
/// implications of `Val1` and `Val2` respectively.
@ -94,16 +102,13 @@ public:
///
/// `Val1` and `Val2` must be distinct.
///
/// `Val1`, `Val2`, and `MergedVal` must model values of type `Type`.
/// `Val1`, `Val2`, and `JoinedVal` must model values of type `Type`.
///
/// `Val1` and `Val2` must be assigned to the same storage location in
/// `Env1` and `Env2` respectively.
virtual bool merge(QualType Type, const Value &Val1,
const Environment &Env1, const Value &Val2,
const Environment &Env2, Value &MergedVal,
Environment &MergedEnv) {
return true;
}
virtual void join(QualType Type, const Value &Val1, const Environment &Env1,
const Value &Val2, const Environment &Env2,
Value &JoinedVal, Environment &JoinedEnv) {}
/// This function may widen the current value -- replace it with an
/// approximation that can reach a fixed point more quickly than iterated
@ -112,14 +117,17 @@ public:
/// serve as a comparison operation, by indicating whether the widened value
/// is equivalent to the previous value.
///
/// Returns either:
///
/// `nullptr`, if this value is not of interest to the model, or
///
/// `&Prev`, if the widened value is equivalent to `Prev`, or
///
/// A non-null value that approximates `Current`. `Prev` is available to
/// inform the chosen approximation.
/// Returns one of the folowing:
/// * `std::nullopt`, if this value is not of interest to the
/// model.
/// * A `WidenResult` with:
/// * A non-null `Value *` that points either to `Current` or a widened
/// version of `Current`. This value must be consistent with
/// the flow condition of `CurrentEnv`. We particularly caution
/// against using `Prev`, which is rarely consistent.
/// * A `LatticeEffect` indicating whether the value should be
/// considered a new value (`Changed`) or one *equivalent* (if not
/// necessarily equal) to `Prev` (`Unchanged`).
///
/// `PrevEnv` and `CurrentEnv` can be used to query child values and path
/// condition implications of `Prev` and `Current`, respectively.
@ -130,17 +138,19 @@ public:
///
/// `Prev` and `Current` must be assigned to the same storage location in
/// `PrevEnv` and `CurrentEnv`, respectively.
virtual Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv,
Value &Current, Environment &CurrentEnv) {
virtual std::optional<WidenResult> widen(QualType Type, Value &Prev,
const Environment &PrevEnv,
Value &Current,
Environment &CurrentEnv) {
// The default implementation reduces to just comparison, since comparison
// is required by the API, even if no widening is performed.
switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) {
case ComparisonResult::Same:
return &Prev;
case ComparisonResult::Different:
return &Current;
case ComparisonResult::Unknown:
return nullptr;
case ComparisonResult::Unknown:
return std::nullopt;
case ComparisonResult::Same:
return WidenResult{&Current, LatticeEffect::Unchanged};
case ComparisonResult::Different:
return WidenResult{&Current, LatticeEffect::Changed};
}
llvm_unreachable("all cases in switch covered");
}
@ -148,7 +158,28 @@ public:
/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program.
explicit Environment(DataflowAnalysisContext &DACtx);
explicit Environment(DataflowAnalysisContext &DACtx)
: DACtx(&DACtx),
FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}
/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program, with `S` as the statement to analyze.
Environment(DataflowAnalysisContext &DACtx, Stmt &S) : Environment(DACtx) {
InitialTargetStmt = &S;
}
/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program, with `FD` as the function to analyze.
///
/// Requirements:
///
/// The function must have a body, i.e.
/// `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
Environment(DataflowAnalysisContext &DACtx, const FunctionDecl &FD)
: Environment(DACtx, *FD.getBody()) {
assert(FD.doesThisDeclarationHaveABody());
InitialTargetFunc = &FD;
}
// Copy-constructor is private, Environments should not be copied. See fork().
Environment &operator=(const Environment &Other) = delete;
@ -156,24 +187,11 @@ public:
Environment(Environment &&Other) = default;
Environment &operator=(Environment &&Other) = default;
/// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program.
///
/// If `DeclCtx` is a function, initializes the environment with symbolic
/// representations of the function parameters.
///
/// If `DeclCtx` is a non-static member function, initializes the environment
/// with a symbolic representation of the `this` pointee.
Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);
/// Assigns storage locations and values to all parameters, captures, global
/// variables, fields and functions referenced in the function currently being
/// analyzed.
/// variables, fields and functions referenced in the `Stmt` or `FunctionDecl`
/// passed to the constructor.
///
/// Requirements:
///
/// The function must have a body, i.e.
/// `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
/// If no `Stmt` or `FunctionDecl` was supplied, this function does nothing.
void initialize();
/// Returns a new environment that is a copy of this one.
@ -186,7 +204,7 @@ public:
/// forked flow condition references the original).
Environment fork() const;
/// Creates and returns an environment to use for an inline analysis of the
/// 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
/// storage location for the corresponding parameter in the callee.
///
@ -218,6 +236,14 @@ public:
bool equivalentTo(const Environment &Other,
Environment::ValueModel &Model) const;
/// How to treat expression state (`ExprToLoc` and `ExprToVal`) in a join.
/// If the join happens within a full expression, expression state should be
/// kept; otherwise, we can discard it.
enum ExprJoinBehavior {
DiscardExprState,
KeepExprState,
};
/// 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`.
@ -226,7 +252,23 @@ public:
///
/// `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`.
static Environment join(const Environment &EnvA, const Environment &EnvB,
Environment::ValueModel &Model);
Environment::ValueModel &Model,
ExprJoinBehavior ExprBehavior);
/// Returns a value that approximates both `Val1` and `Val2`, or null if no
/// such value can be produced.
///
/// `Env1` and `Env2` can be used to query child values and path condition
/// implications of `Val1` and `Val2` respectively. The joined value will be
/// produced in `JoinedEnv`.
///
/// Requirements:
///
/// `Val1` and `Val2` must model values of type `Type`.
static Value *joinValues(QualType Ty, Value *Val1, const Environment &Env1,
Value *Val2, const Environment &Env2,
Environment &JoinedEnv,
Environment::ValueModel &Model);
/// Widens the environment point-wise, using `PrevEnv` as needed to inform the
/// approximation.
@ -235,8 +277,8 @@ public:
///
/// `PrevEnv` must be the immediate previous version of the environment.
/// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`.
LatticeJoinEffect widen(const Environment &PrevEnv,
Environment::ValueModel &Model);
LatticeEffect widen(const Environment &PrevEnv,
Environment::ValueModel &Model);
// FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`,
// `getStableStorageLocation`, or something more appropriate.
@ -329,62 +371,56 @@ public:
/// 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.
RecordStorageLocation &
getResultObjectLocation(const Expr &RecordPRValue) const;
/// Returns the return value of the current function. This can be null if:
/// Returns the return value of the function currently being analyzed.
/// 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.
/// The current analysis target must be a function and 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.
/// Returns the storage location for the reference returned by the function
/// currently being analyzed. This can be null if the function doesn't return
/// a single consistent reference.
///
/// Requirements:
/// The current function must have a reference return type.
/// The current analysis target must be a function and 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.
/// Sets the return value of the function currently being analyzed.
///
/// Requirements:
/// The current function must have a non-reference return type.
/// The current analysis target must be a function and 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.
/// Sets the storage location for the reference returned by the function
/// currently being analyzed.
///
/// Requirements:
/// The current function must have a reference return type.
/// The current analysis target must be a function and must have a reference
/// return type.
void setReturnStorageLocation(StorageLocation *Loc) {
assert(getCurrentFunc() != nullptr &&
getCurrentFunc()->getReturnType()->isReferenceType());
@ -402,20 +438,15 @@ public:
/// storage locations and values for indirections until it finds a
/// non-pointer/non-reference type.
///
/// If `Type` is a class, struct, or union type, creates values for all
/// modeled fields (including synthetic fields) and calls `setValue()` to
/// associate the `RecordValue` with its storage location
/// (`RecordValue::getLoc()`).
///
/// 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.
/// - `Type` must not be null.
/// - `Type` must not be a reference type or record type.
Value *createValue(QualType Type);
/// Creates an object (i.e. a storage location with an associated value) of
@ -444,7 +475,23 @@ public:
return createObjectInternal(&D, D.getType(), InitExpr);
}
/// Initializes the fields (including synthetic fields) of `Loc` with values,
/// unless values of the field type are not supported or we hit one of the
/// limits at which we stop producing values.
/// If a field already has a value, that value is preserved.
/// If `Type` is provided, initializes only those fields that are modeled for
/// `Type`; this is intended for use in cases where `Loc` is a derived type
/// and we only want to initialize the fields of a base type.
void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type);
void initializeFieldsWithValues(RecordStorageLocation &Loc) {
initializeFieldsWithValues(Loc, Loc.getType());
}
/// Assigns `Val` as the value of `Loc` in the environment.
///
/// Requirements:
///
/// `Loc` must not be a `RecordStorageLocation`.
void setValue(const StorageLocation &Loc, Value &Val);
/// Clears any association between `Loc` and a value in the environment.
@ -454,20 +501,24 @@ public:
///
/// Requirements:
///
/// - `E` must be a prvalue
/// - If `Val` is a `RecordValue`, its `RecordStorageLocation` must be
/// `getResultObjectLocation(E)`. An exception to this is if `E` is an
/// expression that originally creates a `RecordValue` (such as a
/// `CXXConstructExpr` or `CallExpr`), as these establish the location of
/// the result object in the first place.
/// - `E` must be a prvalue.
/// - `E` must not have record type.
void setValue(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.
///
/// Requirements:
///
/// `Loc` must not be a `RecordStorageLocation`.
Value *getValue(const StorageLocation &Loc) const;
/// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a
/// storage location in the environment, otherwise returns null.
///
/// Requirements:
///
/// `D` must not have record type.
Value *getValue(const ValueDecl &D) const;
/// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a
@ -606,23 +657,21 @@ public:
/// (or the flow condition is overly constraining) or if the solver times out.
bool allows(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());
return CallStack.empty() ? InitialTargetFunc : CallStack.back();
}
/// Returns the size of the call stack.
/// Returns the size of the call stack, not counting the initial analysis
/// target.
size_t callStackSize() const { return CallStack.size(); }
/// 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;
/// `Callee` (i.e. if `pushCall` can be used).
/// Recursion is not allowed. `MaxDepth` is the maximum size of the call stack
/// (i.e. the maximum value that `callStackSize()` may assume after the call).
bool canDescend(unsigned MaxDepth, const FunctionDecl *Callee) const;
/// Returns the `DataflowAnalysisContext` used by the environment.
DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; }
@ -633,6 +682,9 @@ public:
LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;
private:
using PrValueToResultObject =
llvm::DenseMap<const Expr *, RecordStorageLocation *>;
// The copy-constructor is for use in fork() only.
Environment(const Environment &) = default;
@ -659,6 +711,16 @@ private:
llvm::DenseSet<QualType> &Visited,
int Depth, int &CreatedValuesCount);
/// Initializes the fields (including synthetic fields) of `Loc` with values,
/// unless values of the field type are not supported or we hit one of the
/// limits at which we stop producing values (controlled by `Visited`,
/// `Depth`, and `CreatedValuesCount`). If `Type` is different from
/// `Loc.getType()`, initializes only those fields that are modeled for
/// `Type`.
void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type,
llvm::DenseSet<QualType> &Visited, int Depth,
int &CreatedValuesCount);
/// Shared implementation of `createObject()` overloads.
/// `D` and `InitExpr` may be null.
StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty,
@ -671,27 +733,64 @@ private:
ArrayRef<const Expr *> Args);
/// 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);
/// and functions in `Referenced`.
void initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced);
static PrValueToResultObject
buildResultObjectMap(DataflowAnalysisContext *DACtx,
const FunctionDecl *FuncDecl,
RecordStorageLocation *ThisPointeeLoc,
RecordStorageLocation *LocForRecordReturnVal);
static PrValueToResultObject
buildResultObjectMap(DataflowAnalysisContext *DACtx, Stmt *S,
RecordStorageLocation *ThisPointeeLoc,
RecordStorageLocation *LocForRecordReturnVal);
// `DACtx` is not null and not owned by this object.
DataflowAnalysisContext *DACtx;
// FIXME: move the fields `CallStack`, `ReturnVal`, `ReturnLoc` and
// `ThisPointeeLoc` into a separate call-context object, shared between
// environments in the same call.
// FIXME: move the fields `CallStack`, `ResultObjectMap`, `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;
// The stack of functions called from the initial analysis target.
std::vector<const FunctionDecl *> CallStack;
// Value returned by the function (if it has non-reference return type).
// Initial function to analyze, if a function was passed to the constructor.
// Null otherwise.
const FunctionDecl *InitialTargetFunc = nullptr;
// Top-level statement of the initial analysis target.
// If a function was passed to the constructor, this is its body.
// If a statement was passed to the constructor, this is that statement.
// Null if no analysis target was passed to the constructor.
Stmt *InitialTargetStmt = nullptr;
// Maps from prvalues of record type to their result objects. Shared between
// all environments for the same analysis target.
// FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr`
// here, though the cost is acceptable: The overhead of a `shared_ptr` is
// incurred when it is copied, and this happens only relatively rarely (when
// we fork the environment). The need for a `shared_ptr` will go away once we
// introduce a shared call-context object (see above).
std::shared_ptr<PrValueToResultObject> ResultObjectMap;
// The following three member variables handle various different types of
// return values when the current analysis target is a function.
// - If the return type is not a reference and not a record: Value returned
// by the function.
Value *ReturnVal = nullptr;
// Storage location of the reference returned by the function (if it has
// reference return type).
// - If the return type is a reference: Storage location of the reference
// returned by the function.
StorageLocation *ReturnLoc = nullptr;
// - If the return type is a record or the function being analyzed is a
// constructor: Storage location into which the return value should be
// constructed.
RecordStorageLocation *LocForRecordReturnVal = 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.
// analysis target is not a method.
RecordStorageLocation *ThisPointeeLoc = nullptr;
// Maps from declarations and glvalue expression to storage locations that are
@ -723,16 +822,6 @@ RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
RecordStorageLocation *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 `RecordValue` with `Loc` and returns the new value.
RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env);
/// Associates a new `RecordValue` with `Expr` and returns the new value.
RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env);
} // namespace dataflow
} // namespace clang

View file

@ -17,13 +17,13 @@
namespace clang {
namespace dataflow {
/// Effect indicating whether a lattice join operation resulted in a new value.
// FIXME: Rename to `LatticeEffect` since `widen` uses it as well, and we are
// likely removing it from `join`.
enum class LatticeJoinEffect {
/// Effect indicating whether a lattice operation resulted in a new value.
enum class LatticeEffect {
Unchanged,
Changed,
};
// DEPRECATED. Use `LatticeEffect`.
using LatticeJoinEffect = LatticeEffect;
} // namespace dataflow
} // namespace clang

View file

@ -45,12 +45,12 @@ class DataflowValues {
//===--------------------------------------------------------------------===//
public:
typedef typename ValueTypes::ValTy ValTy;
typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
typedef _AnalysisDirTag AnalysisDirTag;
typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy;
typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
typedef llvm::DenseMap<const Stmt*, ValTy> StmtDataMapTy;
using ValTy = typename ValueTypes::ValTy;
using AnalysisDataTy = typename ValueTypes::AnalysisDataTy;
using AnalysisDirTag = _AnalysisDirTag;
using EdgeDataMapTy = llvm::DenseMap<ProgramPoint, ValTy>;
using BlockDataMapTy = llvm::DenseMap<const CFGBlock *, ValTy>;
using StmtDataMapTy = llvm::DenseMap<const Stmt *, ValTy>;
//===--------------------------------------------------------------------===//
// Predicates.

View file

@ -15,7 +15,7 @@
namespace clang::dataflow {
// Forward declarations so we can use Logger anywhere in the framework.
class ControlFlowContext;
class AdornedCFG;
class TypeErasedDataflowAnalysis;
struct TypeErasedDataflowAnalysisState;
@ -40,8 +40,8 @@ public:
/// 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 beginAnalysis(const AdornedCFG &, TypeErasedDataflowAnalysis &) {
}
virtual void endAnalysis() {}
// At any time during the analysis, we're computing the state for some target

View file

@ -31,7 +31,11 @@ namespace dataflow {
///
/// Requirements:
///
/// `Src` and `Dst` must have the same canonical unqualified type.
/// Either:
/// - `Src` and `Dest` must have the same canonical unqualified type, or
/// - The type of `Src` must be derived from `Dest`, or
/// - The type of `Dest` must be derived from `Src` (in this case, any fields
/// that are only present in `Dest` are not overwritten).
void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst,
Environment &Env);

View file

@ -87,6 +87,9 @@ public:
///
/// All elements in `Vals` must not be null.
virtual Result solve(llvm::ArrayRef<const Formula *> Vals) = 0;
// Did the solver reach its resource limit?
virtual bool reachedLimit() const = 0;
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Solver::Result &);

View file

@ -29,12 +29,12 @@ public:
// `CurState` is the pending state currently associated with this block. These
// are supplied separately as the pending state for the current block may not
// yet be represented in `BlockToState`.
StmtToEnvMap(const ControlFlowContext &CFCtx,
StmtToEnvMap(const AdornedCFG &ACFG,
llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>>
BlockToState,
unsigned CurBlockID,
const TypeErasedDataflowAnalysisState &CurState)
: CFCtx(CFCtx), BlockToState(BlockToState), CurBlockID(CurBlockID),
: ACFG(ACFG), BlockToState(BlockToState), CurBlockID(CurBlockID),
CurState(CurState) {}
/// Returns the environment of the basic block that contains `S`.
@ -42,7 +42,7 @@ public:
const Environment *getEnvironment(const Stmt &S) const;
private:
const ControlFlowContext &CFCtx;
const AdornedCFG &ACFG;
llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>> BlockToState;
unsigned CurBlockID;
const TypeErasedDataflowAnalysisState &CurState;
@ -53,7 +53,8 @@ private:
/// Requirements:
///
/// `S` must not be `ParenExpr` or `ExprWithCleanups`.
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env);
void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,
Environment::ValueModel &Model);
} // namespace dataflow
} // namespace clang

View file

@ -21,7 +21,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/Stmt.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
#include "clang/Analysis/FlowSensitive/AdornedCFG.h"
#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h"
@ -132,12 +132,25 @@ struct TypeErasedDataflowAnalysisState {
}
};
/// A callback to be called with the state before or after visiting a CFG
/// element.
using CFGEltCallbackTypeErased = std::function<void(
const CFGElement &, const TypeErasedDataflowAnalysisState &)>;
/// A pair of callbacks to be called with the state before and after visiting a
/// CFG element.
/// Either or both of the callbacks may be null.
struct CFGEltCallbacksTypeErased {
CFGEltCallbackTypeErased Before;
CFGEltCallbackTypeErased After;
};
/// Performs dataflow analysis and returns a mapping from basic block IDs to
/// dataflow analysis states that model the respective basic blocks. Indices of
/// the returned vector correspond to basic block IDs. Returns an error if the
/// dataflow analysis cannot be performed successfully. Otherwise, calls
/// `PostVisitCFG` on each CFG element with the final analysis results at that
/// program point.
/// `PostAnalysisCallbacks` on each CFG element with the final analysis results
/// before and after that program point.
///
/// `MaxBlockVisits` caps the number of block visits during analysis. It doesn't
/// distinguish between repeat visits to the same block and visits to distinct
@ -146,11 +159,9 @@ struct TypeErasedDataflowAnalysisState {
/// from converging.
llvm::Expected<std::vector<std::optional<TypeErasedDataflowAnalysisState>>>
runTypeErasedDataflowAnalysis(
const ControlFlowContext &CFCtx, TypeErasedDataflowAnalysis &Analysis,
const AdornedCFG &ACFG, TypeErasedDataflowAnalysis &Analysis,
const Environment &InitEnv,
std::function<void(const CFGElement &,
const TypeErasedDataflowAnalysisState &)>
PostVisitCFG,
const CFGEltCallbacksTypeErased &PostAnalysisCallbacks,
std::int32_t MaxBlockVisits);
} // namespace dataflow

View file

@ -35,7 +35,6 @@ public:
enum class Kind {
Integer,
Pointer,
Record,
// TODO: Top values should not be need to be type-specific.
TopBool,
@ -67,7 +66,6 @@ public:
/// Properties may not be set on `RecordValue`s; use synthetic fields instead
/// (for details, see documentation for `RecordStorageLocation`).
void setProperty(llvm::StringRef Name, Value &Val) {
assert(getKind() != Kind::Record);
Properties.insert_or_assign(Name, &Val);
}
@ -184,45 +182,6 @@ private:
StorageLocation &PointeeLoc;
};
/// 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, `RecordValue` also serves only a limited purpose: 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. `RecordValue` 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
/// `RecordValue` that wraps a `RecordStorageLocation`. This
/// `RecordStorageLocation` is then used as the storage location for `S`.
///
/// Over time, we may eliminate `RecordValue` entirely. See also the discussion
/// here: https://reviews.llvm.org/D155204#inline-1503204
class RecordValue final : public Value {
public:
explicit RecordValue(RecordStorageLocation &Loc)
: Value(Kind::Record), Loc(Loc) {}
static bool classof(const Value *Val) {
return Val->getKind() == Kind::Record;
}
/// Returns the storage location that this `RecordValue` is associated with.
RecordStorageLocation &getLoc() const { return Loc; }
private:
RecordStorageLocation &Loc;
};
raw_ostream &operator<<(raw_ostream &OS, const Value &Val);
} // namespace dataflow

View file

@ -17,16 +17,17 @@
#include "clang/Analysis/FlowSensitive/Formula.h"
#include "clang/Analysis/FlowSensitive/Solver.h"
#include "llvm/ADT/ArrayRef.h"
#include <limits>
namespace clang {
namespace dataflow {
/// A SAT solver that is an implementation of Algorithm D from Knuth's The Art
/// of Computer Programming Volume 4: Satisfiability, Fascicle 6. It is based on
/// the Davis-Putnam-Logemann-Loveland (DPLL) algorithm, keeps references to a
/// single "watched" literal per clause, and uses a set of "active" variables
/// the Davis-Putnam-Logemann-Loveland (DPLL) algorithm [1], keeps references to
/// a single "watched" literal per clause, and uses a set of "active" variables
/// for unit propagation.
//
// [1] https://en.wikipedia.org/wiki/DPLL_algorithm
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
@ -48,8 +49,7 @@ public:
Result solve(llvm::ArrayRef<const Formula *> Vals) override;
// The solver reached its maximum number of iterations.
bool reachedLimit() const { return MaxIterations == 0; }
bool reachedLimit() const override { return MaxIterations == 0; }
};
} // namespace dataflow

View file

@ -780,6 +780,9 @@ class PathDiagnostic : public llvm::FoldingSetNode {
PathDiagnosticLocation UniqueingLoc;
const Decl *UniqueingDecl;
/// The top-level entry point from which this issue was discovered.
const Decl *AnalysisEntryPoint = nullptr;
/// Lines executed in the path.
std::unique_ptr<FilesToLineNumsMap> ExecutedLines;
@ -788,7 +791,7 @@ public:
PathDiagnostic(StringRef CheckerName, const Decl *DeclWithIssue,
StringRef bugtype, StringRef verboseDesc, StringRef shortDesc,
StringRef category, PathDiagnosticLocation LocationToUnique,
const Decl *DeclToUnique,
const Decl *DeclToUnique, const Decl *AnalysisEntryPoint,
std::unique_ptr<FilesToLineNumsMap> ExecutedLines);
~PathDiagnostic();
@ -852,6 +855,9 @@ public:
return *ExecutedLines;
}
/// Get the top-level entry point from which this issue was discovered.
const Decl *getAnalysisEntryPoint() const { return AnalysisEntryPoint; }
/// Return the semantic context where an issue occurred. If the
/// issue occurs along a path, this represents the "central" area
/// where the bug manifests.

View file

@ -15,10 +15,10 @@ namespace clang {
template <typename... IdentifierInfos>
static inline Selector getKeywordSelector(ASTContext &Ctx,
IdentifierInfos *... IIs) {
const IdentifierInfos *...IIs) {
static_assert(sizeof...(IdentifierInfos) > 0,
"keyword selectors must have at least one argument");
SmallVector<IdentifierInfo *, 10> II({&Ctx.Idents.get(IIs)...});
SmallVector<const IdentifierInfo *, 10> II({&Ctx.Idents.get(IIs)...});
return Ctx.Selectors.getSelector(II.size(), &II[0]);
}

View file

@ -0,0 +1,21 @@
//===-- AMDGPUTypes.def - Metadata about AMDGPU types -----------*- 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 various AMDGPU builtin types.
//
//===----------------------------------------------------------------------===//
#ifndef AMDGPU_OPAQUE_PTR_TYPE
#define AMDGPU_OPAQUE_PTR_TYPE(Name, MangledName, AS, Width, Align, Id, SingletonId) \
AMDGPU_TYPE(Name, Id, SingletonId)
#endif
AMDGPU_OPAQUE_PTR_TYPE("__amdgpu_buffer_rsrc_t", "__amdgpu_buffer_rsrc_t", 8, 128, 128, AMDGPUBufferRsrc, AMDGPUBufferRsrcTy)
#undef AMDGPU_TYPE
#undef AMDGPU_OPAQUE_PTR_TYPE

View file

@ -0,0 +1,52 @@
//===- ASTSourceDescriptor.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
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Defines the clang::ASTSourceDescriptor class, which abstracts clang modules
/// and precompiled header files
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_BASIC_ASTSOURCEDESCRIPTOR_H
#define LLVM_CLANG_BASIC_ASTSOURCEDESCRIPTOR_H
#include "clang/Basic/Module.h"
#include "llvm/ADT/StringRef.h"
#include <string>
#include <utility>
namespace clang {
/// Abstracts clang modules and precompiled header files and holds
/// everything needed to generate debug info for an imported module
/// or PCH.
class ASTSourceDescriptor {
StringRef PCHModuleName;
StringRef Path;
StringRef ASTFile;
ASTFileSignature Signature;
Module *ClangModule = nullptr;
public:
ASTSourceDescriptor() = default;
ASTSourceDescriptor(StringRef Name, StringRef Path, StringRef ASTFile,
ASTFileSignature Signature)
: PCHModuleName(std::move(Name)), Path(std::move(Path)),
ASTFile(std::move(ASTFile)), Signature(Signature) {}
ASTSourceDescriptor(Module &M);
std::string getModuleName() const;
StringRef getPath() const { return Path; }
StringRef getASTFile() const { return ASTFile; }
ASTFileSignature getSignature() const { return Signature; }
Module *getModuleOrNull() const { return ClangModule; }
};
} // namespace clang
#endif // LLVM_CLANG_BASIC_ASTSOURCEDESCRIPTOR_H

View file

@ -20,6 +20,7 @@
#include "clang/Basic/DiagnosticCrossTU.h"
#include "clang/Basic/DiagnosticDriver.h"
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/DiagnosticInstallAPI.h"
#include "clang/Basic/DiagnosticLex.h"
#include "clang/Basic/DiagnosticParse.h"
#include "clang/Basic/DiagnosticSema.h"

File diff suppressed because it is too large Load diff

View file

@ -1593,6 +1593,11 @@ replacement=\ *string-literal*
a warning about use of a deprecated declaration. The Fix-It will replace
the deprecated declaration with the new declaration specified.
environment=\ *identifier*
Target environment in which this declaration is available. If present,
the availability attribute applies only to targets with the same platform
and environment. The parameter is currently supported only in HLSL.
Multiple availability attributes can be placed on a declaration, which may
correspond to different platforms. For most platforms, the availability
attribute with the platform corresponding to the target platform will be used;
@ -1604,27 +1609,40 @@ specifies availability for the current target platform, the availability
attributes are ignored. Supported platforms are:
``ios``
Apple's iOS operating system. The minimum deployment target is specified by
the ``-mios-version-min=*version*`` or ``-miphoneos-version-min=*version*``
command-line arguments.
Apple's iOS operating system. The minimum deployment target is specified
as part of the ``-target *arch*-apple-ios*version*`` command line argument.
Alternatively, it can be specified by the ``-mtargetos=ios*version*``
command-line argument.
``macos``
Apple's macOS operating system. The minimum deployment target is
specified by the ``-mmacosx-version-min=*version*`` command-line argument.
``macosx`` is supported for backward-compatibility reasons, but it is
deprecated.
Apple's macOS operating system. The minimum deployment target is specified
as part of the ``-target *arch*-apple-macos*version*`` command line argument.
Alternatively, it can be specified by the ``-mtargetos=macos*version*``
command-line argument. ``macosx`` is supported for
backward-compatibility reasons, but it is deprecated.
``tvos``
Apple's tvOS operating system. The minimum deployment target is specified by
the ``-mtvos-version-min=*version*`` command-line argument.
Apple's tvOS operating system. The minimum deployment target is specified
as part of the ``-target *arch*-apple-tvos*version*`` command line argument.
Alternatively, it can be specified by the ``-mtargetos=tvos*version*``
command-line argument.
``watchos``
Apple's watchOS operating system. The minimum deployment target is specified by
the ``-mwatchos-version-min=*version*`` command-line argument.
Apple's watchOS operating system. The minimum deployment target is specified
as part of the ``-target *arch*-apple-watchos*version*`` command line argument.
Alternatively, it can be specified by the ``-mtargetos=watchos*version*``
command-line argument.
``visionos``
Apple's visionOS operating system. The minimum deployment target is specified
as part of the ``-target *arch*-apple-visionos*version*`` command line argument.
Alternatively, it can be specified by the ``-mtargetos=visionos*version*``
command-line argument.
``driverkit``
Apple's DriverKit userspace kernel extensions. The minimum deployment target
is specified as part of the triple.
is specified as part of the ``-target *arch*-apple-driverkit*version*``
command line argument.
A declaration can typically be used even when deploying back to a platform
version prior to when the declaration was introduced. When this happens, the
@ -1996,6 +2014,31 @@ Here is an example:
}];
}
def CXXAssumeDocs : Documentation {
let Category = DocCatStmt;
let Heading = "assume";
let Content = [{
The ``assume`` attribute is used to indicate to the optimizer that a
certain condition is assumed to be true at a certain point in the
program. If this condition is violated at runtime, the behavior is
undefined. ``assume`` can only be applied to a null statement.
Different optimisers are likely to react differently to the presence of
this attribute; in some cases, adding ``assume`` may affect performance
negatively. It should be used with parsimony and care.
Example:
.. code-block:: c++
int f(int x, int y) {
[[assume(x == 27)]];
[[assume(x == y)]];
return y + 1; // May be optimised to `return 28`.
}
}];
}
def LikelihoodDocs : Documentation {
let Category = DocCatStmt;
let Heading = "likely and unlikely";
@ -2486,6 +2529,9 @@ Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2
"avx", "xop" and largely correspond to the machine specific options handled by
the front end.
Note that this attribute does not apply transitively to nested functions such
as blocks or C++ lambdas.
Additionally, this attribute supports function multiversioning for ELF based
x86/x86-64 targets, which can be used to create multiple implementations of the
same function that will be resolved at runtime based on the priority of their
@ -2517,6 +2563,14 @@ function it instructs compiler to emit multiple function versions based on
priority and target features availability. One of the versions is always
( implicitly or explicitly ) the ``default`` (fallback). Attribute strings can
contain dependent features names joined by the "+" sign.
For targets that support the GNU indirect function (IFUNC) feature, dispatch
is performed by emitting an indirect function that is resolved to the appropriate
target clone at load time. The indirect function is given the name the
multiversioned function would have if it had been declared without the attribute.
For backward compatibility with earlier Clang releases, a function alias with an
``.ifunc`` suffix is also emitted. The ``.ifunc`` suffixed symbol is a deprecated
feature and support for it may be removed in the future.
}];
}
@ -2705,6 +2759,33 @@ An error will be given if:
}];
}
def AMDGPUMaxNumWorkGroupsDocs : Documentation {
let Category = DocCatAMDGPUAttributes;
let Content = [{
This attribute specifies the max number of work groups when the kernel
is dispatched.
Clang supports the
``__attribute__((amdgpu_max_num_work_groups(<x>, <y>, <z>)))`` or
``[[clang::amdgpu_max_num_work_groups(<x>, <y>, <z>)]]`` attribute for the
AMDGPU target. This attribute may be attached to HIP or OpenCL kernel function
definitions and is an optimization hint.
The ``<x>`` parameter specifies the maximum number of work groups in the x dimension.
Similarly ``<y>`` and ``<z>`` are for the y and z dimensions respectively.
Each of the three values must be greater than 0 when provided. The ``<x>`` parameter
is required, while ``<y>`` and ``<z>`` are optional with default value of 1.
If specified, the AMDGPU target backend might be able to produce better machine
code.
An error will be given if:
- Specified values violate subtarget specifications;
- Specified values are not compatible with values provided through other
attributes.
}];
}
def DocCatCallingConvs : DocumentationCategory<"Calling Conventions"> {
let Content = [{
Clang supports several different calling conventions, depending on the target
@ -3706,6 +3787,12 @@ for that function.
This attribute is incompatible with the ``always_inline`` and ``minsize``
attributes.
Note that this attribute does not apply recursively to nested functions such as
lambdas or blocks when using declaration-specific attribute syntaxes such as double
square brackets (``[[]]``) or ``__attribute__``. The ``#pragma`` syntax can be
used to apply the attribute to all functions, including nested functions, in a
range of source code.
}];
}
@ -4088,6 +4175,20 @@ non-underscored keywords. For example:
@property (assign, nullable) NSView *superview;
@property (readonly, nonnull) NSArray *subviews;
@end
As well as built-in pointer types, the nullability attributes can be attached
to C++ classes marked with the ``_Nullable`` attribute.
The following C++ standard library types are considered nullable:
``unique_ptr``, ``shared_ptr``, ``auto_ptr``, ``exception_ptr``, ``function``,
``move_only_function`` and ``coroutine_handle``.
Types should be marked nullable only where the type itself leaves nullability
ambiguous. For example, ``std::optional`` is not marked ``_Nullable``, because
``optional<int> _Nullable`` is redundant and ``optional<int> _Nonnull`` is
not a useful type. ``std::weak_ptr`` is not nullable, because its nullability
can change with no visible modification, so static annotation is unlikely to be
unhelpful.
}];
}
@ -4122,6 +4223,17 @@ The ``_Nullable`` nullability qualifier indicates that a value of the
int fetch_or_zero(int * _Nullable ptr);
a caller of ``fetch_or_zero`` can provide null.
The ``_Nullable`` attribute on classes indicates that the given class can
represent null values, and so the ``_Nullable``, ``_Nonnull`` etc qualifiers
make sense for this type. For example:
.. code-block:: c
class _Nullable ArenaPointer { ... };
ArenaPointer _Nonnull x = ...;
ArenaPointer _Nullable y = nullptr;
}];
}
@ -4621,11 +4733,11 @@ For more information see
}];
}
def AssumptionDocs : Documentation {
def OMPAssumeDocs : Documentation {
let Category = DocCatFunction;
let Heading = "assume";
let Content = [{
Clang supports the ``__attribute__((assume("assumption")))`` attribute to
Clang supports the ``[[omp::assume("assumption")]]`` attribute to
provide additional information to the optimizer. The string-literal, here
"assumption", will be attached to the function declaration such that later
analysis and optimization passes can assume the "assumption" to hold.
@ -4637,7 +4749,7 @@ A function can have multiple assume attributes and they propagate from prior
declarations to later definitions. Multiple assumptions are aggregated into a
single comma separated string. Thus, one can provide multiple assumptions via
a comma separated string, i.a.,
``__attribute__((assume("assumption1,assumption2")))``.
``[[omp::assume("assumption1,assumption2")]]``.
While LLVM plugins might provide more assumption strings, the default LLVM
optimization passes are aware of the following assumptions:
@ -5074,10 +5186,11 @@ that does not. A single parameter may not have multiple ABI treatment
attributes.
Support for this feature is target-dependent, although it should be
supported on every target that Swift supports. Query for this support
with ``__has_attribute(swiftcall)``. This implies support for the
``swift_context``, ``swift_error_result``, and ``swift_indirect_result``
attributes.
supported on every target that Swift supports. Query for this attribute
with ``__has_attribute(swiftcall)``. Query if the target supports the
calling convention with ``__has_extension(swiftcc)``. This implies
support for the ``swift_context``, ``swift_error_result``, and
``swift_indirect_result`` attributes.
}];
}
@ -5124,6 +5237,10 @@ the following:
semantically be performed after a guaranteed tail call, such as the
non-trivial destruction of a local variable or temporary,
then the program is ill-formed.
Query for this attribute with ``__has_attribute(swiftasynccall)``. Query if
the target supports the calling convention with
``__has_extension(swiftasynccc)``.
}];
}
@ -5313,6 +5430,29 @@ Putting the attribute on a compound statement suppresses all warnings in scope:
}
}
The attribute can also be placed on entire declarations of functions, classes,
variables, member variables, and so on, to suppress warnings related
to the declarations themselves. When used this way, the attribute additionally
suppresses all warnings in the lexical scope of the declaration:
.. code-block:: c++
class [[clang::suppress]] C {
int foo() {
int *x = nullptr;
...
return *x; // warnings suppressed in the entire class scope
}
int bar();
};
int C::bar() {
int *x = nullptr;
...
return *x; // warning NOT suppressed! - not lexically nested in 'class C{}'
}
Some static analysis warnings are accompanied by one or more notes, and the
line of code against which the warning is emitted isn't necessarily the best
for suppression purposes. In such cases the tools are allowed to implement
@ -5403,6 +5543,17 @@ for clang builtin functions.
}];
}
def RISCVVectorCCDocs : Documentation {
let Category = DocCatCallingConvs;
let Heading = "riscv::vector_cc, riscv_vector_cc, clang::riscv_vector_cc";
let Content = [{
The ``riscv_vector_cc`` attribute can be applied to a function. It preserves 15
registers namely, v1-v7 and v24-v31 as callee-saved. Callers thus don't need
to save these registers before function calls, and callees only need to save
them if they use them.
}];
}
def PreferredNameDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
@ -5506,6 +5657,28 @@ experimental at this time.
}];
}
def PreserveNoneDocs : Documentation {
let Category = DocCatCallingConvs;
let Content = [{
On X86-64 and AArch64 targets, this attribute changes the calling convention of a function.
The ``preserve_none`` calling convention tries to preserve as few general
registers as possible. So all general registers are caller saved registers. It
also uses more general registers to pass arguments. This attribute doesn't
impact floating-point registers. ``preserve_none``'s ABI is still unstable, and
may be changed in the future.
- On X86-64, only RSP and RBP are preserved by the callee.
Registers R12, R13, R14, R15, RDI, RSI, RDX, RCX, R8, R9, R11, and RAX now can
be used to pass function arguments. Floating-point registers (XMMs/YMMs) still
follow the C calling convention.
- On AArch64, only LR and FP are preserved by the callee.
Registers X20-X28, X0-X7, and X9-X14 are used to pass function arguments.
X8, X16-X19, SIMD and floating-point registers follow the AAPCS calling
convention. X15 is not available for argument passing on Windows, but is
used to pass arguments on other platforms.
}];
}
def DeprecatedDocs : Documentation {
let Category = DocCatDecl;
let Content = [{
@ -5560,6 +5733,25 @@ See :doc:`LTOVisibility`.
}];
}
def TypeVisibilityDocs : Documentation {
let Category = DocCatType;
let Content = [{
The ``type_visibility`` attribute allows the visibility of a type and its vague
linkage objects (vtable, typeinfo, typeinfo name) to be controlled separately from
the visibility of functions and data members of the type.
For example, this can be used to give default visibility to the typeinfo and the vtable
of a type while still keeping hidden visibility on its member functions and static data
members.
This attribute can only be applied to types and namespaces.
If both ``visibility`` and ``type_visibility`` are applied to a type or a namespace, the
visibility specified with the ``type_visibility`` attribute overrides the visibility
provided with the regular ``visibility`` attribute.
}];
}
def RenderScriptKernelAttributeDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@ -5608,7 +5800,8 @@ 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/loongarch32/loongarch64/riscv32/riscv64/i386/x86-64 targets.
aarch64/aarch64-be/loongarch32/loongarch64/riscv32/riscv64/i386/x86-64/ppc/ppc64 targets.
For ppc/ppc64 targets, AIX is still not supported.
}];
}
@ -5942,6 +6135,9 @@ def AlwaysDestroyDocs : Documentation {
The ``always_destroy`` attribute specifies that a variable with static or thread
storage duration should have its exit-time destructor run. This attribute is the
default unless clang was invoked with -fno-c++-static-destructors.
If a variable is explicitly declared with this attribute, Clang will silence
otherwise applicable ``-Wexit-time-destructors`` warnings.
}];
}
@ -6390,7 +6586,8 @@ like pointers to an object of type ``T``:
private:
int *valuePointer;
public:
int *getInt() { return &valuePointer; }
IntPointer(const IntOwner&);
int *getInt() { return valuePointer; }
};
The argument ``T`` is optional and is ignored.
@ -6406,12 +6603,8 @@ When the Owner's lifetime ends, it will consider the Pointer to be dangling.
.. code-block:: c++
int f() {
IntPointer P;
if (true) {
IntOwner O(7);
P = IntPointer(O); // P "points into" O
} // P is dangling
return P.get(); // error: Using a dangling Pointer.
IntPointer P(IntOwner{}); // P "points into" a temporary IntOwner object
P.getInt(); // P is dangling
}
}];
@ -7151,6 +7344,100 @@ where shaders must be compiled into a library and linked at runtime.
}];
}
def HLSLLoopHintDocs : Documentation {
let Category = DocCatStmt;
let Heading = "[loop]";
let Content = [{
The ``[loop]`` directive allows loop optimization hints to be
specified for the subsequent loop. The directive allows unrolling to
be disabled and is not compatible with [unroll(x)].
Specifying the parameter, ``[loop]``, directs the
unroller to not unroll the loop.
.. code-block:: hlsl
[loop]
for (...) {
...
}
.. code-block:: hlsl
[loop]
while (...) {
...
}
.. code-block:: hlsl
[loop]
do {
...
} while (...)
See `hlsl loop extensions <https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-for>`_
for details.
}];
}
def HLSLUnrollHintDocs : Documentation {
let Category = DocCatStmt;
let Heading = "[unroll(x)], [unroll]";
let Content = [{
Loop unrolling optimization hints can be specified with ``[unroll(x)]``
. The attribute is placed immediately before a for, while,
or do-while.
Specifying the parameter, ``[unroll(_value_)]``, directs the
unroller to unroll the loop ``_value_`` times. Note: [unroll(x)] is not compatible with [loop].
.. code-block:: hlsl
[unroll(4)]
for (...) {
...
}
.. code-block:: hlsl
[unroll]
for (...) {
...
}
.. code-block:: hlsl
[unroll(4)]
while (...) {
...
}
.. code-block:: hlsl
[unroll]
while (...) {
...
}
.. code-block:: hlsl
[unroll(4)]
do {
...
} while (...)
.. code-block:: hlsl
[unroll]
do {
...
} while (...)
See `hlsl loop extensions <https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-for>`_
for details.
}];
}
def ClangRandomizeLayoutDocs : Documentation {
let Category = DocCatDecl;
let Heading = "randomize_layout, no_randomize_layout";
@ -7210,7 +7497,8 @@ b for constant buffer views (CBV).
Register space is specified in the format ``space[number]`` and defaults to ``space0`` if omitted.
Here're resource binding examples with and without space:
.. code-block:: c++
.. code-block:: hlsl
RWBuffer<float> Uav : register(u3, space1);
Buffer<float> Buf : register(t1);
@ -7219,6 +7507,26 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo
}];
}
def HLSLPackOffsetDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The packoffset attribute is used to change the layout of a cbuffer.
Attribute spelling in HLSL is: ``packoffset( c[Subcomponent][.component] )``.
A subcomponent is a register number, which is an integer. A component is in the form of [.xyzw].
Examples:
.. code-block:: hlsl
cbuffer A {
float3 a : packoffset(c0.y);
float4 b : packoffset(c4);
}
The full documentation is available here: https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-packoffset
}];
}
def HLSLSV_DispatchThreadIDDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
@ -7343,7 +7651,7 @@ means that it can e.g no longer be part of an initializer expression.
/* This may print something else than "6 * 7 = 42",
if there is a non-weak definition of "ANSWER" in
an object linked in */
an object linked in */
printf("6 * 7 = %d\n", ANSWER);
return 0;
@ -7878,3 +8186,86 @@ requirement:
}
}];
}
def ClspvLibclcBuiltinDoc : Documentation {
let Category = DocCatFunction;
let Content = [{
Attribute used by `clspv`_ (OpenCL-C to Vulkan SPIR-V compiler) to identify functions coming from `libclc`_ (OpenCL-C builtin library).
.. code-block:: c
void __attribute__((clspv_libclc_builtin)) libclc_builtin() {}
.. _`clspv`: https://github.com/google/clspv
.. _`libclc`: https://libclc.llvm.org
}];
}
def DocCatNonBlockingNonAllocating : DocumentationCategory<"Performance Constraint Attributes"> {
let Content = [{
The ``nonblocking``, ``blocking``, ``nonallocating`` and ``allocating`` attributes can be attached
to function types, including blocks, C++ lambdas, and member functions. The attributes declare
constraints about a function's behavior pertaining to blocking and heap memory allocation.
There are several rules for function types with these attributes, enforced with
compiler warnings:
- When assigning or otherwise converting to a function pointer of ``nonblocking`` or
``nonallocating`` type, the source must also be a function or function pointer of
that type, unless it is a null pointer, i.e. the attributes should not be "spoofed". Conversions
that remove the attributes are transparent and valid.
- An override of a ``nonblocking`` or ``nonallocating`` virtual method must also be declared
with that same attribute (or a stronger one.) An overriding method may add an attribute.
- A redeclaration of a ``nonblocking`` or ``nonallocating`` function must also be declared with
the same attribute (or a stronger one). A redeclaration may add an attribute.
The warnings are controlled by ``-Wfunction-effects``, which is enabled by default.
In a future commit, the compiler will diagnose function calls from ``nonblocking`` and ``nonallocating``
functions to other functions which lack the appropriate attribute.
}];
}
def NonBlockingDocs : Documentation {
let Category = DocCatNonBlockingNonAllocating;
let Heading = "nonblocking";
let Content = [{
Declares that a function or function type either does or does not block in any way, according
to the optional, compile-time constant boolean argument, which defaults to true. When the argument
is false, the attribute is equivalent to ``blocking``.
For the purposes of diagnostics, ``nonblocking`` is considered to include the
``nonallocating`` guarantee and is therefore a "stronger" constraint or attribute.
}];
}
def NonAllocatingDocs : Documentation {
let Category = DocCatNonBlockingNonAllocating;
let Heading = "nonallocating";
let Content = [{
Declares that a function or function type either does or does not allocate heap memory, according
to the optional, compile-time constant boolean argument, which defaults to true. When the argument
is false, the attribute is equivalent to ``allocating``.
}];
}
def BlockingDocs : Documentation {
let Category = DocCatNonBlockingNonAllocating;
let Heading = "blocking";
let Content = [{
Declares that a function potentially blocks, and prevents any potential inference of ``nonblocking``
by the compiler.
}];
}
def AllocatingDocs : Documentation {
let Category = DocCatNonBlockingNonAllocating;
let Heading = "allocating";
let Content = [{
Declares that a function potentially allocates heap memory, and prevents any potential inference
of ``nonallocating`` by the compiler.
}];
}

View file

@ -52,8 +52,8 @@ public:
/// Context-sensitive version of a keyword attribute.
AS_ContextSensitiveKeyword,
/// <vardecl> : <semantic>
AS_HLSLSemantic,
/// <vardecl> : <annotation>
AS_HLSLAnnotation,
/// The attibute has no source code manifestation and is only created
/// implicitly.
@ -120,7 +120,7 @@ public:
}
static Form Pragma() { return AS_Pragma; }
static Form ContextSensitiveKeyword() { return AS_ContextSensitiveKeyword; }
static Form HLSLSemantic() { return AS_HLSLSemantic; }
static Form HLSLAnnotation() { return AS_HLSLAnnotation; }
static Form Implicit() { return AS_Implicit; }
private:

File diff suppressed because it is too large Load diff

View file

@ -64,7 +64,7 @@ namespace Builtin {
enum ID {
NotBuiltin = 0, // This is not a builtin function.
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
#include "clang/Basic/Builtins.def"
#include "clang/Basic/Builtins.inc"
FirstTSBuiltin
};
@ -280,6 +280,11 @@ public:
return strchr(getRecord(ID).Attributes, 'E') != nullptr;
}
/// Returns true if this is an immediate (consteval) function
bool isImmediate(unsigned ID) const {
return strchr(getRecord(ID).Attributes, 'G') != nullptr;
}
private:
const Info &getRecord(unsigned ID) const;

File diff suppressed because it is too large Load diff

View file

@ -49,6 +49,10 @@ BUILTIN(__builtin_arm_wfe, "v", "")
BUILTIN(__builtin_arm_wfi, "v", "")
BUILTIN(__builtin_arm_sev, "v", "")
BUILTIN(__builtin_arm_sevl, "v", "")
BUILTIN(__builtin_arm_chkfeat, "WUiWUi", "")
// Like __builtin_trap but provide an 16-bit immediate reason code (which goes into `brk #N`).
BUILTIN(__builtin_arm_trap, "vUIs", "nr")
// CRC32
TARGET_BUILTIN(__builtin_arm_crc32b, "UiUiUc", "nc", "crc")
@ -69,7 +73,7 @@ TARGET_BUILTIN(__builtin_arm_stg, "vv*", "t", "mte")
TARGET_BUILTIN(__builtin_arm_subp, "Uiv*v*", "t", "mte")
// SME state function
BUILTIN(__builtin_arm_get_sme_state, "vULi*ULi*", "n")
BUILTIN(__builtin_arm_get_sme_state, "vWUi*WUi*", "n")
// Memory Operations
TARGET_BUILTIN(__builtin_arm_mops_memset_tag, "v*v*iz", "", "mte,mops")
@ -133,12 +137,17 @@ TARGET_BUILTIN(__builtin_arm_st64b, "vv*WUiC*", "n", "ls64")
TARGET_BUILTIN(__builtin_arm_st64bv, "WUiv*WUiC*", "n", "ls64")
TARGET_BUILTIN(__builtin_arm_st64bv0, "WUiv*WUiC*", "n", "ls64")
// Armv9.3-A Guarded Control Stack
TARGET_BUILTIN(__builtin_arm_gcspopm, "WUiWUi", "n", "gcs")
TARGET_BUILTIN(__builtin_arm_gcsss, "vC*vC*", "n", "gcs")
TARGET_HEADER_BUILTIN(_BitScanForward, "UcUNi*UNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanReverse, "UcUNi*UNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanForward64, "UcUNi*ULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanReverse64, "UcUNi*ULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAdd, "NiNiD*Ni", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAdd64, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedAnd64, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64, "LLiLLiD*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
@ -286,7 +295,9 @@ TARGET_HEADER_BUILTIN(_CountLeadingZeros64, "UiULLi", "nh", INTRIN_H, ALL_MS_LAN
TARGET_HEADER_BUILTIN(_CountOneBits, "UiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_CountOneBits64, "UiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__prefetch, "vv*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__prefetch, "vvC*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__hlt, "UiUi.", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
#undef BUILTIN
#undef LANGBUILTIN

Some files were not shown because too many files have changed in this diff Show more