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; # xargs -n1 | sort | uniq -d;
# done # 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/ # 20241014: move divapp to netpfil/common/
OLD_FILES+=usr/tests/sys/netpfil/pf/divapp OLD_FILES+=usr/tests/sys/netpfil/pf/divapp

View file

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

View file

@ -1644,8 +1644,9 @@ enum CXCursorKind {
CXCursor_ObjCSelfExpr = 146, CXCursor_ObjCSelfExpr = 146,
/** OpenMP 5.0 [2.1.5, Array Section]. /** 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. /** Represents an @available(...) check.
*/ */
@ -1675,7 +1676,7 @@ enum CXCursorKind {
CXCursor_ConceptSpecializationExpr = 153, CXCursor_ConceptSpecializationExpr = 153,
/** /**
* Expression that references a C++20 concept. * Expression that references a C++20 requires expression.
*/ */
CXCursor_RequiresExpr = 154, CXCursor_RequiresExpr = 154,
@ -1685,7 +1686,12 @@ enum CXCursorKind {
*/ */
CXCursor_CXXParenListInitExpr = 155, CXCursor_CXXParenListInitExpr = 155,
CXCursor_LastExpr = CXCursor_CXXParenListInitExpr, /**
* Represents a C++26 pack indexing expression.
*/
CXCursor_PackIndexingExpr = 156,
CXCursor_LastExpr = CXCursor_PackIndexingExpr,
/* Statements */ /* Statements */
CXCursor_FirstStmt = 200, CXCursor_FirstStmt = 200,
@ -2140,7 +2146,23 @@ enum CXCursorKind {
*/ */
CXCursor_OMPScopeDirective = 306, 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. * Cursor that represents the translation unit itself.
@ -2981,6 +3003,8 @@ enum CXCallingConv {
CXCallingConv_SwiftAsync = 17, CXCallingConv_SwiftAsync = 17,
CXCallingConv_AArch64SVEPCS = 18, CXCallingConv_AArch64SVEPCS = 18,
CXCallingConv_M68kRTD = 19, CXCallingConv_M68kRTD = 19,
CXCallingConv_PreserveNone = 20,
CXCallingConv_RISCVVectorCall = 21,
CXCallingConv_Invalid = 100, CXCallingConv_Invalid = 100,
CXCallingConv_Unexposed = 200 CXCallingConv_Unexposed = 200
@ -3734,6 +3758,59 @@ enum CX_StorageClass {
CX_SC_Register 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. * Returns the storage class for a function or variable declaration.
* *

View file

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

View file

@ -101,7 +101,7 @@ public:
/// \param Name The name of the class we're looking for. /// \param Name The name of the class we're looking for.
/// ///
/// \returns The information about the class, if known. /// \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. /// 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. /// \param Name The name of the protocol we're looking for.
/// ///
/// \returns The information about the protocol, if known. /// \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 /// Look for information regarding the given Objective-C property in
/// the given context. /// the given context.
@ -141,6 +141,16 @@ public:
ObjCSelectorRef Selector, ObjCSelectorRef Selector,
bool IsInstanceMethod); 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. /// Look for information regarding the given global variable.
/// ///
/// \param Name The name of the global variable. /// \param Name The name of the global variable.
@ -166,6 +176,17 @@ public:
/// \returns information about the enumerator, if known. /// \returns information about the enumerator, if known.
VersionedInfo<EnumConstantInfo> lookupEnumConstant(llvm::StringRef Name); 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 /// Look for information regarding the given tag
/// (struct/union/enum/C++ class). /// (struct/union/enum/C++ class).
/// ///

View file

@ -5,7 +5,13 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // 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 #ifndef LLVM_CLANG_APINOTES_WRITER_H
#define LLVM_CLANG_APINOTES_WRITER_H #define LLVM_CLANG_APINOTES_WRITER_H
@ -20,11 +26,16 @@ namespace clang {
class FileEntry; class FileEntry;
namespace api_notes { 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 APINotesWriter {
class Implementation; class Implementation;
std::unique_ptr<Implementation> Implementation; std::unique_ptr<Implementation> Implementation;
public: public:
/// Create a new API notes writer with the given module name and
/// (optional) source file.
APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF); APINotesWriter(llvm::StringRef ModuleName, const FileEntry *SF);
~APINotesWriter(); ~APINotesWriter();
@ -42,10 +53,10 @@ public:
/// ///
/// \returns the ID of the class, protocol, or namespace, which can be used to /// \returns the ID of the class, protocol, or namespace, which can be used to
/// add properties and methods to the class/protocol/namespace. /// add properties and methods to the class/protocol/namespace.
ContextID addObjCContext(std::optional<ContextID> ParentCtxID, ContextID addContext(std::optional<ContextID> ParentCtxID,
llvm::StringRef Name, ContextKind Kind, llvm::StringRef Name, ContextKind Kind,
const ObjCContextInfo &Info, const ContextInfo &Info,
llvm::VersionTuple SwiftVersion); llvm::VersionTuple SwiftVersion);
/// Add information about a specific Objective-C property. /// Add information about a specific Objective-C property.
/// ///
@ -67,6 +78,14 @@ public:
bool IsInstanceMethod, const ObjCMethodInfo &Info, bool IsInstanceMethod, const ObjCMethodInfo &Info,
llvm::VersionTuple SwiftVersion); 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. /// Add information about a global variable.
/// ///
/// \param Name The name of this global variable. /// \param Name The name of this global variable.

View file

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

View file

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

View file

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

View file

@ -37,6 +37,7 @@
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/TinyPtrVector.h"
#include "llvm/Support/TypeSize.h" #include "llvm/Support/TypeSize.h"
#include <optional> #include <optional>
@ -110,6 +111,9 @@ class VarTemplateDecl;
class VTableContextBase; class VTableContextBase;
class XRayFunctionFilter; class XRayFunctionFilter;
/// A simple array of base specifiers.
typedef SmallVector<CXXBaseSpecifier *, 4> CXXCastPath;
namespace Builtin { namespace Builtin {
class Context; class Context;
@ -214,6 +218,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
DependentTypeOfExprTypes; DependentTypeOfExprTypes;
mutable llvm::ContextualFoldingSet<DependentDecltypeType, ASTContext &> mutable llvm::ContextualFoldingSet<DependentDecltypeType, ASTContext &>
DependentDecltypeTypes; DependentDecltypeTypes;
mutable llvm::FoldingSet<PackIndexingType> DependentPackIndexingTypes;
mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
mutable llvm::FoldingSet<ObjCTypeParamType> ObjCTypeParamTypes; mutable llvm::FoldingSet<ObjCTypeParamType> ObjCTypeParamTypes;
mutable llvm::FoldingSet<SubstTemplateTypeParmType> mutable llvm::FoldingSet<SubstTemplateTypeParmType>
@ -247,6 +254,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
DependentBitIntTypes; DependentBitIntTypes;
llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes; llvm::FoldingSet<BTFTagAttributedType> BTFTagAttributedTypes;
mutable llvm::FoldingSet<CountAttributedType> CountAttributedTypes;
mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames; mutable llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames; mutable llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage> mutable llvm::FoldingSet<SubstTemplateTemplateParmStorage>
@ -255,6 +264,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
ASTContext&> ASTContext&>
SubstTemplateTemplateParmPacks; SubstTemplateTemplateParmPacks;
mutable llvm::ContextualFoldingSet<ArrayParameterType, ASTContext &>
ArrayParameterTypes;
/// The set of nested name specifiers. /// The set of nested name specifiers.
/// ///
/// This set is managed by the NestedNameSpecifier class. /// This set is managed by the NestedNameSpecifier class.
@ -447,7 +459,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
/// initialization of another module). /// initialization of another module).
struct PerModuleInitializers { struct PerModuleInitializers {
llvm::SmallVector<Decl*, 4> Initializers; llvm::SmallVector<Decl*, 4> Initializers;
llvm::SmallVector<uint32_t, 4> LazyInitializers; llvm::SmallVector<GlobalDeclID, 4> LazyInitializers;
void resolve(ASTContext &Ctx); 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. /// This is the top-level (C++20) Named module we are building.
Module *CurrentCXXNamedModule = nullptr; 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 ConstantArrayTypesLog2InitSize = 8;
static constexpr unsigned GeneralTypesLog2InitSize = 9; static constexpr unsigned GeneralTypesLog2InitSize = 9;
static constexpr unsigned FunctionProtoTypesLog2InitSize = 12; static constexpr unsigned FunctionProtoTypesLog2InitSize = 12;
@ -623,6 +643,9 @@ private:
/// address spaces (e.g. OpenCL/CUDA) /// address spaces (e.g. OpenCL/CUDA)
bool AddrSpaceMapMangling; bool AddrSpaceMapMangling;
/// For performance, track whether any function effects are in use.
mutable bool AnyFunctionEffects = false;
const TargetInfo *Target = nullptr; const TargetInfo *Target = nullptr;
const TargetInfo *AuxTarget = nullptr; const TargetInfo *AuxTarget = nullptr;
clang::PrintingPolicy PrintingPolicy; clang::PrintingPolicy PrintingPolicy;
@ -715,6 +738,12 @@ public:
} }
void Deallocate(void *Ptr) const {} 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 /// Allocates a \c DeclListNode or returns one from the \c ListNodeFreeList
/// pool. /// pool.
DeclListNode *AllocateDeclListNode(clang::NamedDecl *ND) { DeclListNode *AllocateDeclListNode(clang::NamedDecl *ND) {
@ -1051,7 +1080,7 @@ public:
/// or an ImportDecl nominating another module that has initializers. /// or an ImportDecl nominating another module that has initializers.
void addModuleInitializer(Module *M, Decl *Init); 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. /// Get the initializations to perform when importing a module, if any.
ArrayRef<Decl*> getModuleInitializers(Module *M); ArrayRef<Decl*> getModuleInitializers(Module *M);
@ -1062,6 +1091,12 @@ public:
/// Get module under construction, nullptr if this is not a C++20 module. /// Get module under construction, nullptr if this is not a C++20 module.
Module *getCurrentNamedModule() const { return CurrentCXXNamedModule; } 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 { TranslationUnitDecl *getTranslationUnitDecl() const {
return TUDecl->getMostRecentDecl(); return TUDecl->getMostRecentDecl();
} }
@ -1108,7 +1143,8 @@ public:
CanQualType BFloat16Ty; CanQualType BFloat16Ty;
CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3 CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
CanQualType VoidPtrTy, NullPtrTy; CanQualType VoidPtrTy, NullPtrTy;
CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy; CanQualType DependentTy, OverloadTy, BoundMemberTy, UnresolvedTemplateTy,
UnknownAnyTy;
CanQualType BuiltinFnTy; CanQualType BuiltinFnTy;
CanQualType PseudoObjectTy, ARCUnbridgedCastTy; CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy; CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
@ -1119,7 +1155,8 @@ public:
CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy; CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy;
CanQualType OCLQueueTy, OCLReserveIDTy; CanQualType OCLQueueTy, OCLReserveIDTy;
CanQualType IncompleteMatrixIdxTy; CanQualType IncompleteMatrixIdxTy;
CanQualType OMPArraySectionTy, OMPArrayShapingTy, OMPIteratorTy; CanQualType ArraySectionTy;
CanQualType OMPArrayShapingTy, OMPIteratorTy;
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
CanQualType Id##Ty; CanQualType Id##Ty;
#include "clang/Basic/OpenCLExtensionTypes.def" #include "clang/Basic/OpenCLExtensionTypes.def"
@ -1134,6 +1171,8 @@ public:
#include "clang/Basic/RISCVVTypes.def" #include "clang/Basic/RISCVVTypes.def"
#define WASM_TYPE(Name, Id, SingletonId) CanQualType SingletonId; #define WASM_TYPE(Name, Id, SingletonId) CanQualType SingletonId;
#include "clang/Basic/WebAssemblyReferenceTypes.def" #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. // Types for deductions in C++0x [stmt.ranged]'s desugaring. Built on demand.
mutable QualType AutoDeductTy; // Deduction against 'auto'. mutable QualType AutoDeductTy; // Deduction against 'auto'.
@ -1160,6 +1199,12 @@ public:
/// in device compilation. /// in device compilation.
llvm::DenseSet<const FunctionDecl *> CUDAImplicitHostDeviceFunUsedByDevice; 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, ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents,
SelectorTable &sels, Builtin::Context &builtins, SelectorTable &sels, Builtin::Context &builtins,
TranslationUnitKind TUKind); TranslationUnitKind TUKind);
@ -1242,6 +1287,14 @@ public:
/// space. /// space.
QualType removeAddrSpaceQualType(QualType T) const; 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. /// Apply Objective-C protocol qualifiers to the given type.
/// \param allowOnPointerType specifies if we can apply protocol /// \param allowOnPointerType specifies if we can apply protocol
/// qualifiers on ObjCObjectPointerType. It can be set to true when /// qualifiers on ObjCObjectPointerType. It can be set to true when
@ -1338,6 +1391,11 @@ public:
return CanQualType::CreateUnsafe(getPointerType((QualType) T)); 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 /// Return the uniqued reference to a type adjusted from the original
/// type to a new type. /// type to a new type.
QualType getAdjustedType(QualType Orig, QualType New) const; QualType getAdjustedType(QualType Orig, QualType New) const;
@ -1357,6 +1415,10 @@ public:
/// type to the decayed type. /// type to the decayed type.
QualType getDecayedType(QualType Orig, QualType Decayed) const; 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 /// Return the uniqued reference to the atomic type for the specified
/// type. /// type.
QualType getAtomicType(QualType T) const; QualType getAtomicType(QualType T) const;
@ -1713,6 +1775,11 @@ public:
/// C++11 decltype. /// C++11 decltype.
QualType getDecltypeType(Expr *e, QualType UnderlyingType) const; 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 /// Unary type transforms
QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType, QualType getUnaryTransformType(QualType BaseType, QualType UnderlyingType,
UnaryTransformType::UTTKind UKind) const; UnaryTransformType::UTTKind UKind) const;
@ -1738,6 +1805,13 @@ public:
QualType DeducedType, QualType DeducedType,
bool IsDependent) const; 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 /// Return the unique reference to the type for the specified TagDecl
/// (struct/union/class/enum) decl. /// (struct/union/class/enum) decl.
QualType getTagDeclType(const TagDecl *Decl) const; QualType getTagDeclType(const TagDecl *Decl) const;
@ -2174,6 +2248,16 @@ public:
return getQualifiedType(type.getUnqualifiedType(), Qs); 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 getFixedPointScale(QualType Ty) const;
unsigned char getFixedPointIBits(QualType Ty) const; unsigned char getFixedPointIBits(QualType Ty) const;
llvm::FixedPointSemantics getFixedPointSemantics(QualType Ty) const; llvm::FixedPointSemantics getFixedPointSemantics(QualType Ty) const;
@ -2405,12 +2489,18 @@ public:
unsigned getTargetDefaultAlignForAttributeAligned() const; unsigned getTargetDefaultAlignForAttributeAligned() const;
/// Return the alignment in bits that should be given to a /// Return the alignment in bits that should be given to a
/// global variable with type \p T. /// global variable with type \p T. If \p VD is non-null it will be
unsigned getAlignOfGlobalVar(QualType T) const; /// considered specifically for the query.
unsigned getAlignOfGlobalVar(QualType T, const VarDecl *VD) const;
/// Return the alignment in characters that should be given to a /// Return the alignment in characters that should be given to a
/// global variable with type \p T. /// global variable with type \p T. If \p VD is non-null it will be
CharUnits getAlignOfGlobalVarInChars(QualType T) const; /// 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 /// Return a conservative estimate of the alignment of the specified
/// decl \p D. /// decl \p D.
@ -2571,7 +2661,11 @@ public:
/// ///
/// \returns if this is an array type, the completely unqualified array type /// \returns if this is an array type, the completely unqualified array type
/// that corresponds to it. Otherwise, returns T.getUnqualifiedType(). /// 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 /// Determine whether the given types are equivalent after
/// cvr-qualifiers have been removed. /// cvr-qualifiers have been removed.
@ -2824,6 +2918,8 @@ public:
return AddrSpaceMapMangling || isTargetAddressSpace(AS); return AddrSpaceMapMangling || isTargetAddressSpace(AS);
} }
bool hasAnyFunctionEffects() const { return AnyFunctionEffects; }
// Merges two exception specifications, such that the resulting // Merges two exception specifications, such that the resulting
// exception spec is the union of both. For example, if either // exception spec is the union of both. For example, if either
// of them can throw something, the result can throw it as well. // 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. // corresponding saturated type for a given fixed point type.
QualType getCorrespondingSaturatedType(QualType Ty) const; 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 // This method accepts fixed point types and returns the corresponding signed
// type. Unlike getCorrespondingUnsignedType(), this only accepts unsigned // type. Unlike getCorrespondingUnsignedType(), this only accepts unsigned
// fixed point types because there are unsigned integer types like bool and // fixed point types because there are unsigned integer types like bool and
@ -3150,9 +3250,6 @@ public:
/// valid feature names. /// valid feature names.
ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD) const; ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD) const;
std::vector<std::string>
filterFunctionTargetVersionAttrs(const TargetVersionAttr *TV) const;
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
const FunctionDecl *) const; const FunctionDecl *) const;
void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
@ -3365,12 +3462,21 @@ public:
/// Whether a C++ static variable or CUDA/HIP kernel should be externalized. /// Whether a C++ static variable or CUDA/HIP kernel should be externalized.
bool shouldExternalize(const Decl *D) const; 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; StringRef getCUIDHash() const;
private: private:
/// All OMPTraitInfo objects live in this collection, one per /// All OMPTraitInfo objects live in this collection, one per
/// `pragma omp [begin] declare variant` directive. /// `pragma omp [begin] declare variant` directive.
SmallVector<std::unique_ptr<OMPTraitInfo>, 4> OMPTraitInfoVector; SmallVector<std::unique_ptr<OMPTraitInfo>, 4> OMPTraitInfoVector;
llvm::DenseMap<GlobalDecl, llvm::StringSet<>> ThunksToBeAbbreviated;
}; };
/// Insertion operator for diagnostics. /// Insertion operator for diagnostics.
@ -3379,13 +3485,13 @@ const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
/// Utility function for constructing a nullary selector. /// Utility function for constructing a nullary selector.
inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) { 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); return Ctx.Selectors.getSelector(0, &II);
} }
/// Utility function for constructing an unary selector. /// Utility function for constructing an unary selector.
inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) { 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); return Ctx.Selectors.getSelector(1, &II);
} }

View file

@ -27,6 +27,7 @@ namespace clang {
class FunctionTemplateDecl; class FunctionTemplateDecl;
class Module; class Module;
class NamedDecl; class NamedDecl;
class NamespaceDecl;
class ObjCCategoryDecl; class ObjCCategoryDecl;
class ObjCContainerDecl; class ObjCContainerDecl;
class ObjCInterfaceDecl; class ObjCInterfaceDecl;
@ -35,6 +36,7 @@ namespace clang {
class QualType; class QualType;
class RecordDecl; class RecordDecl;
class TagDecl; class TagDecl;
class TranslationUnitDecl;
class ValueDecl; class ValueDecl;
class VarDecl; class VarDecl;
class VarTemplateDecl; class VarTemplateDecl;
@ -147,6 +149,31 @@ public:
virtual void AddedAttributeToRecord(const Attr *Attr, virtual void AddedAttributeToRecord(const Attr *Attr,
const RecordDecl *Record) {} 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 // NOTE: If new methods are added they should also be added to
// MultiplexASTMutationListener. // MultiplexASTMutationListener.
}; };

View file

@ -23,7 +23,9 @@
#include "clang/AST/StmtVisitor.h" #include "clang/AST/StmtVisitor.h"
#include "clang/AST/TemplateArgumentVisitor.h" #include "clang/AST/TemplateArgumentVisitor.h"
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/TypeVisitor.h" #include "clang/AST/TypeVisitor.h"
#include "llvm/Support/SaveAndRestore.h"
namespace clang { namespace clang {
@ -48,8 +50,10 @@ struct {
void Visit(const Stmt *Node); void Visit(const Stmt *Node);
void Visit(const Type *T); void Visit(const Type *T);
void Visit(QualType T); void Visit(QualType T);
void Visit(TypeLoc);
void Visit(const Decl *D); void Visit(const Decl *D);
void Visit(const CXXCtorInitializer *Init); void Visit(const CXXCtorInitializer *Init);
void Visit(const OpenACCClause *C);
void Visit(const OMPClause *C); void Visit(const OMPClause *C);
void Visit(const BlockDecl::Capture &C); void Visit(const BlockDecl::Capture &C);
void Visit(const GenericSelectionExpr::ConstAssociation &A); void Visit(const GenericSelectionExpr::ConstAssociation &A);
@ -64,6 +68,7 @@ class ASTNodeTraverser
public comments::ConstCommentVisitor<Derived, void, public comments::ConstCommentVisitor<Derived, void,
const comments::FullComment *>, const comments::FullComment *>,
public TypeVisitor<Derived>, public TypeVisitor<Derived>,
public TypeLocVisitor<Derived>,
public ConstAttrVisitor<Derived>, public ConstAttrVisitor<Derived>,
public ConstTemplateArgumentVisitor<Derived> { public ConstTemplateArgumentVisitor<Derived> {
@ -71,6 +76,14 @@ class ASTNodeTraverser
/// not already been loaded. /// not already been loaded.
bool Deserialize = false; 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; TraversalKind Traversal = TraversalKind::TK_AsIs;
NodeDelegateType &getNodeDelegate() { NodeDelegateType &getNodeDelegate() {
@ -85,7 +98,7 @@ public:
void SetTraversalKind(TraversalKind TK) { Traversal = TK; } void SetTraversalKind(TraversalKind TK) { Traversal = TK; }
TraversalKind GetTraversalKind() const { return Traversal; } TraversalKind GetTraversalKind() const { return Traversal; }
void Visit(const Decl *D) { void Visit(const Decl *D, bool VisitLocs = false) {
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isImplicit()) if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isImplicit())
return; return;
@ -94,7 +107,10 @@ public:
if (!D) if (!D)
return; return;
ConstDeclVisitor<Derived>::Visit(D); {
llvm::SaveAndRestore RestoreVisitLocs(this->VisitLocs, VisitLocs);
ConstDeclVisitor<Derived>::Visit(D);
}
for (const auto &A : D->attrs()) for (const auto &A : D->attrs())
Visit(A); 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) { void Visit(const Attr *A) {
getNodeDelegate().AddChild([=] { getNodeDelegate().AddChild([=] {
getNodeDelegate().Visit(A); 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) { void Visit(const OMPClause *C) {
getNodeDelegate().AddChild([=] { getNodeDelegate().AddChild([=] {
getNodeDelegate().Visit(C); getNodeDelegate().Visit(C);
@ -286,6 +321,8 @@ public:
Visit(*QT); Visit(*QT);
else if (const auto *T = N.get<Type>()) else if (const auto *T = N.get<Type>())
Visit(T); Visit(T);
else if (const auto *TL = N.get<TypeLoc>())
Visit(*TL);
else if (const auto *C = N.get<CXXCtorInitializer>()) else if (const auto *C = N.get<CXXCtorInitializer>())
Visit(C); Visit(C);
else if (const auto *C = N.get<OMPClause>()) else if (const auto *C = N.get<OMPClause>())
@ -346,7 +383,7 @@ public:
void VisitComplexType(const ComplexType *T) { Visit(T->getElementType()); } void VisitComplexType(const ComplexType *T) { Visit(T->getElementType()); }
void VisitLocInfoType(const LocInfoType *T) { void VisitLocInfoType(const LocInfoType *T) {
Visit(T->getTypeSourceInfo()->getType()); Visit(T->getTypeSourceInfo()->getTypeLoc());
} }
void VisitPointerType(const PointerType *T) { Visit(T->getPointeeType()); } void VisitPointerType(const PointerType *T) { Visit(T->getPointeeType()); }
void VisitBlockPointerType(const BlockPointerType *T) { void VisitBlockPointerType(const BlockPointerType *T) {
@ -385,6 +422,12 @@ public:
void VisitDecltypeType(const DecltypeType *T) { void VisitDecltypeType(const DecltypeType *T) {
Visit(T->getUnderlyingExpr()); Visit(T->getUnderlyingExpr());
} }
void VisitPackIndexingType(const PackIndexingType *T) {
Visit(T->getPattern());
Visit(T->getIndexExpr());
}
void VisitUnaryTransformType(const UnaryTransformType *T) { void VisitUnaryTransformType(const UnaryTransformType *T) {
Visit(T->getBaseType()); Visit(T->getBaseType());
} }
@ -415,9 +458,55 @@ public:
if (!T->isSugared()) if (!T->isSugared())
Visit(T->getPattern()); Visit(T->getPattern());
} }
void VisitAutoType(const AutoType *T) {
for (const auto &Arg : T->getTypeConstraintArguments())
Visit(Arg);
}
// FIXME: ElaboratedType, DependentNameType, // FIXME: ElaboratedType, DependentNameType,
// DependentTemplateSpecializationType, ObjCObjectType // 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 VisitTypedefDecl(const TypedefDecl *D) { Visit(D->getUnderlyingType()); }
void VisitEnumConstantDecl(const EnumConstantDecl *D) { void VisitEnumConstantDecl(const EnumConstantDecl *D) {
@ -462,6 +551,8 @@ public:
if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isCXXForRangeDecl()) if (Traversal == TK_IgnoreUnlessSpelledInSource && D->isCXXForRangeDecl())
return; return;
if (const auto *TSI = D->getTypeSourceInfo(); VisitLocs && TSI)
Visit(TSI->getTypeLoc());
if (D->hasInit()) if (D->hasInit())
Visit(D->getInit()); Visit(D->getInit());
} }
@ -604,7 +695,7 @@ public:
if (const auto *TC = D->getTypeConstraint()) if (const auto *TC = D->getTypeConstraint())
Visit(TC->getImmediatelyDeclaredConstraint()); Visit(TC->getImmediatelyDeclaredConstraint());
if (D->hasDefaultArgument()) if (D->hasDefaultArgument())
Visit(D->getDefaultArgument(), SourceRange(), Visit(D->getDefaultArgument().getArgument(), SourceRange(),
D->getDefaultArgStorage().getInheritedFrom(), D->getDefaultArgStorage().getInheritedFrom(),
D->defaultArgumentWasInherited() ? "inherited from" : "previous"); D->defaultArgumentWasInherited() ? "inherited from" : "previous");
} }
@ -613,9 +704,9 @@ public:
if (const auto *E = D->getPlaceholderTypeConstraint()) if (const auto *E = D->getPlaceholderTypeConstraint())
Visit(E); Visit(E);
if (D->hasDefaultArgument()) if (D->hasDefaultArgument())
Visit(D->getDefaultArgument(), SourceRange(), dumpTemplateArgumentLoc(
D->getDefaultArgStorage().getInheritedFrom(), D->getDefaultArgument(), D->getDefaultArgStorage().getInheritedFrom(),
D->defaultArgumentWasInherited() ? "inherited from" : "previous"); D->defaultArgumentWasInherited() ? "inherited from" : "previous");
} }
void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) { void VisitTemplateTemplateParmDecl(const TemplateTemplateParmDecl *D) {
@ -717,6 +808,11 @@ public:
Visit(C); Visit(C);
} }
void VisitOpenACCConstructStmt(const OpenACCConstructStmt *Node) {
for (const auto *C : Node->clauses())
Visit(C);
}
void VisitInitListExpr(const InitListExpr *ILE) { void VisitInitListExpr(const InitListExpr *ILE) {
if (auto *Filler = ILE->getArrayFiller()) { if (auto *Filler = ILE->getArrayFiller()) {
Visit(Filler, "array_filler"); 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) { void VisitRequiresExpr(const RequiresExpr *E) {
for (auto *D : E->getLocalParameters()) for (auto *D : E->getLocalParameters())
Visit(D); Visit(D);
@ -755,6 +857,12 @@ public:
Visit(R); 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) { void VisitLambdaExpr(const LambdaExpr *Node) {
if (Traversal == TK_IgnoreUnlessSpelledInSource) { if (Traversal == TK_IgnoreUnlessSpelledInSource) {
for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) { for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
@ -837,6 +945,14 @@ public:
Visit(TArg); Visit(TArg);
} }
void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node) {
Visit(Node->getExpr());
}
void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node) {
Visit(Node->getExpr());
}
// Implements Visit methods for Attrs. // Implements Visit methods for Attrs.
#include "clang/AST/AttrNodeTraverse.inc" #include "clang/AST/AttrNodeTraverse.inc"
}; };

View file

@ -16,6 +16,7 @@
#include "clang/AST/ASTVector.h" #include "clang/AST/ASTVector.h"
#include "clang/AST/DeclAccessPair.h" #include "clang/AST/DeclAccessPair.h"
#include "clang/AST/DeclID.h"
#include "clang/AST/UnresolvedSet.h" #include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/Specifiers.h" #include "clang/Basic/Specifiers.h"
#include <cassert> #include <cassert>
@ -56,6 +57,10 @@ public:
Decls.push_back(DeclAccessPair::make(D, AS), C); 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. /// Replaces the given declaration with the new one, once.
/// ///
/// \return true if the set changed /// \return true if the set changed
@ -109,10 +114,10 @@ public:
void reserve(ASTContext &C, unsigned N) { Impl.reserve(C, N); } 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()); assert(Impl.empty() || Impl.Decls.isLazy());
Impl.Decls.setLazy(true); 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() { 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"); "update this if the value size changes");
uint32_t value = asImpl().readUInt32(); uint64_t value = asImpl().readUInt64();
return Qualifiers::fromOpaqueValue(value); return Qualifiers::fromOpaqueValue(value);
} }
@ -244,6 +244,15 @@ public:
return FunctionProtoType::ExtParameterInfo::getFromOpaqueValue(value); return FunctionProtoType::ExtParameterInfo::getFromOpaqueValue(value);
} }
FunctionEffect readFunctionEffect() {
uint32_t value = asImpl().readUInt32();
return FunctionEffect::fromOpaqueInt32(value);
}
EffectConditionExpr readEffectConditionExpr() {
return EffectConditionExpr{asImpl().readExprRef()};
}
NestedNameSpecifier *readNestedNameSpecifier() { NestedNameSpecifier *readNestedNameSpecifier() {
auto &ctx = getASTContext(); auto &ctx = getASTContext();

View file

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

View file

@ -14,6 +14,7 @@
#define LLVM_CLANG_AST_AVAILABILITY_H #define LLVM_CLANG_AST_AVAILABILITY_H
#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/Support/VersionTuple.h" #include "llvm/Support/VersionTuple.h"
@ -57,6 +58,68 @@ public:
bool isOtherPlatformSpec() const { return Version.empty(); } 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 } // end namespace clang
#endif #endif

View file

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

View file

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

View file

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

View file

@ -100,6 +100,14 @@ public:
ArrayRef<Comment::Argument> ArrayRef<Comment::Argument>
parseCommandArgs(TextTokenRetokenizer &Retokenizer, unsigned NumArgs); 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(); BlockCommandComment *parseBlockCommand();
InlineCommandComment *parseInlineCommand(); InlineCommandComment *parseInlineCommand();
@ -118,4 +126,3 @@ public:
} // end namespace clang } // end namespace clang
#endif #endif

View file

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

View file

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

View file

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

View file

@ -19,6 +19,7 @@
#include "clang/Basic/Specifiers.h" #include "clang/Basic/Specifiers.h"
#include "llvm/Support/DataTypes.h" #include "llvm/Support/DataTypes.h"
#include "llvm/Support/Endian.h"
namespace clang { namespace clang {
@ -27,9 +28,17 @@ class NamedDecl;
/// A POD class for pairing a NamedDecl* with an access specifier. /// A POD class for pairing a NamedDecl* with an access specifier.
/// Can be put into unions. /// Can be put into unions.
class DeclAccessPair { 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: public:
static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) { static DeclAccessPair make(NamedDecl *D, AccessSpecifier AS) {
@ -38,12 +47,22 @@ public:
return p; 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 { NamedDecl *getDecl() const {
assert(!isDeclID());
return reinterpret_cast<NamedDecl*>(~Mask & Ptr); return reinterpret_cast<NamedDecl*>(~Mask & Ptr);
} }
AccessSpecifier getAccess() const { AccessSpecifier getAccess() const { return AccessSpecifier(ASMask & Ptr); }
return AccessSpecifier(Mask & Ptr);
}
void setDecl(NamedDecl *D) { void setDecl(NamedDecl *D) {
set(D, getAccess()); set(D, getAccess());
@ -52,12 +71,18 @@ public:
set(getDecl(), AS); set(getDecl(), AS);
} }
void set(NamedDecl *D, AccessSpecifier 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(); } operator NamedDecl*() const { return getDecl(); }
NamedDecl *operator->() 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 #endif

View file

@ -15,6 +15,7 @@
#include "clang/AST/ASTDumperUtils.h" #include "clang/AST/ASTDumperUtils.h"
#include "clang/AST/AttrIterator.h" #include "clang/AST/AttrIterator.h"
#include "clang/AST/DeclID.h"
#include "clang/AST/DeclarationName.h" #include "clang/AST/DeclarationName.h"
#include "clang/AST/SelectorLocationsKind.h" #include "clang/AST/SelectorLocationsKind.h"
#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/IdentifierTable.h"
@ -358,7 +359,7 @@ protected:
/// \param Ctx The context in which we will allocate memory. /// \param Ctx The context in which we will allocate memory.
/// \param ID The global ID of the deserialized declaration. /// \param ID The global ID of the deserialized declaration.
/// \param Extra The amount of extra space to allocate after the object. /// \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); std::size_t Extra = 0);
/// Allocate memory for a non-deserialized declaration. /// Allocate memory for a non-deserialized declaration.
@ -669,19 +670,11 @@ public:
/// Whether this declaration comes from another module unit. /// Whether this declaration comes from another module unit.
bool isInAnotherModuleUnit() const; bool isInAnotherModuleUnit() const;
/// FIXME: Implement discarding declarations actually in global module /// Whether this declaration comes from explicit global module.
/// fragment. See [module.global.frag]p3,4 for details. bool isFromExplicitGlobalModule() const;
bool isDiscardedInGlobalModuleFragment() const { return false; }
/// Check if we should skip checking ODRHash for declaration \param D. /// Whether this declaration comes from a named module.
/// bool isInNamedModule() const;
/// 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;
/// Return true if this declaration has an attribute which acts as /// Return true if this declaration has an attribute which acts as
/// definition of the entity, such as 'alias' or 'ifunc'. /// 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 /// Set the owning module ID. This may only be called for
/// deserialized Decls. /// deserialized Decls.
void setOwningModuleID(unsigned ID) { void setOwningModuleID(unsigned ID);
assert(isFromASTFile() && "Only works on a deserialized declaration");
*((unsigned*)this - 2) = ID;
}
public: public:
/// Determine the availability of the given declaration. /// Determine the availability of the given declaration.
@ -787,19 +777,11 @@ public:
/// Retrieve the global declaration ID associated with this /// Retrieve the global declaration ID associated with this
/// declaration, which specifies where this Decl was loaded from. /// declaration, which specifies where this Decl was loaded from.
unsigned getGlobalID() const { GlobalDeclID getGlobalID() const;
if (isFromASTFile())
return *((const unsigned*)this - 1);
return 0;
}
/// Retrieve the global ID of the module that owns this particular /// Retrieve the global ID of the module that owns this particular
/// declaration. /// declaration.
unsigned getOwningModuleID() const { unsigned getOwningModuleID() const;
if (isFromASTFile())
return *((const unsigned*)this - 2);
return 0;
}
private: private:
Module *getOwningModuleSlow() const; Module *getOwningModuleSlow() const;
@ -846,10 +828,7 @@ public:
/// Get the module that owns this declaration for linkage purposes. /// Get the module that owns this declaration for linkage purposes.
/// There only ever is such a standard C++ module. /// There only ever is such a standard C++ module.
/// Module *getOwningModuleForLinkage() const;
/// \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;
/// Determine whether this declaration is definitely visible to name lookup, /// Determine whether this declaration is definitely visible to name lookup,
/// independent of whether the owning module is visible. /// independent of whether the owning module is visible.
@ -1508,6 +1487,27 @@ class DeclContext {
/// Number of bits in DeclContextBitfields. /// Number of bits in DeclContextBitfields.
enum { NumDeclContextBits = 13 }; 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. /// Stores the bits used by TagDecl.
/// If modified NumTagDeclBits and the accessor /// If modified NumTagDeclBits and the accessor
/// methods in TagDecl should be updated appropriately. /// methods in TagDecl should be updated appropriately.
@ -1740,7 +1740,7 @@ class DeclContext {
LLVM_PREFERRED_TYPE(bool) LLVM_PREFERRED_TYPE(bool)
uint64_t IsExplicitlyDefaulted : 1; uint64_t IsExplicitlyDefaulted : 1;
LLVM_PREFERRED_TYPE(bool) LLVM_PREFERRED_TYPE(bool)
uint64_t HasDefaultedFunctionInfo : 1; uint64_t HasDefaultedOrDeletedInfo : 1;
/// For member functions of complete types, whether this is an ineligible /// For member functions of complete types, whether this is an ineligible
/// special member function or an unselected destructor. See /// special member function or an unselected destructor. See
@ -2006,6 +2006,7 @@ protected:
/// 8 bytes with static_asserts in the ctor of DeclContext. /// 8 bytes with static_asserts in the ctor of DeclContext.
union { union {
DeclContextBitfields DeclContextBits; DeclContextBitfields DeclContextBits;
NamespaceDeclBitfields NamespaceDeclBits;
TagDeclBitfields TagDeclBits; TagDeclBitfields TagDeclBits;
EnumDeclBitfields EnumDeclBits; EnumDeclBitfields EnumDeclBits;
RecordDeclBitfields RecordDeclBits; RecordDeclBitfields RecordDeclBits;
@ -2019,6 +2020,8 @@ protected:
static_assert(sizeof(DeclContextBitfields) <= 8, static_assert(sizeof(DeclContextBitfields) <= 8,
"DeclContextBitfields is larger than 8 bytes!"); "DeclContextBitfields is larger than 8 bytes!");
static_assert(sizeof(NamespaceDeclBitfields) <= 8,
"NamespaceDeclBitfields is larger than 8 bytes!");
static_assert(sizeof(TagDeclBitfields) <= 8, static_assert(sizeof(TagDeclBitfields) <= 8,
"TagDeclBitfields is larger than 8 bytes!"); "TagDeclBitfields is larger than 8 bytes!");
static_assert(sizeof(EnumDeclBitfields) <= 8, static_assert(sizeof(EnumDeclBitfields) <= 8,
@ -2130,6 +2133,7 @@ public:
case Decl::Block: case Decl::Block:
case Decl::Captured: case Decl::Captured:
case Decl::ObjCMethod: case Decl::ObjCMethod:
case Decl::TopLevelStmt:
return true; return true;
default: default:
return getDeclKind() >= Decl::firstFunction && return getDeclKind() >= Decl::firstFunction &&
@ -2157,6 +2161,10 @@ public:
getDeclKind() <= Decl::lastRecord; getDeclKind() <= Decl::lastRecord;
} }
bool isRequiresExprBody() const {
return getDeclKind() == Decl::RequiresExprBody;
}
bool isNamespace() const { return getDeclKind() == Decl::Namespace; } bool isNamespace() const { return getDeclKind() == Decl::Namespace; }
bool isStdNamespace() const; bool isStdNamespace() const;

View file

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

View file

@ -42,11 +42,12 @@ class StoredDeclsList {
/// external declarations. /// external declarations.
DeclsAndHasExternalTy Data; DeclsAndHasExternalTy Data;
template<typename Fn> template <typename Fn> DeclListNode::Decls *erase_if(Fn ShouldErase) {
void erase_if(Fn ShouldErase) {
Decls List = Data.getPointer(); Decls List = Data.getPointer();
if (!List) if (!List)
return; return nullptr;
ASTContext &C = getASTContext(); ASTContext &C = getASTContext();
DeclListNode::Decls NewHead = nullptr; DeclListNode::Decls NewHead = nullptr;
DeclListNode::Decls *NewLast = nullptr; DeclListNode::Decls *NewLast = nullptr;
@ -79,6 +80,17 @@ class StoredDeclsList {
Data.setPointer(NewHead); Data.setPointer(NewHead);
assert(llvm::none_of(getLookupResult(), ShouldErase) && "Still exists!"); 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) { void erase(NamedDecl *ND) {
@ -160,12 +172,16 @@ public:
void replaceExternalDecls(ArrayRef<NamedDecl*> Decls) { void replaceExternalDecls(ArrayRef<NamedDecl*> Decls) {
// Remove all declarations that are either external or are replaced with // Remove all declarations that are either external or are replaced with
// external declarations. // external declarations with higher visibilities.
erase_if([Decls](NamedDecl *ND) { DeclListNode::Decls *Tail = erase_if([Decls](NamedDecl *ND) {
if (ND->isFromASTFile()) if (ND->isFromASTFile())
return true; return true;
// FIXME: Can we get rid of this loop completely?
for (NamedDecl *D : Decls) 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 true;
return false; return false;
}); });
@ -185,27 +201,18 @@ public:
DeclsAsList = Node; DeclsAsList = Node;
} }
DeclListNode::Decls Head = Data.getPointer(); if (!Data.getPointer()) {
if (Head.isNull()) {
Data.setPointer(DeclsAsList); Data.setPointer(DeclsAsList);
return; 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. // Append the Decls.
DeclListNode *Node = C.AllocateDeclListNode(Tail->get<NamedDecl *>()); DeclListNode *Node = C.AllocateDeclListNode(Tail->get<NamedDecl *>());
Node->Rest = DeclsAsList; Node->Rest = DeclsAsList;
*Tail = Node; *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 { DeclContext::lookup_result getLookupResult() const {
return DeclContext::lookup_result(Data.getPointer()); return DeclContext::lookup_result(Data.getPointer());
} }

View file

@ -112,7 +112,7 @@ public:
Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_, Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_,
SourceLocation FriendL, SourceLocation FriendL,
ArrayRef<TemplateParameterList *> FriendTypeTPLists = std::nullopt); ArrayRef<TemplateParameterList *> FriendTypeTPLists = std::nullopt);
static FriendDecl *CreateDeserialized(ASTContext &C, unsigned ID, static FriendDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned FriendTypeNumTPLists); unsigned FriendTypeNumTPLists);
/// If this friend declaration names an (untemplated but possibly /// 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, ObjCImplementationControl impControl = ObjCImplementationControl::None,
bool HasRelatedResultType = false); bool HasRelatedResultType = false);
static ObjCMethodDecl *CreateDeserialized(ASTContext &C, unsigned ID); static ObjCMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
ObjCMethodDecl *getCanonicalDecl() override; ObjCMethodDecl *getCanonicalDecl() override;
const ObjCMethodDecl *getCanonicalDecl() const { const ObjCMethodDecl *getCanonicalDecl() const {
@ -614,7 +614,8 @@ public:
IdentifierInfo *name, IdentifierInfo *name,
SourceLocation colonLoc, SourceLocation colonLoc,
TypeSourceInfo *boundInfo); TypeSourceInfo *boundInfo);
static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, unsigned ID); static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx,
GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY; SourceRange getSourceRange() const override LLVM_READONLY;
@ -772,7 +773,7 @@ private:
// Synthesize ivar for this property // Synthesize ivar for this property
ObjCIvarDecl *PropertyIvarDecl = nullptr; ObjCIvarDecl *PropertyIvarDecl = nullptr;
ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, ObjCPropertyDecl(DeclContext *DC, SourceLocation L, const IdentifierInfo *Id,
SourceLocation AtLocation, SourceLocation LParenLocation, SourceLocation AtLocation, SourceLocation LParenLocation,
QualType T, TypeSourceInfo *TSI, PropertyControl propControl) QualType T, TypeSourceInfo *TSI, PropertyControl propControl)
: NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation), : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation),
@ -782,12 +783,14 @@ private:
PropertyImplementation(propControl) {} PropertyImplementation(propControl) {}
public: public:
static ObjCPropertyDecl * static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC,
Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, SourceLocation L, const IdentifierInfo *Id,
SourceLocation AtLocation, SourceLocation LParenLocation, QualType T, SourceLocation AtLocation,
TypeSourceInfo *TSI, PropertyControl propControl = None); 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; } SourceLocation getAtLoc() const { return AtLoc; }
void setAtLoc(SourceLocation L) { AtLoc = L; } void setAtLoc(SourceLocation L) { AtLoc = L; }
@ -952,7 +955,7 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
void anchor() override; void anchor() override;
public: public:
ObjCContainerDecl(Kind DK, DeclContext *DC, IdentifierInfo *Id, ObjCContainerDecl(Kind DK, DeclContext *DC, const IdentifierInfo *Id,
SourceLocation nameLoc, SourceLocation atStartLoc); SourceLocation nameLoc, SourceLocation atStartLoc);
// Iterator access to instance/class properties. // Iterator access to instance/class properties.
@ -1240,7 +1243,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
llvm::PointerIntPair<DefinitionData *, 1, bool> Data; llvm::PointerIntPair<DefinitionData *, 1, bool> Data;
ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc, ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
IdentifierInfo *Id, ObjCTypeParamList *typeParamList, const IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
bool IsInternal); bool IsInternal);
@ -1271,15 +1274,14 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
} }
public: public:
static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC, static ObjCInterfaceDecl *
SourceLocation atLoc, Create(const ASTContext &C, DeclContext *DC, SourceLocation atLoc,
IdentifierInfo *Id, const IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
ObjCTypeParamList *typeParamList, ObjCInterfaceDecl *PrevDecl,
ObjCInterfaceDecl *PrevDecl, SourceLocation ClassLoc = SourceLocation(), bool isInternal = false);
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. /// Retrieve the type parameters of this class.
/// ///
@ -1338,7 +1340,8 @@ public:
ObjCImplementationDecl *getImplementation() const; ObjCImplementationDecl *getImplementation() const;
void setImplementation(ObjCImplementationDecl *ImplD); 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. // Get the local instance/class method declared in a category.
ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const; ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const;
@ -1794,9 +1797,9 @@ public:
data().CategoryList = category; data().CategoryList = category;
} }
ObjCPropertyDecl ObjCPropertyDecl *
*FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId, FindPropertyVisibleInPrimaryClass(const IdentifierInfo *PropertyId,
ObjCPropertyQueryKind QueryKind) const; ObjCPropertyQueryKind QueryKind) const;
void collectPropertiesToImplement(PropertyMap &PM) const override; void collectPropertiesToImplement(PropertyMap &PM) const override;
@ -1954,8 +1957,8 @@ public:
private: private:
ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc, ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc,
SourceLocation IdLoc, IdentifierInfo *Id, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T,
QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
bool synthesized) bool synthesized)
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW, : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
/*Mutable=*/false, /*HasInit=*/ICIS_NoInit), /*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
@ -1964,12 +1967,11 @@ private:
public: public:
static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC, static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC,
SourceLocation StartLoc, SourceLocation IdLoc, SourceLocation StartLoc, SourceLocation IdLoc,
IdentifierInfo *Id, QualType T, const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, TypeSourceInfo *TInfo, AccessControl ac,
AccessControl ac, Expr *BW = nullptr, Expr *BW = nullptr, bool synthesized = false);
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 /// Return the class interface that this ivar is logically contained
/// in; this is either the interface where the ivar was declared, or the /// in; this is either the interface where the ivar was declared, or the
@ -2039,7 +2041,8 @@ public:
SourceLocation IdLoc, IdentifierInfo *Id, SourceLocation IdLoc, IdentifierInfo *Id,
QualType T, Expr *BW); QualType T, Expr *BW);
static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const Decl *D) { return classofKind(D->getKind()); }
@ -2142,7 +2145,7 @@ public:
SourceLocation atStartLoc, SourceLocation atStartLoc,
ObjCProtocolDecl *PrevDecl); ObjCProtocolDecl *PrevDecl);
static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, unsigned ID); static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
const ObjCProtocolList &getReferencedProtocols() const { const ObjCProtocolList &getReferencedProtocols() const {
assert(hasDefinition() && "No definition available!"); assert(hasDefinition() && "No definition available!");
@ -2343,7 +2346,7 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList, ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc = SourceLocation(), SourceLocation IvarLBraceLoc = SourceLocation(),
SourceLocation IvarRBraceLoc = SourceLocation()); SourceLocation IvarRBraceLoc = SourceLocation());
@ -2354,16 +2357,14 @@ public:
friend class ASTDeclReader; friend class ASTDeclReader;
friend class ASTDeclWriter; friend class ASTDeclWriter;
static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC, static ObjCCategoryDecl *
SourceLocation AtLoc, Create(ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
SourceLocation ClassNameLoc, SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
SourceLocation CategoryNameLoc, const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
ObjCInterfaceDecl *IDecl, SourceLocation IvarLBraceLoc = SourceLocation(),
ObjCTypeParamList *typeParamList, SourceLocation IvarRBraceLoc = SourceLocation());
SourceLocation IvarLBraceLoc=SourceLocation(), static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID);
SourceLocation IvarRBraceLoc=SourceLocation());
static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID);
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; } const ObjCInterfaceDecl *getClassInterface() const { return ClassInterface; }
@ -2472,10 +2473,9 @@ class ObjCImplDecl : public ObjCContainerDecl {
void anchor() override; void anchor() override;
protected: protected:
ObjCImplDecl(Kind DK, DeclContext *DC, ObjCImplDecl(Kind DK, DeclContext *DC, ObjCInterfaceDecl *classInterface,
ObjCInterfaceDecl *classInterface, const IdentifierInfo *Id, SourceLocation nameLoc,
IdentifierInfo *Id, SourceLocation atStartLoc)
SourceLocation nameLoc, SourceLocation atStartLoc)
: ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc), : ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc),
ClassInterface(classInterface) {} ClassInterface(classInterface) {}
@ -2543,12 +2543,12 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
// Category name location // Category name location
SourceLocation CategoryNameLoc; SourceLocation CategoryNameLoc;
ObjCCategoryImplDecl(DeclContext *DC, IdentifierInfo *Id, ObjCCategoryImplDecl(DeclContext *DC, const IdentifierInfo *Id,
ObjCInterfaceDecl *classInterface, ObjCInterfaceDecl *classInterface,
SourceLocation nameLoc, SourceLocation atStartLoc, SourceLocation nameLoc, SourceLocation atStartLoc,
SourceLocation CategoryNameLoc) SourceLocation CategoryNameLoc)
: ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id, : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id, nameLoc,
nameLoc, atStartLoc), atStartLoc),
CategoryNameLoc(CategoryNameLoc) {} CategoryNameLoc(CategoryNameLoc) {}
void anchor() override; void anchor() override;
@ -2557,13 +2557,12 @@ public:
friend class ASTDeclReader; friend class ASTDeclReader;
friend class ASTDeclWriter; friend class ASTDeclWriter;
static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC, static ObjCCategoryImplDecl *
IdentifierInfo *Id, Create(ASTContext &C, DeclContext *DC, const IdentifierInfo *Id,
ObjCInterfaceDecl *classInterface, ObjCInterfaceDecl *classInterface, SourceLocation nameLoc,
SourceLocation nameLoc, SourceLocation atStartLoc, SourceLocation CategoryNameLoc);
SourceLocation atStartLoc, static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C,
SourceLocation CategoryNameLoc); GlobalDeclID ID);
static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID);
ObjCCategoryDecl *getCategoryDecl() const; ObjCCategoryDecl *getCategoryDecl() const;
@ -2645,7 +2644,8 @@ public:
SourceLocation IvarLBraceLoc=SourceLocation(), SourceLocation IvarLBraceLoc=SourceLocation(),
SourceLocation IvarRBraceLoc=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. /// init_iterator - Iterates through the ivar initializer list.
using init_iterator = CXXCtorInitializer **; using init_iterator = CXXCtorInitializer **;
@ -2785,7 +2785,7 @@ public:
ObjCInterfaceDecl* aliasedClass); ObjCInterfaceDecl* aliasedClass);
static ObjCCompatibleAliasDecl *CreateDeserialized(ASTContext &C, static ObjCCompatibleAliasDecl *CreateDeserialized(ASTContext &C,
unsigned ID); GlobalDeclID ID);
const ObjCInterfaceDecl *getClassInterface() const { return AliasedClass; } const ObjCInterfaceDecl *getClassInterface() const { return AliasedClass; }
ObjCInterfaceDecl *getClassInterface() { return AliasedClass; } ObjCInterfaceDecl *getClassInterface() { return AliasedClass; }
@ -2856,7 +2856,8 @@ public:
ObjCIvarDecl *ivarDecl, ObjCIvarDecl *ivarDecl,
SourceLocation ivarLoc); SourceLocation ivarLoc);
static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C, unsigned ID); static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY; 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. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information. // See https://llvm.org/LICENSE.txt for license information.
@ -59,7 +59,7 @@ protected:
} }
template <typename T, typename... Params> 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, unsigned NumClauses, unsigned NumChildren,
Params &&... P) { Params &&... P) {
auto *Inst = new (C, ID, size(NumClauses, NumChildren)) auto *Inst = new (C, ID, size(NumClauses, NumChildren))
@ -133,7 +133,7 @@ public:
SourceLocation L, SourceLocation L,
ArrayRef<Expr *> VL); ArrayRef<Expr *> VL);
static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C, static OMPThreadPrivateDecl *CreateDeserialized(ASTContext &C,
unsigned ID, unsigned N); GlobalDeclID ID, unsigned N);
typedef MutableArrayRef<Expr *>::iterator varlist_iterator; typedef MutableArrayRef<Expr *>::iterator varlist_iterator;
typedef ArrayRef<const Expr *>::iterator varlist_const_iterator; typedef ArrayRef<const Expr *>::iterator varlist_const_iterator;
@ -214,7 +214,7 @@ public:
QualType T, OMPDeclareReductionDecl *PrevDeclInScope); QualType T, OMPDeclareReductionDecl *PrevDeclInScope);
/// Create deserialized declare reduction node. /// Create deserialized declare reduction node.
static OMPDeclareReductionDecl *CreateDeserialized(ASTContext &C, static OMPDeclareReductionDecl *CreateDeserialized(ASTContext &C,
unsigned ID); GlobalDeclID ID);
/// Get combiner expression of the declare reduction construct. /// Get combiner expression of the declare reduction construct.
Expr *getCombiner() { return Combiner; } Expr *getCombiner() { return Combiner; }
@ -318,8 +318,8 @@ public:
ArrayRef<OMPClause *> Clauses, ArrayRef<OMPClause *> Clauses,
OMPDeclareMapperDecl *PrevDeclInScope); OMPDeclareMapperDecl *PrevDeclInScope);
/// Creates deserialized declare mapper node. /// Creates deserialized declare mapper node.
static OMPDeclareMapperDecl *CreateDeserialized(ASTContext &C, unsigned ID, static OMPDeclareMapperDecl *CreateDeserialized(ASTContext &C,
unsigned N); GlobalDeclID ID, unsigned N);
using clauselist_iterator = MutableArrayRef<OMPClause *>::iterator; using clauselist_iterator = MutableArrayRef<OMPClause *>::iterator;
using clauselist_const_iterator = ArrayRef<const OMPClause *>::iterator; using clauselist_const_iterator = ArrayRef<const OMPClause *>::iterator;
@ -397,7 +397,8 @@ public:
IdentifierInfo *Id, QualType T, IdentifierInfo *Id, QualType T,
SourceLocation StartLoc); SourceLocation StartLoc);
static OMPCapturedExprDecl *CreateDeserialized(ASTContext &C, unsigned ID); static OMPCapturedExprDecl *CreateDeserialized(ASTContext &C,
GlobalDeclID ID);
SourceRange getSourceRange() const override LLVM_READONLY; SourceRange getSourceRange() const override LLVM_READONLY;
@ -427,7 +428,7 @@ public:
static OMPRequiresDecl *Create(ASTContext &C, DeclContext *DC, static OMPRequiresDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, ArrayRef<OMPClause *> CL); SourceLocation L, ArrayRef<OMPClause *> CL);
/// Create deserialized requires node. /// Create deserialized requires node.
static OMPRequiresDecl *CreateDeserialized(ASTContext &C, unsigned ID, static OMPRequiresDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned N); unsigned N);
using clauselist_iterator = MutableArrayRef<OMPClause *>::iterator; using clauselist_iterator = MutableArrayRef<OMPClause *>::iterator;
@ -495,7 +496,7 @@ public:
static OMPAllocateDecl *Create(ASTContext &C, DeclContext *DC, static OMPAllocateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, ArrayRef<Expr *> VL, SourceLocation L, ArrayRef<Expr *> VL,
ArrayRef<OMPClause *> CL); ArrayRef<OMPClause *> CL);
static OMPAllocateDecl *CreateDeserialized(ASTContext &C, unsigned ID, static OMPAllocateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID,
unsigned NVars, unsigned NClauses); unsigned NVars, unsigned NClauses);
typedef MutableArrayRef<Expr *>::iterator varlist_iterator; typedef MutableArrayRef<Expr *>::iterator varlist_iterator;

View file

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

View file

@ -82,7 +82,7 @@ struct SubobjectAdjustment {
union { union {
struct DTB DerivedToBase; struct DTB DerivedToBase;
FieldDecl *Field; const FieldDecl *Field;
struct P Ptr; struct P Ptr;
}; };
@ -93,8 +93,7 @@ struct SubobjectAdjustment {
DerivedToBase.DerivedClass = DerivedClass; DerivedToBase.DerivedClass = DerivedClass;
} }
SubobjectAdjustment(FieldDecl *Field) SubobjectAdjustment(const FieldDecl *Field) : Kind(FieldAdjustment) {
: Kind(FieldAdjustment) {
this->Field = Field; this->Field = Field;
} }
@ -154,6 +153,12 @@ public:
TR = t; 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 { ExprDependence getDependence() const {
return static_cast<ExprDependence>(ExprBits.Dependent); return static_cast<ExprDependence>(ExprBits.Dependent);
} }
@ -379,7 +384,7 @@ public:
bool isRValue() const { return Kind >= CL_XValue; } bool isRValue() const { return Kind >= CL_XValue; }
bool isModifiable() const { return getModifiable() == CM_Modifiable; } bool isModifiable() const { return getModifiable() == CM_Modifiable; }
/// Create a simple, modifiably lvalue /// Create a simple, modifiable lvalue
static Classification makeSimpleLValue() { static Classification makeSimpleLValue() {
return Classification(CL_LValue, CM_Modifiable); return Classification(CL_LValue, CM_Modifiable);
} }
@ -472,6 +477,13 @@ public:
/// bit-fields, but it will return null for a conditional bit-field. /// bit-fields, but it will return null for a conditional bit-field.
FieldDecl *getSourceBitField(); 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 { const FieldDecl *getSourceBitField() const {
return const_cast<Expr*>(this)->getSourceBitField(); return const_cast<Expr*>(this)->getSourceBitField();
} }
@ -775,6 +787,11 @@ public:
const Expr *PtrExpression, ASTContext &Ctx, const Expr *PtrExpression, ASTContext &Ctx,
EvalResult &Status) const; 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 /// Enumeration used to describe the kind of Null pointer constant
/// returned from \c isNullPointerConstant(). /// returned from \c isNullPointerConstant().
enum NullPointerConstantKind { enum NullPointerConstantKind {
@ -1275,7 +1292,7 @@ class DeclRefExpr final
DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, ValueDecl *D, SourceLocation TemplateKWLoc, ValueDecl *D,
bool RefersToEnlosingVariableOrCapture, bool RefersToEnclosingVariableOrCapture,
const DeclarationNameInfo &NameInfo, NamedDecl *FoundD, const DeclarationNameInfo &NameInfo, NamedDecl *FoundD,
const TemplateArgumentListInfo *TemplateArgs, QualType T, const TemplateArgumentListInfo *TemplateArgs, QualType T,
ExprValueKind VK, NonOdrUseReason NOUR); ExprValueKind VK, NonOdrUseReason NOUR);
@ -1641,14 +1658,14 @@ public:
} }
/// Get a raw enumeration value representing the floating-point semantics of /// 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 { llvm::APFloatBase::Semantics getRawSemantics() const {
return static_cast<llvm::APFloatBase::Semantics>( return static_cast<llvm::APFloatBase::Semantics>(
FloatingLiteralBits.Semantics); FloatingLiteralBits.Semantics);
} }
/// Set the raw enumeration value representing the floating-point semantics of /// 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) { void setRawSemantics(llvm::APFloatBase::Semantics Sem) {
FloatingLiteralBits.Semantics = Sem; FloatingLiteralBits.Semantics = Sem;
} }
@ -1863,6 +1880,17 @@ public:
llvm_unreachable("Unsupported character width!"); 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 getByteLength() const { return getCharByteWidth() * getLength(); }
unsigned getLength() const { return *getTrailingObjects<unsigned>(); } unsigned getLength() const { return *getTrailingObjects<unsigned>(); }
unsigned getCharByteWidth() const { return StringLiteralBits.CharByteWidth; } unsigned getCharByteWidth() const { return StringLiteralBits.CharByteWidth; }
@ -2022,7 +2050,8 @@ public:
} }
static std::string ComputeName(PredefinedIdentKind IK, static std::string ComputeName(PredefinedIdentKind IK,
const Decl *CurrentDecl); const Decl *CurrentDecl,
bool ForceElaboratedPrinting = false);
SourceLocation getBeginLoc() const { return getLocation(); } SourceLocation getBeginLoc() const { return getLocation(); }
SourceLocation getEndLoc() const { return getLocation(); } SourceLocation getEndLoc() const { return getLocation(); }
@ -2101,7 +2130,7 @@ public:
static std::string ComputeName(ASTContext &Context, QualType Ty); 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. /// AST node is only formed if full location information is requested.
class ParenExpr : public Expr { class ParenExpr : public Expr {
SourceLocation L, R; SourceLocation L, R;
@ -2217,7 +2246,7 @@ public:
bool canOverflow() const { return UnaryOperatorBits.CanOverflow; } bool canOverflow() const { return UnaryOperatorBits.CanOverflow; }
void setCanOverflow(bool C) { UnaryOperatorBits.CanOverflow = C; } 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. /// operations on floating point types.
bool isFPContractableWithinStatement(const LangOptions &LO) const { bool isFPContractableWithinStatement(const LangOptions &LO) const {
return getFPFeaturesInEffect(LO).allowFPContractWithinStatement(); return getFPFeaturesInEffect(LO).allowFPContractWithinStatement();
@ -2304,6 +2333,11 @@ public:
return getTrailingFPFeatures(); return getTrailingFPFeatures();
} }
/// Get the store FPOptionsOverride or default if not stored.
FPOptionsOverride getStoredFPFeaturesOrDefault() const {
return hasStoredFPFeatures() ? getStoredFPFeatures() : FPOptionsOverride();
}
protected: protected:
/// Set FPFeatures in trailing storage, used by Serialization & ASTImporter. /// Set FPFeatures in trailing storage, used by Serialization & ASTImporter.
void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; } void setStoredFPFeatures(FPOptionsOverride F) { getTrailingFPFeatures() = F; }
@ -3067,6 +3101,11 @@ public:
*getTrailingFPFeatures() = F; *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 /// Get the FP features status of this operator. Only meaningful for
/// operations on floating point types. /// operations on floating point types.
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { 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. /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F.
/// ///
class MemberExpr final class MemberExpr final
: public Expr, : public Expr,
private llvm::TrailingObjects<MemberExpr, MemberExprNameQualifier, private llvm::TrailingObjects<MemberExpr, NestedNameSpecifierLoc,
ASTTemplateKWAndArgsInfo, DeclAccessPair, ASTTemplateKWAndArgsInfo,
TemplateArgumentLoc> { TemplateArgumentLoc> {
friend class ASTReader; friend class ASTReader;
friend class ASTStmtReader; friend class ASTStmtReader;
@ -3177,26 +3205,30 @@ class MemberExpr final
/// MemberLoc - This is the location of the member name. /// MemberLoc - This is the location of the member name.
SourceLocation MemberLoc; SourceLocation MemberLoc;
size_t numTrailingObjects(OverloadToken<MemberExprNameQualifier>) const { size_t numTrailingObjects(OverloadToken<NestedNameSpecifierLoc>) const {
return hasQualifierOrFoundDecl(); return hasQualifier();
}
size_t numTrailingObjects(OverloadToken<DeclAccessPair>) const {
return hasFoundDecl();
} }
size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const { size_t numTrailingObjects(OverloadToken<ASTTemplateKWAndArgsInfo>) const {
return hasTemplateKWAndArgsInfo(); return hasTemplateKWAndArgsInfo();
} }
bool hasQualifierOrFoundDecl() const { bool hasFoundDecl() const { return MemberExprBits.HasFoundDecl; }
return MemberExprBits.HasQualifierOrFoundDecl;
}
bool hasTemplateKWAndArgsInfo() const { bool hasTemplateKWAndArgsInfo() const {
return MemberExprBits.HasTemplateKWAndArgsInfo; return MemberExprBits.HasTemplateKWAndArgsInfo;
} }
MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
ValueDecl *MemberDecl, const DeclarationNameInfo &NameInfo, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
QualType T, ExprValueKind VK, ExprObjectKind OK, ValueDecl *MemberDecl, DeclAccessPair FoundDecl,
NonOdrUseReason NOUR); const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs, QualType T,
ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR);
MemberExpr(EmptyShell Empty) MemberExpr(EmptyShell Empty)
: Expr(MemberExprClass, Empty), Base(), MemberDecl() {} : Expr(MemberExprClass, Empty), Base(), MemberDecl() {}
@ -3240,24 +3272,24 @@ public:
/// Retrieves the declaration found by lookup. /// Retrieves the declaration found by lookup.
DeclAccessPair getFoundDecl() const { DeclAccessPair getFoundDecl() const {
if (!hasQualifierOrFoundDecl()) if (!hasFoundDecl())
return DeclAccessPair::make(getMemberDecl(), return DeclAccessPair::make(getMemberDecl(),
getMemberDecl()->getAccess()); getMemberDecl()->getAccess());
return getTrailingObjects<MemberExprNameQualifier>()->FoundDecl; return *getTrailingObjects<DeclAccessPair>();
} }
/// Determines whether this member expression actually had /// Determines whether this member expression actually had
/// a C++ nested-name-specifier prior to the name of the member, e.g., /// a C++ nested-name-specifier prior to the name of the member, e.g.,
/// x->Base::foo. /// x->Base::foo.
bool hasQualifier() const { return getQualifier() != nullptr; } bool hasQualifier() const { return MemberExprBits.HasQualifier; }
/// If the member name was qualified, retrieves the /// If the member name was qualified, retrieves the
/// nested-name-specifier that precedes the member name, with source-location /// nested-name-specifier that precedes the member name, with source-location
/// information. /// information.
NestedNameSpecifierLoc getQualifierLoc() const { NestedNameSpecifierLoc getQualifierLoc() const {
if (!hasQualifierOrFoundDecl()) if (!hasQualifier())
return NestedNameSpecifierLoc(); return NestedNameSpecifierLoc();
return getTrailingObjects<MemberExprNameQualifier>()->QualifierLoc; return *getTrailingObjects<NestedNameSpecifierLoc>();
} }
/// If the member name was qualified, retrieves the /// 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_begin() const { return path_buffer(); }
path_const_iterator path_end() const { return path_buffer() + path_size(); } 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() { llvm::iterator_range<path_iterator> path() {
return llvm::make_range(path_begin(), path_end()); return llvm::make_range(path_begin(), path_end());
} }
@ -3558,6 +3602,11 @@ public:
return *getTrailingFPFeatures(); 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 /// Get the FP features status of this operation. Only meaningful for
/// operations on floating point types. /// operations on floating point types.
FPOptions getFPFeaturesInEffect(const LangOptions &LO) const { FPOptions getFPFeaturesInEffect(const LangOptions &LO) const {
@ -4004,6 +4053,10 @@ public:
assert(BinaryOperatorBits.HasFPFeatures); assert(BinaryOperatorBits.HasFPFeatures);
*getTrailingFPFeatures() = F; *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 /// Get the FP features status of this operator. Only meaningful for
/// operations on floating point types. /// operations on floating point types.
@ -4020,7 +4073,7 @@ public:
return FPOptionsOverride(); 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. /// operations on floating point types.
bool isFPContractableWithinStatement(const LangOptions &LO) const { bool isFPContractableWithinStatement(const LangOptions &LO) const {
return getFPFeaturesInEffect(LO).allowFPContractWithinStatement(); return getFPFeaturesInEffect(LO).allowFPContractWithinStatement();
@ -4261,7 +4314,7 @@ public:
} }
/// getFalseExpr - Return the subexpression which will be /// 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. /// defined in terms of the opaque value.
Expr *getFalseExpr() const { Expr *getFalseExpr() const {
return cast<Expr>(SubExprs[RHS]); return cast<Expr>(SubExprs[RHS]);
@ -4770,6 +4823,164 @@ private:
friend class ASTStmtReader; 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. /// Describes an C or C++ initializer list.
/// ///
/// InitListExpr describes an initializer list, which can be used to /// 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. // if *It1 and *It2 are bound to the same objects.
// An alternative design approach was discussed during review; // An alternative design approach was discussed during review;
// store an Association object inside the iterator, and return a reference // 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: // lifetime issues:
// AssociationIterator It = ...; // AssociationIterator It = ...;
// const Association &Assoc = *It++; // Oops, Assoc is dangling. // const Association &Assoc = *It++; // Oops, Assoc is dangling.
@ -5820,7 +6031,7 @@ class GenericSelectionExpr final
std::conditional_t<Const, const Stmt *const *, Stmt **>; std::conditional_t<Const, const Stmt *const *, Stmt **>;
using TSIPtrPtrTy = std::conditional_t<Const, const TypeSourceInfo *const *, using TSIPtrPtrTy = std::conditional_t<Const, const TypeSourceInfo *const *,
TypeSourceInfo **>; TypeSourceInfo **>;
StmtPtrPtrTy E; // = nullptr; FIXME: Once support for gcc 4.8 is dropped. StmtPtrPtrTy E = nullptr;
TSIPtrPtrTy TSI; // Kept in sync with E. TSIPtrPtrTy TSI; // Kept in sync with E.
unsigned Offset = 0, SelectedOffset = 0; unsigned Offset = 0, SelectedOffset = 0;
AssociationIteratorTy(StmtPtrPtrTy E, TSIPtrPtrTy TSI, unsigned Offset, AssociationIteratorTy(StmtPtrPtrTy E, TSIPtrPtrTy TSI, unsigned Offset,
@ -6410,7 +6621,7 @@ public:
enum AtomicOp { enum AtomicOp {
#define BUILTIN(ID, TYPE, ATTRS) #define BUILTIN(ID, TYPE, ATTRS)
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) AO ## ID, #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) AO ## ID,
#include "clang/Basic/Builtins.def" #include "clang/Basic/Builtins.inc"
// Avoid trailing comma // Avoid trailing comma
BI_First = 0 BI_First = 0
}; };
@ -6476,7 +6687,7 @@ public:
#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \
case AO##ID: \ case AO##ID: \
return #ID; return #ID;
#include "clang/Basic/Builtins.def" #include "clang/Basic/Builtins.inc"
} }
llvm_unreachable("not an atomic operator?"); llvm_unreachable("not an atomic operator?");
} }
@ -6505,8 +6716,8 @@ public:
} }
bool isOpenCL() const { bool isOpenCL() const {
return getOp() >= AO__opencl_atomic_init && return getOp() >= AO__opencl_atomic_compare_exchange_strong &&
getOp() <= AO__opencl_atomic_fetch_max; getOp() <= AO__opencl_atomic_store;
} }
SourceLocation getBuiltinLoc() const { return BuiltinLoc; } SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
@ -6531,11 +6742,14 @@ public:
/// \return empty atomic scope model if the atomic op code does not have /// \return empty atomic scope model if the atomic op code does not have
/// scope operand. /// scope operand.
static std::unique_ptr<AtomicScopeModel> getScopeModel(AtomicOp Op) { 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); 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); 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::Generic);
return AtomicScopeModel::create(AtomicScopeModelKind::None); 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 /// Frontend produces RecoveryExprs on semantic errors that prevent creating
/// other well-formed expressions. E.g. when type-checking of a binary operator /// other well-formed expressions. E.g. when type-checking of a binary operator
/// fails, we cannot produce a BinaryOperator expression. Instead, we can choose /// 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); reinterpret_cast<Stmt **>(&const_cast<CXXTypeidExpr *>(this)->Operand);
return const_child_range(begin, begin + 1); 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. /// A member reference to an MSPropertyDecl.
@ -1149,6 +1153,7 @@ class CXXThisExpr : public Expr {
CXXThisExpr(SourceLocation L, QualType Ty, bool IsImplicit, ExprValueKind VK) CXXThisExpr(SourceLocation L, QualType Ty, bool IsImplicit, ExprValueKind VK)
: Expr(CXXThisExprClass, Ty, VK, OK_Ordinary) { : Expr(CXXThisExprClass, Ty, VK, OK_Ordinary) {
CXXThisExprBits.IsImplicit = IsImplicit; CXXThisExprBits.IsImplicit = IsImplicit;
CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = false;
CXXThisExprBits.Loc = L; CXXThisExprBits.Loc = L;
setDependence(computeDependence(this)); setDependence(computeDependence(this));
} }
@ -1170,6 +1175,15 @@ public:
bool isImplicit() const { return CXXThisExprBits.IsImplicit; } bool isImplicit() const { return CXXThisExprBits.IsImplicit; }
void setImplicit(bool I) { CXXThisExprBits.IsImplicit = I; } 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) { static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXThisExprClass; return T->getStmtClass() == CXXThisExprClass;
} }
@ -1472,6 +1486,8 @@ public:
/// const S &s_ref = S(); // Requires a CXXBindTemporaryExpr. /// const S &s_ref = S(); // Requires a CXXBindTemporaryExpr.
/// } /// }
/// \endcode /// \endcode
///
/// Destructor might be null if destructor declaration is not valid.
class CXXBindTemporaryExpr : public Expr { class CXXBindTemporaryExpr : public Expr {
CXXTemporary *Temp = nullptr; CXXTemporary *Temp = nullptr;
Stmt *SubExpr = nullptr; Stmt *SubExpr = nullptr;
@ -2549,7 +2565,7 @@ public:
class PseudoDestructorTypeStorage { class PseudoDestructorTypeStorage {
/// Either the type source information or the name of the type, if /// Either the type source information or the name of the type, if
/// it couldn't be resolved due to type-dependence. /// 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. /// The starting source location of the pseudo-destructor type.
SourceLocation Location; SourceLocation Location;
@ -2557,7 +2573,7 @@ class PseudoDestructorTypeStorage {
public: public:
PseudoDestructorTypeStorage() = default; PseudoDestructorTypeStorage() = default;
PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc) PseudoDestructorTypeStorage(const IdentifierInfo *II, SourceLocation Loc)
: Type(II), Location(Loc) {} : Type(II), Location(Loc) {}
PseudoDestructorTypeStorage(TypeSourceInfo *Info); PseudoDestructorTypeStorage(TypeSourceInfo *Info);
@ -2566,8 +2582,8 @@ public:
return Type.dyn_cast<TypeSourceInfo *>(); return Type.dyn_cast<TypeSourceInfo *>();
} }
IdentifierInfo *getIdentifier() const { const IdentifierInfo *getIdentifier() const {
return Type.dyn_cast<IdentifierInfo *>(); return Type.dyn_cast<const IdentifierInfo *>();
} }
SourceLocation getLocation() const { return Location; } SourceLocation getLocation() const { return Location; }
@ -2698,7 +2714,7 @@ public:
/// In a dependent pseudo-destructor expression for which we do not /// In a dependent pseudo-destructor expression for which we do not
/// have full type information on the destroyed type, provides the name /// have full type information on the destroyed type, provides the name
/// of the destroyed type. /// of the destroyed type.
IdentifierInfo *getDestroyedTypeIdentifier() const { const IdentifierInfo *getDestroyedTypeIdentifier() const {
return DestroyedType.getIdentifier(); return DestroyedType.getIdentifier();
} }
@ -3013,9 +3029,10 @@ protected:
public: public:
struct FindResult { struct FindResult {
OverloadExpr *Expression; OverloadExpr *Expression = nullptr;
bool IsAddressOfOperand; bool IsAddressOfOperand = false;
bool HasFormOfMemberPointer; bool IsAddressOfOperandWithParen = false;
bool HasFormOfMemberPointer = false;
}; };
/// Finds the overloaded expression in the given expression \p E of /// Finds the overloaded expression in the given expression \p E of
@ -3027,6 +3044,7 @@ public:
assert(E->getType()->isSpecificBuiltinType(BuiltinType::Overload)); assert(E->getType()->isSpecificBuiltinType(BuiltinType::Overload));
FindResult Result; FindResult Result;
bool HasParen = isa<ParenExpr>(E);
E = E->IgnoreParens(); E = E->IgnoreParens();
if (isa<UnaryOperator>(E)) { if (isa<UnaryOperator>(E)) {
@ -3036,10 +3054,9 @@ public:
Result.HasFormOfMemberPointer = (E == Ovl && Ovl->getQualifier()); Result.HasFormOfMemberPointer = (E == Ovl && Ovl->getQualifier());
Result.IsAddressOfOperand = true; Result.IsAddressOfOperand = true;
Result.IsAddressOfOperandWithParen = HasParen;
Result.Expression = Ovl; Result.Expression = Ovl;
} else { } else {
Result.HasFormOfMemberPointer = false;
Result.IsAddressOfOperand = false;
Result.Expression = cast<OverloadExpr>(E); Result.Expression = cast<OverloadExpr>(E);
} }
@ -3151,8 +3168,30 @@ public:
/// This arises in several ways: /// This arises in several ways:
/// * we might be waiting for argument-dependent lookup; /// * we might be waiting for argument-dependent lookup;
/// * the name might resolve to an overloaded function; /// * 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: /// and eventually:
/// * the lookup might have included a function template. /// * 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 /// These never include UnresolvedUsingValueDecls, which are always class
/// members and therefore appear only in UnresolvedMemberLookupExprs. /// members and therefore appear only in UnresolvedMemberLookupExprs.
@ -3188,7 +3227,6 @@ class UnresolvedLookupExpr final
NestedNameSpecifierLoc QualifierLoc, NestedNameSpecifierLoc QualifierLoc,
SourceLocation TemplateKWLoc, SourceLocation TemplateKWLoc,
const DeclarationNameInfo &NameInfo, bool RequiresADL, const DeclarationNameInfo &NameInfo, bool RequiresADL,
bool Overloaded,
const TemplateArgumentListInfo *TemplateArgs, const TemplateArgumentListInfo *TemplateArgs,
UnresolvedSetIterator Begin, UnresolvedSetIterator End, UnresolvedSetIterator Begin, UnresolvedSetIterator End,
bool KnownDependent); bool KnownDependent);
@ -3208,8 +3246,9 @@ public:
static UnresolvedLookupExpr * static UnresolvedLookupExpr *
Create(const ASTContext &Context, CXXRecordDecl *NamingClass, Create(const ASTContext &Context, CXXRecordDecl *NamingClass,
NestedNameSpecifierLoc QualifierLoc, NestedNameSpecifierLoc QualifierLoc,
const DeclarationNameInfo &NameInfo, bool RequiresADL, bool Overloaded, const DeclarationNameInfo &NameInfo, bool RequiresADL,
UnresolvedSetIterator Begin, UnresolvedSetIterator End); UnresolvedSetIterator Begin, UnresolvedSetIterator End,
bool KnownDependent);
// After canonicalization, there may be dependent template arguments in // After canonicalization, there may be dependent template arguments in
// CanonicalConverted But none of Args is dependent. When any of // CanonicalConverted But none of Args is dependent. When any of
@ -3230,9 +3269,6 @@ public:
/// argument-dependent lookup. /// argument-dependent lookup.
bool requiresADL() const { return UnresolvedLookupExprBits.RequiresADL; } 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 /// Gets the 'naming class' (in the sense of C++0x
/// [class.access.base]p5) of the lookup. This is the scope /// [class.access.base]p5) of the lookup. This is the scope
/// that was looked in to find these results. /// 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 /// Represents a reference to a non-type template parameter
/// that has been substituted with a template argument. /// that has been substituted with a template argument.
class SubstNonTypeTemplateParmExpr : public Expr { class SubstNonTypeTemplateParmExpr : public Expr {
@ -4939,6 +5085,9 @@ class CoroutineSuspendExpr : public Expr {
OpaqueValueExpr *OpaqueValue = nullptr; OpaqueValueExpr *OpaqueValue = nullptr;
public: 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, CoroutineSuspendExpr(StmtClass SC, SourceLocation KeywordLoc, Expr *Operand,
Expr *Common, Expr *Ready, Expr *Suspend, Expr *Resume, Expr *Common, Expr *Ready, Expr *Suspend, Expr *Resume,
OpaqueValueExpr *OpaqueValue) OpaqueValueExpr *OpaqueValue)
@ -4998,6 +5147,24 @@ public:
return static_cast<Expr *>(SubExprs[SubExpr::Operand]); 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 getKeywordLoc() const { return KeywordLoc; }
SourceLocation getBeginLoc() const LLVM_READONLY { return KeywordLoc; } SourceLocation getBeginLoc() const LLVM_READONLY { return KeywordLoc; }

View file

@ -17,130 +17,6 @@
#include "clang/AST/Expr.h" #include "clang/AST/Expr.h"
namespace clang { 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 /// 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. /// ([s1][s2]...[sn])expr. For example: @c ([3][3])f.
class OMPArrayShapingExpr final class OMPArrayShapingExpr final

View file

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

View file

@ -171,6 +171,14 @@ public:
ZArg, // MS extension 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. // Objective-C specific specifiers.
ObjCObjArg, // '@' ObjCObjArg, // '@'
ObjCBeg = ObjCObjArg, ObjCBeg = ObjCObjArg,
@ -237,6 +245,9 @@ public:
bool isDoubleArg() const { bool isDoubleArg() const {
return kind >= DoubleArgBeg && kind <= DoubleArgEnd; return kind >= DoubleArgBeg && kind <= DoubleArgEnd;
} }
bool isFixedPointArg() const {
return kind >= FixedPointArgBeg && kind <= FixedPointArgEnd;
}
const char *toString() const; const char *toString() const;
@ -273,6 +284,8 @@ public:
/// The conversion specifier and the argument type are disallowed by the C /// The conversion specifier and the argument type are disallowed by the C
/// standard, but are in practice harmless. For instance, "%p" and int*. /// standard, but are in practice harmless. For instance, "%p" and int*.
NoMatchPedantic, NoMatchPedantic,
/// The conversion specifier and the argument type have different sign.
NoMatchSignedness,
/// The conversion specifier and the argument type are compatible, but still /// The conversion specifier and the argument type are compatible, but still
/// seems likely to be an error. For instance, "%hd" and _Bool. /// seems likely to be an error. For instance, "%hd" and _Bool.
NoMatchTypeConfusion, NoMatchTypeConfusion,

View file

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

View file

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

View file

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

View file

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

View file

@ -361,6 +361,12 @@ CAST_OPERATION(AddressSpaceConversion)
// Convert an integer initializer to an OpenCL sampler. // Convert an integer initializer to an OpenCL sampler.
CAST_OPERATION(IntToOCLSampler) 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 -------------------------------------------------===// //===- Binary Operations -------------------------------------------------===//
// Operators listed in order of precedence. // Operators listed in order of precedence.
// Note that additions to this should also update the StmtVisitor class, // 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. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information. // See https://llvm.org/LICENSE.txt for license information.

View file

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

View file

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

View file

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

View file

@ -30,10 +30,12 @@
#include "clang/AST/ExprOpenMP.h" #include "clang/AST/ExprOpenMP.h"
#include "clang/AST/LambdaCapture.h" #include "clang/AST/LambdaCapture.h"
#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/OpenACCClause.h"
#include "clang/AST/OpenMPClause.h" #include "clang/AST/OpenMPClause.h"
#include "clang/AST/Stmt.h" #include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h" #include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h" #include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtOpenMP.h"
#include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h" #include "clang/AST/TemplateName.h"
@ -505,6 +507,11 @@ private:
bool VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *Node); bool VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *Node);
bool PostVisitStmt(Stmt *S); bool PostVisitStmt(Stmt *S);
bool TraverseOpenACCConstructStmt(OpenACCConstructStmt *S);
bool
TraverseOpenACCAssociatedStmtConstruct(OpenACCAssociatedStmtConstruct *S);
bool VisitOpenACCClauseList(ArrayRef<const OpenACCClause *>);
bool VisitOpenACCClause(const OpenACCClause *);
}; };
template <typename Derived> 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 // As a syntax visitor, by default we want to ignore declarations for
// implicit declarations (ones not typed explicitly by the user). // implicit declarations (ones not typed explicitly by the user).
if (!getDerived().shouldVisitImplicitCode() && D->isImplicit()) { if (!getDerived().shouldVisitImplicitCode()) {
// For an implicit template type parameter, its type constraints are not if (D->isImplicit()) {
// implicit and are not represented anywhere else. We still need to visit // For an implicit template type parameter, its type constraints are not
// them. // implicit and are not represented anywhere else. We still need to visit
if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(D)) // them.
return TraverseTemplateTypeParamDeclConstraints(TTPD); if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(D))
return true; 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()) { switch (D->getKind()) {
@ -834,10 +855,14 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclarationNameInfo(
template <typename Derived> template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseTemplateName(TemplateName Template) { bool RecursiveASTVisitor<Derived>::TraverseTemplateName(TemplateName Template) {
if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) {
TRY_TO(TraverseNestedNameSpecifier(DTN->getQualifier())); TRY_TO(TraverseNestedNameSpecifier(DTN->getQualifier()));
else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) } else if (QualifiedTemplateName *QTN =
TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier())); Template.getAsQualifiedTemplateName()) {
if (QTN->getQualifier()) {
TRY_TO(TraverseNestedNameSpecifier(QTN->getQualifier()));
}
}
return true; return true;
} }
@ -989,6 +1014,12 @@ DEF_TRAVERSE_TYPE(ConstantArrayType, {
TRY_TO(TraverseStmt(const_cast<Expr*>(T->getSizeExpr()))); 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, DEF_TRAVERSE_TYPE(IncompleteArrayType,
{ TRY_TO(TraverseType(T->getElementType())); }) { TRY_TO(TraverseType(T->getElementType())); })
@ -1065,6 +1096,11 @@ DEF_TRAVERSE_TYPE(TypeOfType, { TRY_TO(TraverseType(T->getUnmodifiedType())); })
DEF_TRAVERSE_TYPE(DecltypeType, DEF_TRAVERSE_TYPE(DecltypeType,
{ TRY_TO(TraverseStmt(T->getUnderlyingExpr())); }) { TRY_TO(TraverseStmt(T->getUnderlyingExpr())); })
DEF_TRAVERSE_TYPE(PackIndexingType, {
TRY_TO(TraverseType(T->getPattern()));
TRY_TO(TraverseStmt(T->getIndexExpr()));
})
DEF_TRAVERSE_TYPE(UnaryTransformType, { DEF_TRAVERSE_TYPE(UnaryTransformType, {
TRY_TO(TraverseType(T->getBaseType())); TRY_TO(TraverseType(T->getBaseType()));
TRY_TO(TraverseType(T->getUnderlyingType())); TRY_TO(TraverseType(T->getUnderlyingType()));
@ -1101,6 +1137,12 @@ DEF_TRAVERSE_TYPE(InjectedClassNameType, {})
DEF_TRAVERSE_TYPE(AttributedType, DEF_TRAVERSE_TYPE(AttributedType,
{ TRY_TO(TraverseType(T->getModifiedType())); }) { 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, DEF_TRAVERSE_TYPE(BTFTagAttributedType,
{ TRY_TO(TraverseType(T->getWrappedType())); }) { TRY_TO(TraverseType(T->getWrappedType())); })
@ -1245,6 +1287,11 @@ DEF_TRAVERSE_TYPELOC(ConstantArrayType, {
TRY_TO(TraverseArrayTypeLocHelper(TL)); TRY_TO(TraverseArrayTypeLocHelper(TL));
}) })
DEF_TRAVERSE_TYPELOC(ArrayParameterType, {
TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
TRY_TO(TraverseArrayTypeLocHelper(TL));
})
DEF_TRAVERSE_TYPELOC(IncompleteArrayType, { DEF_TRAVERSE_TYPELOC(IncompleteArrayType, {
TRY_TO(TraverseTypeLoc(TL.getElementLoc())); TRY_TO(TraverseTypeLoc(TL.getElementLoc()));
TRY_TO(TraverseArrayTypeLocHelper(TL)); TRY_TO(TraverseArrayTypeLocHelper(TL));
@ -1343,6 +1390,11 @@ DEF_TRAVERSE_TYPELOC(DecltypeType, {
TRY_TO(TraverseStmt(TL.getTypePtr()->getUnderlyingExpr())); 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, { DEF_TRAVERSE_TYPELOC(UnaryTransformType, {
TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc())); TRY_TO(TraverseTypeLoc(TL.getUnderlyingTInfo()->getTypeLoc()));
}) })
@ -1387,6 +1439,9 @@ DEF_TRAVERSE_TYPELOC(MacroQualifiedType,
DEF_TRAVERSE_TYPELOC(AttributedType, DEF_TRAVERSE_TYPELOC(AttributedType,
{ TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); }) { TRY_TO(TraverseTypeLoc(TL.getModifiedLoc())); })
DEF_TRAVERSE_TYPELOC(CountAttributedType,
{ TRY_TO(TraverseTypeLoc(TL.getInnerLoc())); })
DEF_TRAVERSE_TYPELOC(BTFTagAttributedType, DEF_TRAVERSE_TYPELOC(BTFTagAttributedType,
{ TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); }) { TRY_TO(TraverseTypeLoc(TL.getWrappedLoc())); })
@ -1911,7 +1966,7 @@ DEF_TRAVERSE_DECL(TemplateTypeParmDecl, {
TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0))); TRY_TO(TraverseType(QualType(D->getTypeForDecl(), 0)));
TRY_TO(TraverseTemplateTypeParamDeclConstraints(D)); TRY_TO(TraverseTemplateTypeParamDeclConstraints(D));
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
TRY_TO(TraverseTypeLoc(D->getDefaultArgumentInfo()->getTypeLoc())); TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument()));
}) })
DEF_TRAVERSE_DECL(TypedefDecl, { DEF_TRAVERSE_DECL(TypedefDecl, {
@ -1995,6 +2050,15 @@ DEF_TRAVERSE_DECL(RecordDecl, { TRY_TO(TraverseRecordHelper(D)); })
DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(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) \ #define DEF_TRAVERSE_TMPL_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, { \ DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, { \
/* For implicit instantiations ("set<int> x;"), we don't want to \ /* 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 \ TemplateSpecializationType). For explicit instantiations \
("template set<int>;"), we do need a callback, since this \ ("template set<int>;"), we do need a callback, since this \
is the only callback that's made for this instantiation. \ is the only callback that's made for this instantiation. \
We use getTypeAsWritten() to distinguish. */ \ We use getTemplateArgsAsWritten() to distinguish. */ \
if (TypeSourceInfo *TSI = D->getTypeAsWritten()) \ if (const auto *ArgsWritten = D->getTemplateArgsAsWritten()) { \
TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); \ /* The args that remains unspecialized. */ \
TRY_TO(TraverseTemplateArgumentLocsHelper( \
ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs)); \
} \
\ \
if (getDerived().shouldVisitTemplateInstantiations() || \ if (getDerived().shouldVisitTemplateInstantiations() || \
D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { \ 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(Class, CXXRecord)
DEF_TRAVERSE_TMPL_SPEC_DECL(Var, Var) 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) \ #define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND) \
DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \ DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, { \
/* The partial specialization. */ \ /* 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 ... // A non-type template parameter, e.g. "S" in template<int S> class Foo ...
TRY_TO(TraverseDeclaratorHelper(D)); TRY_TO(TraverseDeclaratorHelper(D));
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited())
TRY_TO(TraverseStmt(D->getDefaultArgument())); TRY_TO(TraverseTemplateArgumentLoc(D->getDefaultArgument()));
}) })
DEF_TRAVERSE_DECL(ParmVarDecl, { DEF_TRAVERSE_DECL(ParmVarDecl, {
@ -2705,7 +2763,7 @@ DEF_TRAVERSE_STMT(CXXMemberCallExpr, {})
DEF_TRAVERSE_STMT(AddrLabelExpr, {}) DEF_TRAVERSE_STMT(AddrLabelExpr, {})
DEF_TRAVERSE_STMT(ArraySubscriptExpr, {}) DEF_TRAVERSE_STMT(ArraySubscriptExpr, {})
DEF_TRAVERSE_STMT(MatrixSubscriptExpr, {}) DEF_TRAVERSE_STMT(MatrixSubscriptExpr, {})
DEF_TRAVERSE_STMT(OMPArraySectionExpr, {}) DEF_TRAVERSE_STMT(ArraySectionExpr, {})
DEF_TRAVERSE_STMT(OMPArrayShapingExpr, {}) DEF_TRAVERSE_STMT(OMPArrayShapingExpr, {})
DEF_TRAVERSE_STMT(OMPIteratorExpr, {}) DEF_TRAVERSE_STMT(OMPIteratorExpr, {})
@ -2806,6 +2864,11 @@ DEF_TRAVERSE_STMT(ShuffleVectorExpr, {})
DEF_TRAVERSE_STMT(ConvertVectorExpr, {}) DEF_TRAVERSE_STMT(ConvertVectorExpr, {})
DEF_TRAVERSE_STMT(StmtExpr, {}) DEF_TRAVERSE_STMT(StmtExpr, {})
DEF_TRAVERSE_STMT(SourceLocExpr, {}) 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, { DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc())); TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
@ -2854,6 +2917,7 @@ DEF_TRAVERSE_STMT(CompoundAssignOperator, {})
DEF_TRAVERSE_STMT(CXXNoexceptExpr, {}) DEF_TRAVERSE_STMT(CXXNoexceptExpr, {})
DEF_TRAVERSE_STMT(PackExpansionExpr, {}) DEF_TRAVERSE_STMT(PackExpansionExpr, {})
DEF_TRAVERSE_STMT(SizeOfPackExpr, {}) DEF_TRAVERSE_STMT(SizeOfPackExpr, {})
DEF_TRAVERSE_STMT(PackIndexingExpr, {})
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {}) DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmPackExpr, {})
DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {}) DEF_TRAVERSE_STMT(SubstNonTypeTemplateParmExpr, {})
DEF_TRAVERSE_STMT(FunctionParmPackExpr, {}) DEF_TRAVERSE_STMT(FunctionParmPackExpr, {})
@ -2968,6 +3032,12 @@ DEF_TRAVERSE_STMT(OMPTileDirective,
DEF_TRAVERSE_STMT(OMPUnrollDirective, DEF_TRAVERSE_STMT(OMPUnrollDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); }) { TRY_TO(TraverseOMPExecutableDirective(S)); })
DEF_TRAVERSE_STMT(OMPReverseDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
DEF_TRAVERSE_STMT(OMPInterchangeDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
DEF_TRAVERSE_STMT(OMPForDirective, DEF_TRAVERSE_STMT(OMPForDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); }) { TRY_TO(TraverseOMPExecutableDirective(S)); })
@ -3425,6 +3495,11 @@ bool RecursiveASTVisitor<Derived>::VisitOMPRelaxedClause(OMPRelaxedClause *) {
return true; return true;
} }
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPWeakClause(OMPWeakClause *) {
return true;
}
template <typename Derived> template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPThreadsClause(OMPThreadsClause *) { bool RecursiveASTVisitor<Derived>::VisitOMPThreadsClause(OMPThreadsClause *) {
return true; return true;
@ -3894,6 +3969,51 @@ bool RecursiveASTVisitor<Derived>::VisitOMPXBareClause(OMPXBareClause *C) {
return true; 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 // FIXME: look at the following tricky-seeming exprs to see if we
// need to recurse on anything. These are ones that have methods // need to recurse on anything. These are ones that have methods
// returning decls or qualtypes or nestednamespecifier -- though I'm // returning decls or qualtypes or nestednamespecifier -- though I'm

View file

@ -281,10 +281,10 @@ public:
return tmp; 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; 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; return x.Current != y.Current;
} }
}; };

View file

@ -460,10 +460,10 @@ protected:
unsigned : NumExprBits; unsigned : NumExprBits;
static_assert( static_assert(
llvm::APFloat::S_MaxSemantics < 16, llvm::APFloat::S_MaxSemantics < 32,
"Too many Semantics enum values to fit in bitfield of size 4"); "Too many Semantics enum values to fit in bitfield of size 5");
LLVM_PREFERRED_TYPE(llvm::APFloat::Semantics) 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) LLVM_PREFERRED_TYPE(bool)
unsigned IsExact : 1; unsigned IsExact : 1;
}; };
@ -583,11 +583,13 @@ protected:
unsigned IsArrow : 1; unsigned IsArrow : 1;
/// True if this member expression used a nested-name-specifier to /// 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 /// refer to the member, e.g., "x->Base::f".
/// a using declaration. When true, a MemberExprNameQualifier
/// structure is allocated immediately after the MemberExpr.
LLVM_PREFERRED_TYPE(bool) 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 /// True if this member expression specified a template keyword
/// and/or a template argument list explicitly, e.g., x->f<int>, /// and/or a template argument list explicitly, e.g., x->f<int>,
@ -782,6 +784,11 @@ protected:
LLVM_PREFERRED_TYPE(bool) LLVM_PREFERRED_TYPE(bool)
unsigned IsImplicit : 1; 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". /// The location of the "this".
SourceLocation Loc; SourceLocation Loc;
}; };
@ -1060,11 +1067,6 @@ protected:
/// argument-dependent lookup if this is the operand of a function call. /// argument-dependent lookup if this is the operand of a function call.
LLVM_PREFERRED_TYPE(bool) LLVM_PREFERRED_TYPE(bool)
unsigned RequiresADL : 1; 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, static_assert(sizeof(UnresolvedLookupExprBitfields) <= 4,
"UnresolvedLookupExprBitfields must be <= than 4 bytes to" "UnresolvedLookupExprBitfields must be <= than 4 bytes to"
@ -1656,6 +1658,11 @@ public:
return *getTrailingObjects<FPOptionsOverride>(); 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_iterator = Stmt **;
using body_range = llvm::iterator_range<body_iterator>; using body_range = llvm::iterator_range<body_iterator>;

View file

@ -177,7 +177,8 @@ class ObjCAtTryStmt final
unsigned NumCatchStmts : 16; unsigned NumCatchStmts : 16;
// Whether this statement has a \@finally statement. // 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. /// 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; Stmt *getPreInits() const;
static bool classof(const Stmt *T) { static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPTileDirectiveClass || Stmt::StmtClass C = T->getStmtClass();
T->getStmtClass() == OMPUnrollDirectiveClass; 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 /// 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 /// second. Required for correct codegen of non-associative operations (like
/// << or >>). /// << or >>).
LLVM_PREFERRED_TYPE(bool)
uint8_t IsXLHSInRHSPart : 1; uint8_t IsXLHSInRHSPart : 1;
/// Used for 'atomic update' or 'atomic capture' constructs. They may /// Used for 'atomic update' or 'atomic capture' constructs. They may
/// have atomic expressions of forms: /// have atomic expressions of forms:
@ -2983,9 +2985,11 @@ class OMPAtomicDirective : public OMPExecutableDirective {
/// \endcode /// \endcode
/// This field is 1 for the first(postfix) form of the expression and 0 /// This field is 1 for the first(postfix) form of the expression and 0
/// otherwise. /// otherwise.
LLVM_PREFERRED_TYPE(bool)
uint8_t IsPostfixUpdate : 1; uint8_t IsPostfixUpdate : 1;
/// 1 if 'v' is updated only when the condition is false (compare capture /// 1 if 'v' is updated only when the condition is false (compare capture
/// only). /// only).
LLVM_PREFERRED_TYPE(bool)
uint8_t IsFailOnly : 1; uint8_t IsFailOnly : 1;
} Flags; } 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. /// This represents '#pragma omp scan' directive.
/// ///
/// \code /// \code
@ -6106,6 +6248,8 @@ public:
class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective { class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
friend class ASTStmtReader; friend class ASTStmtReader;
friend class OMPExecutableDirective; 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. /// Build directive with the given start and end location.
/// ///
/// \param StartLoc Starting location of the directive kind. /// \param StartLoc Starting location of the directive kind.
@ -6128,6 +6272,9 @@ class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
llvm::omp::OMPD_target_teams_loop, SourceLocation(), llvm::omp::OMPD_target_teams_loop, SourceLocation(),
SourceLocation(), CollapsedNum) {} SourceLocation(), CollapsedNum) {}
/// Set whether associated loop can be a parallel for.
void setCanBeParallelFor(bool ParFor) { CanBeParallelFor = ParFor; }
public: public:
/// Creates directive with a list of \p Clauses. /// Creates directive with a list of \p Clauses.
/// ///
@ -6142,7 +6289,7 @@ public:
static OMPTargetTeamsGenericLoopDirective * static OMPTargetTeamsGenericLoopDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
Stmt *AssociatedStmt, const HelperExprs &Exprs); Stmt *AssociatedStmt, const HelperExprs &Exprs, bool CanBeParallelFor);
/// Creates an empty directive with the place /// Creates an empty directive with the place
/// for \a NumClauses clauses. /// for \a NumClauses clauses.
@ -6156,6 +6303,10 @@ public:
unsigned CollapsedNum, unsigned CollapsedNum,
EmptyShell); 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) { static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPTargetTeamsGenericLoopDirectiveClass; return T->getStmtClass() == OMPTargetTeamsGenericLoopDirectiveClass;
} }

View file

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

View file

@ -459,7 +459,7 @@ public:
bool IncludeType) const; bool IncludeType) const;
/// Debugging aid that dumps the template argument. /// 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. /// Debugging aid that dumps the template argument to standard error.
void dump() const; void dump() const;

View file

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

View file

@ -24,6 +24,7 @@
#include "clang/AST/StmtVisitor.h" #include "clang/AST/StmtVisitor.h"
#include "clang/AST/TemplateArgumentVisitor.h" #include "clang/AST/TemplateArgumentVisitor.h"
#include "clang/AST/Type.h" #include "clang/AST/Type.h"
#include "clang/AST/TypeLocVisitor.h"
#include "clang/AST/TypeVisitor.h" #include "clang/AST/TypeVisitor.h"
namespace clang { namespace clang {
@ -132,6 +133,7 @@ class TextNodeDumper
public ConstTemplateArgumentVisitor<TextNodeDumper>, public ConstTemplateArgumentVisitor<TextNodeDumper>,
public ConstStmtVisitor<TextNodeDumper>, public ConstStmtVisitor<TextNodeDumper>,
public TypeVisitor<TextNodeDumper>, public TypeVisitor<TextNodeDumper>,
public TypeLocVisitor<TextNodeDumper>,
public ConstDeclVisitor<TextNodeDumper> { public ConstDeclVisitor<TextNodeDumper> {
raw_ostream &OS; raw_ostream &OS;
const bool ShowColors; const bool ShowColors;
@ -179,12 +181,16 @@ public:
void Visit(QualType T); void Visit(QualType T);
void Visit(TypeLoc);
void Visit(const Decl *D); void Visit(const Decl *D);
void Visit(const CXXCtorInitializer *Init); void Visit(const CXXCtorInitializer *Init);
void Visit(const OMPClause *C); void Visit(const OMPClause *C);
void Visit(const OpenACCClause *C);
void Visit(const BlockDecl::Capture &C); void Visit(const BlockDecl::Capture &C);
void Visit(const GenericSelectionExpr::ConstAssociation &A); void Visit(const GenericSelectionExpr::ConstAssociation &A);
@ -207,6 +213,9 @@ public:
void dumpTemplateSpecializationKind(TemplateSpecializationKind TSK); void dumpTemplateSpecializationKind(TemplateSpecializationKind TSK);
void dumpNestedNameSpecifier(const NestedNameSpecifier *NNS); void dumpNestedNameSpecifier(const NestedNameSpecifier *NNS);
void dumpConceptReference(const ConceptReference *R); 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 = {}); void dumpDeclRef(const Decl *D, StringRef Label = {});
@ -291,6 +300,8 @@ public:
void VisitTypeTraitExpr(const TypeTraitExpr *Node); void VisitTypeTraitExpr(const TypeTraitExpr *Node);
void VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *Node); void VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *Node);
void VisitExpressionTraitExpr(const ExpressionTraitExpr *Node); void VisitExpressionTraitExpr(const ExpressionTraitExpr *Node);
void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node);
void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node);
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node); void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node);
void VisitExprWithCleanups(const ExprWithCleanups *Node); void VisitExprWithCleanups(const ExprWithCleanups *Node);
void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node); void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node);
@ -337,6 +348,8 @@ public:
void VisitObjCInterfaceType(const ObjCInterfaceType *T); void VisitObjCInterfaceType(const ObjCInterfaceType *T);
void VisitPackExpansionType(const PackExpansionType *T); void VisitPackExpansionType(const PackExpansionType *T);
void VisitTypeLoc(TypeLoc TL);
void VisitLabelDecl(const LabelDecl *D); void VisitLabelDecl(const LabelDecl *D);
void VisitTypedefDecl(const TypedefDecl *D); void VisitTypedefDecl(const TypedefDecl *D);
void VisitEnumDecl(const EnumDecl *D); void VisitEnumDecl(const EnumDecl *D);
@ -344,6 +357,7 @@ public:
void VisitEnumConstantDecl(const EnumConstantDecl *D); void VisitEnumConstantDecl(const EnumConstantDecl *D);
void VisitIndirectFieldDecl(const IndirectFieldDecl *D); void VisitIndirectFieldDecl(const IndirectFieldDecl *D);
void VisitFunctionDecl(const FunctionDecl *D); void VisitFunctionDecl(const FunctionDecl *D);
void VisitCXXDeductionGuideDecl(const CXXDeductionGuideDecl *D);
void VisitFieldDecl(const FieldDecl *D); void VisitFieldDecl(const FieldDecl *D);
void VisitVarDecl(const VarDecl *D); void VisitVarDecl(const VarDecl *D);
void VisitBindingDecl(const BindingDecl *D); void VisitBindingDecl(const BindingDecl *D);
@ -393,6 +407,9 @@ public:
void void
VisitLifetimeExtendedTemporaryDecl(const LifetimeExtendedTemporaryDecl *D); VisitLifetimeExtendedTemporaryDecl(const LifetimeExtendedTemporaryDecl *D);
void VisitHLSLBufferDecl(const HLSLBufferDecl *D); void VisitHLSLBufferDecl(const HLSLBufferDecl *D);
void VisitOpenACCConstructStmt(const OpenACCConstructStmt *S);
void VisitOpenACCLoopConstruct(const OpenACCLoopConstruct *S);
void VisitEmbedExpr(const EmbedExpr *S);
}; };
} // namespace clang } // 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. /// pointer types, but not through decltype or typedefs.
AutoTypeLoc getContainedAutoTypeLoc() const; AutoTypeLoc getContainedAutoTypeLoc() const;
/// Get the SourceLocation of the template keyword (if any).
SourceLocation getTemplateKeywordLoc() const;
/// Initializes this to state that every location in this /// Initializes this to state that every location in this
/// type is the given location. /// type is the given location.
/// ///
@ -229,6 +232,9 @@ public:
/// __nullable, or __null_unspecifier), if there is one. /// __nullable, or __null_unspecifier), if there is one.
SourceLocation findNullabilityLoc() const; SourceLocation findNullabilityLoc() const;
void dump() const;
void dump(llvm::raw_ostream &, const ASTContext &) const;
private: private:
static bool isKind(const TypeLoc&) { static bool isKind(const TypeLoc&) {
return true; return true;
@ -884,6 +890,10 @@ public:
return getInnerTypeLoc(); return getInnerTypeLoc();
} }
TypeLoc getEquivalentTypeLoc() const {
return TypeLoc(getTypePtr()->getEquivalentType(), getNonLocalData());
}
/// The type attribute. /// The type attribute.
const Attr *getAttr() const { const Attr *getAttr() const {
return getLocalData()->TypeAttr; 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 { struct MacroQualifiedLocInfo {
SourceLocation ExpansionLoc; SourceLocation ExpansionLoc;
}; };
@ -1575,6 +1611,11 @@ class ConstantArrayTypeLoc :
ConstantArrayType> { ConstantArrayType> {
}; };
/// Wrapper for source info for array parameter types.
class ArrayParameterTypeLoc
: public InheritingConcreteTypeLoc<
ConstantArrayTypeLoc, ArrayParameterTypeLoc, ArrayParameterType> {};
class IncompleteArrayTypeLoc : class IncompleteArrayTypeLoc :
public InheritingConcreteTypeLoc<ArrayTypeLoc, public InheritingConcreteTypeLoc<ArrayTypeLoc,
IncompleteArrayTypeLoc, IncompleteArrayTypeLoc,
@ -1684,7 +1725,7 @@ public:
} }
void initializeLocal(ASTContext &Context, SourceLocation Loc) { void initializeLocal(ASTContext &Context, SourceLocation Loc) {
setTemplateKeywordLoc(Loc); setTemplateKeywordLoc(SourceLocation());
setTemplateNameLoc(Loc); setTemplateNameLoc(Loc);
setLAngleLoc(Loc); setLAngleLoc(Loc);
setRAngleLoc(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 { struct UnaryTransformTypeLocInfo {
// FIXME: While there's only one unary transform right now, future ones may // FIXME: While there's only one unary transform right now, future ones may
// need different representations // need different representations

View file

@ -25,6 +25,25 @@ let Class = PointerType in {
def : Creator<[{ return ctx.getPointerType(pointeeType); }]>; 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 { let Class = AdjustedType in {
def : Property<"originalType", QualType> { def : Property<"originalType", QualType> {
let Read = [{ node->getOriginalType() }]; 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 { let Class = IncompleteArrayType in {
def : Creator<[{ def : Creator<[{
return ctx.getIncompleteArrayType(elementType, sizeModifier, return ctx.getIncompleteArrayType(elementType, sizeModifier,
@ -326,6 +352,12 @@ let Class = FunctionProtoType in {
def : Property<"AArch64SMEAttributes", UInt32> { def : Property<"AArch64SMEAttributes", UInt32> {
let Read = [{ node->getAArch64SMEAttributes() }]; let Read = [{ node->getAArch64SMEAttributes() }];
} }
def : Property<"functionEffects", Array<FunctionEffect>> {
let Read = [{ node->getFunctionEffectsWithoutConditions() }];
}
def : Property<"functionEffectConds", Array<EffectConditionExpr>> {
let Read = [{ node->getFunctionEffectConditions() }];
}
def : Creator<[{ def : Creator<[{
auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm, auto extInfo = FunctionType::ExtInfo(noReturn, hasRegParm, regParm,
@ -342,6 +374,7 @@ let Class = FunctionProtoType in {
epi.ExtParameterInfos = epi.ExtParameterInfos =
extParameterInfo.empty() ? nullptr : extParameterInfo.data(); extParameterInfo.empty() ? nullptr : extParameterInfo.data();
epi.AArch64SMEAttributes = AArch64SMEAttributes; epi.AArch64SMEAttributes = AArch64SMEAttributes;
epi.FunctionEffects = FunctionEffectsRef::create(functionEffects, functionEffectConds);
return ctx.getFunctionType(returnType, parameters, epi); 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 { let Class = UnaryTransformType in {
def : Property<"baseType", QualType> { def : Property<"baseType", QualType> {
let Read = [{ node->getBaseType() }]; let Read = [{ node->getBaseType() }];
@ -821,6 +868,10 @@ let Class = BuiltinType in {
case BuiltinType::ID: return ctx.SINGLETON_ID; case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/Basic/WebAssemblyReferenceTypes.def" #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) \ #define BUILTIN_TYPE(ID, SINGLETON_ID) \
case BuiltinType::ID: return ctx.SINGLETON_ID; case BuiltinType::ID: return ctx.SINGLETON_ID;
#include "clang/AST/BuiltinTypes.def" #include "clang/AST/BuiltinTypes.def"

View file

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

View file

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

View file

@ -361,6 +361,10 @@ public:
}; };
class ItaniumVTableContext : public VTableContextBase { class ItaniumVTableContext : public VTableContextBase {
public:
typedef llvm::DenseMap<const CXXMethodDecl *, const CXXMethodDecl *>
OriginalMethodMapTy;
private: private:
/// Contains the index (relative to the vtable address point) /// Contains the index (relative to the vtable address point)
@ -384,6 +388,10 @@ private:
VirtualBaseClassOffsetOffsetsMapTy; VirtualBaseClassOffsetOffsetsMapTy;
VirtualBaseClassOffsetOffsetsMapTy VirtualBaseClassOffsetOffsets; 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; void computeVTableRelatedInformation(const CXXRecordDecl *RD) override;
public: public:
@ -425,6 +433,27 @@ public:
CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD, CharUnits getVirtualBaseOffsetOffset(const CXXRecordDecl *RD,
const CXXRecordDecl *VBase); 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) { static bool classof(const VTableContextBase *VT) {
return !VT->isMicrosoft(); return !VT->isMicrosoft();
} }

View file

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

View file

@ -8,11 +8,9 @@
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
#define 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 "clang/ASTMatchers/ASTMatchers.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include <memory>
namespace clang { namespace clang {
@ -21,14 +19,74 @@ class FunctionParmMutationAnalyzer;
/// Analyzes whether any mutative operations are applied to an expression within /// Analyzes whether any mutative operations are applied to an expression within
/// a given statement. /// a given statement.
class ExprMutationAnalyzer { class ExprMutationAnalyzer {
friend class FunctionParmMutationAnalyzer;
public: 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) 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 Expr *Exp) { return findMutation(Exp) != nullptr; }
bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; } bool isMutated(const Decl *Dec) { return findMutation(Dec) != nullptr; }
const Stmt *findMutation(const Expr *Exp); const Stmt *findMutation(const Expr *Exp) { return A.findMutation(Exp); }
const Stmt *findMutation(const Decl *Dec); const Stmt *findMutation(const Decl *Dec) { return A.findMutation(Dec); }
bool isPointeeMutated(const Expr *Exp) { bool isPointeeMutated(const Expr *Exp) {
return findPointeeMutation(Exp) != nullptr; return findPointeeMutation(Exp) != nullptr;
@ -36,51 +94,40 @@ public:
bool isPointeeMutated(const Decl *Dec) { bool isPointeeMutated(const Decl *Dec) {
return findPointeeMutation(Dec) != nullptr; return findPointeeMutation(Dec) != nullptr;
} }
const Stmt *findPointeeMutation(const Expr *Exp); const Stmt *findPointeeMutation(const Expr *Exp) {
const Stmt *findPointeeMutation(const Decl *Dec); return A.findPointeeMutation(Exp);
}
const Stmt *findPointeeMutation(const Decl *Dec) {
return A.findPointeeMutation(Dec);
}
static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm, static bool isUnevaluated(const Stmt *Smt, const Stmt &Stm,
ASTContext &Context); ASTContext &Context) {
return Analyzer::isUnevaluated(Smt, Stm, Context);
}
private: private:
using MutationFinder = const Stmt *(ExprMutationAnalyzer::*)(const Expr *); Memoized Memorized;
using ResultMap = llvm::DenseMap<const Expr *, const Stmt *>; Analyzer A;
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;
}; };
// A convenient wrapper around ExprMutationAnalyzer for analyzing function // A convenient wrapper around ExprMutationAnalyzer for analyzing function
// params. // params.
class FunctionParmMutationAnalyzer { class FunctionParmMutationAnalyzer {
public: 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) { bool isMutated(const ParmVarDecl *Parm) {
return findMutation(Parm) != nullptr; return findMutation(Parm) != nullptr;
@ -88,8 +135,11 @@ public:
const Stmt *findMutation(const ParmVarDecl *Parm); const Stmt *findMutation(const ParmVarDecl *Parm);
private: private:
ExprMutationAnalyzer BodyAnalyzer; ExprMutationAnalyzer::Analyzer BodyAnalyzer;
llvm::DenseMap<const ParmVarDecl *, const Stmt *> Results; llvm::DenseMap<const ParmVarDecl *, const Stmt *> Results;
FunctionParmMutationAnalyzer(const FunctionDecl &Func, ASTContext &Context,
ExprMutationAnalyzer::Memoized &Memorized);
}; };
} // namespace clang } // namespace clang

View file

@ -70,7 +70,41 @@ public:
}; };
private: 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; std::vector<const CFGBlock *> Blocks;
using BlockOrderTy = llvm::DenseMap<const CFGBlock *, unsigned>; using BlockOrderTy = llvm::DenseMap<const CFGBlock *, unsigned>;

View file

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

View file

@ -16,6 +16,7 @@
#include "clang/AST/Decl.h" #include "clang/AST/Decl.h"
#include "clang/AST/Stmt.h" #include "clang/AST/Stmt.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
namespace clang { namespace clang {
@ -41,6 +42,43 @@ public:
virtual VarGrpRef getGroupOfParms() const =0; 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 /// The interface that lets the caller handle unsafe buffer usage analysis
/// results by overriding this class's handle... methods. /// results by overriding this class's handle... methods.
class UnsafeBufferUsageHandler { class UnsafeBufferUsageHandler {
@ -68,15 +106,22 @@ public:
virtual void handleUnsafeOperation(const Stmt *Operation, virtual void handleUnsafeOperation(const Stmt *Operation,
bool IsRelatedToDecl, ASTContext &Ctx) = 0; 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 /// 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 /// 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. /// 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` /// `D` is the declaration of the callable under analysis that owns `Variable`
/// and all of its group mates. /// and all of its group mates.
virtual void handleUnsafeVariableGroup(const VarDecl *Variable, virtual void
const VariableGroupsManager &VarGrpMgr, handleUnsafeVariableGroup(const VarDecl *Variable,
FixItList &&Fixes, const Decl *D) = 0; const VariableGroupsManager &VarGrpMgr,
FixItList &&Fixes, const Decl *D,
const FixitStrategy &VarTargetTypes) = 0;
#ifndef NDEBUG #ifndef NDEBUG
public: public:
@ -98,9 +143,14 @@ public:
#endif #endif
public: 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; 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 virtual std::string
getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc, getUnsafeBufferUsageAttributeTextAt(SourceLocation Loc,
StringRef WSSuffix = "") const = 0; StringRef WSSuffix = "") const = 0;

View file

@ -18,6 +18,12 @@
#define WARNING_GADGET(name) GADGET(name) #define WARNING_GADGET(name) GADGET(name)
#endif #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 /// 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 /// properly recognized in order to emit correct warnings and fixes over unsafe
/// gadgets. /// gadgets.
@ -30,7 +36,9 @@ WARNING_GADGET(Decrement)
WARNING_GADGET(ArraySubscript) WARNING_GADGET(ArraySubscript)
WARNING_GADGET(PointerArithmetic) WARNING_GADGET(PointerArithmetic)
WARNING_GADGET(UnsafeBufferUsageAttr) WARNING_GADGET(UnsafeBufferUsageAttr)
WARNING_GADGET(UnsafeBufferUsageCtorAttr)
WARNING_GADGET(DataInvocation) 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(ULCArraySubscript) // `DRE[any]` in an Unspecified Lvalue Context
FIXABLE_GADGET(DerefSimplePtrArithFixable) FIXABLE_GADGET(DerefSimplePtrArithFixable)
FIXABLE_GADGET(PointerDereference) FIXABLE_GADGET(PointerDereference)
@ -38,9 +46,11 @@ FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified Poin
FIXABLE_GADGET(UPCStandalonePointer) FIXABLE_GADGET(UPCStandalonePointer)
FIXABLE_GADGET(UPCPreIncrement) // '++Ptr' in an Unspecified Pointer Context FIXABLE_GADGET(UPCPreIncrement) // '++Ptr' in an Unspecified Pointer Context
FIXABLE_GADGET(UUCAddAssign) // 'Ptr += n' in an Unspecified Untyped Context FIXABLE_GADGET(UUCAddAssign) // 'Ptr += n' in an Unspecified Untyped Context
FIXABLE_GADGET(PointerAssignment) FIXABLE_GADGET(PtrToPtrAssignment)
FIXABLE_GADGET(CArrayToPtrAssignment)
FIXABLE_GADGET(PointerInit) FIXABLE_GADGET(PointerInit)
#undef FIXABLE_GADGET #undef FIXABLE_GADGET
#undef WARNING_GADGET #undef WARNING_GADGET
#undef WARNING_CONTAINER_GADGET
#undef GADGET #undef GADGET

View file

@ -879,6 +879,7 @@ private:
/// ///
/// Optimization Note: This bit could be profitably folded with Terminator's /// Optimization Note: This bit could be profitably folded with Terminator's
/// storage if the memory usage of CFGBlock becomes an issue. /// storage if the memory usage of CFGBlock becomes an issue.
LLVM_PREFERRED_TYPE(bool)
unsigned HasNoReturnElement : 1; unsigned HasNoReturnElement : 1;
/// The parent CFG that owns this CFGBlock. /// The parent CFG that owns this CFGBlock.
@ -1007,7 +1008,9 @@ public:
class FilterOptions { class FilterOptions {
public: public:
LLVM_PREFERRED_TYPE(bool)
unsigned IgnoreNullPredecessors : 1; unsigned IgnoreNullPredecessors : 1;
LLVM_PREFERRED_TYPE(bool)
unsigned IgnoreDefaultsWithCoveredEnums : 1; unsigned IgnoreDefaultsWithCoveredEnums : 1;
FilterOptions() 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/AST/ASTContext.h"
#include "clang/Analysis/CFG.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/DataflowEnvironment.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h" #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/MatchSwitch.h" #include "clang/Analysis/FlowSensitive/MatchSwitch.h"
@ -54,10 +54,9 @@ namespace dataflow {
/// Environment &Env)` - applies the analysis transfer /// Environment &Env)` - applies the analysis transfer
/// function for a given edge from a CFG block of a conditional statement. /// function for a given edge from a CFG block of a conditional statement.
/// ///
/// `Derived` can optionally override the following members: /// `Derived` can optionally override the virtual functions in the
/// * `bool merge(QualType, const Value &, const Value &, Value &, /// `Environment::ValueModel` interface (which is an indirect base class of
/// Environment &)` - joins distinct values. This could be a strict /// this class).
/// lattice join or a more general widening operation.
/// ///
/// `LatticeT` is a bounded join-semilattice that is used by `Derived` and must /// `LatticeT` is a bounded join-semilattice that is used by `Derived` and must
/// provide the following public members: /// provide the following public members:
@ -179,13 +178,50 @@ template <typename LatticeT> struct DataflowAnalysisState {
Environment Env; 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 /// Performs dataflow analysis and returns a mapping from basic block IDs to
/// dataflow analysis states that model the respective basic blocks. The /// dataflow analysis states that model the respective basic blocks. The
/// returned vector, if any, will have the same size as the number of CFG /// 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 /// blocks, with indices corresponding to basic block IDs. Returns an error if
/// the dataflow analysis cannot be performed successfully. Otherwise, calls /// the dataflow analysis cannot be performed successfully. Otherwise, calls
/// `PostVisitCFG` on each CFG element with the final analysis results at that /// `PostAnalysisCallbacks` on each CFG element with the final analysis results
/// program point. /// before and after that program point.
/// ///
/// `MaxBlockVisits` caps the number of block visits during analysis. See /// `MaxBlockVisits` caps the number of block visits during analysis. See
/// `runTypeErasedDataflowAnalysis` for a full description. The default value is /// `runTypeErasedDataflowAnalysis` for a full description. The default value is
@ -195,31 +231,40 @@ template <typename LatticeT> struct DataflowAnalysisState {
template <typename AnalysisT> template <typename AnalysisT>
llvm::Expected<std::vector< llvm::Expected<std::vector<
std::optional<DataflowAnalysisState<typename AnalysisT::Lattice>>>> std::optional<DataflowAnalysisState<typename AnalysisT::Lattice>>>>
runDataflowAnalysis( runDataflowAnalysis(const AdornedCFG &ACFG, AnalysisT &Analysis,
const ControlFlowContext &CFCtx, AnalysisT &Analysis, const Environment &InitEnv,
const Environment &InitEnv, CFGEltCallbacks<AnalysisT> PostAnalysisCallbacks,
std::function<void(const CFGElement &, const DataflowAnalysisState< std::int32_t MaxBlockVisits = kDefaultMaxBlockVisits) {
typename AnalysisT::Lattice> &)> CFGEltCallbacksTypeErased TypeErasedCallbacks;
PostVisitCFG = nullptr, if (PostAnalysisCallbacks.Before) {
std::int32_t MaxBlockVisits = 20'000) { TypeErasedCallbacks.Before =
std::function<void(const CFGElement &, [&PostAnalysisCallbacks](const CFGElement &Element,
const TypeErasedDataflowAnalysisState &)> const TypeErasedDataflowAnalysisState &State) {
PostVisitCFGClosure = nullptr; auto *Lattice =
if (PostVisitCFG) { llvm::any_cast<typename AnalysisT::Lattice>(&State.Lattice.Value);
PostVisitCFGClosure = [&PostVisitCFG]( // FIXME: we should not be copying the environment here!
const CFGElement &Element, // Ultimately the `CFGEltCallback` only gets a const reference anyway.
const TypeErasedDataflowAnalysisState &State) { PostAnalysisCallbacks.Before(
auto *Lattice = Element, DataflowAnalysisState<typename AnalysisT::Lattice>{
llvm::any_cast<typename AnalysisT::Lattice>(&State.Lattice.Value); *Lattice, State.Env.fork()});
// FIXME: we should not be copying the environment here! };
// Ultimately the PostVisitCFG only gets a const reference anyway. }
PostVisitCFG(Element, DataflowAnalysisState<typename AnalysisT::Lattice>{ if (PostAnalysisCallbacks.After) {
*Lattice, State.Env.fork()}); 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( auto TypeErasedBlockStates = runTypeErasedDataflowAnalysis(
CFCtx, Analysis, InitEnv, PostVisitCFGClosure, MaxBlockVisits); ACFG, Analysis, InitEnv, TypeErasedCallbacks, MaxBlockVisits);
if (!TypeErasedBlockStates) if (!TypeErasedBlockStates)
return TypeErasedBlockStates.takeError(); return TypeErasedBlockStates.takeError();
@ -241,6 +286,22 @@ runDataflowAnalysis(
return std::move(BlockStates); 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 // Create an analysis class that is derived from `DataflowAnalysis`. This is an
// SFINAE adapter that allows us to call two different variants of constructor // SFINAE adapter that allows us to call two different variants of constructor
// (either with or without the optional `Environment` parameter). // (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 /// `runDataflowAnalysis` for a full description and explanation of the default
/// value. /// value.
template <typename AnalysisT, typename Diagnostic> template <typename AnalysisT, typename Diagnostic>
llvm::Expected<llvm::SmallVector<Diagnostic>> diagnoseFunction( llvm::Expected<llvm::SmallVector<Diagnostic>>
const FunctionDecl &FuncDecl, ASTContext &ASTCtx, diagnoseFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx,
llvm::function_ref<llvm::SmallVector<Diagnostic>( DiagnosisCallbacks<AnalysisT, Diagnostic> Diagnoser,
const CFGElement &, ASTContext &, std::int64_t MaxSATIterations = kDefaultMaxSATIterations,
const TransferStateForDiagnostics<typename AnalysisT::Lattice> &)> std::int32_t MaxBlockVisits = kDefaultMaxBlockVisits) {
Diagnoser, llvm::Expected<AdornedCFG> Context = AdornedCFG::build(FuncDecl);
std::int64_t MaxSATIterations = 1'000'000'000,
std::int32_t MaxBlockVisits = 20'000) {
llvm::Expected<ControlFlowContext> Context =
ControlFlowContext::build(FuncDecl);
if (!Context) if (!Context)
return Context.takeError(); return Context.takeError();
auto OwnedSolver = std::make_unique<WatchedLiteralsSolver>(MaxSATIterations); auto Solver = std::make_unique<WatchedLiteralsSolver>(MaxSATIterations);
const WatchedLiteralsSolver *Solver = OwnedSolver.get(); DataflowAnalysisContext AnalysisContext(*Solver);
DataflowAnalysisContext AnalysisContext(std::move(OwnedSolver));
Environment Env(AnalysisContext, FuncDecl); Environment Env(AnalysisContext, FuncDecl);
AnalysisT Analysis = createAnalysis<AnalysisT>(ASTCtx, Env); AnalysisT Analysis = createAnalysis<AnalysisT>(ASTCtx, Env);
llvm::SmallVector<Diagnostic> Diagnostics; 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 = if (llvm::Error Err =
runTypeErasedDataflowAnalysis( runTypeErasedDataflowAnalysis(*Context, Analysis, Env,
*Context, Analysis, Env, PostAnalysisCallbacks, MaxBlockVisits)
[&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)
.takeError()) .takeError())
return std::move(Err); return std::move(Err);
@ -317,6 +390,21 @@ llvm::Expected<llvm::SmallVector<Diagnostic>> diagnoseFunction(
return Diagnostics; 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 /// Abstract base class for dataflow "models": reusable analysis components that
/// model a particular aspect of program semantics in the `Environment`. For /// model a particular aspect of program semantics in the `Environment`. For
/// example, a model may capture a type and its related functions. /// 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/Decl.h"
#include "clang/AST/Expr.h" #include "clang/AST/Expr.h"
#include "clang/AST/TypeOrdering.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/Arena.h"
#include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
#include "clang/Analysis/FlowSensitive/Solver.h" #include "clang/Analysis/FlowSensitive/Solver.h"
#include "clang/Analysis/FlowSensitive/StorageLocation.h" #include "clang/Analysis/FlowSensitive/StorageLocation.h"
#include "clang/Analysis/FlowSensitive/Value.h" #include "clang/Analysis/FlowSensitive/Value.h"
@ -30,38 +31,11 @@
#include <cassert> #include <cassert>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <type_traits>
#include <utility>
#include <vector>
namespace clang { namespace clang {
namespace dataflow { namespace dataflow {
class Logger; 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 { struct ContextSensitiveOptions {
/// The maximum depth to analyze. A value of zero is equivalent to disabling /// The maximum depth to analyze. A value of zero is equivalent to disabling
/// context-sensitive analysis entirely. /// context-sensitive analysis entirely.
@ -93,13 +67,27 @@ public:
DataflowAnalysisContext(std::unique_ptr<Solver> S, DataflowAnalysisContext(std::unique_ptr<Solver> S,
Options Opts = Options{ Options Opts = Options{
/*ContextSensitiveOpts=*/std::nullopt, /*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(); ~DataflowAnalysisContext();
/// Sets a callback that returns the names and types of the synthetic fields /// Sets a callback that returns the names and types of the synthetic fields
/// to add to a `RecordStorageLocation` of a given type. /// to add to a `RecordStorageLocation` of a given type.
/// Typically, this is called from the constructor of a `DataflowAnalysis` /// 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 /// To maintain the invariant that all `RecordStorageLocation`s of a given
/// type have the same fields: /// type have the same fields:
/// * The callback must always return the same result for a given type /// * 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_DUMP_METHOD void dumpFlowCondition(Atom Token,
llvm::raw_ostream &OS = llvm::dbgs()); 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. /// returns null.
const ControlFlowContext *getControlFlowContext(const FunctionDecl *F); const AdornedCFG *getAdornedCFG(const FunctionDecl *F);
const Options &getOptions() { return Opts; } const Options &getOptions() { return Opts; }
@ -205,8 +193,17 @@ public:
/// type. /// type.
llvm::StringMap<QualType> getSyntheticFields(QualType Type) { llvm::StringMap<QualType> getSyntheticFields(QualType Type) {
assert(Type->isRecordType()); assert(Type->isRecordType());
if (SyntheticFieldCallback) if (SyntheticFieldCallback) {
return SyntheticFieldCallback(Type); 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 {}; return {};
} }
@ -224,6 +221,13 @@ private:
using DenseMapInfo::isEqual; 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. // Extends the set of modeled field declarations.
void addModeledFields(const FieldSet &Fields); void addModeledFields(const FieldSet &Fields);
@ -247,7 +251,8 @@ private:
Solver::Result::Status::Unsatisfiable; Solver::Result::Status::Unsatisfiable;
} }
std::unique_ptr<Solver> S; Solver &S;
std::unique_ptr<Solver> OwnedSolver;
std::unique_ptr<Arena> A; std::unique_ptr<Arena> A;
// Maps from program declarations and statements to storage locations that are // Maps from program declarations and statements to storage locations that are
@ -285,7 +290,7 @@ private:
llvm::DenseMap<Atom, const Formula *> FlowConditionConstraints; llvm::DenseMap<Atom, const Formula *> FlowConditionConstraints;
const Formula *Invariant = nullptr; const Formula *Invariant = nullptr;
llvm::DenseMap<const FunctionDecl *, ControlFlowContext> FunctionContexts; llvm::DenseMap<const FunctionDecl *, AdornedCFG> FunctionContexts;
// Fields modeled by environments covered by this context. // Fields modeled by environments covered by this context.
FieldSet ModeledFields; FieldSet ModeledFields;

View file

@ -19,7 +19,7 @@
#include "clang/AST/DeclBase.h" #include "clang/AST/DeclBase.h"
#include "clang/AST/Expr.h" #include "clang/AST/Expr.h"
#include "clang/AST/Type.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/DataflowAnalysisContext.h"
#include "clang/Analysis/FlowSensitive/DataflowLattice.h" #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
#include "clang/Analysis/FlowSensitive/Formula.h" #include "clang/Analysis/FlowSensitive/Formula.h"
@ -31,9 +31,11 @@
#include "llvm/ADT/MapVector.h" #include "llvm/ADT/MapVector.h"
#include "llvm/Support/Compiler.h" #include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <vector>
namespace clang { namespace clang {
namespace dataflow { namespace dataflow {
@ -45,6 +47,15 @@ enum class ComparisonResult {
Unknown, 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. /// 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 /// WARNING: Symbolic values that are created by the environment for static
@ -76,16 +87,13 @@ public:
virtual ComparisonResult compare(QualType Type, const Value &Val1, virtual ComparisonResult compare(QualType Type, const Value &Val1,
const Environment &Env1, const Value &Val2, const Environment &Env1, const Value &Val2,
const Environment &Env2) { 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. // argument here.
return ComparisonResult::Unknown; return ComparisonResult::Unknown;
} }
/// Modifies `MergedVal` to approximate both `Val1` and `Val2`. This could /// Modifies `JoinedVal` to approximate both `Val1` and `Val2`. This should
/// be a strict lattice join or a more general widening operation. /// obey the properties of a lattice join.
///
/// If this function returns true, `MergedVal` will be assigned to a storage
/// location of type `Type` in `MergedEnv`.
/// ///
/// `Env1` and `Env2` can be used to query child values and path condition /// `Env1` and `Env2` can be used to query child values and path condition
/// implications of `Val1` and `Val2` respectively. /// implications of `Val1` and `Val2` respectively.
@ -94,16 +102,13 @@ public:
/// ///
/// `Val1` and `Val2` must be distinct. /// `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 /// `Val1` and `Val2` must be assigned to the same storage location in
/// `Env1` and `Env2` respectively. /// `Env1` and `Env2` respectively.
virtual bool merge(QualType Type, const Value &Val1, virtual void join(QualType Type, const Value &Val1, const Environment &Env1,
const Environment &Env1, const Value &Val2, const Value &Val2, const Environment &Env2,
const Environment &Env2, Value &MergedVal, Value &JoinedVal, Environment &JoinedEnv) {}
Environment &MergedEnv) {
return true;
}
/// This function may widen the current value -- replace it with an /// This function may widen the current value -- replace it with an
/// approximation that can reach a fixed point more quickly than iterated /// 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 /// serve as a comparison operation, by indicating whether the widened value
/// is equivalent to the previous value. /// is equivalent to the previous value.
/// ///
/// Returns either: /// Returns one of the folowing:
/// /// * `std::nullopt`, if this value is not of interest to the
/// `nullptr`, if this value is not of interest to the model, or /// model.
/// /// * A `WidenResult` with:
/// `&Prev`, if the widened value is equivalent to `Prev`, or /// * A non-null `Value *` that points either to `Current` or a widened
/// /// version of `Current`. This value must be consistent with
/// A non-null value that approximates `Current`. `Prev` is available to /// the flow condition of `CurrentEnv`. We particularly caution
/// inform the chosen approximation. /// 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 /// `PrevEnv` and `CurrentEnv` can be used to query child values and path
/// condition implications of `Prev` and `Current`, respectively. /// condition implications of `Prev` and `Current`, respectively.
@ -130,17 +138,19 @@ public:
/// ///
/// `Prev` and `Current` must be assigned to the same storage location in /// `Prev` and `Current` must be assigned to the same storage location in
/// `PrevEnv` and `CurrentEnv`, respectively. /// `PrevEnv` and `CurrentEnv`, respectively.
virtual Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv, virtual std::optional<WidenResult> widen(QualType Type, Value &Prev,
Value &Current, Environment &CurrentEnv) { const Environment &PrevEnv,
Value &Current,
Environment &CurrentEnv) {
// The default implementation reduces to just comparison, since comparison // The default implementation reduces to just comparison, since comparison
// is required by the API, even if no widening is performed. // is required by the API, even if no widening is performed.
switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) { switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) {
case ComparisonResult::Same: case ComparisonResult::Unknown:
return &Prev; return std::nullopt;
case ComparisonResult::Different: case ComparisonResult::Same:
return &Current; return WidenResult{&Current, LatticeEffect::Unchanged};
case ComparisonResult::Unknown: case ComparisonResult::Different:
return nullptr; return WidenResult{&Current, LatticeEffect::Changed};
} }
llvm_unreachable("all cases in switch covered"); llvm_unreachable("all cases in switch covered");
} }
@ -148,7 +158,28 @@ public:
/// Creates an environment that uses `DACtx` to store objects that encompass /// Creates an environment that uses `DACtx` to store objects that encompass
/// the state of a program. /// 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(). // Copy-constructor is private, Environments should not be copied. See fork().
Environment &operator=(const Environment &Other) = delete; Environment &operator=(const Environment &Other) = delete;
@ -156,24 +187,11 @@ public:
Environment(Environment &&Other) = default; Environment(Environment &&Other) = default;
Environment &operator=(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 /// Assigns storage locations and values to all parameters, captures, global
/// variables, fields and functions referenced in the function currently being /// variables, fields and functions referenced in the `Stmt` or `FunctionDecl`
/// analyzed. /// passed to the constructor.
/// ///
/// Requirements: /// If no `Stmt` or `FunctionDecl` was supplied, this function does nothing.
///
/// The function must have a body, i.e.
/// `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
void initialize(); void initialize();
/// Returns a new environment that is a copy of this one. /// Returns a new environment that is a copy of this one.
@ -186,7 +204,7 @@ public:
/// forked flow condition references the original). /// forked flow condition references the original).
Environment fork() const; 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 /// callee. Uses the storage location from each argument in the `Call` as the
/// storage location for the corresponding parameter in the callee. /// storage location for the corresponding parameter in the callee.
/// ///
@ -218,6 +236,14 @@ public:
bool equivalentTo(const Environment &Other, bool equivalentTo(const Environment &Other,
Environment::ValueModel &Model) const; 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 /// Joins two environments by taking the intersection of storage locations and
/// values that are stored in them. Distinct values that are assigned to the /// values that are stored in them. Distinct values that are assigned to the
/// same storage locations in `EnvA` and `EnvB` are merged using `Model`. /// same storage locations in `EnvA` and `EnvB` are merged using `Model`.
@ -226,7 +252,23 @@ public:
/// ///
/// `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`. /// `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`.
static Environment join(const Environment &EnvA, const Environment &EnvB, 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 /// Widens the environment point-wise, using `PrevEnv` as needed to inform the
/// approximation. /// approximation.
@ -235,8 +277,8 @@ public:
/// ///
/// `PrevEnv` must be the immediate previous version of the environment. /// `PrevEnv` must be the immediate previous version of the environment.
/// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`. /// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`.
LatticeJoinEffect widen(const Environment &PrevEnv, LatticeEffect widen(const Environment &PrevEnv,
Environment::ValueModel &Model); Environment::ValueModel &Model);
// FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`, // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`,
// `getStableStorageLocation`, or something more appropriate. // `getStableStorageLocation`, or something more appropriate.
@ -329,62 +371,56 @@ public:
/// location of the result object to pass in `this`, even though prvalues are /// location of the result object to pass in `this`, even though prvalues are
/// otherwise not associated with storage locations. /// 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: /// Requirements:
/// `E` must be a prvalue of record type. /// `E` must be a prvalue of record type.
RecordStorageLocation & RecordStorageLocation &
getResultObjectLocation(const Expr &RecordPRValue) const; 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 /// - The function has a void return type
/// - No return value could be determined for the function, for example /// - No return value could be determined for the function, for example
/// because it calls a function without a body. /// because it calls a function without a body.
/// ///
/// Requirements: /// 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 { Value *getReturnValue() const {
assert(getCurrentFunc() != nullptr && assert(getCurrentFunc() != nullptr &&
!getCurrentFunc()->getReturnType()->isReferenceType()); !getCurrentFunc()->getReturnType()->isReferenceType());
return ReturnVal; return ReturnVal;
} }
/// Returns the storage location for the reference returned by the current /// Returns the storage location for the reference returned by the function
/// function. This can be null if function doesn't return a single consistent /// currently being analyzed. This can be null if the function doesn't return
/// reference. /// a single consistent reference.
/// ///
/// Requirements: /// 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 { StorageLocation *getReturnStorageLocation() const {
assert(getCurrentFunc() != nullptr && assert(getCurrentFunc() != nullptr &&
getCurrentFunc()->getReturnType()->isReferenceType()); getCurrentFunc()->getReturnType()->isReferenceType());
return ReturnLoc; return ReturnLoc;
} }
/// Sets the return value of the current function. /// Sets the return value of the function currently being analyzed.
/// ///
/// Requirements: /// 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) { void setReturnValue(Value *Val) {
assert(getCurrentFunc() != nullptr && assert(getCurrentFunc() != nullptr &&
!getCurrentFunc()->getReturnType()->isReferenceType()); !getCurrentFunc()->getReturnType()->isReferenceType());
ReturnVal = Val; ReturnVal = Val;
} }
/// Sets the storage location for the reference returned by the current /// Sets the storage location for the reference returned by the function
/// function. /// currently being analyzed.
/// ///
/// Requirements: /// 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) { void setReturnStorageLocation(StorageLocation *Loc) {
assert(getCurrentFunc() != nullptr && assert(getCurrentFunc() != nullptr &&
getCurrentFunc()->getReturnType()->isReferenceType()); getCurrentFunc()->getReturnType()->isReferenceType());
@ -402,20 +438,15 @@ public:
/// storage locations and values for indirections until it finds a /// storage locations and values for indirections until it finds a
/// non-pointer/non-reference type. /// 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 /// If `Type` is one of the following types, this function will always return
/// a non-null pointer: /// a non-null pointer:
/// - `bool` /// - `bool`
/// - Any integer type /// - Any integer type
/// - Any class, struct, or union type
/// ///
/// Requirements: /// 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); Value *createValue(QualType Type);
/// Creates an object (i.e. a storage location with an associated value) of /// Creates an object (i.e. a storage location with an associated value) of
@ -444,7 +475,23 @@ public:
return createObjectInternal(&D, D.getType(), InitExpr); 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. /// Assigns `Val` as the value of `Loc` in the environment.
///
/// Requirements:
///
/// `Loc` must not be a `RecordStorageLocation`.
void setValue(const StorageLocation &Loc, Value &Val); void setValue(const StorageLocation &Loc, Value &Val);
/// Clears any association between `Loc` and a value in the environment. /// Clears any association between `Loc` and a value in the environment.
@ -454,20 +501,24 @@ public:
/// ///
/// Requirements: /// Requirements:
/// ///
/// - `E` must be a prvalue /// - `E` must be a prvalue.
/// - If `Val` is a `RecordValue`, its `RecordStorageLocation` must be /// - `E` must not have record type.
/// `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.
void setValue(const Expr &E, Value &Val); void setValue(const Expr &E, Value &Val);
/// Returns the value assigned to `Loc` in the environment or null if `Loc` /// Returns the value assigned to `Loc` in the environment or null if `Loc`
/// isn't assigned a value in the environment. /// isn't assigned a value in the environment.
///
/// Requirements:
///
/// `Loc` must not be a `RecordStorageLocation`.
Value *getValue(const StorageLocation &Loc) const; Value *getValue(const StorageLocation &Loc) const;
/// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a /// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a
/// storage location in the environment, otherwise returns null. /// storage location in the environment, otherwise returns null.
///
/// Requirements:
///
/// `D` must not have record type.
Value *getValue(const ValueDecl &D) const; Value *getValue(const ValueDecl &D) const;
/// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a /// 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. /// (or the flow condition is overly constraining) or if the solver times out.
bool allows(const Formula &) const; 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 /// Returns the function currently being analyzed, or null if the code being
/// analyzed isn't part of a function. /// analyzed isn't part of a function.
const FunctionDecl *getCurrentFunc() const { 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(); } size_t callStackSize() const { return CallStack.size(); }
/// Returns whether this `Environment` can be extended to analyze the given /// Returns whether this `Environment` can be extended to analyze the given
/// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a /// `Callee` (i.e. if `pushCall` can be used).
/// given `MaxDepth`. /// Recursion is not allowed. `MaxDepth` is the maximum size of the call stack
bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const; /// (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. /// Returns the `DataflowAnalysisContext` used by the environment.
DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; } DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; }
@ -633,6 +682,9 @@ public:
LLVM_DUMP_METHOD void dump(raw_ostream &OS) const; LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;
private: private:
using PrValueToResultObject =
llvm::DenseMap<const Expr *, RecordStorageLocation *>;
// The copy-constructor is for use in fork() only. // The copy-constructor is for use in fork() only.
Environment(const Environment &) = default; Environment(const Environment &) = default;
@ -659,6 +711,16 @@ private:
llvm::DenseSet<QualType> &Visited, llvm::DenseSet<QualType> &Visited,
int Depth, int &CreatedValuesCount); 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. /// Shared implementation of `createObject()` overloads.
/// `D` and `InitExpr` may be null. /// `D` and `InitExpr` may be null.
StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty, StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty,
@ -671,27 +733,64 @@ private:
ArrayRef<const Expr *> Args); ArrayRef<const Expr *> Args);
/// Assigns storage locations and values to all global variables, fields /// Assigns storage locations and values to all global variables, fields
/// and functions referenced in `FuncDecl`. `FuncDecl` must have a body. /// and functions in `Referenced`.
void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl); 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. // `DACtx` is not null and not owned by this object.
DataflowAnalysisContext *DACtx; DataflowAnalysisContext *DACtx;
// FIXME: move the fields `CallStack`, `ReturnVal`, `ReturnLoc` and // FIXME: move the fields `CallStack`, `ResultObjectMap`, `ReturnVal`,
// `ThisPointeeLoc` into a separate call-context object, shared between // `ReturnLoc` and `ThisPointeeLoc` into a separate call-context object,
// environments in the same call. // shared between environments in the same call.
// https://github.com/llvm/llvm-project/issues/59005 // https://github.com/llvm/llvm-project/issues/59005
// `DeclContext` of the block being analysed if provided. // The stack of functions called from the initial analysis target.
std::vector<const DeclContext *> CallStack; 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; Value *ReturnVal = nullptr;
// Storage location of the reference returned by the function (if it has // - If the return type is a reference: Storage location of the reference
// reference return type). // returned by the function.
StorageLocation *ReturnLoc = nullptr; 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 // 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; RecordStorageLocation *ThisPointeeLoc = nullptr;
// Maps from declarations and glvalue expression to storage locations that are // 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, RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
const Environment &Env); 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 dataflow
} // namespace clang } // namespace clang

View file

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

View file

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

View file

@ -15,7 +15,7 @@
namespace clang::dataflow { namespace clang::dataflow {
// Forward declarations so we can use Logger anywhere in the framework. // Forward declarations so we can use Logger anywhere in the framework.
class ControlFlowContext; class AdornedCFG;
class TypeErasedDataflowAnalysis; class TypeErasedDataflowAnalysis;
struct TypeErasedDataflowAnalysisState; struct TypeErasedDataflowAnalysisState;
@ -40,8 +40,8 @@ public:
/// Called by the framework as we start analyzing a new function or statement. /// Called by the framework as we start analyzing a new function or statement.
/// Forms a pair with endAnalysis(). /// Forms a pair with endAnalysis().
virtual void beginAnalysis(const ControlFlowContext &, virtual void beginAnalysis(const AdornedCFG &, TypeErasedDataflowAnalysis &) {
TypeErasedDataflowAnalysis &) {} }
virtual void endAnalysis() {} virtual void endAnalysis() {}
// At any time during the analysis, we're computing the state for some target // At any time during the analysis, we're computing the state for some target

View file

@ -31,7 +31,11 @@ namespace dataflow {
/// ///
/// Requirements: /// 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, void copyRecord(RecordStorageLocation &Src, RecordStorageLocation &Dst,
Environment &Env); Environment &Env);

View file

@ -87,6 +87,9 @@ public:
/// ///
/// All elements in `Vals` must not be null. /// All elements in `Vals` must not be null.
virtual Result solve(llvm::ArrayRef<const Formula *> Vals) = 0; 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 &); 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 // `CurState` is the pending state currently associated with this block. These
// are supplied separately as the pending state for the current block may not // are supplied separately as the pending state for the current block may not
// yet be represented in `BlockToState`. // yet be represented in `BlockToState`.
StmtToEnvMap(const ControlFlowContext &CFCtx, StmtToEnvMap(const AdornedCFG &ACFG,
llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>> llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>>
BlockToState, BlockToState,
unsigned CurBlockID, unsigned CurBlockID,
const TypeErasedDataflowAnalysisState &CurState) const TypeErasedDataflowAnalysisState &CurState)
: CFCtx(CFCtx), BlockToState(BlockToState), CurBlockID(CurBlockID), : ACFG(ACFG), BlockToState(BlockToState), CurBlockID(CurBlockID),
CurState(CurState) {} CurState(CurState) {}
/// Returns the environment of the basic block that contains `S`. /// Returns the environment of the basic block that contains `S`.
@ -42,7 +42,7 @@ public:
const Environment *getEnvironment(const Stmt &S) const; const Environment *getEnvironment(const Stmt &S) const;
private: private:
const ControlFlowContext &CFCtx; const AdornedCFG &ACFG;
llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>> BlockToState; llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>> BlockToState;
unsigned CurBlockID; unsigned CurBlockID;
const TypeErasedDataflowAnalysisState &CurState; const TypeErasedDataflowAnalysisState &CurState;
@ -53,7 +53,8 @@ private:
/// Requirements: /// Requirements:
/// ///
/// `S` must not be `ParenExpr` or `ExprWithCleanups`. /// `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 dataflow
} // namespace clang } // namespace clang

View file

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

View file

@ -35,7 +35,6 @@ public:
enum class Kind { enum class Kind {
Integer, Integer,
Pointer, Pointer,
Record,
// TODO: Top values should not be need to be type-specific. // TODO: Top values should not be need to be type-specific.
TopBool, TopBool,
@ -67,7 +66,6 @@ public:
/// Properties may not be set on `RecordValue`s; use synthetic fields instead /// Properties may not be set on `RecordValue`s; use synthetic fields instead
/// (for details, see documentation for `RecordStorageLocation`). /// (for details, see documentation for `RecordStorageLocation`).
void setProperty(llvm::StringRef Name, Value &Val) { void setProperty(llvm::StringRef Name, Value &Val) {
assert(getKind() != Kind::Record);
Properties.insert_or_assign(Name, &Val); Properties.insert_or_assign(Name, &Val);
} }
@ -184,45 +182,6 @@ private:
StorageLocation &PointeeLoc; 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); raw_ostream &operator<<(raw_ostream &OS, const Value &Val);
} // namespace dataflow } // namespace dataflow

View file

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

View file

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

View file

@ -15,10 +15,10 @@ namespace clang {
template <typename... IdentifierInfos> template <typename... IdentifierInfos>
static inline Selector getKeywordSelector(ASTContext &Ctx, static inline Selector getKeywordSelector(ASTContext &Ctx,
IdentifierInfos *... IIs) { const IdentifierInfos *...IIs) {
static_assert(sizeof...(IdentifierInfos) > 0, static_assert(sizeof...(IdentifierInfos) > 0,
"keyword selectors must have at least one argument"); "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]); 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/DiagnosticCrossTU.h"
#include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/DiagnosticDriver.h"
#include "clang/Basic/DiagnosticFrontend.h" #include "clang/Basic/DiagnosticFrontend.h"
#include "clang/Basic/DiagnosticInstallAPI.h"
#include "clang/Basic/DiagnosticLex.h" #include "clang/Basic/DiagnosticLex.h"
#include "clang/Basic/DiagnosticParse.h" #include "clang/Basic/DiagnosticParse.h"
#include "clang/Basic/DiagnosticSema.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 a warning about use of a deprecated declaration. The Fix-It will replace
the deprecated declaration with the new declaration specified. 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 Multiple availability attributes can be placed on a declaration, which may
correspond to different platforms. For most platforms, the availability correspond to different platforms. For most platforms, the availability
attribute with the platform corresponding to the target platform will be used; 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: attributes are ignored. Supported platforms are:
``ios`` ``ios``
Apple's iOS operating system. The minimum deployment target is specified by Apple's iOS operating system. The minimum deployment target is specified
the ``-mios-version-min=*version*`` or ``-miphoneos-version-min=*version*`` as part of the ``-target *arch*-apple-ios*version*`` command line argument.
command-line arguments. Alternatively, it can be specified by the ``-mtargetos=ios*version*``
command-line argument.
``macos`` ``macos``
Apple's macOS operating system. The minimum deployment target is Apple's macOS operating system. The minimum deployment target is specified
specified by the ``-mmacosx-version-min=*version*`` command-line argument. as part of the ``-target *arch*-apple-macos*version*`` command line argument.
``macosx`` is supported for backward-compatibility reasons, but it is Alternatively, it can be specified by the ``-mtargetos=macos*version*``
deprecated. command-line argument. ``macosx`` is supported for
backward-compatibility reasons, but it is deprecated.
``tvos`` ``tvos``
Apple's tvOS operating system. The minimum deployment target is specified by Apple's tvOS operating system. The minimum deployment target is specified
the ``-mtvos-version-min=*version*`` command-line argument. 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`` ``watchos``
Apple's watchOS operating system. The minimum deployment target is specified by Apple's watchOS operating system. The minimum deployment target is specified
the ``-mwatchos-version-min=*version*`` command-line argument. 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`` ``driverkit``
Apple's DriverKit userspace kernel extensions. The minimum deployment target 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 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 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 { def LikelihoodDocs : Documentation {
let Category = DocCatStmt; let Category = DocCatStmt;
let Heading = "likely and unlikely"; 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 "avx", "xop" and largely correspond to the machine specific options handled by
the front end. 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 Additionally, this attribute supports function multiversioning for ELF based
x86/x86-64 targets, which can be used to create multiple implementations of the 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 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 priority and target features availability. One of the versions is always
( implicitly or explicitly ) the ``default`` (fallback). Attribute strings can ( implicitly or explicitly ) the ``default`` (fallback). Attribute strings can
contain dependent features names joined by the "+" sign. 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"> { def DocCatCallingConvs : DocumentationCategory<"Calling Conventions"> {
let Content = [{ let Content = [{
Clang supports several different calling conventions, depending on the target 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`` This attribute is incompatible with the ``always_inline`` and ``minsize``
attributes. 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 (assign, nullable) NSView *superview;
@property (readonly, nonnull) NSArray *subviews; @property (readonly, nonnull) NSArray *subviews;
@end @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); int fetch_or_zero(int * _Nullable ptr);
a caller of ``fetch_or_zero`` can provide null. 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 Category = DocCatFunction;
let Heading = "assume"; let Heading = "assume";
let Content = [{ 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 provide additional information to the optimizer. The string-literal, here
"assumption", will be attached to the function declaration such that later "assumption", will be attached to the function declaration such that later
analysis and optimization passes can assume the "assumption" to hold. 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 declarations to later definitions. Multiple assumptions are aggregated into a
single comma separated string. Thus, one can provide multiple assumptions via single comma separated string. Thus, one can provide multiple assumptions via
a comma separated string, i.a., 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 While LLVM plugins might provide more assumption strings, the default LLVM
optimization passes are aware of the following assumptions: 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. attributes.
Support for this feature is target-dependent, although it should be Support for this feature is target-dependent, although it should be
supported on every target that Swift supports. Query for this support supported on every target that Swift supports. Query for this attribute
with ``__has_attribute(swiftcall)``. This implies support for the with ``__has_attribute(swiftcall)``. Query if the target supports the
``swift_context``, ``swift_error_result``, and ``swift_indirect_result`` calling convention with ``__has_extension(swiftcc)``. This implies
attributes. 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 semantically be performed after a guaranteed tail call, such as the
non-trivial destruction of a local variable or temporary, non-trivial destruction of a local variable or temporary,
then the program is ill-formed. 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 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 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 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 { def PreferredNameDocs : Documentation {
let Category = DocCatDecl; let Category = DocCatDecl;
let Content = [{ 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 { def DeprecatedDocs : Documentation {
let Category = DocCatDecl; let Category = DocCatDecl;
let Content = [{ 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 { def RenderScriptKernelAttributeDocs : Documentation {
let Category = DocCatFunction; let Category = DocCatFunction;
let Content = [{ let Content = [{
@ -5608,7 +5800,8 @@ takes precedence over the command line option ``-fpatchable-function-entry=N,M``
``M`` defaults to 0 if omitted. ``M`` defaults to 0 if omitted.
This attribute is only supported on 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 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 storage duration should have its exit-time destructor run. This attribute is the
default unless clang was invoked with -fno-c++-static-destructors. 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: private:
int *valuePointer; int *valuePointer;
public: public:
int *getInt() { return &valuePointer; } IntPointer(const IntOwner&);
int *getInt() { return valuePointer; }
}; };
The argument ``T`` is optional and is ignored. 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++ .. code-block:: c++
int f() { int f() {
IntPointer P; IntPointer P(IntOwner{}); // P "points into" a temporary IntOwner object
if (true) { P.getInt(); // P is dangling
IntOwner O(7);
P = IntPointer(O); // P "points into" O
} // P is dangling
return P.get(); // error: Using a dangling Pointer.
} }
}]; }];
@ -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 { def ClangRandomizeLayoutDocs : Documentation {
let Category = DocCatDecl; let Category = DocCatDecl;
let Heading = "randomize_layout, no_randomize_layout"; 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. Register space is specified in the format ``space[number]`` and defaults to ``space0`` if omitted.
Here're resource binding examples with and without space: Here're resource binding examples with and without space:
.. code-block:: c++
.. code-block:: hlsl
RWBuffer<float> Uav : register(u3, space1); RWBuffer<float> Uav : register(u3, space1);
Buffer<float> Buf : register(t1); 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 { def HLSLSV_DispatchThreadIDDocs : Documentation {
let Category = DocCatFunction; let Category = DocCatFunction;
let Content = [{ 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", /* This may print something else than "6 * 7 = 42",
if there is a non-weak definition of "ANSWER" in if there is a non-weak definition of "ANSWER" in
an object linked in */ an object linked in */
printf("6 * 7 = %d\n", ANSWER); printf("6 * 7 = %d\n", ANSWER);
return 0; 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. /// Context-sensitive version of a keyword attribute.
AS_ContextSensitiveKeyword, AS_ContextSensitiveKeyword,
/// <vardecl> : <semantic> /// <vardecl> : <annotation>
AS_HLSLSemantic, AS_HLSLAnnotation,
/// The attibute has no source code manifestation and is only created /// The attibute has no source code manifestation and is only created
/// implicitly. /// implicitly.
@ -120,7 +120,7 @@ public:
} }
static Form Pragma() { return AS_Pragma; } static Form Pragma() { return AS_Pragma; }
static Form ContextSensitiveKeyword() { return AS_ContextSensitiveKeyword; } static Form ContextSensitiveKeyword() { return AS_ContextSensitiveKeyword; }
static Form HLSLSemantic() { return AS_HLSLSemantic; } static Form HLSLAnnotation() { return AS_HLSLAnnotation; }
static Form Implicit() { return AS_Implicit; } static Form Implicit() { return AS_Implicit; }
private: private:

File diff suppressed because it is too large Load diff

View file

@ -64,7 +64,7 @@ namespace Builtin {
enum ID { enum ID {
NotBuiltin = 0, // This is not a builtin function. NotBuiltin = 0, // This is not a builtin function.
#define BUILTIN(ID, TYPE, ATTRS) BI##ID, #define BUILTIN(ID, TYPE, ATTRS) BI##ID,
#include "clang/Basic/Builtins.def" #include "clang/Basic/Builtins.inc"
FirstTSBuiltin FirstTSBuiltin
}; };
@ -280,6 +280,11 @@ public:
return strchr(getRecord(ID).Attributes, 'E') != nullptr; 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: private:
const Info &getRecord(unsigned ID) const; 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_wfi, "v", "")
BUILTIN(__builtin_arm_sev, "v", "") BUILTIN(__builtin_arm_sev, "v", "")
BUILTIN(__builtin_arm_sevl, "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 // CRC32
TARGET_BUILTIN(__builtin_arm_crc32b, "UiUiUc", "nc", "crc") 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") TARGET_BUILTIN(__builtin_arm_subp, "Uiv*v*", "t", "mte")
// SME state function // SME state function
BUILTIN(__builtin_arm_get_sme_state, "vULi*ULi*", "n") BUILTIN(__builtin_arm_get_sme_state, "vWUi*WUi*", "n")
// Memory Operations // Memory Operations
TARGET_BUILTIN(__builtin_arm_mops_memset_tag, "v*v*iz", "", "mte,mops") 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_st64bv, "WUiv*WUiC*", "n", "ls64")
TARGET_BUILTIN(__builtin_arm_st64bv0, "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(_BitScanForward, "UcUNi*UNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanReverse, "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(_BitScanForward64, "UcUNi*ULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_BitScanReverse64, "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(_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(_InterlockedAnd64, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedDecrement64, "LLiLLiD*", "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, "") 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(_CountOneBits, "UiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_CountOneBits64, "UiULLi", "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 BUILTIN
#undef LANGBUILTIN #undef LANGBUILTIN

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