aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGaius Mulley <gaiusmod2@gmail.com>2022-12-07 19:51:10 +0000
committerGaius Mulley <gaiusmod2@gmail.com>2022-12-07 19:51:10 +0000
commitaaa673daca2fd4fd159dae2a88f2b68dfc9f58b1 (patch)
tree8d4a57d99a33cc78cac8812be9815a9def6180bf
parent442bcd0e9f6650c611fec17c5558637e13c0ac21 (diff)
parent952c8a1dc6235dc49ab207a7f18f63d2bc97fbc9 (diff)
downloadgcc-aaa673daca2fd4fd159dae2a88f2b68dfc9f58b1.zip
gcc-aaa673daca2fd4fd159dae2a88f2b68dfc9f58b1.tar.gz
gcc-aaa673daca2fd4fd159dae2a88f2b68dfc9f58b1.tar.bz2
Merge branch 'master' into devel/modula-2.
Signed-off-by: Gaius Mulley <gaiusmod2@gmail.com>
-rw-r--r--MAINTAINERS1
-rw-r--r--Makefile.def13
-rw-r--r--Makefile.in120
-rwxr-xr-xconfigure11
-rw-r--r--configure.ac10
-rw-r--r--contrib/ChangeLog4
-rw-r--r--contrib/gcc.doxy2
-rw-r--r--gcc/ChangeLog458
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/Makefile.in4
-rw-r--r--gcc/ada/ChangeLog223
-rw-r--r--gcc/ada/accessibility.adb2305
-rw-r--r--gcc/ada/accessibility.ads222
-rw-r--r--gcc/ada/checks.adb113
-rw-r--r--gcc/ada/checks.ads10
-rw-r--r--gcc/ada/contracts.adb32
-rw-r--r--gcc/ada/doc/gnat_rm/the_gnat_library.rst40
-rw-r--r--gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst15
-rw-r--r--gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst16
-rw-r--r--gcc/ada/doc/share/conf.py100
-rw-r--r--gcc/ada/einfo.ads8
-rw-r--r--gcc/ada/exp_aggr.adb2
-rw-r--r--gcc/ada/exp_attr.adb15
-rw-r--r--gcc/ada/exp_ch3.adb469
-rw-r--r--gcc/ada/exp_ch4.adb442
-rw-r--r--gcc/ada/exp_ch5.adb1
-rw-r--r--gcc/ada/exp_ch6.adb109
-rw-r--r--gcc/ada/exp_ch6.ads27
-rw-r--r--gcc/ada/exp_ch9.adb1
-rw-r--r--gcc/ada/exp_disp.adb1
-rw-r--r--gcc/ada/exp_util.adb6
-rw-r--r--gcc/ada/gcc-interface/Make-lang.in1
-rw-r--r--gcc/ada/gcc-interface/trans.cc17
-rw-r--r--gcc/ada/gen_il-fields.ads3
-rw-r--r--gcc/ada/gen_il-gen-gen_nodes.adb3
-rw-r--r--gcc/ada/gen_il-internals.adb2
-rw-r--r--gcc/ada/gnat_rm.texi66
-rw-r--r--gcc/ada/gnat_ugn.texi19
-rw-r--r--gcc/ada/lib-xref.adb2
-rw-r--r--gcc/ada/libgnat/i-c.adb15
-rw-r--r--gcc/ada/sem_aggr.adb2
-rw-r--r--gcc/ada/sem_attr.adb162
-rw-r--r--gcc/ada/sem_ch13.adb7
-rw-r--r--gcc/ada/sem_ch3.adb140
-rw-r--r--gcc/ada/sem_ch4.adb65
-rw-r--r--gcc/ada/sem_ch5.adb7
-rw-r--r--gcc/ada/sem_ch6.adb654
-rw-r--r--gcc/ada/sem_ch9.adb1
-rw-r--r--gcc/ada/sem_elab.adb24
-rw-r--r--gcc/ada/sem_prag.adb49
-rw-r--r--gcc/ada/sem_res.adb53
-rw-r--r--gcc/ada/sem_util.adb1336
-rw-r--r--gcc/ada/sem_util.ads141
-rw-r--r--gcc/ada/sem_warn.adb41
-rw-r--r--gcc/ada/sinfo.ads15
-rw-r--r--gcc/ada/treepr.adb5
-rw-r--r--gcc/analyzer/ChangeLog329
-rw-r--r--gcc/analyzer/analyzer.cc2
-rw-r--r--gcc/analyzer/analyzer.h6
-rw-r--r--gcc/analyzer/bounds-checking.cc943
-rw-r--r--gcc/analyzer/call-details.cc231
-rw-r--r--gcc/analyzer/call-details.h77
-rw-r--r--gcc/analyzer/call-info.cc16
-rw-r--r--gcc/analyzer/call-summary.h2
-rw-r--r--gcc/analyzer/checker-event.cc166
-rw-r--r--gcc/analyzer/checker-event.h187
-rw-r--r--gcc/analyzer/checker-path.cc17
-rw-r--r--gcc/analyzer/checker-path.h6
-rw-r--r--gcc/analyzer/diagnostic-manager.cc103
-rw-r--r--gcc/analyzer/diagnostic-manager.h3
-rw-r--r--gcc/analyzer/engine.cc87
-rw-r--r--gcc/analyzer/infinite-recursion.cc7
-rw-r--r--gcc/analyzer/kf-analyzer.cc386
-rw-r--r--gcc/analyzer/kf-lang-cp.cc111
-rw-r--r--gcc/analyzer/known-function-manager.cc1
-rw-r--r--gcc/analyzer/pending-diagnostic.cc38
-rw-r--r--gcc/analyzer/pending-diagnostic.h36
-rw-r--r--gcc/analyzer/region-model-impl-calls.cc619
-rw-r--r--gcc/analyzer/region-model-manager.cc14
-rw-r--r--gcc/analyzer/region-model-manager.h1
-rw-r--r--gcc/analyzer/region-model.cc748
-rw-r--r--gcc/analyzer/region-model.h56
-rw-r--r--gcc/analyzer/region.cc12
-rw-r--r--gcc/analyzer/region.h2
-rw-r--r--gcc/analyzer/sm-fd.cc7
-rw-r--r--gcc/analyzer/sm-fd.dot6
-rw-r--r--gcc/analyzer/sm-file.cc1
-rw-r--r--gcc/analyzer/sm-malloc.cc1
-rw-r--r--gcc/analyzer/sm-signal.cc2
-rw-r--r--gcc/analyzer/state-purge.cc4
-rw-r--r--gcc/analyzer/store.cc30
-rw-r--r--gcc/analyzer/store.h8
-rw-r--r--gcc/analyzer/varargs.cc18
-rw-r--r--gcc/attribs.cc30
-rw-r--r--gcc/attribs.h2
-rw-r--r--gcc/c-family/ChangeLog20
-rw-r--r--gcc/c-family/c-attribs.cc2
-rw-r--r--gcc/c-family/c-omp.cc9
-rw-r--r--gcc/c/ChangeLog5
-rw-r--r--gcc/c/c-decl.cc21
-rw-r--r--gcc/cfghooks.cc1
-rw-r--r--gcc/config/aarch64/aarch64-protos.h7
-rw-r--r--gcc/config/aarch64/aarch64-sve-builtins-base.cc15
-rw-r--r--gcc/config/aarch64/aarch64.cc193
-rw-r--r--gcc/config/aarch64/aarch64.md17
-rw-r--r--gcc/config/aarch64/constraints.md5
-rw-r--r--gcc/config/arm/mve.md10
-rw-r--r--gcc/config/gcn/gcn-opts.h6
-rw-r--r--gcc/config/gcn/gcn.h40
-rw-r--r--gcc/config/i386/i386-expand.cc47
-rw-r--r--gcc/config/i386/i386.md36
-rw-r--r--gcc/config/i386/mmx.md3
-rw-r--r--gcc/config/i386/x86-tune.def3
-rw-r--r--gcc/config/riscv/constraints.md5
-rw-r--r--gcc/config/riscv/predicates.md5
-rw-r--r--gcc/config/riscv/riscv-protos.h15
-rw-r--r--gcc/config/riscv/riscv-selftests.cc127
-rw-r--r--gcc/config/riscv/riscv-v.cc130
-rw-r--r--gcc/config/riscv/riscv-vector-switch.def97
-rw-r--r--gcc/config/riscv/riscv.cc15
-rw-r--r--gcc/config/riscv/riscv.h3
-rw-r--r--gcc/config/riscv/vector-iterators.md9
-rw-r--r--gcc/config/riscv/vector.md240
-rw-r--r--gcc/config/rs6000/rs6000-call.cc10
-rw-r--r--gcc/config/rs6000/vsx.md4
-rwxr-xr-xgcc/configure266
-rw-r--r--gcc/configure.ac2
-rw-r--r--gcc/cp/ChangeLog84
-rw-r--r--gcc/cp/Make-lang.in4
-rw-r--r--gcc/cp/constraint.cc18
-rw-r--r--gcc/cp/contracts.cc2
-rw-r--r--gcc/cp/coroutines.cc1
-rw-r--r--gcc/cp/cp-tree.h10
-rw-r--r--gcc/cp/decl.cc25
-rw-r--r--gcc/cp/g++spec.cc4
-rw-r--r--gcc/cp/method.cc2
-rw-r--r--gcc/cp/parser.cc32
-rw-r--r--gcc/cp/pt.cc31
-rw-r--r--gcc/cp/semantics.cc15
-rw-r--r--gcc/cp/tree.cc21
-rw-r--r--gcc/d/ChangeLog28
-rw-r--r--gcc/diagnostic-path.h3
-rw-r--r--gcc/diagnostic.cc37
-rw-r--r--gcc/doc/analyzer.texi10
-rw-r--r--gcc/doc/install.texi3
-rw-r--r--gcc/doc/invoke.texi30
-rw-r--r--gcc/fold-const.cc6
-rw-r--r--gcc/fortran/ChangeLog23
-rw-r--r--gcc/fortran/intrinsic.texi60
-rw-r--r--gcc/fortran/resolve.cc2
-rw-r--r--gcc/fortran/simplify.cc11
-rw-r--r--gcc/function.cc3
-rw-r--r--gcc/gcc.cc7
-rw-r--r--gcc/gimple-array-bounds.cc150
-rw-r--r--gcc/gimple-fold.cc17
-rw-r--r--gcc/gimple-fold.h1
-rw-r--r--gcc/gimple-predicate-analysis.cc24
-rw-r--r--gcc/gimple-predicate-analysis.h23
-rw-r--r--gcc/gimple-ssa-warn-access.cc52
-rw-r--r--gcc/gimplify.cc3
-rw-r--r--gcc/ipa-pure-const.cc5
-rw-r--r--gcc/jit/jit-playback.cc27
-rw-r--r--gcc/jit/jit-playback.h2
-rw-r--r--gcc/jit/jit-recording.cc3
-rw-r--r--gcc/jit/jit-recording.h18
-rw-r--r--gcc/lra-constraints.cc13
-rw-r--r--gcc/match.pd26
-rw-r--r--gcc/params.opt4
-rw-r--r--gcc/pointer-query.cc20
-rw-r--r--gcc/pointer-query.h5
-rw-r--r--gcc/range-op-float.cc109
-rw-r--r--gcc/testsuite/ChangeLog410
-rw-r--r--gcc/testsuite/c-c++-common/gomp/target-teams-1.c2
-rw-r--r--gcc/testsuite/c-c++-common/pr57371-4.c8
-rw-r--r--gcc/testsuite/c-c++-common/pr57371-5.c47
-rw-r--r--gcc/testsuite/g++.dg/coroutines/pr100611.C94
-rw-r--r--gcc/testsuite/g++.dg/coroutines/pr101367.C72
-rw-r--r--gcc/testsuite/g++.dg/coroutines/pr101976.C78
-rw-r--r--gcc/testsuite/g++.dg/coroutines/pr99576_1.C124
-rw-r--r--gcc/testsuite/g++.dg/coroutines/pr99576_2.C72
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/decomp56.C29
-rw-r--r--gcc/testsuite/g++.dg/cpp23/constexpr-nonlit10.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp23/constexpr-nonlit11.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires33.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/spaceship-eq3.C1
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/using-enum-10.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/using-enum-10a.C19
-rw-r--r--gcc/testsuite/g++.dg/diagnostic/return-type-loc1.C20
-rw-r--r--gcc/testsuite/g++.dg/gomp/for-21.C18
-rw-r--r--gcc/testsuite/g++.dg/gomp/for-22.C57
-rw-r--r--gcc/testsuite/g++.dg/gomp/pr84469.C24
-rw-r--r--gcc/testsuite/g++.dg/gomp/target-teams-1.C2
-rw-r--r--gcc/testsuite/g++.dg/template/canon-type-19.C18
-rw-r--r--gcc/testsuite/g++.dg/warn/Warray-bounds-pr104165-1.C27
-rw-r--r--gcc/testsuite/g++.target/aarch64/sve/pr107920.C19
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-6.x1
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-9.c31
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-9.x16
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/ieee/ieee.exp3
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr107879.c25
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-11.c2
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-1.c39
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-2.c39
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-3.c39
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-4.c39
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-5.c39
-rw-r--r--gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-6.c39
-rw-r--r--gcc/testsuite/gcc.dg/Wdangling-pointer-pr106868.c14
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-1.c59
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-2.c62
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/attr-nonnull-pr106325.c250
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/attribute-nonnull.c18
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c3
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/fd-bind-pr107928.c10
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/fd-connect-pr107928.c10
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c31
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c98
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/feasibility-pr107948.c49
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/memcpy-pr107882.c8
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-1.c18
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-2.c15
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-3.c27
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-4.c15
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-5.c20
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-container_of.c4
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-multiline-1.c37
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-multiline-2.c32
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-char-arr.c47
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-int-arr.c28
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-struct-arr.c65
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-char-arr.c41
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-int-arr.c22
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-struct-arr.c65
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/pr101962.c2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/realloc-5.c2
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/string-ops-concat-pair.c67
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/string-ops-dup.c61
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/zlib-3.c2
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c1
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c1
-rw-r--r--gcc/testsuite/gcc.dg/pr105676.c14
-rw-r--r--gcc/testsuite/gcc.dg/pr107937.c24
-rw-r--r--gcc/testsuite/gcc.dg/pr107975.c15
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr107833.c33
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr107935.c18
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/branchless-cond.c26
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-18.c7
-rw-r--r--gcc/testsuite/gcc.dg/uninit-pr107839.c13
-rw-r--r--gcc/testsuite/gcc.dg/uninit-pr40635.c33
-rw-r--r--gcc/testsuite/gcc.dg/uninit-pred-9_b.c2
-rw-r--r--gcc/testsuite/gcc.target/aarch64/interleave-init-1.c37
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr107920.c10
-rw-r--r--gcc/testsuite/gcc.target/arm/mve/pr107987.c11
-rw-r--r--gcc/testsuite/gcc.target/arm/simd/mve-compare-1.c48
-rw-r--r--gcc/testsuite/gcc.target/arm/simd/mve-compare-scalar-1.c48
-rw-r--r--gcc/testsuite/gcc.target/arm/simd/mve-vabs.c2
-rw-r--r--gcc/testsuite/gcc.target/arm/simd/mve-vadd-1.c10
-rw-r--r--gcc/testsuite/gcc.target/arm/simd/mve-vadd-scalar-1.c10
-rw-r--r--gcc/testsuite/gcc.target/arm/simd/mve-vcmp.c16
-rw-r--r--gcc/testsuite/gcc.target/arm/simd/pr101325.c4
-rw-r--r--gcc/testsuite/gcc.target/i386/cbranchbf4.c15
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106577.c10
-rw-r--r--gcc/testsuite/gcc.target/i386/pr107627-1.c22
-rw-r--r--gcc/testsuite/gcc.target/i386/pr107627-2.c22
-rw-r--r--gcc/testsuite/gcc.target/i386/pr107863.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr107934.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr107969.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/pr107970.c10
-rw-r--r--gcc/testsuite/gcc.target/mips/pr106462.c12
-rw-r--r--gcc/testsuite/gcc.target/powerpc/pr100866-1.c11
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/base/dup-1.c521
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/base/dup-2.c75
-rw-r--r--gcc/testsuite/gcc.target/x86_64/abi/bf16/abi-bf16.exp12
-rw-r--r--gcc/testsuite/gcc.target/x86_64/abi/bf16/args.h4
-rw-r--r--gcc/testsuite/gcc.target/x86_64/abi/bf16/asm-support-darwin.S97
-rw-r--r--gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/abi-bf16-ymm.exp12
-rw-r--r--gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/args.h4
-rw-r--r--gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/asm-support-darwin.S97
-rw-r--r--gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/abi-bf16-zmm.exp12
-rw-r--r--gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/args.h4
-rw-r--r--gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/asm-support-darwin.S113
-rw-r--r--gcc/testsuite/gfortran.dg/gomp/defaultmap-4.f904
-rw-r--r--gcc/testsuite/gfortran.dg/gomp/defaultmap-5.f904
-rw-r--r--gcc/testsuite/gfortran.dg/gomp/defaultmap-6.f902
-rw-r--r--gcc/testsuite/gfortran.dg/merge_1.f9022
-rw-r--r--gcc/testsuite/gfortran.dg/pr107899.f9013
-rw-r--r--gcc/testsuite/gfortran.dg/unpack_field_1.f9015
-rw-r--r--gcc/testsuite/jit.dg/harness.h15
-rw-r--r--gcc/testsuite/jit.dg/test-expressions.c234
-rw-r--r--gcc/tree-into-ssa.cc11
-rw-r--r--gcc/tree-ssa-loop-im.cc24
-rw-r--r--gcc/tree-ssa-loop-ivopts.cc111
-rw-r--r--gcc/tree-ssa-loop-unswitch.cc4
-rw-r--r--gcc/tree-ssa-sccvn.cc7
-rw-r--r--gcc/tree-ssa.cc93
-rw-r--r--gcc/tree-ssa.h25
-rw-r--r--gcc/tree-vect-patterns.cc2
-rw-r--r--gcc/tree.cc159
-rw-r--r--gcc/tree.h12
-rw-r--r--gcc/varasm.cc2
-rw-r--r--libgomp/ChangeLog57
-rw-r--r--libgomp/config/gcn/icv-device.c15
-rw-r--r--libgomp/config/nvptx/icv-device.c15
-rw-r--r--libgomp/icv-device.c17
-rw-r--r--libgomp/icv.c15
-rw-r--r--libgomp/libgomp.texi10
-rw-r--r--libgomp/plugin/plugin-gcn.c14
-rw-r--r--libgomp/target.c188
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/icv-4.c2
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/icv-5.c198
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/icv-6.c61
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/icv-7.c83
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/icv-9.c72
-rw-r--r--libgomp/testsuite/libgomp.fortran/icv-5.f90226
-rw-r--r--libgomp/testsuite/libgomp.fortran/icv-6.f90140
-rw-r--r--libsanitizer/ChangeLog4
-rw-r--r--libsanitizer/configure.tgt2
-rw-r--r--libstdc++-v3/ChangeLog94
-rw-r--r--libstdc++-v3/config/os/bsd/darwin/os_defines.h18
-rw-r--r--libstdc++-v3/include/bits/std_mutex.h1
-rw-r--r--libstdc++-v3/include/bits/unique_lock.h5
-rw-r--r--libstdc++-v3/include/bits/vector.tcc40
-rw-r--r--libstdc++-v3/include/std/chrono145
-rw-r--r--libstdc++-v3/include/std/format37
-rw-r--r--libstdc++-v3/include/std/mutex14
-rw-r--r--libstdc++-v3/include/std/shared_mutex22
-rw-r--r--libstdc++-v3/include/std/stacktrace19
-rw-r--r--libstdc++-v3/testsuite/17_intro/names.cc7
-rw-r--r--libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/clock_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/30_threads/shared_lock/locking/3.cc2
-rw-r--r--libstdc++-v3/testsuite/30_threads/shared_lock/locking/4.cc2
-rw-r--r--libstdc++-v3/testsuite/30_threads/shared_lock/locking/clock_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/30_threads/try_lock/4.cc2
-rw-r--r--libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc2
-rw-r--r--libstdc++-v3/testsuite/30_threads/unique_lock/locking/3.cc2
-rw-r--r--libstdc++-v3/testsuite/30_threads/unique_lock/locking/clock_neg.cc4
-rw-r--r--libstdc++-v3/testsuite/std/format/functions/107871.cc14
-rw-r--r--libstdc++-v3/testsuite/std/format/functions/format.cc4
-rw-r--r--libstdc++-v3/testsuite/std/format/parse_ctx.cc45
-rw-r--r--libstdc++-v3/testsuite/std/time/hh_mm_ss/1.cc56
-rw-r--r--maintainer-scripts/ChangeLog5
345 files changed, 14710 insertions, 6134 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 55c5ef9..d2eea04 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -165,6 +165,7 @@ D front end Iain Buclaw <ibuclaw@gdcproject.org>
go Ian Lance Taylor <ian@airs.com>
objective-c/c++ Mike Stump <mikestump@comcast.net>
objective-c/c++ Iain Sandoe <iain@sandoe.co.uk>
+Rust Arthur Cohen <arthur.cohen@embecosm.com>
Various Maintainers
diff --git a/Makefile.def b/Makefile.def
index 4a685cc..410c48c 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -50,7 +50,7 @@ host_modules= { module= gcc; bootstrap=true;
extra_make_flags="$(EXTRA_GCC_FLAGS)"; };
host_modules= { module= gmp; lib_path=.libs; bootstrap=true;
// Work around in-tree gmp configure bug with missing flex.
- extra_configure_flags='--disable-shared LEX="touch lex.yy.c"';
+ extra_configure_flags='--disable-shared LEX="touch lex.yy.c" @host_libs_picflag@';
extra_make_flags='AM_CFLAGS="-DNO_ASM"';
no_install= true;
// none-*-* disables asm optimizations, bootstrap-testing
@@ -60,18 +60,19 @@ host_modules= { module= gmp; lib_path=.libs; bootstrap=true;
// different from host for target.
target="none-${host_vendor}-${host_os}"; };
host_modules= { module= mpfr; lib_path=src/.libs; bootstrap=true;
- extra_configure_flags='--disable-shared @extra_mpfr_configure_flags@';
+ extra_configure_flags='--disable-shared @extra_mpfr_configure_flags@ @host_libs_picflag@';
extra_make_flags='AM_CFLAGS="-DNO_ASM"';
no_install= true; };
host_modules= { module= mpc; lib_path=src/.libs; bootstrap=true;
- extra_configure_flags='--disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ --disable-maintainer-mode';
+ extra_configure_flags='--disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ @host_libs_picflag@ --disable-maintainer-mode';
no_install= true; };
host_modules= { module= isl; lib_path=.libs; bootstrap=true;
- extra_configure_flags='--disable-shared @extra_isl_gmp_configure_flags@';
+ extra_configure_flags='--disable-shared @extra_isl_gmp_configure_flags@ @host_libs_picflag@';
extra_make_flags='V=1';
no_install= true; };
host_modules= { module= gold; bootstrap=true; };
host_modules= { module= gprof; };
+// intl acts on 'host_shared' directly, and does not support --with-pic.
host_modules= { module= intl; bootstrap=true; };
host_modules= { module= tcl;
missing=mostlyclean; };
@@ -107,7 +108,7 @@ host_modules= { module= libiberty-linker-plugin; bootstrap=true;
// We abuse missing to avoid installing anything for libiconv.
host_modules= { module= libiconv;
bootstrap=true;
- extra_configure_flags='--disable-shared';
+ extra_configure_flags='--disable-shared @host_libs_picflag@';
no_install= true;
missing= pdf;
missing= html;
@@ -122,7 +123,7 @@ host_modules= { module= sim; };
host_modules= { module= texinfo; no_install= true; };
host_modules= { module= zlib; no_install=true; no_check=true;
bootstrap=true;
- extra_configure_flags='@extra_host_zlib_configure_flags@';};
+ extra_configure_flags='@extra_host_zlib_configure_flags@ @host_libs_picflag@';};
host_modules= { module= gnulib; };
host_modules= { module= gdbsupport; };
host_modules= { module= gdbserver; };
diff --git a/Makefile.in b/Makefile.in
index 019c9a2..8b88677 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -13156,7 +13156,7 @@ configure-gmp:
$$s/$$module_srcdir/configure \
--srcdir=$${topdir}/$$module_srcdir \
$(HOST_CONFIGARGS) --build=${build_alias} --host=none-${host_vendor}-${host_os} \
- --target=none-${host_vendor}-${host_os} --disable-shared LEX="touch lex.yy.c" \
+ --target=none-${host_vendor}-${host_os} --disable-shared LEX="touch lex.yy.c" @host_libs_picflag@ \
|| exit 1
@endif gmp
@@ -13192,7 +13192,7 @@ configure-stage1-gmp:
--target=none-${host_vendor}-${host_os} \
\
$(STAGE1_CONFIGURE_FLAGS) \
- --disable-shared LEX="touch lex.yy.c"
+ --disable-shared LEX="touch lex.yy.c" @host_libs_picflag@
@endif gmp-bootstrap
.PHONY: configure-stage2-gmp maybe-configure-stage2-gmp
@@ -13226,7 +13226,7 @@ configure-stage2-gmp:
--target=none-${host_vendor}-${host_os} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE2_CONFIGURE_FLAGS) \
- --disable-shared LEX="touch lex.yy.c"
+ --disable-shared LEX="touch lex.yy.c" @host_libs_picflag@
@endif gmp-bootstrap
.PHONY: configure-stage3-gmp maybe-configure-stage3-gmp
@@ -13260,7 +13260,7 @@ configure-stage3-gmp:
--target=none-${host_vendor}-${host_os} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE3_CONFIGURE_FLAGS) \
- --disable-shared LEX="touch lex.yy.c"
+ --disable-shared LEX="touch lex.yy.c" @host_libs_picflag@
@endif gmp-bootstrap
.PHONY: configure-stage4-gmp maybe-configure-stage4-gmp
@@ -13294,7 +13294,7 @@ configure-stage4-gmp:
--target=none-${host_vendor}-${host_os} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE4_CONFIGURE_FLAGS) \
- --disable-shared LEX="touch lex.yy.c"
+ --disable-shared LEX="touch lex.yy.c" @host_libs_picflag@
@endif gmp-bootstrap
.PHONY: configure-stageprofile-gmp maybe-configure-stageprofile-gmp
@@ -13328,7 +13328,7 @@ configure-stageprofile-gmp:
--target=none-${host_vendor}-${host_os} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEprofile_CONFIGURE_FLAGS) \
- --disable-shared LEX="touch lex.yy.c"
+ --disable-shared LEX="touch lex.yy.c" @host_libs_picflag@
@endif gmp-bootstrap
.PHONY: configure-stagetrain-gmp maybe-configure-stagetrain-gmp
@@ -13362,7 +13362,7 @@ configure-stagetrain-gmp:
--target=none-${host_vendor}-${host_os} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEtrain_CONFIGURE_FLAGS) \
- --disable-shared LEX="touch lex.yy.c"
+ --disable-shared LEX="touch lex.yy.c" @host_libs_picflag@
@endif gmp-bootstrap
.PHONY: configure-stagefeedback-gmp maybe-configure-stagefeedback-gmp
@@ -13396,7 +13396,7 @@ configure-stagefeedback-gmp:
--target=none-${host_vendor}-${host_os} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEfeedback_CONFIGURE_FLAGS) \
- --disable-shared LEX="touch lex.yy.c"
+ --disable-shared LEX="touch lex.yy.c" @host_libs_picflag@
@endif gmp-bootstrap
.PHONY: configure-stageautoprofile-gmp maybe-configure-stageautoprofile-gmp
@@ -13430,7 +13430,7 @@ configure-stageautoprofile-gmp:
--target=none-${host_vendor}-${host_os} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautoprofile_CONFIGURE_FLAGS) \
- --disable-shared LEX="touch lex.yy.c"
+ --disable-shared LEX="touch lex.yy.c" @host_libs_picflag@
@endif gmp-bootstrap
.PHONY: configure-stageautofeedback-gmp maybe-configure-stageautofeedback-gmp
@@ -13464,7 +13464,7 @@ configure-stageautofeedback-gmp:
--target=none-${host_vendor}-${host_os} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautofeedback_CONFIGURE_FLAGS) \
- --disable-shared LEX="touch lex.yy.c"
+ --disable-shared LEX="touch lex.yy.c" @host_libs_picflag@
@endif gmp-bootstrap
@@ -14293,7 +14293,7 @@ configure-mpfr:
$$s/$$module_srcdir/configure \
--srcdir=$${topdir}/$$module_srcdir \
$(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
- --target=${target_alias} --disable-shared @extra_mpfr_configure_flags@ \
+ --target=${target_alias} --disable-shared @extra_mpfr_configure_flags@ @host_libs_picflag@ \
|| exit 1
@endif mpfr
@@ -14329,7 +14329,7 @@ configure-stage1-mpfr:
--target=${target_alias} \
\
$(STAGE1_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpfr_configure_flags@
+ --disable-shared @extra_mpfr_configure_flags@ @host_libs_picflag@
@endif mpfr-bootstrap
.PHONY: configure-stage2-mpfr maybe-configure-stage2-mpfr
@@ -14363,7 +14363,7 @@ configure-stage2-mpfr:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE2_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpfr_configure_flags@
+ --disable-shared @extra_mpfr_configure_flags@ @host_libs_picflag@
@endif mpfr-bootstrap
.PHONY: configure-stage3-mpfr maybe-configure-stage3-mpfr
@@ -14397,7 +14397,7 @@ configure-stage3-mpfr:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE3_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpfr_configure_flags@
+ --disable-shared @extra_mpfr_configure_flags@ @host_libs_picflag@
@endif mpfr-bootstrap
.PHONY: configure-stage4-mpfr maybe-configure-stage4-mpfr
@@ -14431,7 +14431,7 @@ configure-stage4-mpfr:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE4_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpfr_configure_flags@
+ --disable-shared @extra_mpfr_configure_flags@ @host_libs_picflag@
@endif mpfr-bootstrap
.PHONY: configure-stageprofile-mpfr maybe-configure-stageprofile-mpfr
@@ -14465,7 +14465,7 @@ configure-stageprofile-mpfr:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEprofile_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpfr_configure_flags@
+ --disable-shared @extra_mpfr_configure_flags@ @host_libs_picflag@
@endif mpfr-bootstrap
.PHONY: configure-stagetrain-mpfr maybe-configure-stagetrain-mpfr
@@ -14499,7 +14499,7 @@ configure-stagetrain-mpfr:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEtrain_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpfr_configure_flags@
+ --disable-shared @extra_mpfr_configure_flags@ @host_libs_picflag@
@endif mpfr-bootstrap
.PHONY: configure-stagefeedback-mpfr maybe-configure-stagefeedback-mpfr
@@ -14533,7 +14533,7 @@ configure-stagefeedback-mpfr:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEfeedback_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpfr_configure_flags@
+ --disable-shared @extra_mpfr_configure_flags@ @host_libs_picflag@
@endif mpfr-bootstrap
.PHONY: configure-stageautoprofile-mpfr maybe-configure-stageautoprofile-mpfr
@@ -14567,7 +14567,7 @@ configure-stageautoprofile-mpfr:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautoprofile_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpfr_configure_flags@
+ --disable-shared @extra_mpfr_configure_flags@ @host_libs_picflag@
@endif mpfr-bootstrap
.PHONY: configure-stageautofeedback-mpfr maybe-configure-stageautofeedback-mpfr
@@ -14601,7 +14601,7 @@ configure-stageautofeedback-mpfr:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautofeedback_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpfr_configure_flags@
+ --disable-shared @extra_mpfr_configure_flags@ @host_libs_picflag@
@endif mpfr-bootstrap
@@ -15430,7 +15430,7 @@ configure-mpc:
$$s/$$module_srcdir/configure \
--srcdir=$${topdir}/$$module_srcdir \
$(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
- --target=${target_alias} --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ --disable-maintainer-mode \
+ --target=${target_alias} --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ @host_libs_picflag@ --disable-maintainer-mode \
|| exit 1
@endif mpc
@@ -15466,7 +15466,7 @@ configure-stage1-mpc:
--target=${target_alias} \
\
$(STAGE1_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ --disable-maintainer-mode
+ --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ @host_libs_picflag@ --disable-maintainer-mode
@endif mpc-bootstrap
.PHONY: configure-stage2-mpc maybe-configure-stage2-mpc
@@ -15500,7 +15500,7 @@ configure-stage2-mpc:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE2_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ --disable-maintainer-mode
+ --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ @host_libs_picflag@ --disable-maintainer-mode
@endif mpc-bootstrap
.PHONY: configure-stage3-mpc maybe-configure-stage3-mpc
@@ -15534,7 +15534,7 @@ configure-stage3-mpc:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE3_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ --disable-maintainer-mode
+ --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ @host_libs_picflag@ --disable-maintainer-mode
@endif mpc-bootstrap
.PHONY: configure-stage4-mpc maybe-configure-stage4-mpc
@@ -15568,7 +15568,7 @@ configure-stage4-mpc:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE4_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ --disable-maintainer-mode
+ --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ @host_libs_picflag@ --disable-maintainer-mode
@endif mpc-bootstrap
.PHONY: configure-stageprofile-mpc maybe-configure-stageprofile-mpc
@@ -15602,7 +15602,7 @@ configure-stageprofile-mpc:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEprofile_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ --disable-maintainer-mode
+ --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ @host_libs_picflag@ --disable-maintainer-mode
@endif mpc-bootstrap
.PHONY: configure-stagetrain-mpc maybe-configure-stagetrain-mpc
@@ -15636,7 +15636,7 @@ configure-stagetrain-mpc:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEtrain_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ --disable-maintainer-mode
+ --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ @host_libs_picflag@ --disable-maintainer-mode
@endif mpc-bootstrap
.PHONY: configure-stagefeedback-mpc maybe-configure-stagefeedback-mpc
@@ -15670,7 +15670,7 @@ configure-stagefeedback-mpc:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEfeedback_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ --disable-maintainer-mode
+ --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ @host_libs_picflag@ --disable-maintainer-mode
@endif mpc-bootstrap
.PHONY: configure-stageautoprofile-mpc maybe-configure-stageautoprofile-mpc
@@ -15704,7 +15704,7 @@ configure-stageautoprofile-mpc:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautoprofile_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ --disable-maintainer-mode
+ --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ @host_libs_picflag@ --disable-maintainer-mode
@endif mpc-bootstrap
.PHONY: configure-stageautofeedback-mpc maybe-configure-stageautofeedback-mpc
@@ -15738,7 +15738,7 @@ configure-stageautofeedback-mpc:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautofeedback_CONFIGURE_FLAGS) \
- --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ --disable-maintainer-mode
+ --disable-shared @extra_mpc_gmp_configure_flags@ @extra_mpc_mpfr_configure_flags@ @host_libs_picflag@ --disable-maintainer-mode
@endif mpc-bootstrap
@@ -16567,7 +16567,7 @@ configure-isl:
$$s/$$module_srcdir/configure \
--srcdir=$${topdir}/$$module_srcdir \
$(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
- --target=${target_alias} --disable-shared @extra_isl_gmp_configure_flags@ \
+ --target=${target_alias} --disable-shared @extra_isl_gmp_configure_flags@ @host_libs_picflag@ \
|| exit 1
@endif isl
@@ -16603,7 +16603,7 @@ configure-stage1-isl:
--target=${target_alias} \
\
$(STAGE1_CONFIGURE_FLAGS) \
- --disable-shared @extra_isl_gmp_configure_flags@
+ --disable-shared @extra_isl_gmp_configure_flags@ @host_libs_picflag@
@endif isl-bootstrap
.PHONY: configure-stage2-isl maybe-configure-stage2-isl
@@ -16637,7 +16637,7 @@ configure-stage2-isl:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE2_CONFIGURE_FLAGS) \
- --disable-shared @extra_isl_gmp_configure_flags@
+ --disable-shared @extra_isl_gmp_configure_flags@ @host_libs_picflag@
@endif isl-bootstrap
.PHONY: configure-stage3-isl maybe-configure-stage3-isl
@@ -16671,7 +16671,7 @@ configure-stage3-isl:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE3_CONFIGURE_FLAGS) \
- --disable-shared @extra_isl_gmp_configure_flags@
+ --disable-shared @extra_isl_gmp_configure_flags@ @host_libs_picflag@
@endif isl-bootstrap
.PHONY: configure-stage4-isl maybe-configure-stage4-isl
@@ -16705,7 +16705,7 @@ configure-stage4-isl:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE4_CONFIGURE_FLAGS) \
- --disable-shared @extra_isl_gmp_configure_flags@
+ --disable-shared @extra_isl_gmp_configure_flags@ @host_libs_picflag@
@endif isl-bootstrap
.PHONY: configure-stageprofile-isl maybe-configure-stageprofile-isl
@@ -16739,7 +16739,7 @@ configure-stageprofile-isl:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEprofile_CONFIGURE_FLAGS) \
- --disable-shared @extra_isl_gmp_configure_flags@
+ --disable-shared @extra_isl_gmp_configure_flags@ @host_libs_picflag@
@endif isl-bootstrap
.PHONY: configure-stagetrain-isl maybe-configure-stagetrain-isl
@@ -16773,7 +16773,7 @@ configure-stagetrain-isl:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEtrain_CONFIGURE_FLAGS) \
- --disable-shared @extra_isl_gmp_configure_flags@
+ --disable-shared @extra_isl_gmp_configure_flags@ @host_libs_picflag@
@endif isl-bootstrap
.PHONY: configure-stagefeedback-isl maybe-configure-stagefeedback-isl
@@ -16807,7 +16807,7 @@ configure-stagefeedback-isl:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEfeedback_CONFIGURE_FLAGS) \
- --disable-shared @extra_isl_gmp_configure_flags@
+ --disable-shared @extra_isl_gmp_configure_flags@ @host_libs_picflag@
@endif isl-bootstrap
.PHONY: configure-stageautoprofile-isl maybe-configure-stageautoprofile-isl
@@ -16841,7 +16841,7 @@ configure-stageautoprofile-isl:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautoprofile_CONFIGURE_FLAGS) \
- --disable-shared @extra_isl_gmp_configure_flags@
+ --disable-shared @extra_isl_gmp_configure_flags@ @host_libs_picflag@
@endif isl-bootstrap
.PHONY: configure-stageautofeedback-isl maybe-configure-stageautofeedback-isl
@@ -16875,7 +16875,7 @@ configure-stageautofeedback-isl:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautofeedback_CONFIGURE_FLAGS) \
- --disable-shared @extra_isl_gmp_configure_flags@
+ --disable-shared @extra_isl_gmp_configure_flags@ @host_libs_picflag@
@endif isl-bootstrap
@@ -29673,7 +29673,7 @@ configure-libiconv:
$$s/$$module_srcdir/configure \
--srcdir=$${topdir}/$$module_srcdir \
$(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
- --target=${target_alias} --disable-shared \
+ --target=${target_alias} --disable-shared @host_libs_picflag@ \
|| exit 1
@endif libiconv
@@ -29709,7 +29709,7 @@ configure-stage1-libiconv:
--target=${target_alias} \
\
$(STAGE1_CONFIGURE_FLAGS) \
- --disable-shared
+ --disable-shared @host_libs_picflag@
@endif libiconv-bootstrap
.PHONY: configure-stage2-libiconv maybe-configure-stage2-libiconv
@@ -29743,7 +29743,7 @@ configure-stage2-libiconv:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE2_CONFIGURE_FLAGS) \
- --disable-shared
+ --disable-shared @host_libs_picflag@
@endif libiconv-bootstrap
.PHONY: configure-stage3-libiconv maybe-configure-stage3-libiconv
@@ -29777,7 +29777,7 @@ configure-stage3-libiconv:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE3_CONFIGURE_FLAGS) \
- --disable-shared
+ --disable-shared @host_libs_picflag@
@endif libiconv-bootstrap
.PHONY: configure-stage4-libiconv maybe-configure-stage4-libiconv
@@ -29811,7 +29811,7 @@ configure-stage4-libiconv:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE4_CONFIGURE_FLAGS) \
- --disable-shared
+ --disable-shared @host_libs_picflag@
@endif libiconv-bootstrap
.PHONY: configure-stageprofile-libiconv maybe-configure-stageprofile-libiconv
@@ -29845,7 +29845,7 @@ configure-stageprofile-libiconv:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEprofile_CONFIGURE_FLAGS) \
- --disable-shared
+ --disable-shared @host_libs_picflag@
@endif libiconv-bootstrap
.PHONY: configure-stagetrain-libiconv maybe-configure-stagetrain-libiconv
@@ -29879,7 +29879,7 @@ configure-stagetrain-libiconv:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEtrain_CONFIGURE_FLAGS) \
- --disable-shared
+ --disable-shared @host_libs_picflag@
@endif libiconv-bootstrap
.PHONY: configure-stagefeedback-libiconv maybe-configure-stagefeedback-libiconv
@@ -29913,7 +29913,7 @@ configure-stagefeedback-libiconv:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEfeedback_CONFIGURE_FLAGS) \
- --disable-shared
+ --disable-shared @host_libs_picflag@
@endif libiconv-bootstrap
.PHONY: configure-stageautoprofile-libiconv maybe-configure-stageautoprofile-libiconv
@@ -29947,7 +29947,7 @@ configure-stageautoprofile-libiconv:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautoprofile_CONFIGURE_FLAGS) \
- --disable-shared
+ --disable-shared @host_libs_picflag@
@endif libiconv-bootstrap
.PHONY: configure-stageautofeedback-libiconv maybe-configure-stageautofeedback-libiconv
@@ -29981,7 +29981,7 @@ configure-stageautofeedback-libiconv:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautofeedback_CONFIGURE_FLAGS) \
- --disable-shared
+ --disable-shared @host_libs_picflag@
@endif libiconv-bootstrap
@@ -33045,7 +33045,7 @@ configure-zlib:
$$s/$$module_srcdir/configure \
--srcdir=$${topdir}/$$module_srcdir \
$(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
- --target=${target_alias} @extra_host_zlib_configure_flags@ \
+ --target=${target_alias} @extra_host_zlib_configure_flags@ @host_libs_picflag@ \
|| exit 1
@endif zlib
@@ -33081,7 +33081,7 @@ configure-stage1-zlib:
--target=${target_alias} \
\
$(STAGE1_CONFIGURE_FLAGS) \
- @extra_host_zlib_configure_flags@
+ @extra_host_zlib_configure_flags@ @host_libs_picflag@
@endif zlib-bootstrap
.PHONY: configure-stage2-zlib maybe-configure-stage2-zlib
@@ -33115,7 +33115,7 @@ configure-stage2-zlib:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE2_CONFIGURE_FLAGS) \
- @extra_host_zlib_configure_flags@
+ @extra_host_zlib_configure_flags@ @host_libs_picflag@
@endif zlib-bootstrap
.PHONY: configure-stage3-zlib maybe-configure-stage3-zlib
@@ -33149,7 +33149,7 @@ configure-stage3-zlib:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE3_CONFIGURE_FLAGS) \
- @extra_host_zlib_configure_flags@
+ @extra_host_zlib_configure_flags@ @host_libs_picflag@
@endif zlib-bootstrap
.PHONY: configure-stage4-zlib maybe-configure-stage4-zlib
@@ -33183,7 +33183,7 @@ configure-stage4-zlib:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGE4_CONFIGURE_FLAGS) \
- @extra_host_zlib_configure_flags@
+ @extra_host_zlib_configure_flags@ @host_libs_picflag@
@endif zlib-bootstrap
.PHONY: configure-stageprofile-zlib maybe-configure-stageprofile-zlib
@@ -33217,7 +33217,7 @@ configure-stageprofile-zlib:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEprofile_CONFIGURE_FLAGS) \
- @extra_host_zlib_configure_flags@
+ @extra_host_zlib_configure_flags@ @host_libs_picflag@
@endif zlib-bootstrap
.PHONY: configure-stagetrain-zlib maybe-configure-stagetrain-zlib
@@ -33251,7 +33251,7 @@ configure-stagetrain-zlib:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEtrain_CONFIGURE_FLAGS) \
- @extra_host_zlib_configure_flags@
+ @extra_host_zlib_configure_flags@ @host_libs_picflag@
@endif zlib-bootstrap
.PHONY: configure-stagefeedback-zlib maybe-configure-stagefeedback-zlib
@@ -33285,7 +33285,7 @@ configure-stagefeedback-zlib:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEfeedback_CONFIGURE_FLAGS) \
- @extra_host_zlib_configure_flags@
+ @extra_host_zlib_configure_flags@ @host_libs_picflag@
@endif zlib-bootstrap
.PHONY: configure-stageautoprofile-zlib maybe-configure-stageautoprofile-zlib
@@ -33319,7 +33319,7 @@ configure-stageautoprofile-zlib:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautoprofile_CONFIGURE_FLAGS) \
- @extra_host_zlib_configure_flags@
+ @extra_host_zlib_configure_flags@ @host_libs_picflag@
@endif zlib-bootstrap
.PHONY: configure-stageautofeedback-zlib maybe-configure-stageautofeedback-zlib
@@ -33353,7 +33353,7 @@ configure-stageautofeedback-zlib:
--target=${target_alias} \
--with-build-libsubdir=$(HOST_SUBDIR) \
$(STAGEautofeedback_CONFIGURE_FLAGS) \
- @extra_host_zlib_configure_flags@
+ @extra_host_zlib_configure_flags@ @host_libs_picflag@
@endif zlib-bootstrap
diff --git a/configure b/configure
index d0ceabd..332f841 100755
--- a/configure
+++ b/configure
@@ -686,6 +686,7 @@ get_gcc_base_ver
extra_host_zlib_configure_flags
extra_host_libiberty_configure_flags
stage1_languages
+host_libs_picflag
host_shared
extra_linker_plugin_flags
extra_linker_plugin_configure_flags
@@ -8626,6 +8627,16 @@ fi
+
+# If we are building PIC/PIE host executables, and we are building dependent
+# libs (e.g. GMP) in-tree those libs need to be configured to generate PIC
+# code.
+host_libs_picflag=
+if test "$host_shared" = "yes";then
+host_libs_picflag='--with-pic'
+fi
+
+
# By default, C and C++ are the only stage 1 languages.
stage1_languages=,c,
diff --git a/configure.ac b/configure.ac
index 126210f..c5191ce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1877,8 +1877,18 @@ AC_ARG_ENABLE(host-shared,
x86_64-*-darwin* | aarch64-*-darwin*) host_shared=yes ;;
*) host_shared=no ;;
esac])
+
AC_SUBST(host_shared)
+# If we are building PIC/PIE host executables, and we are building dependent
+# libs (e.g. GMP) in-tree those libs need to be configured to generate PIC
+# code.
+host_libs_picflag=
+if test "$host_shared" = "yes";then
+host_libs_picflag='--with-pic'
+fi
+AC_SUBST(host_libs_picflag)
+
# By default, C and C++ are the only stage 1 languages.
stage1_languages=,c,
diff --git a/contrib/ChangeLog b/contrib/ChangeLog
index 944f67e..6cfef78 100644
--- a/contrib/ChangeLog
+++ b/contrib/ChangeLog
@@ -1,3 +1,7 @@
+2022-12-06 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.doxy (INPUT): Add gcc/analyzer subdirectory.
+
2022-11-25 Martin Liska <mliska@suse.cz>
Revert:
diff --git a/contrib/gcc.doxy b/contrib/gcc.doxy
index a8eeb03..9e0a1af 100644
--- a/contrib/gcc.doxy
+++ b/contrib/gcc.doxy
@@ -478,7 +478,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = gcc
+INPUT = gcc gcc/analyzer
# This tag can be used to specify the character encoding of the source files that
# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 90f6649..2e6869f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,461 @@
+2022-12-06 Wilco Dijkstra <wilco.dijkstra@arm.com>
+
+ * config/aarch64/aarch64.cc (aarch64_bitmask_imm): Use unsigned type.
+ (aarch64_is_mov_xn_imm): New function.
+ (aarch64_move_imm): Refactor, assert mode is SImode or DImode.
+ (aarch64_internal_mov_immediate): Assert mode is SImode or DImode.
+ Simplify special cases.
+ (aarch64_uimm12_shift): Simplify code.
+ (aarch64_clamp_to_uimm12_shift): Likewise.
+ (aarch64_movw_imm): Rename to aarch64_is_movz.
+ (aarch64_float_const_rtx_p): Pass either SImode or DImode to
+ aarch64_internal_mov_immediate.
+ (aarch64_rtx_costs): Likewise.
+ * config/aarch64/aarch64.md (movdi_aarch64): Merge 'N' and 'M'
+ constraints into single 'O'.
+ (mov<mode>_aarch64): Likewise.
+ * config/aarch64/aarch64-protos.h (aarch64_move_imm): Use unsigned.
+ (aarch64_bitmask_imm): Likewise.
+ (aarch64_uimm12_shift): Likewise.
+ (aarch64_is_mov_xn_imm): New prototype.
+ * config/aarch64/constraints.md: Add 'O' for 32/64-bit immediates,
+ limit 'N' to 64-bit only moves.
+
+2022-12-06 Qing Zhao <qing.zhao@oracle.com>
+
+ * attribs.cc (strict_flex_array_level_of): New function.
+ * attribs.h (strict_flex_array_level_of): Prototype for new function.
+ * doc/invoke.texi: Update -Warray-bounds by specifying the impact from
+ -fstrict-flex-arrays. Also update -Warray-bounds=2 by eliminating its
+ impact on treating trailing arrays as flexible array members.
+ * gimple-array-bounds.cc (get_up_bounds_for_array_ref): New function.
+ (check_out_of_bounds_and_warn): New function.
+ (array_bounds_checker::check_array_ref): Update with call to the above
+ new functions.
+ * tree.cc (array_ref_flexible_size_p): Add one new argument.
+ (component_ref_sam_type): New function.
+ (component_ref_size): Control with level of strict-flex-array.
+ * tree.h (array_ref_flexible_size_p): Update prototype.
+ (enum struct special_array_member): Add two new enum values.
+ (component_ref_sam_type): New prototype.
+
+2022-12-06 David Malcolm <dmalcolm@redhat.com>
+
+ * doc/analyzer.texi: Drop out-of-date ideas for other checkers.
+
+2022-12-06 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (ANALYZER_OBJS): Add analyzer/call-details.o,
+ analyzer/kf-analyzer.o, and kf-lang-cp.o.
+
+2022-12-06 Marcel Vollweiler <marcel@codesourcery.com>
+
+ * gimplify.cc (optimize_target_teams): Set initial num_teams_upper
+ to "-2" instead of "1" for non-existing num_teams clause in order to
+ disambiguate from the case of an existing num_teams clause with value 1.
+
+2022-12-06 Andre Vieira <andre.simoesdiasvieira@arm.com>
+
+ PR target/107987
+ * config/arm/mve.md (mve_vcmp<mve_cmp_op>q_n_<mode>,
+ @mve_vcmp<mve_cmp_op>q_n_f<mode>): Apply vec_duplicate to scalar
+ operand.
+
+2022-12-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/107969
+ * config/i386/i386.md (cbranchbf4, cstorebf4): Guard expanders
+ with the same condition as cbranchsf4 or cstoresf4 expanders.
+
+2022-12-06 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/104475
+ * pointer-query.h (access_ref::ref_nullptr_p): New flag.
+ * pointer-query.cc (access_ref::access_ref): Initialize
+ ref_nullptr_p.
+ (compute_objsize_r): Set ref_nullptr_p if we treat it that way.
+ (access_ref::inform_access): If ref was treated as nullptr
+ based, indicate that.
+
+2022-12-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/107972
+ * range-op-float.cc (frange_drop_infs): New function.
+ (float_binary_op_range_finish): Add DIV_OP2 argument. If DIV_OP2 is
+ false and lhs is finite or if DIV_OP2 is true and lhs is non-zero and
+ not NAN, r must be finite too.
+ (foperator_div::op2_range): Pass true to DIV_OP2 of
+ float_binary_op_range_finish.
+
+2022-12-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/107975
+ * range-op-float.cc (foperator_mult::op1_range,
+ foperator_div::op1_range, foperator_div::op2_range): Just
+ return float_binary_op_range_finish result if lhs is known
+ NAN, or the other operand is known NAN or UNDEFINED.
+
+2022-12-06 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+
+ * config/aarch64/aarch64.cc (aarch64_expand_vector_init): Use dup
+ and zip1 for interleaving elements in vector initializer.
+
+2022-12-05 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/40635
+ * tree-into-ssa.cc (rewrite_update_phi_arguments): Only
+ update the argument when the reaching definition is different
+ from the current argument. Keep an existing argument
+ location.
+
+2022-12-05 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/106868
+ * gimple-ssa-warn-access.cc (pass_waccess::gimple_call_return_arg_ref):
+ Inline into single user ...
+ (pass_waccess::check_dangling_uses): ... here and adjust the
+ call and the PHI case to require that ref.aref is the address
+ of the decl.
+
+2022-12-05 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/106805
+ * match.pd (cmp @0 REAL_CST@1): Don't optimize x cmp NaN
+ or NaN cmp x to false/true for cmp >/>=/</<= if -ftrapping-math.
+
+2022-12-05 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/107879
+ * range-op-float.cc (foperator_mult::op1_range): If both
+ lhs and op2 ranges contain zero or both ranges contain
+ some infinity, set r range to zero_to_inf_range depending on
+ signbit_known_p.
+ (foperator_div::op2_range): Similarly for lhs and op1 ranges.
+ (foperator_div::op1_range): If lhs range contains zero and op2
+ range contains some infinity or vice versa, set r range to
+ zero_to_inf_range depending on signbit_known_p.
+ (foperator_div::rv_fold): Fix up condition for returning known NAN.
+
+2022-12-05 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/107833
+ PR tree-optimization/107839
+ * cfghooks.cc: Include tree.h.
+ * tree-ssa-loop-im.cc (movement_possibility): Wrap and
+ make stmts using any ssa_name_maybe_undef_p operand
+ to preserve execution.
+ (loop_invariant_motion_in_fun): Call mark_ssa_maybe_undefs
+ to init maybe-undefined status.
+ * tree-ssa-loop-ivopts.cc (ssa_name_maybe_undef_p,
+ ssa_name_set_maybe_undef, ssa_name_any_use_dominates_bb_p,
+ mark_ssa_maybe_undefs): Move ...
+ * tree-ssa.cc: ... here.
+ * tree-ssa.h (ssa_name_any_use_dominates_bb_p,
+ mark_ssa_maybe_undefs): Declare.
+ (ssa_name_maybe_undef_p, ssa_name_set_maybe_undef): Define.
+
+2022-12-05 Andrew Pinski <pinskia@gmail.com>
+
+ PR tree-optimization/107956
+ * tree-vect-patterns.cc (vect_recog_mask_conversion_pattern):
+ Check for NULL LHS on masked loads.
+
+2022-12-05 Kewen Lin <linkw@linux.ibm.com>
+ Richard Sandiford <richard.sandiford@arm.com>
+
+ PR tree-optimization/107412
+ * gimple-fold.cc (gimple_fold_partial_load_store_mem_ref): Use
+ untruncated type for the length, and avoid to_constant and tree
+ arithmetic for subtraction.
+
+2022-12-02 Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
+ Jason Merrill <jason@redhat.com>
+
+ * function.cc (init_function_start): Use DECL_RESULT location
+ for -Waggregate-return warning.
+
+2022-12-02 Andrew MacLeod <amacleod@redhat.com>
+
+ * fold-const.cc (fold_unary_loc): Check TREE_TYPE of node.
+ (tree_invalid_nonnegative_warnv_p): Likewise.
+
+2022-12-02 Jason Merrill <jason@redhat.com>
+
+ * gcc.cc (validate_switches): Reset suffix/starred on loop.
+
+2022-12-02 Vladimir N. Makarov <vmakarov@redhat.com>
+
+ * lra-constraints.cc (curr_insn_transform): Check available hard
+ regs for pseudo and its subreg to decide what to reload.
+
+2022-12-02 liuhongt <hongtao.liu@intel.com>
+
+ * config/i386/i386-expand.cc
+ (ix86_expand_fast_convert_bf_to_sf): Use extendbfsf2_1 for
+ nonimmediate operand.
+
+2022-12-02 Martin Liska <mliska@suse.cz>
+
+ * configure: Regenerate.
+
+2022-12-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/106577
+ * config/i386/i386-expand.cc (ix86_vector_duplicate_value): Save/restore
+ recog_data around recog_memoized calls.
+
+2022-12-02 Michael Collison <collison@rivosinc.com>
+
+ * match.pd ((x & 0x1) == 0) ? y : z <op> y
+ -> (-(typeof(y))(x & 0x1) & z) <op> y.
+
+2022-12-02 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/107946
+ * params.opt (-param=max-unswitch-depth=): New.
+ * doc/invoke.texi (--param=max-unswitch-depth): Document.
+ * tree-ssa-loop-unswitch.cc (init_loop_unswitch_info): Honor
+ --param=max-unswitch-depth
+
+2022-12-02 Eric Gallager <egallager@gcc.gnu.org>
+
+ PR bootstrap/59447
+ * configure: Regenerate.
+ * configure.ac: Document --with-dwarf2 flag as also
+ applying to later DWARF standards.
+ * doc/install.texi: Likewise.
+
+2022-12-02 liuhongt <hongtao.liu@intel.com>
+
+ PR target/107934
+ * config/i386/i386.md (extendbfsf2_1): Change type from
+ sseishft to sseishft1.
+
+2022-12-01 Alex Coplan <alex.coplan@arm.com>
+
+ * varasm.cc (assemble_variable): Fix type confusion bug when
+ checking for ".vtable_map_vars" section.
+
+2022-12-01 Ju-Zhe Zhong <juzhe.zhong@rivai.ai>
+
+ * config/riscv/riscv-v.cc (emit_pred_op): Adapt for mask mode.
+ * config/riscv/vector.md: Remove Tail && make policy operand for mask mode mov.
+
+2022-12-01 Ju-Zhe Zhong <juzhe.zhong@rivai.ai>
+
+ * config/riscv/riscv-protos.h (enum vlmul_type): New enum.
+ (get_vlmul): New function.
+ (get_ratio): Ditto.
+ * config/riscv/riscv-v.cc (struct mode_vtype_group): New struct.
+ (ENTRY): Adapt for attributes.
+ (enum vlmul_type): New enum.
+ (get_vlmul): New function.
+ (get_ratio): New function.
+ * config/riscv/riscv-vector-switch.def (ENTRY): Adapt for attributes.
+ * config/riscv/riscv.cc (ENTRY): Ditto.
+ * config/riscv/vector.md (false,true): Add attributes.
+
+2022-12-01 Ju-Zhe Zhong <juzhe.zhong@rivai.ai>
+
+ * config/riscv/constraints.md (Wdm): New constraint.
+ * config/riscv/predicates.md (direct_broadcast_operand): New predicate.
+ * config/riscv/riscv-protos.h (RVV_VLMAX): New macro.
+ (emit_pred_op): Refine function.
+ * config/riscv/riscv-selftests.cc (run_const_vector_selftests): New function.
+ (run_broadcast_selftests): Ditto.
+ (BROADCAST_TEST): New tests.
+ (riscv_run_selftests): More tests.
+ * config/riscv/riscv-v.cc (emit_pred_move): Refine function.
+ (emit_vlmax_vsetvl): Ditto.
+ (emit_pred_op): Ditto.
+ (expand_const_vector): New function.
+ (legitimize_move): Add constant vector support.
+ * config/riscv/riscv.cc (riscv_print_operand): New asm print rule for const vector.
+ * config/riscv/riscv.h (X0_REGNUM): New macro.
+ * config/riscv/vector-iterators.md: New attribute.
+ * config/riscv/vector.md (vec_duplicate<mode>): New pattern.
+ (@pred_broadcast<mode>): New pattern.
+
+2022-12-01 Paul-Antoine Arras <pa@codesourcery.com>
+
+ * config/gcn/gcn-opts.h (TARGET_FIJI): -march=fiji.
+ (TARGET_VEGA10): -march=gfx900.
+ (TARGET_VEGA20): -march=gfx906.
+ (TARGET_GFX908): -march=gfx908.
+ (TARGET_GFX90a): -march=gfx90a.
+ * config/gcn/gcn.h (TARGET_CPU_CPP_BUILTINS): Define a builtin that
+ uniquely maps to '-march'.
+
+2022-12-01 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/107937
+ * gimple-predicate-analysis.h (predicate::is_true): New.
+ (predicate::is_false): Likewise.
+ (predicate::empty_val): Likewise.
+ (uninit_analysis::uninit_analysis): Properly initialize
+ def_preds.
+ * gimple-predicate-analysis.cc (simplify_1b): Indicate
+ whether the chain became empty.
+ (predicate::simplify): Release emptied chain before removing it.
+ (predicate::normalize): Replace temporary object with assertion.
+ (uninit_analysis::is_use_guarded): Deal with predicates
+ that simplify to true/false.
+
+2022-12-01 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/107935
+ * tree-ssa-sccvn.cc (visit_phi): Honor forced VARYING on
+ backedges.
+
+2022-12-01 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/107627
+ * config/i386/i386.md (*concat<mode><dwi>3_1, *concat<mode><dwi>3_2):
+ For operands which are zero_extend arguments allow memory if
+ output operand is a register.
+ (*concat<mode><dwi>3_3, *concat<mode><dwi>3_4): Likewise. If
+ both input operands are memory, use early clobber on output operand.
+ * config/i386/i386-expand.cc (split_double_concat): Deal with corner
+ cases where one input is memory and the other is not and the address
+ of the memory input uses a register we'd overwrite before loading
+ the memory into a register.
+
+2022-12-01 Haochen Gui <guihaoc@gcc.gnu.org>
+
+ * config/rs6000/rs6000-call.cc (swap_endian_selector_for_mode):
+ Corrects comments of this function and make them clear.
+
+2022-12-01 liuhongt <hongtao.liu@intel.com>
+
+ PR target/107863
+ * config/i386/i386-expand.cc (ix86_expand_vec_set_builtin):
+ Convert op1 to target mode whenever mode mismatch.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106626
+ * diagnostic-path.h
+ (diagnostic_path::get_first_event_in_a_function): New decl.
+ * diagnostic.cc (diagnostic_path::get_first_event_in_a_function):
+ New.
+ (diagnostic_path::interprocedural_p): Ignore leading events that
+ are outside of any function.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (ANALYZER_OBJS): Add analyzer/bounds-checking.o.
+
+2022-12-01 Haochen Gui <guihaoc@gcc.gnu.org>
+
+ PR target/100866
+ * config/rs6000/rs6000-call.cc (swap_endian_selector_for_mode):
+ Generate permute index directly for little endian targets.
+ * config/rs6000/vsx.md (revb_<mode>): Call vprem directly with
+ corresponding permute indexes.
+
+2022-11-30 John David Anglin <danglin@gcc.gnu.org>
+
+ * config/pa/pa.md (addvdi3): Force operand 2 to a register.
+ Remove "addi,tsv,*" instruction from unamed pattern.
+ (subvdi3): Force operand 1 to a register.
+ Remove "subi,tsv" instruction from from unamed pattern.
+
+2022-11-30 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * config/aarch64/aarch64.md (aarch64_cpymemdi): Specify clobber of CC reg.
+ (*aarch64_cpymemdi): Likewise.
+ (aarch64_movmemdi): Likewise.
+ (aarch64_setmemdi): Likewise.
+ (*aarch64_setmemdi): Likewise.
+
+2022-11-30 Martin Liska <mliska@suse.cz>
+
+ * tree-switch-conversion.cc (bit_test_cluster::emit): Remove
+ dead variable bt_range.
+
+2022-11-30 Iskander Shakirzyanov <iskander@ispras.ru>
+ Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
+
+ PR driver/107787
+ * common.opt (Warray-bounds): Turn into alias of
+ -Warray-bounds=1.
+ * builtins.cc (c_strlen): Use OPT_Warray_bounds_
+ instead of OPT_Warray_bounds.
+ * diagnostic-spec.cc (nowarn_spec_t::nowarn_spec_t): Ditto.
+ * gimple-array-bounds.cc (array_bounds_checker::check_array_ref,
+ array_bounds_checker::check_mem_ref,
+ array_bounds_checker::check_addr_expr,
+ array_bounds_checker::check_array_bounds): Ditto.
+ * gimple-ssa-warn-restrict.cc (maybe_diag_access_bounds): Ditto.
+
+2022-11-30 Martin Liska <mliska@suse.cz>
+
+ PR tree-optimization/101301
+ PR tree-optimization/103680
+ * tree-switch-conversion.cc (bit_test_cluster::emit):
+ Handle correctly remaining probability.
+ (switch_decision_tree::try_switch_expansion): Fix BB's count
+ where a cluster expansion happens.
+ (switch_decision_tree::emit_cmp_and_jump_insns): Fill up also
+ BB count.
+ (switch_decision_tree::do_jump_if_equal): Likewise.
+ (switch_decision_tree::emit_case_nodes): Handle special case
+ for BT expansion which can also fallback to a default BB.
+ * tree-switch-conversion.h (cluster::cluster): Add
+ m_default_prob probability.
+
+2022-11-30 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/107919
+ * gimple-predicate-analysis.cc (simplify_1): Rename to ...
+ (simplify_1a): .. this.
+ (simplify_1b): New.
+ (predicate::simplify): Call both simplify_1a and simplify_1b.
+
+2022-11-30 Richard Biener <rguenther@suse.de>
+
+ * tree-ssa-uninit.cc (find_uninit_use): Dump the edge for a
+ PHI node.
+
+2022-11-30 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/107919
+ * gimple-predicate-analysis.cc (predicate::simplify_2):
+ Handle predicates of arbitrary length.
+
+2022-11-30 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/107835
+ * tree-chrec.cc (chrec_apply): Don't handle "{a, +, a} (x-1)"
+ as "a*x" if type is a pointer type.
+
+2022-11-30 Paul-Antoine Arras <pa@codesourcery.com>
+
+ * config/gcn/gcn.cc (gcn_omp_device_kind_arch_isa): Add gfx803.
+ * config/gcn/t-omp-device: Add gfx803.
+
+2022-11-30 Lulu Cheng <chenglulu@loongson.cn>
+
+ * config/loongarch/linux.h (STACK_CHECK_MOVING_SP):
+ Define this macro to 1.
+ * config/loongarch/loongarch.cc (STACK_CLASH_PROTECTION_GUARD_SIZE):
+ Size of guard page.
+ (loongarch_first_stack_step): Return the size of the first drop stack
+ according to whether stack checking is performed.
+ (loongarch_emit_probe_stack_range): Adjust the method of stack checking in prologue.
+ (loongarch_output_probe_stack_range): Delete useless code.
+ (loongarch_expand_prologue): Adjust the method of stack checking in prologue.
+ (loongarch_option_override_internal): Enforce that interval is the same
+ size as size so the mid-end does the right thing.
+ * config/loongarch/loongarch.h (STACK_CLASH_MAX_UNROLL_PAGES):
+ New macro decide whether to loop stack detection.
+
+2022-11-30 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/103546
+ * doc/invoke.texi (Static Analyzer Options): Add isatty, ferror,
+ fileno, and getc to the list of functions known to the analyzer.
+
2022-11-29 Richard Biener <rguenther@suse.de>
PR tree-optimization/107852
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index e6a7597..ec18fda0 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20221130
+20221207
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index fa5e5b4..7bcc5e5 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1255,6 +1255,8 @@ ANALYZER_OBJS = \
analyzer/analyzer-pass.o \
analyzer/analyzer-selftests.o \
analyzer/bar-chart.o \
+ analyzer/bounds-checking.o \
+ analyzer/call-details.o \
analyzer/call-info.o \
analyzer/call-string.o \
analyzer/call-summary.o \
@@ -1267,6 +1269,8 @@ ANALYZER_OBJS = \
analyzer/feasible-graph.o \
analyzer/function-set.o \
analyzer/infinite-recursion.o \
+ analyzer/kf-analyzer.o \
+ analyzer/kf-lang-cp.o \
analyzer/known-function-manager.o \
analyzer/pending-diagnostic.o \
analyzer/program-point.o \
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index 00b3756..7ecefd8 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,226 @@
+2022-12-06 Yannick Moy <moy@adacore.com>
+
+ * contracts.adb (Add_Contract_Item): Allow No_Caching on types.
+ (Check_Type_Or_Object_External_Properties): Check No_Caching.
+ Check that non-effectively volatile types does not contain an
+ effectively volatile component (instead of just a volatile
+ component).
+ (Analyze_Object_Contract): Remove shared checking of No_Caching.
+ * sem_prag.adb (Analyze_External_Property_In_Decl_Part): Adapt checking
+ of No_Caching for types.
+ (Analyze_Pragma): Allow No_Caching on types.
+ * sem_util.adb (Has_Effectively_Volatile_Component): New query function.
+ (Is_Effectively_Volatile): Type with Volatile and No_Caching is not
+ effectively volatile.
+ (No_Caching_Enabled): Remove assertion to apply to all entities.
+ * sem_util.ads: Same.
+
+2022-12-06 Javier Miranda <miranda@adacore.com>
+
+ * exp_ch6.adb
+ (Build_Static_Check_Helper_Call): Perform implicit type conversion
+ to ensure matching types and avoid reporting spurious errors.
+
+2022-12-06 Eric Botcazou <ebotcazou@adacore.com>
+
+ * sem_warn.adb (Warn_On_Constant_Valid_Condition): Bail out for a
+ membership test with a mark for a subtype that is predicated.
+
+2022-12-06 Eric Botcazou <ebotcazou@adacore.com>
+
+ * sem_elab.adb (Processing_In_State): Add Within_Freezing_Actions
+ component.
+ (Process_Conditional_ABE_Call): Compute its value.
+ (Process_Conditional_ABE_Call_SPARK): For a call and a target in
+ the main unit, do not emit any ABE diagnostics if the call occurs
+ in a freezing actions context.
+
+2022-12-06 Eric Botcazou <ebotcazou@adacore.com>
+
+ * einfo.ads (Actual_Subtype): Document additional usage.
+ * exp_aggr.adb (Expand_Array_Aggregate): Replace test on
+ Is_Build_In_Place_Return_Object with Is_Special_Return_Object.
+ * exp_ch3.adb (Expand_N_Object_Declaration): Factor out parts of the
+ processing done for build-in-place return objects and reuse them to
+ implement a similar processing for specific return objects.
+ * exp_ch4.adb (Expand_Allocator_Expression): Do not generate a tag
+ assignment or an adjustment if the allocator was made for a special
+ return object.
+ (Expand_Concatenate): If the result is allocated on the secondary
+ stack, use an unconstrained allocation.
+ * exp_ch6.ads (Apply_CW_Accessibility_Check): New declaration.
+ (Is_By_Reference_Return_Object): Likewise.
+ (Is_Secondary_Stack_Return_Object): Likewise.
+ (Is_Special_Return_Object): Likewise.
+ * exp_ch6.adb (Expand_Ctrl_Function_Call): Do not bail out for the
+ expression in the declaration of a special return object.
+ (Expand_N_Extended_Return_Statement): Add missing guard and move
+ the class-wide accessibility check to Expand_N_Object_Declaration.
+ (Expand_Simple_Function_Return): Delete obsolete commentary.
+ Skip the special processing for types that require finalization or
+ are returned on the secondary stack if the return originally comes
+ from an extended return statement. Add missing Constant_Present.
+ (Is_By_Reference_Return_Object): New predicate.
+ (Is_Secondary_Stack_Return_Object): Likewise.
+ (Is_Special_Return_Object): Likewise.
+ * exp_util.adb (Is_Related_To_Func_Return): Also return true if the
+ parent of the expression is the renaming declaration generated for
+ the expansion of a return object.
+ * gen_il-fields.ads (Opt_Field_Enum): Replace Alloc_For_BIP_Return
+ with For_Special_Return_Object.
+ * gen_il-gen-gen_nodes.adb (N_Allocator): Likewise.
+ * gen_il-internals.adb (Image): Remove Alloc_For_BIP_Return.
+ * sem_ch3.adb (Check_Return_Subtype_Indication): New procedure
+ moved from sem_ch6.adb.
+ (Analyze_Object_Declaration): Call it on a return object.
+ * sem_ch4.adb: Add with and use clauses for Rtsfind.
+ (Analyze_Allocator): Test For_Special_Return_Object to skip checks
+ for allocators made for special return objects.
+ Do not report restriction violations for the return stack pool.
+ * sem_ch5.adb (Analyze_Assignment.Set_Assignment_Type): Return the
+ Actual_Subtype for return objects that live on the secondary stack.
+ * sem_ch6.adb (Check_Return_Subtype_Indication): Move procedure to
+ sem_ch3.adb.
+ (Analyze_Function_Return): Do not call above procedure.
+ * sem_res.adb (Resolve_Allocator): Replace Alloc_For_BIP_Return
+ with For_Special_Return_Object.
+ * sinfo.ads: Likewise.
+ * treepr.adb (Image): Remove Alloc_For_BIP_Return.
+ * gcc-interface/trans.cc (gnat_to_gnu): Do not convert to the result
+ type in the unconstrained array type case if the parent is a simple
+ return statement.
+
+2022-12-06 Eric Botcazou <ebotcazou@adacore.com>
+
+ * sem_res.adb (Resolve_Membership_Op): Adjust latest change.
+
+2022-12-06 Eric Botcazou <ebotcazou@adacore.com>
+
+ * exp_ch4.adb (Expand_N_In) <Substitute_Valid_Check>: Rename to...
+ <Substitute_Valid_Test>: ...this.
+ Use Is_Entity_Name to test for the presence of entity references.
+ Do not warn or substitute a valid test for a test with a mark for
+ a subtype that is predicated.
+ Apply the same transformation for a test with a mark for a subtype
+ that is predicated as for a subtype that is not.
+ Remove useless return statement.
+ * sem_res.adb (Resolve_Membership_Op): Perform a special resolution
+ if the left operand is of a universal numeric type.
+
+2022-12-06 Justin Squirek <squirek@adacore.com>
+
+ * accessibility.adb, accessibility.ads
+ (Accessibility_Message): Moved from sem_attr.
+ (Apply_Accessibility_Check): Moved from checks.
+ (Apply_Accessibility_Check_For_Allocator): Moved from exp_ch4 and
+ renamed
+ (Check_Return_Construct_Accessibility): Moved from sem_ch6.
+ (Innermost_Master_Scope_Depth): Moved from sem_util. Add condition
+ to detect expanded iterators.
+ (Prefix_With_Safe_Accessibility_Level): Moved from sem_attr.
+ (Static_Accessibility_Level): Moved from sem_util.
+ (Has_Unconstrained_Access_Discriminants): Likewise.
+ (Has_Anonymous_Access_Discriminant): Likewise.
+ (Is_Anonymous_Access_Actual): Likewise.
+ (Is_Special_Aliased_Formal_Access): Likewise.
+ (Needs_Result_Accessibility_Level): Likewise.
+ (Subprogram_Access_Level): Likewise.
+ (Type_Access_Level): Likewise.
+ (Deepest_Type_Access_Level): Likewise.
+ (Effective_Extra_Accessibility): Likewise.
+ (Get_Dynamic_Accessibility): Likewise.
+ (Has_Access_Values): Likewise.
+ (Accessibility_Level): Likewise.
+ * exp_attr.adb (Access_Cases): Obtain the proper enclosing object
+ which applies to a given 'Access by looking through type
+ conversions.
+ * exp_ch4.adb (Apply_Accessibility_Check): Moved to accessibility.
+ * exp_ch5.adb: Likewise.
+ * exp_ch6.adb: Likewise.
+ * exp_ch9.adb: Likewise.
+ * exp_disp.adb: Likewise.
+ * gen_il-fields.ads: Add new flag Comes_From_Iterator.
+ * gen_il-gen-gen_nodes.adb: Add new flag Comes_From_Iterator for
+ N_Object_Renaming_Declaration.
+ * sem_ch5.adb (Analyze_Iterator_Specification): Mark object
+ renamings resulting from iterator expansion with the new flag
+ Comes_From_Iterator.
+ * sem_aggr.adb (Resolve_Container_Aggregate): Refine test.
+ * sem_ch13.adb: Add dependence on the accessibility package.
+ * sem_ch3.adb: Likewise.
+ * sem_ch4.adb: Likewise.
+ * sem_ch9.adb: Likewise.
+ * sem_res.adb: Likewise.
+ * sem_warn.adb: Likewise.
+ * exp_ch3.adb: Likewise.
+ * sem_attr.adb (Accessibility_Message): Moved to accessibility.
+ (Prefix_With_Safe_Accessibility_Level): Likewise.
+ * checks.adb, checks.ads (Apply_Accessibility_Check): Likewise.
+ * sem_ch6.adb (Check_Return_Construct_Accessibility): Likewise.
+ * sem_util.adb, sem_util.ads
+ (Accessibility_Level): Likewise.
+ (Deepest_Type_Access_Level): Likewise.
+ (Effective_Extra_Accessibility): Likewise.
+ (Get_Dynamic_Accessibility): Likewise.
+ (Has_Access_Values): Likewise.
+ (Has_Anonymous_Access_Discriminant): Likewise.
+ (Static_Accessibility_Level): Likewise.
+ (Has_Unconstrained_Access_Discriminants): Likewise.
+ (Is_Anonymous_Access_Actual): Likewise.
+ (Is_Special_Aliased_Formal_Access): Likewise.
+ (Needs_Result_Accessibility_Level): Likewise.
+ (Subprogram_Access_Level): Likewise.
+ (Type_Access_Level): Likewise.
+ * sinfo.ads: Document new flag Comes_From_Iterator.
+ * gcc-interface/Make-lang.in: Add entry for new Accessibility package.
+
+2022-12-06 Liaiss Merzougue <merzougue@adacore.com>
+
+ * libgnat/i-c.adb (To_C): Simplify code for having a single
+ exception raise. Add pragma annotate about uninitialized value
+ which happen only on exception raising.
+
+2022-12-01 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/trans.cc (get_storage_model_access): Strip any type
+ conversion around the node before looking into it.
+
+2022-12-01 Steve Baird <baird@adacore.com>
+
+ * sem_ch13.adb
+ (Validate_Aspect_Aggregate): Reject illegal case where none of
+ Add_Named, Add_Unnamed, and Assign_Indexed are specified.
+
+2022-12-01 Eric Botcazou <ebotcazou@adacore.com>
+
+ * doc/gnat_ugn/gnat_and_program_execution.rst (Non-Symbolic
+ Traceback): Add compilation line.
+ (Symbolic Traceback): Remove obsolete stuff.
+ * doc/gnat_ugn/gnat_utility_programs.rst (gnatsymbolize): Adjust.
+ * gnat_ugn.texi: Regenerate.
+
+2022-12-01 Ronan Desplanques <desplanques@adacore.com>
+
+ * lib-xref.adb (Generate_Reference): Fix misphrasing in comment.
+
+2022-12-01 Gary Dismukes <dismukes@adacore.com>
+
+ * sem_attr.adb (Analyze_Attribute, Attribute_Address): In the case
+ where the attribute's prefix is a dereference of a value of an
+ access type that has aspect Designated_Storage_Model (or a
+ renaming of such a dereference), set the attribute's type to the
+ corresponding Storage_Model_Type's associated address type rather
+ than System.Address.
+
+2022-12-01 Ronan Desplanques <desplanques@adacore.com>
+
+ * doc/gnat_rm/the_gnat_library.rst: Fix minor issues.
+ * gnat_rm.texi: Regenerate.
+
+2022-12-01 Josue Nava Bello <nava@adacore.com>
+
+ * doc/share/conf.py: minor updates
+
2022-11-28 Eric Botcazou <ebotcazou@adacore.com>
* libgnat/g-traceb.ads: Minor tweaks in the commentary.
diff --git a/gcc/ada/accessibility.adb b/gcc/ada/accessibility.adb
new file mode 100644
index 0000000..3162806
--- /dev/null
+++ b/gcc/ada/accessibility.adb
@@ -0,0 +1,2305 @@
+------------------------------------------------------------------------------
+-- --
+-- GNAT COMPILER COMPONENTS --
+-- --
+-- A C C E S S I B I L I T Y --
+-- --
+-- B o d y --
+-- --
+-- Copyright (C) 2022-2022, Free Software Foundation, Inc. --
+-- --
+-- GNAT is free software; you can redistribute it and/or modify it under --
+-- terms of the GNU General Public License as published by the Free Soft- --
+-- ware Foundation; either version 3, or (at your option) any later ver- --
+-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
+-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
+-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
+-- for more details. You should have received a copy of the GNU General --
+-- Public License distributed with GNAT; see file COPYING3. If not, go to --
+-- http://www.gnu.org/licenses for a complete copy of the license. --
+-- --
+-- GNAT was originally developed by the GNAT team at New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc. --
+-- --
+------------------------------------------------------------------------------
+
+with Atree; use Atree;
+with Checks; use Checks;
+with Debug; use Debug;
+with Einfo; use Einfo;
+with Einfo.Entities; use Einfo.Entities;
+with Elists; use Elists;
+with Errout; use Errout;
+with Einfo.Utils; use Einfo.Utils;
+with Exp_Atag; use Exp_Atag;
+with Exp_Ch3; use Exp_Ch3;
+with Exp_Ch7; use Exp_Ch7;
+with Exp_Tss; use Exp_Tss;
+with Exp_Util; use Exp_Util;
+with Namet; use Namet;
+with Nlists; use Nlists;
+with Nmake; use Nmake;
+with Opt; use Opt;
+with Restrict; use Restrict;
+with Rtsfind; use Rtsfind;
+with Sem; use Sem;
+with Sem_Aux; use Sem_Aux;
+with Sem_Ch8; use Sem_Ch8;
+with Sem_Res; use Sem_Res;
+with Sem_Util; use Sem_Util;
+with Sinfo; use Sinfo;
+with Sinfo.Nodes; use Sinfo.Nodes;
+with Sinfo.Utils; use Sinfo.Utils;
+with Snames; use Snames;
+with Stand; use Stand;
+with Tbuild; use Tbuild;
+
+package body Accessibility is
+
+ ---------------------------
+ -- Accessibility_Message --
+ ---------------------------
+
+ procedure Accessibility_Message (N : Node_Id; Typ : Entity_Id) is
+ Loc : constant Source_Ptr := Sloc (N);
+ P : constant Node_Id := Prefix (N);
+ Indic : Node_Id := Parent (Parent (N));
+
+ begin
+ -- In an instance, this is a runtime check, but one we know will fail,
+ -- so generate an appropriate warning.
+
+ if In_Instance_Body then
+ Error_Msg_Warn := SPARK_Mode /= On;
+ Error_Msg_F
+ ("non-local pointer cannot point to local object<<", P);
+ Error_Msg_F ("\Program_Error [<<", P);
+ Rewrite (N,
+ Make_Raise_Program_Error (Loc,
+ Reason => PE_Accessibility_Check_Failed));
+ Set_Etype (N, Typ);
+ return;
+
+ else
+ Error_Msg_F ("non-local pointer cannot point to local object", P);
+
+ -- Check for case where we have a missing access definition
+
+ if Is_Record_Type (Current_Scope)
+ and then
+ Nkind (Parent (N)) in N_Discriminant_Association
+ | N_Index_Or_Discriminant_Constraint
+ then
+ Indic := Parent (Parent (N));
+ while Present (Indic)
+ and then Nkind (Indic) /= N_Subtype_Indication
+ loop
+ Indic := Parent (Indic);
+ end loop;
+
+ if Present (Indic) then
+ Error_Msg_NE
+ ("\use an access definition for" &
+ " the access discriminant of&",
+ N, Entity (Subtype_Mark (Indic)));
+ end if;
+ end if;
+ end if;
+ end Accessibility_Message;
+
+ -------------------------
+ -- Accessibility_Level --
+ -------------------------
+
+ function Accessibility_Level
+ (Expr : Node_Id;
+ Level : Accessibility_Level_Kind;
+ In_Return_Context : Boolean := False;
+ Allow_Alt_Model : Boolean := True) return Node_Id
+ is
+ Loc : constant Source_Ptr := Sloc (Expr);
+
+ function Accessibility_Level (Expr : Node_Id) return Node_Id
+ is (Accessibility_Level (Expr, Level, In_Return_Context));
+ -- Renaming of the enclosing function to facilitate recursive calls
+
+ function Make_Level_Literal (Level : Uint) return Node_Id;
+ -- Construct an integer literal representing an accessibility level with
+ -- its type set to Natural.
+
+ function Innermost_Master_Scope_Depth (N : Node_Id) return Uint;
+ -- Returns the scope depth of the given node's innermost enclosing scope
+ -- (effectively the accessibility level of the innermost enclosing
+ -- master).
+
+ function Function_Call_Or_Allocator_Level (N : Node_Id) return Node_Id;
+ -- Centralized processing of subprogram calls which may appear in prefix
+ -- notation.
+
+ function Typ_Access_Level (Typ : Entity_Id) return Uint
+ is (Type_Access_Level (Typ, Allow_Alt_Model));
+ -- Renaming of Type_Access_Level with Allow_Alt_Model specified to avoid
+ -- passing the parameter specifically in every call.
+
+ ----------------------------------
+ -- Innermost_Master_Scope_Depth --
+ ----------------------------------
+
+ function Innermost_Master_Scope_Depth (N : Node_Id) return Uint is
+ Encl_Scop : Entity_Id;
+ Ent : Entity_Id;
+ Node_Par : Node_Id := Parent (N);
+ Master_Lvl_Modifier : Int := 0;
+
+ begin
+ -- Locate the nearest enclosing node (by traversing Parents)
+ -- that Defining_Entity can be applied to, and return the
+ -- depth of that entity's nearest enclosing scope.
+
+ -- The RM 7.6.1(3) definition of "master" includes statements
+ -- and conditions for loops among other things. Are these cases
+ -- detected properly ???
+
+ while Present (Node_Par) loop
+ Ent := Defining_Entity_Or_Empty (Node_Par);
+
+ if Present (Ent) then
+ Encl_Scop := Find_Enclosing_Scope (Ent);
+
+ -- Ignore transient scopes made during expansion while also
+ -- taking into account certain expansions - like iterators
+ -- which get expanded into renamings and thus not marked
+ -- as coming from source.
+
+ if Comes_From_Source (Node_Par)
+ or else (Nkind (Node_Par) = N_Object_Renaming_Declaration
+ and then Comes_From_Iterator (Node_Par))
+ then
+ -- Note that in some rare cases the scope depth may not be
+ -- set, for example, when we are in the middle of analyzing
+ -- a type and the enclosing scope is said type. So, instead,
+ -- continue to move up the parent chain since the scope
+ -- depth of the type's parent is the same as that of the
+ -- type.
+
+ if not Scope_Depth_Set (Encl_Scop) then
+ pragma Assert (Nkind (Parent (Encl_Scop))
+ = N_Full_Type_Declaration);
+ else
+ return
+ Scope_Depth (Encl_Scop) + Master_Lvl_Modifier;
+ end if;
+ end if;
+
+ -- For a return statement within a function, return
+ -- the depth of the function itself. This is not just
+ -- a small optimization, but matters when analyzing
+ -- the expression in an expression function before
+ -- the body is created.
+
+ elsif Nkind (Node_Par) in N_Extended_Return_Statement
+ | N_Simple_Return_Statement
+ then
+ return Scope_Depth (Enclosing_Subprogram (Node_Par));
+
+ -- Statements are counted as masters
+
+ elsif Is_Master (Node_Par) then
+ Master_Lvl_Modifier := Master_Lvl_Modifier + 1;
+
+ end if;
+
+ Node_Par := Parent (Node_Par);
+ end loop;
+
+ -- Should never reach the following return
+
+ pragma Assert (False);
+
+ return Scope_Depth (Current_Scope) + 1;
+ end Innermost_Master_Scope_Depth;
+
+ ------------------------
+ -- Make_Level_Literal --
+ ------------------------
+
+ function Make_Level_Literal (Level : Uint) return Node_Id is
+ Result : constant Node_Id := Make_Integer_Literal (Loc, Level);
+
+ begin
+ Set_Etype (Result, Standard_Natural);
+ return Result;
+ end Make_Level_Literal;
+
+ --------------------------------------
+ -- Function_Call_Or_Allocator_Level --
+ --------------------------------------
+
+ function Function_Call_Or_Allocator_Level (N : Node_Id) return Node_Id is
+ Par : Node_Id;
+ Prev_Par : Node_Id;
+ begin
+ -- Results of functions are objects, so we either get the
+ -- accessibility of the function or, in case of a call which is
+ -- indirect, the level of the access-to-subprogram type.
+
+ -- This code looks wrong ???
+
+ if Nkind (N) = N_Function_Call
+ and then Ada_Version < Ada_2005
+ then
+ if Is_Entity_Name (Name (N)) then
+ return Make_Level_Literal
+ (Subprogram_Access_Level (Entity (Name (N))));
+ else
+ return Make_Level_Literal
+ (Typ_Access_Level (Etype (Prefix (Name (N)))));
+ end if;
+
+ -- We ignore coextensions as they cannot be implemented under the
+ -- "small-integer" model.
+
+ elsif Nkind (N) = N_Allocator
+ and then (Is_Static_Coextension (N)
+ or else Is_Dynamic_Coextension (N))
+ then
+ return Make_Level_Literal (Scope_Depth (Standard_Standard));
+ end if;
+
+ -- Named access types have a designated level
+
+ if Is_Named_Access_Type (Etype (N)) then
+ return Make_Level_Literal (Typ_Access_Level (Etype (N)));
+
+ -- Otherwise, the level is dictated by RM 3.10.2 (10.7/3)
+
+ else
+ -- Check No_Dynamic_Accessibility_Checks restriction override for
+ -- alternative accessibility model.
+
+ if Allow_Alt_Model
+ and then No_Dynamic_Accessibility_Checks_Enabled (N)
+ and then Is_Anonymous_Access_Type (Etype (N))
+ then
+ -- In the alternative model the level is that of the
+ -- designated type.
+
+ if Debug_Flag_Underscore_B then
+ return Make_Level_Literal (Typ_Access_Level (Etype (N)));
+
+ -- For function calls the level is that of the innermost
+ -- master, otherwise (for allocators etc.) we get the level
+ -- of the corresponding anonymous access type, which is
+ -- calculated through the normal path of execution.
+
+ elsif Nkind (N) = N_Function_Call then
+ return Make_Level_Literal
+ (Innermost_Master_Scope_Depth (Expr));
+ end if;
+ end if;
+
+ if Nkind (N) = N_Function_Call then
+ -- Dynamic checks are generated when we are within a return
+ -- value or we are in a function call within an anonymous
+ -- access discriminant constraint of a return object (signified
+ -- by In_Return_Context) on the side of the callee.
+
+ -- So, in this case, return accessibility level of the
+ -- enclosing subprogram.
+
+ if In_Return_Value (N)
+ or else In_Return_Context
+ then
+ return Make_Level_Literal
+ (Subprogram_Access_Level (Current_Subprogram));
+ end if;
+ end if;
+
+ -- When the call is being dereferenced the level is that of the
+ -- enclosing master of the dereferenced call.
+
+ if Nkind (Parent (N)) in N_Explicit_Dereference
+ | N_Indexed_Component
+ | N_Selected_Component
+ then
+ return Make_Level_Literal
+ (Innermost_Master_Scope_Depth (Expr));
+ end if;
+
+ -- Find any relevant enclosing parent nodes that designate an
+ -- object being initialized.
+
+ -- Note: The above is only relevant if the result is used "in its
+ -- entirety" as RM 3.10.2 (10.2/3) states. However, this is
+ -- accounted for in the case statement in the main body of
+ -- Accessibility_Level for N_Selected_Component.
+
+ Par := Parent (Expr);
+ Prev_Par := Empty;
+ while Present (Par) loop
+ -- Detect an expanded implicit conversion, typically this
+ -- occurs on implicitly converted actuals in calls.
+
+ -- Does this catch all implicit conversions ???
+
+ if Nkind (Par) = N_Type_Conversion
+ and then Is_Named_Access_Type (Etype (Par))
+ then
+ return Make_Level_Literal
+ (Typ_Access_Level (Etype (Par)));
+ end if;
+
+ -- Jump out when we hit an object declaration or the right-hand
+ -- side of an assignment, or a construct such as an aggregate
+ -- subtype indication which would be the result is not used
+ -- "in its entirety."
+
+ exit when Nkind (Par) in N_Object_Declaration
+ or else (Nkind (Par) = N_Assignment_Statement
+ and then Name (Par) /= Prev_Par);
+
+ Prev_Par := Par;
+ Par := Parent (Par);
+ end loop;
+
+ -- Assignment statements are handled in a similar way in
+ -- accordance to the left-hand part. However, strictly speaking,
+ -- this is illegal according to the RM, but this change is needed
+ -- to pass an ACATS C-test and is useful in general ???
+
+ case Nkind (Par) is
+ when N_Object_Declaration =>
+ return Make_Level_Literal
+ (Scope_Depth
+ (Scope (Defining_Identifier (Par))));
+
+ when N_Assignment_Statement =>
+ -- Return the accessibility level of the left-hand part
+
+ return Accessibility_Level
+ (Expr => Name (Par),
+ Level => Object_Decl_Level,
+ In_Return_Context => In_Return_Context);
+
+ when others =>
+ return Make_Level_Literal
+ (Innermost_Master_Scope_Depth (Expr));
+ end case;
+ end if;
+ end Function_Call_Or_Allocator_Level;
+
+ -- Local variables
+
+ E : Node_Id := Original_Node (Expr);
+ Pre : Node_Id;
+
+ -- Start of processing for Accessibility_Level
+
+ begin
+ -- We could be looking at a reference to a formal due to the expansion
+ -- of entries and other cases, so obtain the renaming if necessary.
+
+ if Present (Param_Entity (Expr)) then
+ E := Param_Entity (Expr);
+ end if;
+
+ -- Extract the entity
+
+ if Nkind (E) in N_Has_Entity and then Present (Entity (E)) then
+ E := Entity (E);
+
+ -- Deal with a possible renaming of a private protected component
+
+ if Ekind (E) in E_Constant | E_Variable and then Is_Prival (E) then
+ E := Prival_Link (E);
+ end if;
+ end if;
+
+ -- Perform the processing on the expression
+
+ case Nkind (E) is
+ -- The level of an aggregate is that of the innermost master that
+ -- evaluates it as defined in RM 3.10.2 (10/4).
+
+ when N_Aggregate =>
+ return Make_Level_Literal (Innermost_Master_Scope_Depth (Expr));
+
+ -- The accessibility level is that of the access type, except for an
+ -- anonymous allocators which have special rules defined in RM 3.10.2
+ -- (14/3).
+
+ when N_Allocator =>
+ return Function_Call_Or_Allocator_Level (E);
+
+ -- We could reach this point for two reasons. Either the expression
+ -- applies to a special attribute ('Loop_Entry, 'Result, or 'Old), or
+ -- we are looking at the access attributes directly ('Access,
+ -- 'Address, or 'Unchecked_Access).
+
+ when N_Attribute_Reference =>
+ Pre := Original_Node (Prefix (E));
+
+ -- Regular 'Access attribute presence means we have to look at the
+ -- prefix.
+
+ if Attribute_Name (E) = Name_Access then
+ return Accessibility_Level (Prefix (E));
+
+ -- Unchecked or unrestricted attributes have unlimited depth
+
+ elsif Attribute_Name (E) in Name_Address
+ | Name_Unchecked_Access
+ | Name_Unrestricted_Access
+ then
+ return Make_Level_Literal (Scope_Depth (Standard_Standard));
+
+ -- 'Access can be taken further against other special attributes,
+ -- so handle these cases explicitly.
+
+ elsif Attribute_Name (E)
+ in Name_Old | Name_Loop_Entry | Name_Result
+ then
+ -- Named access types
+
+ if Is_Named_Access_Type (Etype (Pre)) then
+ return Make_Level_Literal
+ (Typ_Access_Level (Etype (Pre)));
+
+ -- Anonymous access types
+
+ elsif Nkind (Pre) in N_Has_Entity
+ and then Ekind (Entity (Pre)) not in Subprogram_Kind
+ and then Present (Get_Dynamic_Accessibility (Entity (Pre)))
+ and then Level = Dynamic_Level
+ then
+ return New_Occurrence_Of
+ (Get_Dynamic_Accessibility (Entity (Pre)), Loc);
+
+ -- Otherwise the level is treated in a similar way as
+ -- aggregates according to RM 6.1.1 (35.1/4) which concerns
+ -- an implicit constant declaration - in turn defining the
+ -- accessibility level to be that of the implicit constant
+ -- declaration.
+
+ else
+ return Make_Level_Literal
+ (Innermost_Master_Scope_Depth (Expr));
+ end if;
+
+ else
+ raise Program_Error;
+ end if;
+
+ -- This is the "base case" for accessibility level calculations which
+ -- means we are near the end of our recursive traversal.
+
+ when N_Defining_Identifier =>
+ -- A dynamic check is performed on the side of the callee when we
+ -- are within a return statement, so return a library-level
+ -- accessibility level to null out checks on the side of the
+ -- caller.
+
+ if Is_Explicitly_Aliased (E)
+ and then (In_Return_Context
+ or else (Level /= Dynamic_Level
+ and then In_Return_Value (Expr)))
+ then
+ return Make_Level_Literal (Scope_Depth (Standard_Standard));
+
+ -- Something went wrong and an extra accessibility formal has not
+ -- been generated when one should have ???
+
+ elsif Is_Formal (E)
+ and then No (Get_Dynamic_Accessibility (E))
+ and then Ekind (Etype (E)) = E_Anonymous_Access_Type
+ then
+ return Make_Level_Literal (Scope_Depth (Standard_Standard));
+
+ -- Stand-alone object of an anonymous access type "SAOAAT"
+
+ elsif (Is_Formal (E)
+ or else Ekind (E) in E_Variable
+ | E_Constant)
+ and then Present (Get_Dynamic_Accessibility (E))
+ and then (Level = Dynamic_Level
+ or else Level = Zero_On_Dynamic_Level)
+ then
+ if Level = Zero_On_Dynamic_Level then
+ return Make_Level_Literal
+ (Scope_Depth (Standard_Standard));
+ end if;
+
+ -- No_Dynamic_Accessibility_Checks restriction override for
+ -- alternative accessibility model.
+
+ if Allow_Alt_Model
+ and then No_Dynamic_Accessibility_Checks_Enabled (E)
+ then
+ -- In the alternative model the level is that of the
+ -- designated type entity's context.
+
+ if Debug_Flag_Underscore_B then
+ return Make_Level_Literal (Typ_Access_Level (Etype (E)));
+
+ -- Otherwise the level depends on the entity's context
+
+ elsif Is_Formal (E) then
+ return Make_Level_Literal
+ (Subprogram_Access_Level
+ (Enclosing_Subprogram (E)));
+ else
+ return Make_Level_Literal
+ (Scope_Depth (Enclosing_Dynamic_Scope (E)));
+ end if;
+ end if;
+
+ -- Return the dynamic level in the normal case
+
+ return New_Occurrence_Of
+ (Get_Dynamic_Accessibility (E), Loc);
+
+ -- Initialization procedures have a special extra accessibility
+ -- parameter associated with the level at which the object
+ -- being initialized exists
+
+ elsif Ekind (E) = E_Record_Type
+ and then Is_Limited_Record (E)
+ and then Current_Scope = Init_Proc (E)
+ and then Present (Init_Proc_Level_Formal (Current_Scope))
+ then
+ return New_Occurrence_Of
+ (Init_Proc_Level_Formal (Current_Scope), Loc);
+
+ -- Current instance of the type is deeper than that of the type
+ -- according to RM 3.10.2 (21).
+
+ elsif Is_Type (E) then
+ -- When restriction No_Dynamic_Accessibility_Checks is active
+ -- along with -gnatd_b.
+
+ if Allow_Alt_Model
+ and then No_Dynamic_Accessibility_Checks_Enabled (E)
+ and then Debug_Flag_Underscore_B
+ then
+ return Make_Level_Literal (Typ_Access_Level (E));
+ end if;
+
+ -- Normal path
+
+ return Make_Level_Literal (Typ_Access_Level (E) + 1);
+
+ -- Move up the renamed entity or object if it came from source
+ -- since expansion may have created a dummy renaming under
+ -- certain circumstances.
+
+ -- Note: We check if the original node of the renaming comes
+ -- from source because the node may have been rewritten.
+
+ elsif Present (Renamed_Entity_Or_Object (E))
+ and then Comes_From_Source
+ (Original_Node (Renamed_Entity_Or_Object (E)))
+ then
+ return Accessibility_Level (Renamed_Entity_Or_Object (E));
+
+ -- Named access types get their level from their associated type
+
+ elsif Is_Named_Access_Type (Etype (E)) then
+ return Make_Level_Literal
+ (Typ_Access_Level (Etype (E)));
+
+ -- Check if E is an expansion-generated renaming of an iterator
+ -- by examining Related_Expression. If so, determine the
+ -- accessibility level based on the original expression.
+
+ elsif Ekind (E) in E_Constant | E_Variable
+ and then Present (Related_Expression (E))
+ then
+ return Accessibility_Level (Related_Expression (E));
+
+ elsif Level = Dynamic_Level
+ and then Ekind (E) in E_In_Parameter | E_In_Out_Parameter
+ and then Present (Init_Proc_Level_Formal (Scope (E)))
+ then
+ return New_Occurrence_Of
+ (Init_Proc_Level_Formal (Scope (E)), Loc);
+
+ -- Normal object - get the level of the enclosing scope
+
+ else
+ return Make_Level_Literal
+ (Scope_Depth (Enclosing_Dynamic_Scope (E)));
+ end if;
+
+ -- Handle indexed and selected components including the special cases
+ -- whereby there is an implicit dereference, a component of a
+ -- composite type, or a function call in prefix notation.
+
+ -- We don't handle function calls in prefix notation correctly ???
+
+ when N_Indexed_Component | N_Selected_Component | N_Slice =>
+ Pre := Prefix (E);
+
+ -- Fetch the original node when the prefix comes from the result
+ -- of expanding a function call since we want to find the level
+ -- of the original source call.
+
+ if not Comes_From_Source (Pre)
+ and then Nkind (Original_Node (Pre)) = N_Function_Call
+ then
+ Pre := Original_Node (Pre);
+ end if;
+
+ -- When E is an indexed component or selected component and
+ -- the current Expr is a function call, we know that we are
+ -- looking at an expanded call in prefix notation.
+
+ if Nkind (Expr) = N_Function_Call then
+ return Function_Call_Or_Allocator_Level (Expr);
+
+ -- If the prefix is a named access type, then we are dealing
+ -- with an implicit deferences. In that case the level is that
+ -- of the named access type in the prefix.
+
+ elsif Is_Named_Access_Type (Etype (Pre)) then
+ return Make_Level_Literal
+ (Typ_Access_Level (Etype (Pre)));
+
+ -- The current expression is a named access type, so there is no
+ -- reason to look at the prefix. Instead obtain the level of E's
+ -- named access type.
+
+ elsif Is_Named_Access_Type (Etype (E)) then
+ return Make_Level_Literal
+ (Typ_Access_Level (Etype (E)));
+
+ -- A nondiscriminant selected component where the component
+ -- is an anonymous access type means that its associated
+ -- level is that of the containing type - see RM 3.10.2 (16).
+
+ -- Note that when restriction No_Dynamic_Accessibility_Checks is
+ -- in effect we treat discriminant components as regular
+ -- components.
+
+ elsif
+ (Nkind (E) = N_Selected_Component
+ and then Ekind (Etype (E)) = E_Anonymous_Access_Type
+ and then Ekind (Etype (Pre)) /= E_Anonymous_Access_Type
+ and then (not (Nkind (Selector_Name (E)) in N_Has_Entity
+ and then Ekind (Entity (Selector_Name (E)))
+ = E_Discriminant)
+
+ -- The alternative accessibility models both treat
+ -- discriminants as regular components.
+
+ or else (No_Dynamic_Accessibility_Checks_Enabled (E)
+ and then Allow_Alt_Model)))
+
+ -- Arrays featuring components of anonymous access components
+ -- get their corresponding level from their containing type's
+ -- declaration.
+
+ or else
+ (Nkind (E) = N_Indexed_Component
+ and then Ekind (Etype (E)) = E_Anonymous_Access_Type
+ and then Ekind (Etype (Pre)) in Array_Kind
+ and then Ekind (Component_Type (Base_Type (Etype (Pre))))
+ = E_Anonymous_Access_Type)
+ then
+ -- When restriction No_Dynamic_Accessibility_Checks is active
+ -- and -gnatd_b set, the level is that of the designated type.
+
+ if Allow_Alt_Model
+ and then No_Dynamic_Accessibility_Checks_Enabled (E)
+ and then Debug_Flag_Underscore_B
+ then
+ return Make_Level_Literal
+ (Typ_Access_Level (Etype (E)));
+ end if;
+
+ -- Otherwise proceed normally
+
+ return Make_Level_Literal
+ (Typ_Access_Level (Etype (Prefix (E))));
+
+ -- The accessibility calculation routine that handles function
+ -- calls (Function_Call_Level) assumes, in the case the
+ -- result is of an anonymous access type, that the result will be
+ -- used "in its entirety" when the call is present within an
+ -- assignment or object declaration.
+
+ -- To properly handle cases where the result is not used in its
+ -- entirety, we test if the prefix of the component in question is
+ -- a function call, which tells us that one of its components has
+ -- been identified and is being accessed. Therefore we can
+ -- conclude that the result is not used "in its entirety"
+ -- according to RM 3.10.2 (10.2/3).
+
+ elsif Nkind (Pre) = N_Function_Call
+ and then not Is_Named_Access_Type (Etype (Pre))
+ then
+ -- Dynamic checks are generated when we are within a return
+ -- value or we are in a function call within an anonymous
+ -- access discriminant constraint of a return object (signified
+ -- by In_Return_Context) on the side of the callee.
+
+ -- So, in this case, return a library accessibility level to
+ -- null out the check on the side of the caller.
+
+ if (In_Return_Value (E)
+ or else In_Return_Context)
+ and then Level /= Dynamic_Level
+ then
+ return Make_Level_Literal
+ (Scope_Depth (Standard_Standard));
+ end if;
+
+ return Make_Level_Literal
+ (Innermost_Master_Scope_Depth (Expr));
+
+ -- Otherwise, continue recursing over the expression prefixes
+
+ else
+ return Accessibility_Level (Prefix (E));
+ end if;
+
+ -- Qualified expressions
+
+ when N_Qualified_Expression =>
+ if Is_Named_Access_Type (Etype (E)) then
+ return Make_Level_Literal
+ (Typ_Access_Level (Etype (E)));
+ else
+ return Accessibility_Level (Expression (E));
+ end if;
+
+ -- Handle function calls
+
+ when N_Function_Call =>
+ return Function_Call_Or_Allocator_Level (E);
+
+ -- Explicit dereference accessibility level calculation
+
+ when N_Explicit_Dereference =>
+ Pre := Original_Node (Prefix (E));
+
+ -- The prefix is a named access type so the level is taken from
+ -- its type.
+
+ if Is_Named_Access_Type (Etype (Pre)) then
+ return Make_Level_Literal (Typ_Access_Level (Etype (Pre)));
+
+ -- Otherwise, recurse deeper
+
+ else
+ return Accessibility_Level (Prefix (E));
+ end if;
+
+ -- Type conversions
+
+ when N_Type_Conversion | N_Unchecked_Type_Conversion =>
+ -- View conversions are special in that they require use to
+ -- inspect the expression of the type conversion.
+
+ -- Allocators of anonymous access types are internally generated,
+ -- so recurse deeper in that case as well.
+
+ if Is_View_Conversion (E)
+ or else Ekind (Etype (E)) = E_Anonymous_Access_Type
+ then
+ return Accessibility_Level (Expression (E));
+
+ -- We don't care about the master if we are looking at a named
+ -- access type.
+
+ elsif Is_Named_Access_Type (Etype (E)) then
+ return Make_Level_Literal
+ (Typ_Access_Level (Etype (E)));
+
+ -- In section RM 3.10.2 (10/4) the accessibility rules for
+ -- aggregates and value conversions are outlined. Are these
+ -- followed in the case of initialization of an object ???
+
+ -- Should use Innermost_Master_Scope_Depth ???
+
+ else
+ return Accessibility_Level (Current_Scope);
+ end if;
+
+ -- Default to the type accessibility level for the type of the
+ -- expression's entity.
+
+ when others =>
+ return Make_Level_Literal (Typ_Access_Level (Etype (E)));
+ end case;
+ end Accessibility_Level;
+
+ -------------------------------
+ -- Apply_Accessibility_Check --
+ -------------------------------
+
+ procedure Apply_Accessibility_Check
+ (N : Node_Id;
+ Typ : Entity_Id;
+ Insert_Node : Node_Id)
+ is
+ Loc : constant Source_Ptr := Sloc (N);
+
+ Check_Cond : Node_Id;
+ Param_Ent : Entity_Id := Param_Entity (N);
+ Param_Level : Node_Id;
+ Type_Level : Node_Id;
+
+ begin
+ -- Verify we haven't tried to add a dynamic accessibility check when we
+ -- shouldn't.
+
+ pragma Assert (not No_Dynamic_Accessibility_Checks_Enabled (N));
+
+ if Ada_Version >= Ada_2012
+ and then No (Param_Ent)
+ and then Is_Entity_Name (N)
+ and then Ekind (Entity (N)) in E_Constant | E_Variable
+ and then Present (Effective_Extra_Accessibility (Entity (N)))
+ then
+ Param_Ent := Entity (N);
+ while Present (Renamed_Object (Param_Ent)) loop
+ -- Renamed_Object must return an Entity_Name here
+ -- because of preceding "Present (E_E_A (...))" test.
+
+ Param_Ent := Entity (Renamed_Object (Param_Ent));
+ end loop;
+ end if;
+
+ if Inside_A_Generic then
+ return;
+
+ -- Only apply the run-time check if the access parameter has an
+ -- associated extra access level parameter and when accessibility checks
+ -- are enabled.
+
+ elsif Present (Param_Ent)
+ and then Present (Get_Dynamic_Accessibility (Param_Ent))
+ and then not Accessibility_Checks_Suppressed (Param_Ent)
+ and then not Accessibility_Checks_Suppressed (Typ)
+ then
+ -- Obtain the parameter's accessibility level
+
+ Param_Level :=
+ New_Occurrence_Of (Get_Dynamic_Accessibility (Param_Ent), Loc);
+
+ -- Use the dynamic accessibility parameter for the function's result
+ -- when one has been created instead of statically referring to the
+ -- deepest type level so as to appropriatly handle the rules for
+ -- RM 3.10.2 (10.1/3).
+
+ if Ekind (Scope (Param_Ent)) = E_Function
+ and then In_Return_Value (N)
+ and then Ekind (Typ) = E_Anonymous_Access_Type
+ then
+ -- Associate the level of the result type to the extra result
+ -- accessibility parameter belonging to the current function.
+
+ if Present (Extra_Accessibility_Of_Result (Scope (Param_Ent))) then
+ Type_Level :=
+ New_Occurrence_Of
+ (Extra_Accessibility_Of_Result (Scope (Param_Ent)), Loc);
+
+ -- In Ada 2005 and earlier modes, a result extra accessibility
+ -- parameter is not generated and no dynamic check is performed.
+
+ else
+ return;
+ end if;
+
+ -- Otherwise get the type's accessibility level normally
+
+ else
+ Type_Level :=
+ Make_Integer_Literal (Loc, Deepest_Type_Access_Level (Typ));
+ end if;
+
+ -- Raise Program_Error if the accessibility level of the access
+ -- parameter is deeper than the level of the target access type.
+
+ Check_Cond :=
+ Make_Op_Gt (Loc,
+ Left_Opnd => Param_Level,
+ Right_Opnd => Type_Level);
+
+ Insert_Action (Insert_Node,
+ Make_Raise_Program_Error (Loc,
+ Condition => Check_Cond,
+ Reason => PE_Accessibility_Check_Failed));
+
+ Analyze_And_Resolve (N);
+
+ -- If constant folding has happened on the condition for the
+ -- generated error, then warn about it being unconditional.
+
+ if Nkind (Check_Cond) = N_Identifier
+ and then Entity (Check_Cond) = Standard_True
+ then
+ Error_Msg_Warn := SPARK_Mode /= On;
+ Error_Msg_N ("accessibility check fails<<", N);
+ Error_Msg_N ("\Program_Error [<<", N);
+ end if;
+ end if;
+ end Apply_Accessibility_Check;
+
+ ---------------------------------------------
+ -- Apply_Accessibility_Check_For_Allocator --
+ ---------------------------------------------
+
+ procedure Apply_Accessibility_Check_For_Allocator
+ (N : Node_Id;
+ Exp : Node_Id;
+ Ref : Node_Id;
+ Built_In_Place : Boolean := False)
+ is
+ Loc : constant Source_Ptr := Sloc (N);
+ PtrT : constant Entity_Id := Etype (N);
+ DesigT : constant Entity_Id := Designated_Type (PtrT);
+ Pool_Id : constant Entity_Id := Associated_Storage_Pool (PtrT);
+ Cond : Node_Id;
+ Fin_Call : Node_Id;
+ Free_Stmt : Node_Id;
+ Obj_Ref : Node_Id;
+ Stmts : List_Id;
+
+ begin
+ if Ada_Version >= Ada_2005
+ and then Is_Class_Wide_Type (DesigT)
+ and then Tagged_Type_Expansion
+ and then not Scope_Suppress.Suppress (Accessibility_Check)
+ and then not No_Dynamic_Accessibility_Checks_Enabled (Ref)
+ and then
+ (Type_Access_Level (Etype (Exp)) > Type_Access_Level (PtrT)
+ or else
+ (Is_Class_Wide_Type (Etype (Exp))
+ and then Scope (PtrT) /= Current_Scope))
+ then
+ -- If the allocator was built in place, Ref is already a reference
+ -- to the access object initialized to the result of the allocator
+ -- (see Exp_Ch6.Make_Build_In_Place_Call_In_Allocator). We call
+ -- Remove_Side_Effects for cases where the build-in-place call may
+ -- still be the prefix of the reference (to avoid generating
+ -- duplicate calls). Otherwise, it is the entity associated with
+ -- the object containing the address of the allocated object.
+
+ if Built_In_Place then
+ Remove_Side_Effects (Ref);
+ Obj_Ref := New_Copy_Tree (Ref);
+ else
+ Obj_Ref := New_Occurrence_Of (Ref, Loc);
+ end if;
+
+ -- For access to interface types we must generate code to displace
+ -- the pointer to the base of the object since the subsequent code
+ -- references components located in the TSD of the object (which
+ -- is associated with the primary dispatch table --see a-tags.ads)
+ -- and also generates code invoking Free, which requires also a
+ -- reference to the base of the unallocated object.
+
+ if Is_Interface (DesigT) and then Tagged_Type_Expansion then
+ Obj_Ref :=
+ Unchecked_Convert_To (Etype (Obj_Ref),
+ Make_Function_Call (Loc,
+ Name =>
+ New_Occurrence_Of (RTE (RE_Base_Address), Loc),
+ Parameter_Associations => New_List (
+ Unchecked_Convert_To (RTE (RE_Address),
+ New_Copy_Tree (Obj_Ref)))));
+ end if;
+
+ -- Step 1: Create the object clean up code
+
+ Stmts := New_List;
+
+ -- Deallocate the object if the accessibility check fails. This is
+ -- done only on targets or profiles that support deallocation.
+
+ -- Free (Obj_Ref);
+
+ if RTE_Available (RE_Free) then
+ Free_Stmt := Make_Free_Statement (Loc, New_Copy_Tree (Obj_Ref));
+ Set_Storage_Pool (Free_Stmt, Pool_Id);
+
+ Append_To (Stmts, Free_Stmt);
+
+ -- The target or profile cannot deallocate objects
+
+ else
+ Free_Stmt := Empty;
+ end if;
+
+ -- Finalize the object if applicable. Generate:
+
+ -- [Deep_]Finalize (Obj_Ref.all);
+
+ if Needs_Finalization (DesigT)
+ and then not No_Heap_Finalization (PtrT)
+ then
+ Fin_Call :=
+ Make_Final_Call
+ (Obj_Ref =>
+ Make_Explicit_Dereference (Loc, New_Copy (Obj_Ref)),
+ Typ => DesigT);
+
+ -- Guard against a missing [Deep_]Finalize when the designated
+ -- type was not properly frozen.
+
+ if No (Fin_Call) then
+ Fin_Call := Make_Null_Statement (Loc);
+ end if;
+
+ -- When the target or profile supports deallocation, wrap the
+ -- finalization call in a block to ensure proper deallocation even
+ -- if finalization fails. Generate:
+
+ -- begin
+ -- <Fin_Call>
+ -- exception
+ -- when others =>
+ -- <Free_Stmt>
+ -- raise;
+ -- end;
+
+ if Present (Free_Stmt) then
+ Fin_Call :=
+ Make_Block_Statement (Loc,
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => New_List (Fin_Call),
+
+ Exception_Handlers => New_List (
+ Make_Exception_Handler (Loc,
+ Exception_Choices => New_List (
+ Make_Others_Choice (Loc)),
+ Statements => New_List (
+ New_Copy_Tree (Free_Stmt),
+ Make_Raise_Statement (Loc))))));
+ end if;
+
+ Prepend_To (Stmts, Fin_Call);
+ end if;
+
+ -- Signal the accessibility failure through a Program_Error
+
+ Append_To (Stmts,
+ Make_Raise_Program_Error (Loc,
+ Reason => PE_Accessibility_Check_Failed));
+
+ -- Step 2: Create the accessibility comparison
+
+ -- Generate:
+ -- Ref'Tag
+
+ Obj_Ref :=
+ Make_Attribute_Reference (Loc,
+ Prefix => Obj_Ref,
+ Attribute_Name => Name_Tag);
+
+ -- For tagged types, determine the accessibility level by looking at
+ -- the type specific data of the dispatch table. Generate:
+
+ -- Type_Specific_Data (Address (Ref'Tag)).Access_Level
+
+ if Tagged_Type_Expansion then
+ Cond := Build_Get_Access_Level (Loc, Obj_Ref);
+
+ -- Use a runtime call to determine the accessibility level when
+ -- compiling on virtual machine targets. Generate:
+
+ -- Get_Access_Level (Ref'Tag)
+
+ else
+ Cond :=
+ Make_Function_Call (Loc,
+ Name =>
+ New_Occurrence_Of (RTE (RE_Get_Access_Level), Loc),
+ Parameter_Associations => New_List (Obj_Ref));
+ end if;
+
+ Cond :=
+ Make_Op_Gt (Loc,
+ Left_Opnd => Cond,
+ Right_Opnd => Accessibility_Level (N, Dynamic_Level));
+
+ -- Due to the complexity and side effects of the check, utilize an if
+ -- statement instead of the regular Program_Error circuitry.
+
+ Insert_Action (N,
+ Make_Implicit_If_Statement (N,
+ Condition => Cond,
+ Then_Statements => Stmts));
+ end if;
+ end Apply_Accessibility_Check_For_Allocator;
+
+ ------------------------------------------
+ -- Check_Return_Construct_Accessibility --
+ ------------------------------------------
+
+ procedure Check_Return_Construct_Accessibility
+ (Return_Stmt : Node_Id;
+ Stm_Entity : Entity_Id)
+ is
+ Loc : constant Source_Ptr := Sloc (Return_Stmt);
+ Scope_Id : constant Entity_Id := Return_Applies_To (Stm_Entity);
+
+ R_Type : constant Entity_Id := Etype (Scope_Id);
+ -- Function result subtype
+
+ function First_Selector (Assoc : Node_Id) return Node_Id;
+ -- Obtain the first selector or choice from a given association
+
+ function Is_Formal_Of_Current_Function
+ (Assoc_Expr : Entity_Id) return Boolean;
+ -- Predicate to test if a given expression associated with a
+ -- discriminant is a formal parameter to the function in which the
+ -- return construct we checking applies to.
+
+ --------------------
+ -- First_Selector --
+ --------------------
+
+ function First_Selector (Assoc : Node_Id) return Node_Id is
+ begin
+ if Nkind (Assoc) = N_Component_Association then
+ return First (Choices (Assoc));
+
+ elsif Nkind (Assoc) = N_Discriminant_Association then
+ return (First (Selector_Names (Assoc)));
+
+ else
+ raise Program_Error;
+ end if;
+ end First_Selector;
+
+ -----------------------------------
+ -- Is_Formal_Of_Current_Function --
+ -----------------------------------
+
+ function Is_Formal_Of_Current_Function
+ (Assoc_Expr : Entity_Id) return Boolean is
+ begin
+ return Is_Entity_Name (Assoc_Expr)
+ and then Enclosing_Subprogram
+ (Entity (Assoc_Expr)) = Scope_Id
+ and then Is_Formal (Entity (Assoc_Expr));
+ end Is_Formal_Of_Current_Function;
+
+ -- Local declarations
+
+ Assoc : Node_Id := Empty;
+ -- Assoc should perhaps be renamed and declared as a
+ -- Node_Or_Entity_Id since it encompasses not only component and
+ -- discriminant associations, but also discriminant components within
+ -- a type declaration or subtype indication ???
+
+ Assoc_Expr : Node_Id;
+ Assoc_Present : Boolean := False;
+
+ Check_Cond : Node_Id;
+ Unseen_Disc_Count : Nat := 0;
+ Seen_Discs : Elist_Id;
+ Disc : Entity_Id;
+ First_Disc : Entity_Id;
+
+ Obj_Decl : Node_Id;
+ Return_Con : Node_Id;
+ Unqual : Node_Id;
+
+ -- Start of processing for Check_Return_Construct_Accessibility
+
+ begin
+ -- Only perform checks on record types with access discriminants and
+ -- non-internally generated functions.
+
+ if not Is_Record_Type (R_Type)
+ or else not Has_Anonymous_Access_Discriminant (R_Type)
+ or else not Comes_From_Source (Return_Stmt)
+ then
+ return;
+ end if;
+
+ -- We are only interested in return statements
+
+ if Nkind (Return_Stmt) not in
+ N_Extended_Return_Statement | N_Simple_Return_Statement
+ then
+ return;
+ end if;
+
+ -- Fetch the object from the return statement, in the case of a
+ -- simple return statement the expression is part of the node.
+
+ if Nkind (Return_Stmt) = N_Extended_Return_Statement then
+ -- Obtain the object definition from the expanded extended return
+
+ Return_Con := First (Return_Object_Declarations (Return_Stmt));
+ while Present (Return_Con) loop
+ -- Inspect the original node to avoid object declarations
+ -- expanded into renamings.
+
+ if Nkind (Original_Node (Return_Con)) = N_Object_Declaration
+ and then Comes_From_Source (Original_Node (Return_Con))
+ then
+ exit;
+ end if;
+
+ Nlists.Next (Return_Con);
+ end loop;
+
+ pragma Assert (Present (Return_Con));
+
+ -- Could be dealing with a renaming
+
+ Return_Con := Original_Node (Return_Con);
+ else
+ Return_Con := Expression (Return_Stmt);
+ end if;
+
+ -- Obtain the accessibility levels of the expressions associated
+ -- with all anonymous access discriminants, then generate a
+ -- dynamic check or static error when relevant.
+
+ -- Note the repeated use of Original_Node to avoid checking
+ -- expanded code.
+
+ Unqual := Original_Node (Unqualify (Original_Node (Return_Con)));
+
+ -- Get the corresponding declaration based on the return object's
+ -- identifier.
+
+ if Nkind (Unqual) = N_Identifier
+ and then Nkind (Parent (Entity (Unqual)))
+ in N_Object_Declaration
+ | N_Object_Renaming_Declaration
+ then
+ Obj_Decl := Original_Node (Parent (Entity (Unqual)));
+
+ -- We were passed the object declaration directly, so use it
+
+ elsif Nkind (Unqual) in N_Object_Declaration
+ | N_Object_Renaming_Declaration
+ then
+ Obj_Decl := Unqual;
+
+ -- Otherwise, we are looking at something else
+
+ else
+ Obj_Decl := Empty;
+
+ end if;
+
+ -- Hop up object renamings when present
+
+ if Present (Obj_Decl)
+ and then Nkind (Obj_Decl) = N_Object_Renaming_Declaration
+ then
+ while Nkind (Obj_Decl) = N_Object_Renaming_Declaration loop
+
+ if Nkind (Name (Obj_Decl)) not in N_Entity then
+ -- We may be looking at the expansion of iterators or
+ -- some other internally generated construct, so it is safe
+ -- to ignore checks ???
+
+ if not Comes_From_Source (Obj_Decl) then
+ return;
+ end if;
+
+ Obj_Decl := Original_Node
+ (Declaration_Node
+ (Ultimate_Prefix (Name (Obj_Decl))));
+
+ -- Move up to the next declaration based on the object's name
+
+ else
+ Obj_Decl := Original_Node
+ (Declaration_Node (Name (Obj_Decl)));
+ end if;
+ end loop;
+ end if;
+
+ -- Obtain the discriminant values from the return aggregate
+
+ -- Do we cover extension aggregates correctly ???
+
+ if Nkind (Unqual) = N_Aggregate then
+ if Present (Expressions (Unqual)) then
+ Assoc := First (Expressions (Unqual));
+ else
+ Assoc := First (Component_Associations (Unqual));
+ end if;
+
+ -- There is an object declaration for the return object
+
+ elsif Present (Obj_Decl) then
+ -- When a subtype indication is present in an object declaration
+ -- it must contain the object's discriminants.
+
+ if Nkind (Object_Definition (Obj_Decl)) = N_Subtype_Indication then
+ Assoc := First
+ (Constraints
+ (Constraint
+ (Object_Definition (Obj_Decl))));
+
+ -- The object declaration contains an aggregate
+
+ elsif Present (Expression (Obj_Decl)) then
+
+ if Nkind (Unqualify (Expression (Obj_Decl))) = N_Aggregate then
+ -- Grab the first associated discriminant expresion
+
+ if Present
+ (Expressions (Unqualify (Expression (Obj_Decl))))
+ then
+ Assoc := First
+ (Expressions
+ (Unqualify (Expression (Obj_Decl))));
+ else
+ Assoc := First
+ (Component_Associations
+ (Unqualify (Expression (Obj_Decl))));
+ end if;
+
+ -- Otherwise, this is something else
+
+ else
+ return;
+ end if;
+
+ -- There are no supplied discriminants in the object declaration,
+ -- so get them from the type definition since they must be default
+ -- initialized.
+
+ -- Do we handle constrained subtypes correctly ???
+
+ elsif Nkind (Unqual) = N_Object_Declaration then
+ Assoc := First_Discriminant
+ (Etype (Object_Definition (Obj_Decl)));
+
+ else
+ Assoc := First_Discriminant (Etype (Unqual));
+ end if;
+
+ -- When we are not looking at an aggregate or an identifier, return
+ -- since any other construct (like a function call) is not
+ -- applicable since checks will be performed on the side of the
+ -- callee.
+
+ else
+ return;
+ end if;
+
+ -- Obtain the discriminants so we know the actual type in case the
+ -- value of their associated expression gets implicitly converted.
+
+ if No (Obj_Decl) then
+ pragma Assert (Nkind (Unqual) = N_Aggregate);
+
+ Disc := First_Discriminant (Etype (Unqual));
+
+ else
+ Disc := First_Discriminant
+ (Etype (Defining_Identifier (Obj_Decl)));
+ end if;
+
+ -- Preserve the first discriminant for checking named associations
+
+ First_Disc := Disc;
+
+ -- Count the number of discriminants for processing an aggregate
+ -- which includes an others.
+
+ Disc := First_Disc;
+ while Present (Disc) loop
+ Unseen_Disc_Count := Unseen_Disc_Count + 1;
+
+ Next_Discriminant (Disc);
+ end loop;
+
+ Seen_Discs := New_Elmt_List;
+
+ -- Loop through each of the discriminants and check each expression
+ -- associated with an anonymous access discriminant.
+
+ -- When named associations occur in the return aggregate then
+ -- discriminants can be in any order, so we need to ensure we do
+ -- not continue to loop when all discriminants have been seen.
+
+ Disc := First_Disc;
+ while Present (Assoc)
+ and then (Present (Disc) or else Assoc_Present)
+ and then Unseen_Disc_Count > 0
+ loop
+ -- Handle named associations by searching through the names of
+ -- the relevant discriminant components.
+
+ if Nkind (Assoc)
+ in N_Component_Association | N_Discriminant_Association
+ then
+ Assoc_Expr := Expression (Assoc);
+ Assoc_Present := True;
+
+ -- We currently don't handle box initialized discriminants,
+ -- however, since default initialized anonymous access
+ -- discriminants are a corner case, this is ok for now ???
+
+ if Nkind (Assoc) = N_Component_Association
+ and then Box_Present (Assoc)
+ then
+ if Nkind (First_Selector (Assoc)) = N_Others_Choice then
+ Unseen_Disc_Count := 0;
+ end if;
+
+ -- When others is present we must identify a discriminant we
+ -- haven't already seen so as to get the appropriate type for
+ -- the static accessibility check.
+
+ -- This works because all components within an others clause
+ -- must have the same type.
+
+ elsif Nkind (First_Selector (Assoc)) = N_Others_Choice then
+
+ Disc := First_Disc;
+ Outer : while Present (Disc) loop
+ declare
+ Current_Seen_Disc : Elmt_Id;
+ begin
+ -- Move through the list of identified discriminants
+
+ Current_Seen_Disc := First_Elmt (Seen_Discs);
+ while Present (Current_Seen_Disc) loop
+ -- Exit the loop when we found a match
+
+ exit when
+ Chars (Node (Current_Seen_Disc)) = Chars (Disc);
+
+ Next_Elmt (Current_Seen_Disc);
+ end loop;
+
+ -- When we have exited the above loop without finding
+ -- a match then we know that Disc has not been seen.
+
+ exit Outer when No (Current_Seen_Disc);
+ end;
+
+ Next_Discriminant (Disc);
+ end loop Outer;
+
+ -- If we got to an others clause with a non-zero
+ -- discriminant count there must be a discriminant left to
+ -- check.
+
+ pragma Assert (Present (Disc));
+
+ -- Set the unseen discriminant count to zero because we know
+ -- an others clause sets all remaining components of an
+ -- aggregate.
+
+ Unseen_Disc_Count := 0;
+
+ -- Move through each of the selectors in the named association
+ -- and obtain a discriminant for accessibility checking if one
+ -- is referenced in the list. Also track which discriminants
+ -- are referenced for the purpose of handling an others clause.
+
+ else
+ declare
+ Assoc_Choice : Node_Id;
+ Curr_Disc : Node_Id;
+ begin
+
+ Disc := Empty;
+ Curr_Disc := First_Disc;
+ while Present (Curr_Disc) loop
+ -- Check each of the choices in the associations for a
+ -- match to the name of the current discriminant.
+
+ Assoc_Choice := First_Selector (Assoc);
+ while Present (Assoc_Choice) loop
+ -- When the name matches we track that we have seen
+ -- the discriminant, but instead of exiting the
+ -- loop we continue iterating to make sure all the
+ -- discriminants within the named association get
+ -- tracked.
+
+ if Chars (Assoc_Choice) = Chars (Curr_Disc) then
+ Append_Elmt (Curr_Disc, Seen_Discs);
+
+ Disc := Curr_Disc;
+ Unseen_Disc_Count := Unseen_Disc_Count - 1;
+ end if;
+
+ Next (Assoc_Choice);
+ end loop;
+
+ Next_Discriminant (Curr_Disc);
+ end loop;
+ end;
+ end if;
+
+ -- Unwrap the associated expression if we are looking at a default
+ -- initialized type declaration. In this case Assoc is not really
+ -- an association, but a component declaration. Should Assoc be
+ -- renamed in some way to be more clear ???
+
+ -- This occurs when the return object does not initialize
+ -- discriminant and instead relies on the type declaration for
+ -- their supplied values.
+
+ elsif Nkind (Assoc) in N_Entity
+ and then Ekind (Assoc) = E_Discriminant
+ then
+ Append_Elmt (Disc, Seen_Discs);
+
+ Assoc_Expr := Discriminant_Default_Value (Assoc);
+ Unseen_Disc_Count := Unseen_Disc_Count - 1;
+
+ -- Otherwise, there is nothing to do because Assoc is an
+ -- expression within the return aggregate itself.
+
+ else
+ Append_Elmt (Disc, Seen_Discs);
+
+ Assoc_Expr := Assoc;
+ Unseen_Disc_Count := Unseen_Disc_Count - 1;
+ end if;
+
+ -- Check the accessibility level of the expression when the
+ -- discriminant is of an anonymous access type.
+
+ if Present (Assoc_Expr)
+ and then Present (Disc)
+ and then Ekind (Etype (Disc)) = E_Anonymous_Access_Type
+
+ -- We disable the check when we have a tagged return type and
+ -- the associated expression for the discriminant is a formal
+ -- parameter since the check would require us to compare the
+ -- accessibility level of Assoc_Expr to the level of the
+ -- Extra_Accessibility_Of_Result of the function - which is
+ -- currently disabled for functions with tagged return types.
+ -- This may change in the future ???
+
+ -- See Needs_Result_Accessibility_Level for details.
+
+ and then not
+ (No (Extra_Accessibility_Of_Result (Scope_Id))
+ and then Is_Formal_Of_Current_Function (Assoc_Expr)
+ and then Is_Tagged_Type (Etype (Scope_Id)))
+ then
+ -- Generate a dynamic check based on the extra accessibility of
+ -- the result or the scope of the current function.
+
+ Check_Cond :=
+ Make_Op_Gt (Loc,
+ Left_Opnd => Accessibility_Level
+ (Expr => Assoc_Expr,
+ Level => Dynamic_Level,
+ In_Return_Context => True),
+ Right_Opnd =>
+ (if Present (Extra_Accessibility_Of_Result (Scope_Id))
+
+ -- When Assoc_Expr is a formal we have to look at the
+ -- extra accessibility-level formal associated with
+ -- the result.
+
+ and then Is_Formal_Of_Current_Function (Assoc_Expr)
+ then
+ New_Occurrence_Of
+ (Extra_Accessibility_Of_Result (Scope_Id), Loc)
+
+ -- Otherwise, we compare the level of Assoc_Expr to the
+ -- scope of the current function.
+
+ else
+ Make_Integer_Literal
+ (Loc, Scope_Depth (Scope (Scope_Id)))));
+
+ Insert_Before_And_Analyze (Return_Stmt,
+ Make_Raise_Program_Error (Loc,
+ Condition => Check_Cond,
+ Reason => PE_Accessibility_Check_Failed));
+
+ -- If constant folding has happened on the condition for the
+ -- generated error, then warn about it being unconditional when
+ -- we know an error will be raised.
+
+ if Nkind (Check_Cond) = N_Identifier
+ and then Entity (Check_Cond) = Standard_True
+ then
+ Error_Msg_N
+ ("access discriminant in return object would be a dangling"
+ & " reference", Return_Stmt);
+ end if;
+ end if;
+
+ -- Iterate over the discriminants, except when we have encountered
+ -- a named association since the discriminant order becomes
+ -- irrelevant in that case.
+
+ if not Assoc_Present then
+ Next_Discriminant (Disc);
+ end if;
+
+ -- Iterate over associations
+
+ if not Is_List_Member (Assoc) then
+ exit;
+ else
+ Nlists.Next (Assoc);
+ end if;
+ end loop;
+ end Check_Return_Construct_Accessibility;
+
+ -------------------------------
+ -- Deepest_Type_Access_Level --
+ -------------------------------
+
+ function Deepest_Type_Access_Level
+ (Typ : Entity_Id;
+ Allow_Alt_Model : Boolean := True) return Uint
+ is
+ begin
+ if Ekind (Typ) = E_Anonymous_Access_Type
+ and then not Is_Local_Anonymous_Access (Typ)
+ and then Nkind (Associated_Node_For_Itype (Typ)) = N_Object_Declaration
+ then
+ -- No_Dynamic_Accessibility_Checks override for alternative
+ -- accessibility model.
+
+ if Allow_Alt_Model
+ and then No_Dynamic_Accessibility_Checks_Enabled (Typ)
+ then
+ return Type_Access_Level (Typ, Allow_Alt_Model);
+ end if;
+
+ -- Typ is the type of an Ada 2012 stand-alone object of an anonymous
+ -- access type.
+
+ return
+ Scope_Depth (Enclosing_Dynamic_Scope
+ (Defining_Identifier
+ (Associated_Node_For_Itype (Typ))));
+
+ -- For generic formal type, return Int'Last (infinite).
+ -- See comment preceding Is_Generic_Type call in Type_Access_Level.
+
+ elsif Is_Generic_Type (Root_Type (Typ)) then
+ return UI_From_Int (Int'Last);
+
+ else
+ return Type_Access_Level (Typ, Allow_Alt_Model);
+ end if;
+ end Deepest_Type_Access_Level;
+
+ -----------------------------------
+ -- Effective_Extra_Accessibility --
+ -----------------------------------
+
+ function Effective_Extra_Accessibility (Id : Entity_Id) return Entity_Id is
+ begin
+ if Present (Renamed_Object (Id))
+ and then Is_Entity_Name (Renamed_Object (Id))
+ then
+ return Effective_Extra_Accessibility (Entity (Renamed_Object (Id)));
+ else
+ return Extra_Accessibility (Id);
+ end if;
+ end Effective_Extra_Accessibility;
+
+ -------------------------------
+ -- Get_Dynamic_Accessibility --
+ -------------------------------
+
+ function Get_Dynamic_Accessibility (E : Entity_Id) return Entity_Id is
+ begin
+ -- When minimum accessibility is set for E then we utilize it - except
+ -- in a few edge cases like the expansion of select statements where
+ -- generated subprogram may attempt to unnecessarily use a minimum
+ -- accessibility object declared outside of scope.
+
+ -- To avoid these situations where expansion may get complex we verify
+ -- that the minimum accessibility object is within scope.
+
+ if Is_Formal (E)
+ and then Present (Minimum_Accessibility (E))
+ and then In_Open_Scopes (Scope (Minimum_Accessibility (E)))
+ then
+ return Minimum_Accessibility (E);
+ end if;
+
+ return Extra_Accessibility (E);
+ end Get_Dynamic_Accessibility;
+
+ -----------------------
+ -- Has_Access_Values --
+ -----------------------
+
+ function Has_Access_Values (T : Entity_Id) return Boolean
+ is
+ Typ : constant Entity_Id := Underlying_Type (T);
+
+ begin
+ -- Case of a private type which is not completed yet. This can only
+ -- happen in the case of a generic formal type appearing directly, or
+ -- as a component of the type to which this function is being applied
+ -- at the top level. Return False in this case, since we certainly do
+ -- not know that the type contains access types.
+
+ if No (Typ) then
+ return False;
+
+ elsif Is_Access_Type (Typ) then
+ return True;
+
+ elsif Is_Array_Type (Typ) then
+ return Has_Access_Values (Component_Type (Typ));
+
+ elsif Is_Record_Type (Typ) then
+ declare
+ Comp : Entity_Id;
+
+ begin
+ -- Loop to check components
+
+ Comp := First_Component_Or_Discriminant (Typ);
+ while Present (Comp) loop
+
+ -- Check for access component, tag field does not count, even
+ -- though it is implemented internally using an access type.
+
+ if Has_Access_Values (Etype (Comp))
+ and then Chars (Comp) /= Name_uTag
+ then
+ return True;
+ end if;
+
+ Next_Component_Or_Discriminant (Comp);
+ end loop;
+ end;
+
+ return False;
+
+ else
+ return False;
+ end if;
+ end Has_Access_Values;
+
+ ---------------------------------------
+ -- Has_Anonymous_Access_Discriminant --
+ ---------------------------------------
+
+ function Has_Anonymous_Access_Discriminant (Typ : Entity_Id) return Boolean
+ is
+ Disc : Node_Id;
+
+ begin
+ if not Has_Discriminants (Typ) then
+ return False;
+ end if;
+
+ Disc := First_Discriminant (Typ);
+ while Present (Disc) loop
+ if Ekind (Etype (Disc)) = E_Anonymous_Access_Type then
+ return True;
+ end if;
+
+ Next_Discriminant (Disc);
+ end loop;
+
+ return False;
+ end Has_Anonymous_Access_Discriminant;
+
+ --------------------------------------------
+ -- Has_Unconstrained_Access_Discriminants --
+ --------------------------------------------
+
+ function Has_Unconstrained_Access_Discriminants
+ (Subtyp : Entity_Id) return Boolean
+ is
+ Discr : Entity_Id;
+
+ begin
+ if Has_Discriminants (Subtyp)
+ and then not Is_Constrained (Subtyp)
+ then
+ Discr := First_Discriminant (Subtyp);
+ while Present (Discr) loop
+ if Ekind (Etype (Discr)) = E_Anonymous_Access_Type then
+ return True;
+ end if;
+
+ Next_Discriminant (Discr);
+ end loop;
+ end if;
+
+ return False;
+ end Has_Unconstrained_Access_Discriminants;
+
+ --------------------------------
+ -- Is_Anonymous_Access_Actual --
+ --------------------------------
+
+ function Is_Anonymous_Access_Actual (N : Node_Id) return Boolean is
+ Par : Node_Id;
+ begin
+ if Ekind (Etype (N)) /= E_Anonymous_Access_Type then
+ return False;
+ end if;
+
+ Par := Parent (N);
+ while Present (Par)
+ and then Nkind (Par) in N_Case_Expression
+ | N_If_Expression
+ | N_Parameter_Association
+ loop
+ Par := Parent (Par);
+ end loop;
+ return Nkind (Par) in N_Subprogram_Call;
+ end Is_Anonymous_Access_Actual;
+
+ --------------------------------------
+ -- Is_Special_Aliased_Formal_Access --
+ --------------------------------------
+
+ function Is_Special_Aliased_Formal_Access
+ (Exp : Node_Id;
+ In_Return_Context : Boolean := False) return Boolean
+ is
+ Scop : constant Entity_Id := Current_Subprogram;
+ begin
+ -- Verify the expression is an access reference to 'Access within a
+ -- return statement as this is the only time an explicitly aliased
+ -- formal has different semantics.
+
+ if Nkind (Exp) /= N_Attribute_Reference
+ or else Get_Attribute_Id (Attribute_Name (Exp)) /= Attribute_Access
+ or else not (In_Return_Value (Exp)
+ or else In_Return_Context)
+ or else not Needs_Result_Accessibility_Level (Scop)
+ then
+ return False;
+ end if;
+
+ -- Check if the prefix of the reference is indeed an explicitly aliased
+ -- formal parameter for the function Scop. Additionally, we must check
+ -- that Scop returns an anonymous access type, otherwise the special
+ -- rules dictating a need for a dynamic check are not in effect.
+
+ return Is_Entity_Name (Prefix (Exp))
+ and then Is_Explicitly_Aliased (Entity (Prefix (Exp)));
+ end Is_Special_Aliased_Formal_Access;
+
+ --------------------------------------
+ -- Needs_Result_Accessibility_Level --
+ --------------------------------------
+
+ function Needs_Result_Accessibility_Level
+ (Func_Id : Entity_Id) return Boolean
+ is
+ Func_Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id));
+
+ function Has_Unconstrained_Access_Discriminant_Component
+ (Comp_Typ : Entity_Id) return Boolean;
+ -- Returns True if any component of the type has an unconstrained access
+ -- discriminant.
+
+ -----------------------------------------------------
+ -- Has_Unconstrained_Access_Discriminant_Component --
+ -----------------------------------------------------
+
+ function Has_Unconstrained_Access_Discriminant_Component
+ (Comp_Typ : Entity_Id) return Boolean
+ is
+ begin
+ if not Is_Limited_Type (Comp_Typ) then
+ return False;
+
+ -- Only limited types can have access discriminants with
+ -- defaults.
+
+ elsif Has_Unconstrained_Access_Discriminants (Comp_Typ) then
+ return True;
+
+ elsif Is_Array_Type (Comp_Typ) then
+ return Has_Unconstrained_Access_Discriminant_Component
+ (Underlying_Type (Component_Type (Comp_Typ)));
+
+ elsif Is_Record_Type (Comp_Typ) then
+ declare
+ Comp : Entity_Id;
+
+ begin
+ Comp := First_Component (Comp_Typ);
+ while Present (Comp) loop
+ if Has_Unconstrained_Access_Discriminant_Component
+ (Underlying_Type (Etype (Comp)))
+ then
+ return True;
+ end if;
+
+ Next_Component (Comp);
+ end loop;
+ end;
+ end if;
+
+ return False;
+ end Has_Unconstrained_Access_Discriminant_Component;
+
+ Disable_Tagged_Cases : constant Boolean := True;
+ -- Flag used to temporarily disable a "True" result for tagged types.
+ -- See comments further below for details.
+
+ -- Start of processing for Needs_Result_Accessibility_Level
+
+ begin
+ -- False if completion unavailable, which can happen when we are
+ -- analyzing an abstract subprogram or if the subprogram has
+ -- delayed freezing.
+
+ if No (Func_Typ) then
+ return False;
+
+ -- False if not a function, also handle enum-lit renames case
+
+ elsif Func_Typ = Standard_Void_Type
+ or else Is_Scalar_Type (Func_Typ)
+ then
+ return False;
+
+ -- Handle a corner case, a cross-dialect subp renaming. For example,
+ -- an Ada 2012 renaming of an Ada 2005 subprogram. This can occur when
+ -- an Ada 2005 (or earlier) unit references predefined run-time units.
+
+ elsif Present (Alias (Func_Id)) then
+
+ -- Unimplemented: a cross-dialect subp renaming which does not set
+ -- the Alias attribute (e.g., a rename of a dereference of an access
+ -- to subprogram value). ???
+
+ return Present (Extra_Accessibility_Of_Result (Alias (Func_Id)));
+
+ -- Remaining cases require Ada 2012 mode, unless they are dispatching
+ -- operations, since they may be overridden by Ada_2012 primitives.
+
+ elsif Ada_Version < Ada_2012
+ and then not Is_Dispatching_Operation (Func_Id)
+ then
+ return False;
+
+ -- Handle the situation where a result is an anonymous access type
+ -- RM 3.10.2 (10.3/3).
+
+ elsif Ekind (Func_Typ) = E_Anonymous_Access_Type then
+ return True;
+
+ -- In the case of, say, a null tagged record result type, the need for
+ -- this extra parameter might not be obvious so this function returns
+ -- True for all tagged types for compatibility reasons.
+
+ -- A function with, say, a tagged null controlling result type might
+ -- be overridden by a primitive of an extension having an access
+ -- discriminant and the overrider and overridden must have compatible
+ -- calling conventions (including implicitly declared parameters).
+
+ -- Similarly, values of one access-to-subprogram type might designate
+ -- both a primitive subprogram of a given type and a function which is,
+ -- for example, not a primitive subprogram of any type. Again, this
+ -- requires calling convention compatibility. It might be possible to
+ -- solve these issues by introducing wrappers, but that is not the
+ -- approach that was chosen.
+
+ -- Note: Despite the reasoning noted above, the extra accessibility
+ -- parameter for tagged types is disabled for performance reasons.
+
+ elsif Is_Tagged_Type (Func_Typ) then
+ return not Disable_Tagged_Cases;
+
+ elsif Has_Unconstrained_Access_Discriminants (Func_Typ) then
+ return True;
+
+ elsif Has_Unconstrained_Access_Discriminant_Component (Func_Typ) then
+ return True;
+
+ -- False for all other cases
+
+ else
+ return False;
+ end if;
+ end Needs_Result_Accessibility_Level;
+
+ ------------------------------------------
+ -- Prefix_With_Safe_Accessibility_Level --
+ ------------------------------------------
+
+ function Prefix_With_Safe_Accessibility_Level
+ (N : Node_Id;
+ Typ : Entity_Id) return Boolean
+ is
+ P : constant Node_Id := Prefix (N);
+ Aname : constant Name_Id := Attribute_Name (N);
+ Attr_Id : constant Attribute_Id := Get_Attribute_Id (Aname);
+ Btyp : constant Entity_Id := Base_Type (Typ);
+
+ function Safe_Value_Conversions return Boolean;
+ -- Return False if the prefix has a value conversion of an array type
+
+ ----------------------------
+ -- Safe_Value_Conversions --
+ ----------------------------
+
+ function Safe_Value_Conversions return Boolean is
+ PP : Node_Id := P;
+
+ begin
+ loop
+ if Nkind (PP) in N_Selected_Component | N_Indexed_Component then
+ PP := Prefix (PP);
+
+ elsif Comes_From_Source (PP)
+ and then Nkind (PP) in N_Type_Conversion
+ | N_Unchecked_Type_Conversion
+ and then Is_Array_Type (Etype (PP))
+ then
+ return False;
+
+ elsif Comes_From_Source (PP)
+ and then Nkind (PP) = N_Qualified_Expression
+ and then Is_Array_Type (Etype (PP))
+ and then Nkind (Original_Node (Expression (PP))) in
+ N_Aggregate | N_Extension_Aggregate
+ then
+ return False;
+
+ else
+ exit;
+ end if;
+ end loop;
+
+ return True;
+ end Safe_Value_Conversions;
+
+ -- Start of processing for Prefix_With_Safe_Accessibility_Level
+
+ begin
+ -- No check required for unchecked and unrestricted access
+
+ if Attr_Id = Attribute_Unchecked_Access
+ or else Attr_Id = Attribute_Unrestricted_Access
+ then
+ return True;
+
+ -- Check value conversions
+
+ elsif Ekind (Btyp) = E_General_Access_Type
+ and then not Safe_Value_Conversions
+ then
+ return False;
+ end if;
+
+ return True;
+ end Prefix_With_Safe_Accessibility_Level;
+
+ -----------------------------
+ -- Subprogram_Access_Level --
+ -----------------------------
+
+ function Subprogram_Access_Level (Subp : Entity_Id) return Uint is
+ begin
+ if Present (Alias (Subp)) then
+ return Subprogram_Access_Level (Alias (Subp));
+ else
+ return Scope_Depth (Enclosing_Dynamic_Scope (Subp));
+ end if;
+ end Subprogram_Access_Level;
+
+ --------------------------------
+ -- Static_Accessibility_Level --
+ --------------------------------
+
+ function Static_Accessibility_Level
+ (Expr : Node_Id;
+ Level : Static_Accessibility_Level_Kind;
+ In_Return_Context : Boolean := False) return Uint
+ is
+ begin
+ return Intval
+ (Accessibility_Level (Expr, Level, In_Return_Context));
+ end Static_Accessibility_Level;
+
+ -----------------------
+ -- Type_Access_Level --
+ -----------------------
+
+ function Type_Access_Level
+ (Typ : Entity_Id;
+ Allow_Alt_Model : Boolean := True;
+ Assoc_Ent : Entity_Id := Empty) return Uint
+ is
+ Btyp : Entity_Id := Base_Type (Typ);
+ Def_Ent : Entity_Id;
+
+ begin
+ -- Ada 2005 (AI-230): For most cases of anonymous access types, we
+ -- simply use the level where the type is declared. This is true for
+ -- stand-alone object declarations, and for anonymous access types
+ -- associated with components the level is the same as that of the
+ -- enclosing composite type. However, special treatment is needed for
+ -- the cases of access parameters, return objects of an anonymous access
+ -- type, and, in Ada 95, access discriminants of limited types.
+
+ if Is_Access_Type (Btyp) then
+ if Ekind (Btyp) = E_Anonymous_Access_Type then
+ -- No_Dynamic_Accessibility_Checks restriction override for
+ -- alternative accessibility model.
+
+ if Allow_Alt_Model
+ and then No_Dynamic_Accessibility_Checks_Enabled (Btyp)
+ then
+ -- In the -gnatd_b model, the level of an anonymous access
+ -- type is always that of the designated type.
+
+ if Debug_Flag_Underscore_B then
+ return Type_Access_Level
+ (Designated_Type (Btyp), Allow_Alt_Model);
+ end if;
+
+ -- When an anonymous access type's Assoc_Ent is specified,
+ -- calculate the result based on the general accessibility
+ -- level routine.
+
+ -- We would like to use Associated_Node_For_Itype here instead,
+ -- but in some cases it is not fine grained enough ???
+
+ if Present (Assoc_Ent) then
+ return Static_Accessibility_Level
+ (Assoc_Ent, Object_Decl_Level);
+ end if;
+
+ -- Otherwise take the context of the anonymous access type into
+ -- account.
+
+ -- Obtain the defining entity for the internally generated
+ -- anonymous access type.
+
+ Def_Ent := Defining_Entity_Or_Empty
+ (Associated_Node_For_Itype (Typ));
+
+ if Present (Def_Ent) then
+ -- When the defining entity is a subprogram then we know the
+ -- anonymous access type Typ has been generated to either
+ -- describe an anonymous access type formal or an anonymous
+ -- access result type.
+
+ -- Since we are only interested in the formal case, avoid
+ -- the anonymous access result type.
+
+ if Is_Subprogram (Def_Ent)
+ and then not (Ekind (Def_Ent) = E_Function
+ and then Etype (Def_Ent) = Typ)
+ then
+ -- When the type comes from an anonymous access
+ -- parameter, the level is that of the subprogram
+ -- declaration.
+
+ return Scope_Depth (Def_Ent);
+
+ -- When the type is an access discriminant, the level is
+ -- that of the type.
+
+ elsif Ekind (Def_Ent) = E_Discriminant then
+ return Scope_Depth (Scope (Def_Ent));
+ end if;
+ end if;
+
+ -- If the type is a nonlocal anonymous access type (such as for
+ -- an access parameter) we treat it as being declared at the
+ -- library level to ensure that names such as X.all'access don't
+ -- fail static accessibility checks.
+
+ elsif not Is_Local_Anonymous_Access (Typ) then
+ return Scope_Depth (Standard_Standard);
+
+ -- If this is a return object, the accessibility level is that of
+ -- the result subtype of the enclosing function. The test here is
+ -- little complicated, because we have to account for extended
+ -- return statements that have been rewritten as blocks, in which
+ -- case we have to find and the Is_Return_Object attribute of the
+ -- itype's associated object. It would be nice to find a way to
+ -- simplify this test, but it doesn't seem worthwhile to add a new
+ -- flag just for purposes of this test. ???
+
+ elsif Ekind (Scope (Btyp)) = E_Return_Statement
+ or else
+ (Is_Itype (Btyp)
+ and then Nkind (Associated_Node_For_Itype (Btyp)) =
+ N_Object_Declaration
+ and then Is_Return_Object
+ (Defining_Identifier
+ (Associated_Node_For_Itype (Btyp))))
+ then
+ declare
+ Scop : Entity_Id;
+
+ begin
+ Scop := Scope (Scope (Btyp));
+ while Present (Scop) loop
+ exit when Ekind (Scop) = E_Function;
+ Scop := Scope (Scop);
+ end loop;
+
+ -- Treat the return object's type as having the level of the
+ -- function's result subtype (as per RM05-6.5(5.3/2)).
+
+ return Type_Access_Level (Etype (Scop), Allow_Alt_Model);
+ end;
+ end if;
+ end if;
+
+ Btyp := Root_Type (Btyp);
+
+ -- The accessibility level of anonymous access types associated with
+ -- discriminants is that of the current instance of the type, and
+ -- that's deeper than the type itself (AARM 3.10.2 (12.3.21)).
+
+ -- AI-402: access discriminants have accessibility based on the
+ -- object rather than the type in Ada 2005, so the above paragraph
+ -- doesn't apply.
+
+ -- ??? Needs completion with rules from AI-416
+
+ if Ada_Version <= Ada_95
+ and then Ekind (Typ) = E_Anonymous_Access_Type
+ and then Present (Associated_Node_For_Itype (Typ))
+ and then Nkind (Associated_Node_For_Itype (Typ)) =
+ N_Discriminant_Specification
+ then
+ return Scope_Depth (Enclosing_Dynamic_Scope (Btyp)) + 1;
+ end if;
+ end if;
+
+ -- Return library level for a generic formal type. This is done because
+ -- RM(10.3.2) says that "The statically deeper relationship does not
+ -- apply to ... a descendant of a generic formal type". Rather than
+ -- checking at each point where a static accessibility check is
+ -- performed to see if we are dealing with a formal type, this rule is
+ -- implemented by having Type_Access_Level and Deepest_Type_Access_Level
+ -- return extreme values for a formal type; Deepest_Type_Access_Level
+ -- returns Int'Last. By calling the appropriate function from among the
+ -- two, we ensure that the static accessibility check will pass if we
+ -- happen to run into a formal type. More specifically, we should call
+ -- Deepest_Type_Access_Level instead of Type_Access_Level whenever the
+ -- call occurs as part of a static accessibility check and the error
+ -- case is the case where the type's level is too shallow (as opposed
+ -- to too deep).
+
+ if Is_Generic_Type (Root_Type (Btyp)) then
+ return Scope_Depth (Standard_Standard);
+ end if;
+
+ return Scope_Depth (Enclosing_Dynamic_Scope (Btyp));
+ end Type_Access_Level;
+
+end Accessibility;
diff --git a/gcc/ada/accessibility.ads b/gcc/ada/accessibility.ads
new file mode 100644
index 0000000..454ad75
--- /dev/null
+++ b/gcc/ada/accessibility.ads
@@ -0,0 +1,222 @@
+------------------------------------------------------------------------------
+-- --
+-- GNAT COMPILER COMPONENTS --
+-- --
+-- A C C E S S I B I L I T Y --
+-- --
+-- S p e c --
+-- --
+-- Copyright (C) 2022-2022, Free Software Foundation, Inc. --
+-- --
+-- GNAT is free software; you can redistribute it and/or modify it under --
+-- terms of the GNU General Public License as published by the Free Soft- --
+-- ware Foundation; either version 3, or (at your option) any later ver- --
+-- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
+-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
+-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
+-- for more details. You should have received a copy of the GNU General --
+-- Public License distributed with GNAT; see file COPYING3. If not, go to --
+-- http://www.gnu.org/licenses for a complete copy of the license. --
+-- --
+-- GNAT was originally developed by the GNAT team at New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc. --
+-- --
+------------------------------------------------------------------------------
+
+-- Accessibility level and check generation routines
+
+with Types; use Types;
+with Uintp; use Uintp;
+
+package Accessibility is
+
+ procedure Accessibility_Message (N : Node_Id; Typ : Entity_Id);
+ -- Error, or warning within an instance, if the static accessibility
+ -- rules of 3.10.2 are violated.
+
+ type Accessibility_Level_Kind is
+ (Dynamic_Level,
+ Object_Decl_Level,
+ Zero_On_Dynamic_Level);
+ -- Accessibility_Level_Kind is an enumerated type which captures the
+ -- different modes in which an accessibility level could be obtained for
+ -- a given expression.
+
+ -- When in the context of the function Accessibility_Level,
+ -- Accessibility_Level_Kind signals what type of accessibility level to
+ -- obtain. For example, when Level is Dynamic_Level, a defining identifier
+ -- associated with a SAOOAAT may be returned or an N_Integer_Literal node.
+ -- When the level is Object_Decl_Level, an N_Integer_Literal node is
+ -- returned containing the level of the declaration of the object if
+ -- relevant (be it a SAOOAAT or otherwise). Finally, Zero_On_Dynamic_Level
+ -- returns library level for all cases where the accessibility level is
+ -- dynamic (used to bypass static accessibility checks in dynamic cases).
+
+ function Accessibility_Level
+ (Expr : Node_Id;
+ Level : Accessibility_Level_Kind;
+ In_Return_Context : Boolean := False;
+ Allow_Alt_Model : Boolean := True) return Node_Id;
+ -- Centralized accessibility level calculation routine for finding the
+ -- accessibility level of a given expression Expr.
+
+ -- In_Return_Context forces the Accessibility_Level calculations to be
+ -- carried out "as if" Expr existed in a return value. This is useful for
+ -- calculating the accessibility levels for discriminant associations
+ -- and return aggregates.
+
+ -- The Allow_Alt_Model parameter allows the alternative level calculation
+ -- under the restriction No_Dynamic_Accessibility_Checks to be performed.
+
+ procedure Apply_Accessibility_Check
+ (N : Node_Id;
+ Typ : Entity_Id;
+ Insert_Node : Node_Id);
+ -- Given a name N denoting an access parameter, emits a run-time
+ -- accessibility check (if necessary), checking that the level of
+ -- the object denoted by the access parameter is not deeper than the
+ -- level of the type Typ. Program_Error is raised if the check fails.
+ -- Insert_Node indicates the node where the check should be inserted.
+
+ procedure Apply_Accessibility_Check_For_Allocator
+ (N : Node_Id;
+ Exp : Node_Id;
+ Ref : Node_Id;
+ Built_In_Place : Boolean := False);
+ -- Ada 2005 (AI-344): For an allocator with a class-wide designated
+ -- type, generate an accessibility check to verify that the level of the
+ -- type of the created object is not deeper than the level of the access
+ -- type. If the type of the qualified expression is class-wide, then
+ -- always generate the check (except in the case where it is known to be
+ -- unnecessary, see comment below). Otherwise, only generate the check
+ -- if the level of the qualified expression type is statically deeper
+ -- than the access type.
+ --
+ -- Although the static accessibility will generally have been performed
+ -- as a legality check, it won't have been done in cases where the
+ -- allocator appears in generic body, so a run-time check is needed in
+ -- general. One special case is when the access type is declared in the
+ -- same scope as the class-wide allocator, in which case the check can
+ -- never fail, so it need not be generated.
+ --
+ -- As an open issue, there seem to be cases where the static level
+ -- associated with the class-wide object's underlying type is not
+ -- sufficient to perform the proper accessibility check, such as for
+ -- allocators in nested subprograms or accept statements initialized by
+ -- class-wide formals when the actual originates outside at a deeper
+ -- static level. The nested subprogram case might require passing
+ -- accessibility levels along with class-wide parameters, and the task
+ -- case seems to be an actual gap in the language rules that needs to
+ -- be fixed by the ARG. ???
+
+ procedure Check_Return_Construct_Accessibility
+ (Return_Stmt : Node_Id;
+ Stm_Entity : Entity_Id);
+ -- Apply legality rule of 6.5 (5.9) to the access discriminants of an
+ -- aggregate in a return statement.
+
+ function Deepest_Type_Access_Level
+ (Typ : Entity_Id;
+ Allow_Alt_Model : Boolean := True) return Uint;
+ -- Same as Type_Access_Level, except that if the type is the type of an Ada
+ -- 2012 stand-alone object of an anonymous access type, then return the
+ -- static accessibility level of the object. In that case, the dynamic
+ -- accessibility level of the object may take on values in a range. The low
+ -- bound of that range is returned by Type_Access_Level; this function
+ -- yields the high bound of that range. Also differs from Type_Access_Level
+ -- in the case of a descendant of a generic formal type (returns Int'Last
+ -- instead of 0).
+
+ -- The Allow_Alt_Model parameter allows the alternative level calculation
+ -- under the restriction No_Dynamic_Accessibility_Checks to be performed.
+
+ function Effective_Extra_Accessibility (Id : Entity_Id) return Entity_Id;
+ -- Same as Einfo.Extra_Accessibility except thtat object renames
+ -- are looked through.
+
+ function Get_Dynamic_Accessibility (E : Entity_Id) return Entity_Id;
+ -- Obtain the accessibility level for a given entity formal taking into
+ -- account both extra and minimum accessibility.
+
+ function Has_Access_Values (T : Entity_Id) return Boolean;
+ -- Returns true if the underlying type of T is an access type, or has a
+ -- component (at any recursive level) that is an access type. This is a
+ -- conservative predicate, if it is not known whether or not T contains
+ -- access values (happens for generic formals in some cases), then False is
+ -- returned. Note that tagged types return False. Even though the tag is
+ -- implemented as an access type internally, this function tests only for
+ -- access types known to the programmer. See also Has_Tagged_Component.
+
+ function Has_Anonymous_Access_Discriminant (Typ : Entity_Id) return Boolean;
+ -- Returns True if Typ has one or more anonymous access discriminants
+
+ function Prefix_With_Safe_Accessibility_Level
+ (N : Node_Id;
+ Typ : Entity_Id) return Boolean;
+ -- Return True if the prefix does not have a value conversion of an
+ -- array because a value conversion is like an aggregate with respect
+ -- to determining accessibility level (RM 3.10.2); even if evaluation
+ -- of a value conversion is guaranteed to not create a new object,
+ -- accessibility rules are defined as if it might.
+
+ subtype Static_Accessibility_Level_Kind
+ is Accessibility_Level_Kind range Object_Decl_Level
+ .. Zero_On_Dynamic_Level;
+ -- Restrict the reange of Accessibility_Level_Kind to be non-dynamic for
+ -- use in the static version of Accessibility_Level below.
+
+ function Static_Accessibility_Level
+ (Expr : Node_Id;
+ Level : Static_Accessibility_Level_Kind;
+ In_Return_Context : Boolean := False) return Uint;
+ -- Overloaded version of Accessibility_Level which returns a universal
+ -- integer for use in compile-time checking. Note: Level is restricted to
+ -- be non-dynamic.
+
+ function Has_Unconstrained_Access_Discriminants
+ (Subtyp : Entity_Id) return Boolean;
+ -- Returns True if the given subtype is unconstrained and has one or more
+ -- access discriminants.
+
+ function Is_Anonymous_Access_Actual (N : Node_Id) return Boolean;
+ -- Determine if N is used as an actual for a call whose corresponding
+ -- formal is of an anonymous access type.
+
+ function Is_Special_Aliased_Formal_Access
+ (Exp : Node_Id;
+ In_Return_Context : Boolean := False) return Boolean;
+ -- Determines whether a dynamic check must be generated for explicitly
+ -- aliased formals within a function Scop for the expression Exp.
+
+ -- In_Return_Context forces Is_Special_Aliased_Formal_Access to assume
+ -- that Exp is within a return value which is useful for checking
+ -- expressions within discriminant associations of return objects.
+
+ -- More specially, Is_Special_Aliased_Formal_Access checks that Exp is a
+ -- 'Access attribute reference within a return statement where the ultimate
+ -- prefix is an aliased formal of Scop and that Scop returns an anonymous
+ -- access type. See RM 3.10.2 for more details.
+
+ function Needs_Result_Accessibility_Level
+ (Func_Id : Entity_Id) return Boolean;
+ -- Ada 2012 (AI05-0234): Return True if the function needs an implicit
+ -- parameter to identify the accessibility level of the function result
+ -- "determined by the point of call".
+
+ function Subprogram_Access_Level (Subp : Entity_Id) return Uint;
+ -- Return the accessibility level of the view denoted by Subp
+
+ function Type_Access_Level
+ (Typ : Entity_Id;
+ Allow_Alt_Model : Boolean := True;
+ Assoc_Ent : Entity_Id := Empty) return Uint;
+ -- Return the accessibility level of Typ
+
+ -- The Allow_Alt_Model parameter allows the alternative level calculation
+ -- under the restriction No_Dynamic_Accessibility_Checks to be performed.
+
+ -- Assoc_Ent allows for the optional specification of the entity associated
+ -- with Typ. This gets utilized mostly for anonymous access type
+ -- processing, where context matters in interpreting Typ's level.
+
+end Accessibility;
diff --git a/gcc/ada/checks.adb b/gcc/ada/checks.adb
index 2a45f4d..5833be3 100644
--- a/gcc/ada/checks.adb
+++ b/gcc/ada/checks.adb
@@ -570,119 +570,6 @@ package body Checks is
Install_Null_Excluding_Check (P);
end Apply_Access_Check;
- -------------------------------
- -- Apply_Accessibility_Check --
- -------------------------------
-
- procedure Apply_Accessibility_Check
- (N : Node_Id;
- Typ : Entity_Id;
- Insert_Node : Node_Id)
- is
- Loc : constant Source_Ptr := Sloc (N);
-
- Check_Cond : Node_Id;
- Param_Ent : Entity_Id := Param_Entity (N);
- Param_Level : Node_Id;
- Type_Level : Node_Id;
-
- begin
- -- Verify we haven't tried to add a dynamic accessibility check when we
- -- shouldn't.
-
- pragma Assert (not No_Dynamic_Accessibility_Checks_Enabled (N));
-
- if Ada_Version >= Ada_2012
- and then No (Param_Ent)
- and then Is_Entity_Name (N)
- and then Ekind (Entity (N)) in E_Constant | E_Variable
- and then Present (Effective_Extra_Accessibility (Entity (N)))
- then
- Param_Ent := Entity (N);
- while Present (Renamed_Object (Param_Ent)) loop
- -- Renamed_Object must return an Entity_Name here
- -- because of preceding "Present (E_E_A (...))" test.
-
- Param_Ent := Entity (Renamed_Object (Param_Ent));
- end loop;
- end if;
-
- if Inside_A_Generic then
- return;
-
- -- Only apply the run-time check if the access parameter has an
- -- associated extra access level parameter and when accessibility checks
- -- are enabled.
-
- elsif Present (Param_Ent)
- and then Present (Get_Dynamic_Accessibility (Param_Ent))
- and then not Accessibility_Checks_Suppressed (Param_Ent)
- and then not Accessibility_Checks_Suppressed (Typ)
- then
- -- Obtain the parameter's accessibility level
-
- Param_Level :=
- New_Occurrence_Of (Get_Dynamic_Accessibility (Param_Ent), Loc);
-
- -- Use the dynamic accessibility parameter for the function's result
- -- when one has been created instead of statically referring to the
- -- deepest type level so as to appropriatly handle the rules for
- -- RM 3.10.2 (10.1/3).
-
- if Ekind (Scope (Param_Ent)) = E_Function
- and then In_Return_Value (N)
- and then Ekind (Typ) = E_Anonymous_Access_Type
- then
- -- Associate the level of the result type to the extra result
- -- accessibility parameter belonging to the current function.
-
- if Present (Extra_Accessibility_Of_Result (Scope (Param_Ent))) then
- Type_Level :=
- New_Occurrence_Of
- (Extra_Accessibility_Of_Result (Scope (Param_Ent)), Loc);
-
- -- In Ada 2005 and earlier modes, a result extra accessibility
- -- parameter is not generated and no dynamic check is performed.
-
- else
- return;
- end if;
-
- -- Otherwise get the type's accessibility level normally
-
- else
- Type_Level :=
- Make_Integer_Literal (Loc, Deepest_Type_Access_Level (Typ));
- end if;
-
- -- Raise Program_Error if the accessibility level of the access
- -- parameter is deeper than the level of the target access type.
-
- Check_Cond :=
- Make_Op_Gt (Loc,
- Left_Opnd => Param_Level,
- Right_Opnd => Type_Level);
-
- Insert_Action (Insert_Node,
- Make_Raise_Program_Error (Loc,
- Condition => Check_Cond,
- Reason => PE_Accessibility_Check_Failed));
-
- Analyze_And_Resolve (N);
-
- -- If constant folding has happened on the condition for the
- -- generated error, then warn about it being unconditional.
-
- if Nkind (Check_Cond) = N_Identifier
- and then Entity (Check_Cond) = Standard_True
- then
- Error_Msg_Warn := SPARK_Mode /= On;
- Error_Msg_N ("accessibility check fails<<", N);
- Error_Msg_N ("\Program_Error [<<", N);
- end if;
- end if;
- end Apply_Accessibility_Check;
-
--------------------------------
-- Apply_Address_Clause_Check --
--------------------------------
diff --git a/gcc/ada/checks.ads b/gcc/ada/checks.ads
index a7d05a3..772adf0 100644
--- a/gcc/ada/checks.ads
+++ b/gcc/ada/checks.ads
@@ -189,16 +189,6 @@ package Checks is
-- Determines whether an expression node requires a run-time access
-- check and if so inserts the appropriate run-time check.
- procedure Apply_Accessibility_Check
- (N : Node_Id;
- Typ : Entity_Id;
- Insert_Node : Node_Id);
- -- Given a name N denoting an access parameter, emits a run-time
- -- accessibility check (if necessary), checking that the level of
- -- the object denoted by the access parameter is not deeper than the
- -- level of the type Typ. Program_Error is raised if the check fails.
- -- Insert_Node indicates the node where the check should be inserted.
-
procedure Apply_Address_Clause_Check (E : Entity_Id; N : Node_Id);
-- E is the entity for an object which has an address clause. If checks
-- are enabled, then this procedure generates a check that the specified
diff --git a/gcc/ada/contracts.adb b/gcc/ada/contracts.adb
index 6f474eb..59121ca 100644
--- a/gcc/ada/contracts.adb
+++ b/gcc/ada/contracts.adb
@@ -316,6 +316,7 @@ package body Contracts is
| Name_Async_Writers
| Name_Effective_Reads
| Name_Effective_Writes
+ | Name_No_Caching
or else (Ekind (Id) = E_Task_Type
and Prag_Nam in Name_Part_Of
| Name_Depends
@@ -859,6 +860,7 @@ package body Contracts is
AW_Val : Boolean := False;
ER_Val : Boolean := False;
EW_Val : Boolean := False;
+ NC_Val : Boolean;
Seen : Boolean := False;
Prag : Node_Id;
Obj_Typ : Entity_Id;
@@ -956,18 +958,25 @@ package body Contracts is
end if;
-- Verify the mutual interaction of the various external properties.
- -- For variables for which No_Caching is enabled, it has been checked
- -- already that only False values for other external properties are
- -- allowed.
+ -- For types and variables for which No_Caching is enabled, it has been
+ -- checked already that only False values for other external properties
+ -- are allowed.
if Seen
- and then (Ekind (Type_Or_Obj_Id) /= E_Variable
- or else not No_Caching_Enabled (Type_Or_Obj_Id))
+ and then not No_Caching_Enabled (Type_Or_Obj_Id)
then
Check_External_Properties
(Type_Or_Obj_Id, AR_Val, AW_Val, ER_Val, EW_Val);
end if;
+ -- Analyze the non-external volatility property No_Caching
+
+ Prag := Get_Pragma (Type_Or_Obj_Id, Pragma_No_Caching);
+
+ if Present (Prag) then
+ Analyze_External_Property_In_Decl_Part (Prag, NC_Val);
+ end if;
+
-- The following checks are relevant only when SPARK_Mode is on, as
-- they are not standard Ada legality rules. Internally generated
-- temporaries are ignored, as well as return objects.
@@ -1047,10 +1056,10 @@ package body Contracts is
if Is_Type_Id
and then not Is_Effectively_Volatile (Type_Or_Obj_Id)
- and then Has_Volatile_Component (Type_Or_Obj_Id)
+ and then Has_Effectively_Volatile_Component (Type_Or_Obj_Id)
then
Error_Msg_N
- ("non-volatile type & cannot have volatile"
+ ("non-volatile type & cannot have effectively volatile"
& " components",
Type_Or_Obj_Id);
end if;
@@ -1076,7 +1085,6 @@ package body Contracts is
Saved_SMP : constant Node_Id := SPARK_Mode_Pragma;
-- Save the SPARK_Mode-related data to restore on exit
- NC_Val : Boolean;
Items : Node_Id;
Prag : Node_Id;
Ref_Elmt : Elmt_Id;
@@ -1118,14 +1126,6 @@ package body Contracts is
Check_Type_Or_Object_External_Properties (Type_Or_Obj_Id => Obj_Id);
- -- Analyze the non-external volatility property No_Caching
-
- Prag := Get_Pragma (Obj_Id, Pragma_No_Caching);
-
- if Present (Prag) then
- Analyze_External_Property_In_Decl_Part (Prag, NC_Val);
- end if;
-
-- Constant-related checks
if Ekind (Obj_Id) = E_Constant then
diff --git a/gcc/ada/doc/gnat_rm/the_gnat_library.rst b/gcc/ada/doc/gnat_rm/the_gnat_library.rst
index d791f81..3aae70a 100644
--- a/gcc/ada/doc/gnat_rm/the_gnat_library.rst
+++ b/gcc/ada/doc/gnat_rm/the_gnat_library.rst
@@ -47,7 +47,7 @@ of GNAT, and will generate a warning message.
This child of ``Ada.Characters``
provides a set of definitions corresponding to those in the
RM-defined package ``Ada.Characters.Latin_1`` but with the
-few modifications required for ``Latin-9``
+few modifications required for ``Latin-9``.
The provision of such a package
is specifically authorized by the Ada Reference Manual
(RM A.3.3(27)).
@@ -69,12 +69,12 @@ instead of ``Character``. The provision of such a package
is specifically authorized by the Ada Reference Manual
(RM A.3.3(27)).
-.. _`Ada.Characters.Wide_Latin_9_(a-cwila1.ads)`:
+.. _`Ada.Characters.Wide_Latin_9_(a-cwila9.ads)`:
-``Ada.Characters.Wide_Latin_9`` (:file:`a-cwila1.ads`)
+``Ada.Characters.Wide_Latin_9`` (:file:`a-cwila9.ads`)
======================================================
-.. index:: Ada.Characters.Wide_Latin_9 (a-cwila1.ads)
+.. index:: Ada.Characters.Wide_Latin_9 (a-cwila9.ads)
.. index:: Latin_9 constants for Wide_Character
@@ -159,8 +159,8 @@ where this concept makes sense.
This child of ``Ada.Command_Line``
provides a mechanism for logically removing
arguments from the argument list. Once removed, an argument is not visible
-to further calls on the subprograms in ``Ada.Command_Line`` will not
-see the removed argument.
+to further calls to the subprograms in ``Ada.Command_Line``. These calls
+will not see the removed argument.
.. _`Ada.Command_Line.Response_File_(a-clrefi.ads)`:
@@ -833,7 +833,7 @@ obtaining information about exceptions provided by Ada 83 compilers.
.. index:: Memory corruption debugging
-Provide a debugging storage pools that helps tracking memory corruption
+Provides a debugging storage pools that helps tracking memory corruption
problems.
See ``The GNAT Debug_Pool Facility`` section in the :title:`GNAT User's Guide`.
@@ -1043,7 +1043,7 @@ a message from a subprogram in a pure package, since the
necessary types and subprograms are in ``Ada.Exceptions``
which is not a pure unit. ``GNAT.Exceptions`` provides a
facility for getting around this limitation for a few
-predefined exceptions, and for example allow raising
+predefined exceptions, and for example allows raising
``Constraint_Error`` with a message from a pure subprogram.
.. _`GNAT.Expect_(g-expect.ads)`:
@@ -1098,7 +1098,7 @@ in this package can be used to reestablish the required mode.
.. index:: Formatted String
Provides support for C/C++ printf() formatted strings. The format is
-copied from the printf() routine and should therefore gives identical
+copied from the printf() routine and should therefore give identical
output. Some generic routines are provided to be able to use types
derived from Integer, Float or enumerations as values for the
formatted string.
@@ -1314,7 +1314,7 @@ Provides a generator of static minimal perfect hash functions. No
collisions occur and each item can be retrieved from the table in one
probe (perfect property). The hash table size corresponds to the exact
size of the key set and no larger (minimal property). The key set has to
-be know in advance (static property). The hash functions are also order
+be known in advance (static property). The hash functions are also order
preserving. If w2 is inserted after w1 in the generator, their
hashcode are in the same order. These hashing functions are very
convenient for use with realtime applications.
@@ -1399,7 +1399,7 @@ this interface usable for large files or socket streams.
.. index:: Secondary Stack Info
-Provide the capability to query the high water mark of the current task's
+Provides the capability to query the high water mark of the current task's
secondary stack.
.. _`GNAT.Semaphores_(g-semaph.ads)`:
@@ -1514,7 +1514,7 @@ targets.
A high level and portable interface to develop sockets based applications.
This package is based on the sockets thin binding found in
``GNAT.Sockets.Thin``. Currently ``GNAT.Sockets`` is implemented
-on all native GNAT ports and on VxWorks cross prots. It is not implemented for
+on all native GNAT ports and on VxWorks cross ports. It is not implemented for
the LynxOS cross port.
.. _`GNAT.Source_Info_(g-souinf.ads)`:
@@ -1781,12 +1781,12 @@ in various debugging situations.
.. index:: Trace back facilities
-.. _`GNAT.UTF_32_(g-table.ads)`:
+.. _`GNAT.UTF_32_(g-utf_32.ads)`:
-``GNAT.UTF_32`` (:file:`g-table.ads`)
-=====================================
+``GNAT.UTF_32`` (:file:`g-utf_32.ads`)
+======================================
-.. index:: GNAT.UTF_32 (g-table.ads)
+.. index:: GNAT.UTF_32 (g-utf_32.ads)
.. index:: Wide character codes
@@ -1800,12 +1800,12 @@ lexical rules for identifiers and strings, and also a
lower case to upper case fold routine corresponding to
the Ada 2005 rules for identifier equivalence.
-.. _`GNAT.Wide_Spelling_Checker_(g-u3spch.ads)`:
+.. _`GNAT.UTF_32_Spelling_Checker_(g-u3spch.ads)`:
-``GNAT.Wide_Spelling_Checker`` (:file:`g-u3spch.ads`)
-=====================================================
+``GNAT.UTF_32_Spelling_Checker`` (:file:`g-u3spch.ads`)
+=======================================================
-.. index:: GNAT.Wide_Spelling_Checker (g-u3spch.ads)
+.. index:: GNAT.UTF_32_Spelling_Checker (g-u3spch.ads)
.. index:: Spell checking
diff --git a/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst b/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
index 45ecea7..5dab2d4 100644
--- a/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
+++ b/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
@@ -928,10 +928,9 @@ Ada facilities defined in ``Ada.Exceptions``. Here is a simple example:
P2;
end STB;
-This program will output:
-
::
+ $ gnatmake stb -g -bargs -E -largs -no-pie
$ stb
raised CONSTRAINT_ERROR : stb.adb:12 range check failed
@@ -1070,7 +1069,7 @@ Here is an example:
::
- $ gnatmake -g .\stb -bargs -E
+ $ gnatmake -g stb -bargs -E
$ stb
0040149F in stb.p1 at stb.adb:8
@@ -1082,16 +1081,6 @@ Here is an example:
004011F1 in mainCRTStartup at crt1.c:222
77E892A4 in ?? at ??:0
-In the above example the ``.\`` syntax in the ``gnatmake`` command
-is currently required by ``addr2line`` for files that are in
-the current working directory.
-Moreover, the exact sequence of linker options may vary from platform
-to platform.
-The above :switch:`-largs` section is for Windows platforms. By contrast,
-under Unix there is no need for the :switch:`-largs` section.
-Differences across platforms are due to details of linker implementation.
-
-
.. rubric:: Tracebacks From Anywhere in a Program
It is possible to get a symbolic stack traceback
diff --git a/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst b/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst
index f2d42e9..7df45d5 100644
--- a/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst
+++ b/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst
@@ -2154,6 +2154,7 @@ building specialized scripts.
with GNAT.IO; use GNAT.IO;
with GNAT.Traceback; use GNAT.Traceback;
with GNAT.Debug_Utilities;
+
package body Pck is
procedure Call_Me_Third is
TB : Tracebacks_Array (1 .. 5);
@@ -2177,10 +2178,25 @@ building specialized scripts.
Call_Me_Second;
end Call_Me_First;
end Pck;
+
+ with GNAT.IO; use GNAT.IO;
+ with GNAT.Debug_Utilities;
+ with GNAT.Traceback;
+ with System;
+
with Pck; use Pck;
procedure Foo is
+ LA : constant System.Address := \
+ GNAT.Traceback.Executable_Load_Address;
+
+ use type System.Address;
+
begin
+ if LA /= System.Null_Address then
+ Put_Line ("Load address: " & GNAT.Debug_Utilities.Image_C (LA));
+ end if;
+
Global_Val := 123;
Call_Me_First;
end Foo;
diff --git a/gcc/ada/doc/share/conf.py b/gcc/ada/doc/share/conf.py
index 9ab80e7..48f1a96 100644
--- a/gcc/ada/doc/share/conf.py
+++ b/gcc/ada/doc/share/conf.py
@@ -2,6 +2,9 @@
# Style_Check:Python_Fragment (meaning no pyflakes check)
#
# GNAT build configuration file
+# --------------------------------
+# This file defines the configuration for all files created
+# by Sphinx. In this case, pdf (using latex) and html
import sys
import os
@@ -13,16 +16,12 @@ sys.path.append('.')
import ada_pygments
import latex_elements
-# Some configuration values for the various documentation handled by
-# this conf.py
-
+# Define list of documents to be built and their title
DOCS = {
- 'gnat_rm': {
- 'title': 'GNAT Reference Manual'},
- 'gnat_ugn': {
- 'title': 'GNAT User\'s Guide for Native Platforms'},
- 'gnat-style': {
- 'title': 'GNAT Coding Style: A Guide for GNAT Developers'}}
+ "gnat_rm": {"title": "GNAT Reference Manual"},
+ "gnat_ugn": {"title": "GNAT User's Guide for Native Platforms"},
+ "gnat-style": {"title": "GNAT Coding Style: A Guide for GNAT Developers"},
+}
# Then retrieve the source directory
root_source_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -30,14 +29,17 @@ gnatvsn_spec = os.path.join(root_source_dir, '..', 'gnatvsn.ads')
basever = os.path.join(root_source_dir, '..', '..', 'BASE-VER')
texi_fsf = True # Set to False when FSF doc is switched to sphinx by default
+# get vsn specs
with open(gnatvsn_spec, 'r') as fd:
gnatvsn_content = fd.read()
+# read copyright test from .rst file (used also for sanity-checking)
def get_copyright():
return '2008-%s, Free Software Foundation' % time.strftime('%Y')
+# get environment gnat version (used also for sanity-checking)
def get_gnat_version():
m = re.search(r'Gnat_Static_Version_String : ' +
r'constant String := "([^\(\)]+)\(.*\)?";',
@@ -58,6 +60,7 @@ def get_gnat_version():
sys.exit(1)
+# get gnat build type from runtime
def get_gnat_build_type():
m = re.search(r'Build_Type : constant Gnat_Build_Type := (.+);',
gnatvsn_content)
@@ -70,7 +73,35 @@ def get_gnat_build_type():
sys.exit(1)
+# Enable Sphinx extensions
+# Note that these are active for all files to be build (see DOCS list)
+extensions = ['sphinx_rtd_theme']
+
+# todo interprets ".. todo::" commands in .rst files
+# mathjax enables math equations to render correctly
+extensions += ['sphinx.ext.todo', 'sphinx.ext.mathjax']
+todo_include_todos = True
+
+# define templates source folder
+templates_path = ['_templates']
+# define the types of files to read as source for documents
+source_suffix = '.rst'
+
+# enable figure, object, table numeration on documents
+print('enabling table, code-block and figure numeration')
+numfig = True
+numfig_format = {
+ 'figure': 'figure %s',
+ 'table': 'table %s',
+ 'code-block': 'listing %s',
+ 'section': 'section %s',
+}
+print('done')
+
+
+# Start building the documents
# First retrieve the name of the documentation we are building
+print('checking doc name... ')
doc_name = os.environ.get('DOC_NAME', None)
if doc_name is None:
print('DOC_NAME environment variable should be set')
@@ -79,7 +110,7 @@ if doc_name is None:
if doc_name not in DOCS:
print('%s is not a valid documentation name' % doc_name)
sys.exit(1)
-
+print('found... ' , doc_name)
# Exclude sources that are not part of the current documentation
exclude_patterns = []
@@ -88,16 +119,13 @@ for d in os.listdir(root_source_dir):
exclude_patterns.append(d)
print('ignoring %s' % d)
+# Special condition for gnat_rm
if doc_name == 'gnat_rm':
exclude_patterns.append('share/gnat_project_manager.rst')
print('ignoring share/gnat_project_manager.rst')
-extensions = ['sphinx_rtd_theme']
-templates_path = ['_templates']
-source_suffix = '.rst'
-master_doc = doc_name
-
# General information about the project.
+master_doc = doc_name
project = DOCS[doc_name]['title']
copyright = get_copyright()
@@ -107,42 +135,58 @@ release = get_gnat_version()
pygments_style = None
tags.add(get_gnat_build_type())
+
+# Define figures to be included
html_theme = 'sphinx_rtd_theme'
if os.path.isfile('adacore_transparent.png'):
+ # split html and pdf logos to avoid 'same name' error in sphinx <5.2+
html_logo = 'adacore_transparent.png'
+ latex_logo = 'adacore_transparent.png'
if os.path.isfile('favicon.ico'):
html_favicon = 'favicon.ico'
html_static_path = ['_static']
+# Use gnat.sty for bulding documents
latex_additional_files = ['gnat.sty']
+# Add copyright info to file
copyright_macros = {
'date': time.strftime("%b %d, %Y"),
'edition': 'GNAT %s Edition' % 'Pro' if get_gnat_build_type() == 'PRO'
else 'GPL',
'name': 'GNU Ada',
'tool': 'GNAT',
- 'version': version}
+ 'version': version
+}
+# Send info to latex for building document
latex_elements = {
- 'preamble': '\\usepackage{gnat}\n' +
- latex_elements.TOC_DEPTH +
- latex_elements.PAGE_BLANK +
- latex_elements.TOC_CMD +
- latex_elements.LATEX_HYPHEN +
- latex_elements.doc_settings(DOCS[doc_name]['title'],
- get_gnat_version()),
- 'tableofcontents': latex_elements.TOC % copyright_macros}
-
+ 'preamble': '\\usepackage{gnat}\n' # use gnat.sty format
+ + latex_elements.TOC_DEPTH # define table of contents max depth to display
+ + latex_elements.PAGE_BLANK # define blank pages and when to be used
+ + latex_elements.TOC_CMD # write table of contents
+ + latex_elements.LATEX_HYPHEN # define latex hyphen '-'
+ + '\\sloppy\n\n' # sloppy/fussy define how words are spread in a paragraph
+ # the following is used to send title and gnat version to latex
+ + latex_elements.doc_settings(DOCS[doc_name]['title'], get_gnat_version()),
+ 'tableofcontents': latex_elements.TOC % copyright_macros, # build TOC
+ 'papersize': 'a4paper,table', # papersize as a4, else default letter
+ 'figure_align': 'H', # align figure as square and to paragraph text
+ 'maketitle': '\\maketitle', # execute custom maketitle
+}
+
+# Show page references for cross-reference in docs
+latex_show_pagerefs = True
+# Define latex metadata
latex_documents = [
(master_doc, '%s.tex' % doc_name, project, 'AdaCore', 'manual')]
-
+# Define .txt files metadata
texinfo_documents = [
- (master_doc, doc_name, project,
- 'AdaCore', doc_name, doc_name, '')]
+ (master_doc, doc_name, project, 'AdaCore', doc_name, doc_name, '')]
+# setup AdaCore custom pygments
def setup(app):
app.add_lexer('ada', ada_pygments.AdaLexer)
app.add_lexer('gpr', ada_pygments.GNATProjectLexer)
diff --git a/gcc/ada/einfo.ads b/gcc/ada/einfo.ads
index 2a1a406..d71dcaf 100644
--- a/gcc/ada/einfo.ads
+++ b/gcc/ada/einfo.ads
@@ -358,9 +358,11 @@ package Einfo is
--
-- For objects, the Actual_Subtype is set only if this is a discriminated
-- type. For arrays, the bounds of the expression are obtained and the
--- Etype of the object is directly the constrained subtype. This is
--- rather irregular, and the semantic checks that depend on the nominal
--- subtype being unconstrained use flag Is_Constr_Subt_For_U_Nominal(qv).
+-- Etype of the object is directly the constrained subtype, except in the
+-- case of a return object that lives on the secondary stack where Etype
+-- is the nominal unconstrained subtype. This is rather irregular and the
+-- semantic checks that depend on the nominal subtype being unconstrained
+-- use flag Is_Constr_Subt_For_U_Nominal(qv).
-- Address_Clause (synthesized)
-- Applies to entries, objects and subprograms. Set if an address clause
diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb
index 3f51ed6..4d8bb817 100644
--- a/gcc/ada/exp_aggr.adb
+++ b/gcc/ada/exp_aggr.adb
@@ -6841,7 +6841,7 @@ package body Exp_Aggr is
or else Parent_Kind = N_Component_Association
or else (Parent_Kind = N_Object_Declaration
and then (Needs_Finalization (Typ)
- or else Is_Build_In_Place_Return_Object
+ or else Is_Special_Return_Object
(Defining_Identifier (Parent_Node))))
or else (Parent_Kind = N_Assignment_Statement
and then Inside_Init_Proc)
diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb
index 9c8d80f..b7554e0 100644
--- a/gcc/ada/exp_attr.adb
+++ b/gcc/ada/exp_attr.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Aspects; use Aspects;
with Atree; use Atree;
with Checks; use Checks;
@@ -2215,13 +2216,25 @@ package body Exp_Attr is
-- Local declarations
- Enc_Object : constant Node_Id := Enclosing_Object (Ref_Object);
+ Enc_Object : Node_Id := Enclosing_Object (Ref_Object);
-- Start of processing for Access_Cases
begin
Btyp_DDT := Designated_Type (Btyp);
+ -- When Enc_Object is a view conversion then RM 3.10.2 (9)
+ -- applies and we obtain the expression being converted.
+ -- Otherwise we do not dig any deeper since a conversion
+ -- might generate a copy and we can't assume it will be as
+ -- long-lived as the original.
+
+ while Nkind (Enc_Object) = N_Type_Conversion
+ and then Is_View_Conversion (Enc_Object)
+ loop
+ Enc_Object := Expression (Enc_Object);
+ end loop;
+
-- Handle designated types that come from the limited view
if From_Limited_With (Btyp_DDT)
diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb
index 2661a3f..6de5843 100644
--- a/gcc/ada/exp_ch3.adb
+++ b/gcc/ada/exp_ch3.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Aspects; use Aspects;
with Atree; use Atree;
with Checks; use Checks;
@@ -6288,6 +6289,18 @@ package body Exp_Ch3 is
-- Generate all default initialization actions for object Def_Id. Any
-- new code is inserted after node After.
+ procedure Initialize_Return_Object
+ (Tag_Assign : Node_Id;
+ Adj_Call : Node_Id;
+ Expr : Node_Id;
+ Init_Stmt : Node_Id;
+ After : Node_Id);
+ -- Generate all initialization actions for return object Def_Id. Any
+ -- new code is inserted after node After.
+
+ function Make_Allocator_For_Return (Expr : Node_Id) return Node_Id;
+ -- Make an allocator for a return object initialized with Expr
+
function OK_To_Rename_Ref (N : Node_Id) return Boolean;
-- Return True if N denotes an entity with OK_To_Rename set
@@ -7046,6 +7059,108 @@ package body Exp_Ch3 is
end if;
end Default_Initialize_Object;
+ ------------------------------
+ -- Initialize_Return_Object --
+ ------------------------------
+
+ procedure Initialize_Return_Object
+ (Tag_Assign : Node_Id;
+ Adj_Call : Node_Id;
+ Expr : Node_Id;
+ Init_Stmt : Node_Id;
+ After : Node_Id)
+ is
+ begin
+ if Present (Tag_Assign) then
+ Insert_Action_After (After, Tag_Assign);
+ end if;
+
+ if Present (Adj_Call) then
+ Insert_Action_After (After, Adj_Call);
+ end if;
+
+ if No (Expr) then
+ Default_Initialize_Object (After);
+
+ elsif Is_Delayed_Aggregate (Expr)
+ and then not No_Initialization (N)
+ then
+ Convert_Aggr_In_Object_Decl (N);
+
+ elsif Present (Init_Stmt) then
+ Insert_Action_After (After, Init_Stmt);
+ Set_Expression (N, Empty);
+ end if;
+ end Initialize_Return_Object;
+
+ -------------------------------
+ -- Make_Allocator_For_Return --
+ -------------------------------
+
+ function Make_Allocator_For_Return (Expr : Node_Id) return Node_Id is
+ Func_Id : constant Entity_Id := Return_Applies_To (Scope (Def_Id));
+
+ Alloc : Node_Id;
+
+ begin
+ -- If the return object's declaration includes an expression and the
+ -- declaration isn't marked as No_Initialization, then we generate an
+ -- allocator with a qualified expression. Although this is necessary
+ -- only in the case where the result type is an interface (or class-
+ -- wide interface), we do it in all cases for the sake of consistency
+ -- instead of subsequently generating a separate assignment.
+
+ if Present (Expr)
+ and then not Is_Delayed_Aggregate (Expr)
+ and then not No_Initialization (N)
+ then
+ -- Ada 2005 (AI95-344): If the result type is class-wide, insert
+ -- a check that the level of the return expression's underlying
+ -- type is not deeper than the level of the master enclosing the
+ -- function.
+
+ -- AI12-043: The check is made immediately after the return object
+ -- is created.
+
+ if Is_Class_Wide_Type (Etype (Func_Id)) then
+ Apply_CW_Accessibility_Check (Expr, Func_Id);
+ end if;
+
+ -- We always use the type of the expression for the qualified
+ -- expression, rather than the return object's type. We cannot
+ -- always use the return object's type because the expression
+ -- might be of a specific type and the result object mignt not.
+
+ Alloc :=
+ Make_Allocator (Loc,
+ Expression =>
+ Make_Qualified_Expression (Loc,
+ Subtype_Mark =>
+ New_Occurrence_Of (Etype (Expr), Loc),
+ Expression => New_Copy_Tree (Expr)));
+
+ else
+ Alloc :=
+ Make_Allocator (Loc,
+ Expression => New_Occurrence_Of (Typ, Loc));
+
+ -- If the return object requires default initialization, then it
+ -- will happen later following the elaboration of the renaming.
+ -- If we don't turn it off here, then the object will be default
+ -- initialized twice.
+
+ Set_No_Initialization (Alloc);
+ end if;
+
+ -- Set the flag indicating that the allocator is made for a special
+ -- return object. This is used to bypass various legality checks as
+ -- well as to make sure that the result is not adjusted twice.
+
+ Set_For_Special_Return_Object (Alloc);
+
+ return Alloc;
+ end Make_Allocator_For_Return;
+
----------------------
-- OK_To_Rename_Ref --
----------------------
@@ -7059,10 +7174,9 @@ package body Exp_Ch3 is
-- Local variables
- Adj_Call : Node_Id;
- Expr_Q : Node_Id;
- Id_Ref : Node_Id;
- Tag_Assign : Node_Id;
+ Adj_Call : Node_Id := Empty;
+ Expr_Q : Node_Id := Empty;
+ Tag_Assign : Node_Id := Empty;
Init_After : Node_Id := N;
-- Node after which the initialization actions are to be inserted. This
@@ -7171,8 +7285,6 @@ package body Exp_Ch3 is
-- Default initialization required, and no expression present
if No (Expr) then
- Expr_Q := Expr;
-
-- If we have a type with a variant part, the initialization proc
-- will contain implicit tests of the discriminant values, which
-- counts as a violation of the restriction No_Implicit_Conditionals.
@@ -7231,7 +7343,7 @@ package body Exp_Ch3 is
end if;
end if;
- if not Is_Build_In_Place_Return_Object (Def_Id) then
+ if not Is_Special_Return_Object (Def_Id) then
Default_Initialize_Object (Init_After);
end if;
@@ -7291,7 +7403,7 @@ package body Exp_Ch3 is
Expander_Mode_Restore;
end if;
- if not Is_Build_In_Place_Return_Object (Def_Id) then
+ if not Is_Special_Return_Object (Def_Id) then
Convert_Aggr_In_Object_Decl (N);
end if;
@@ -7362,12 +7474,12 @@ package body Exp_Ch3 is
then
pragma Assert (Is_Class_Wide_Type (Typ));
- -- If the object is a built-in-place return object, bypass special
+ -- If the object is a special return object, then bypass special
-- treatment of class-wide interface initialization below. In this
-- case, the expansion of the return statement will take care of
-- creating the object (via allocator) and initializing it.
- if Is_Build_In_Place_Return_Object (Def_Id) then
+ if Is_Special_Return_Object (Def_Id) then
null;
elsif Tagged_Type_Expansion then
@@ -7667,8 +7779,7 @@ package body Exp_Ch3 is
if Present (Tag_Assign) then
if Present (Following_Address_Clause (N)) then
Ensure_Freeze_Node (Def_Id);
-
- else
+ elsif not Is_Special_Return_Object (Def_Id) then
Insert_Action_After (Init_After, Tag_Assign);
end if;
@@ -7678,23 +7789,26 @@ package body Exp_Ch3 is
-- record type.
elsif Is_CPP_Constructor_Call (Expr) then
+ declare
+ Id_Ref : constant Node_Id := New_Occurrence_Of (Def_Id, Loc);
- -- The call to the initialization procedure does NOT freeze the
- -- object being initialized.
+ begin
+ -- The call to the initialization procedure does NOT freeze
+ -- the object being initialized.
- Id_Ref := New_Occurrence_Of (Def_Id, Loc);
- Set_Must_Not_Freeze (Id_Ref);
- Set_Assignment_OK (Id_Ref);
+ Set_Must_Not_Freeze (Id_Ref);
+ Set_Assignment_OK (Id_Ref);
- Insert_Actions_After (Init_After,
- Build_Initialization_Call (Loc, Id_Ref, Typ,
- Constructor_Ref => Expr));
+ Insert_Actions_After (Init_After,
+ Build_Initialization_Call (Loc, Id_Ref, Typ,
+ Constructor_Ref => Expr));
- -- We remove here the original call to the constructor
- -- to avoid its management in the backend
+ -- We remove here the original call to the constructor
+ -- to avoid its management in the backend
- Set_Expression (N, Empty);
- return;
+ Set_Expression (N, Empty);
+ return;
+ end;
-- Handle initialization of limited tagged types
@@ -7734,18 +7848,15 @@ package body Exp_Ch3 is
then
Set_Is_Known_Valid (Def_Id);
- elsif Is_Access_Type (Typ) then
-
- -- For access types set the Is_Known_Non_Null flag if the
- -- initializing value is known to be non-null. We can also set
- -- Can_Never_Be_Null if this is a constant.
+ -- For access types, set the Is_Known_Non_Null flag if the
+ -- initializing value is known to be non-null. We can also
+ -- set Can_Never_Be_Null if this is a constant.
- if Known_Non_Null (Expr) then
- Set_Is_Known_Non_Null (Def_Id, True);
+ elsif Is_Access_Type (Typ) and then Known_Non_Null (Expr) then
+ Set_Is_Known_Non_Null (Def_Id, True);
- if Constant_Present (N) then
- Set_Can_Never_Be_Null (Def_Id);
- end if;
+ if Constant_Present (N) then
+ Set_Can_Never_Be_Null (Def_Id);
end if;
end if;
@@ -7761,6 +7872,7 @@ package body Exp_Ch3 is
and then not Is_Generic_Type (Typ)
then
Ensure_Valid (Expr);
+
if Safe_To_Capture_Value (N, Def_Id) then
Set_Is_Known_Valid (Def_Id);
end if;
@@ -7838,10 +7950,9 @@ package body Exp_Ch3 is
Obj_Ref => New_Occurrence_Of (Def_Id, Loc),
Typ => Base_Typ);
- -- Guard against a missing [Deep_]Adjust when the base type
- -- was not properly frozen.
-
- if Present (Adj_Call) then
+ if Present (Adj_Call)
+ and then not Is_Special_Return_Object (Def_Id)
+ then
Insert_Action_After (Init_After, Adj_Call);
end if;
end if;
@@ -8091,78 +8202,12 @@ package body Exp_Ch3 is
-- an unconstrained array on the heap. In this case the
-- result object's type is a constrained array type even
-- though the function's type is unconstrained.
+
Obj_Alloc_Formal : constant Entity_Id :=
Build_In_Place_Formal (Func_Id, BIP_Alloc_Form);
Pool_Id : constant Entity_Id :=
Make_Temporary (Loc, 'P');
- function Make_Allocator_For_BIP_Return return Node_Id;
- -- Make an allocator for the BIP return being processed
-
- -----------------------------------
- -- Make_Allocator_For_BIP_Return --
- -----------------------------------
-
- function Make_Allocator_For_BIP_Return return Node_Id is
- Alloc : Node_Id;
-
- begin
- if Present (Expr_Q)
- and then not Is_Delayed_Aggregate (Expr_Q)
- and then not No_Initialization (N)
- then
- -- Always use the type of the expression for the
- -- qualified expression, rather than the result type.
- -- In general we cannot always use the result type
- -- for the allocator, because the expression might be
- -- of a specific type, such as in the case of an
- -- aggregate or even a nonlimited object when the
- -- result type is a limited class-wide interface type.
-
- Alloc :=
- Make_Allocator (Loc,
- Expression =>
- Make_Qualified_Expression (Loc,
- Subtype_Mark =>
- New_Occurrence_Of (Etype (Expr_Q), Loc),
- Expression => New_Copy_Tree (Expr_Q)));
-
- else
- -- If the function returns a class-wide type we cannot
- -- use the return type for the allocator. Instead we
- -- use the type of the expression, which must be an
- -- aggregate of a definite type.
-
- if Is_Class_Wide_Type (Typ) then
- Alloc :=
- Make_Allocator (Loc,
- Expression =>
- New_Occurrence_Of (Etype (Expr_Q), Loc));
-
- else
- Alloc :=
- Make_Allocator (Loc,
- Expression =>
- New_Occurrence_Of (Typ, Loc));
- end if;
-
- -- If the object requires default initialization then
- -- that will happen later following the elaboration of
- -- the object renaming. If we don't turn it off here
- -- then the object will be default initialized twice.
-
- Set_No_Initialization (Alloc);
- end if;
-
- -- Set the flag indicating that the allocator came from
- -- a build-in-place return statement, so we can avoid
- -- adjusting the allocated object.
-
- Set_Alloc_For_BIP_Return (Alloc);
-
- return Alloc;
- end Make_Allocator_For_BIP_Return;
-
Acc_Typ : Entity_Id;
Alloc_Obj_Decl : Node_Id;
Alloc_Obj_Id : Entity_Id;
@@ -8208,13 +8253,13 @@ package body Exp_Ch3 is
-- First create the Heap_Allocator
- Heap_Allocator := Make_Allocator_For_BIP_Return;
+ Heap_Allocator := Make_Allocator_For_Return (Expr_Q);
-- The Pool_Allocator is just like the Heap_Allocator,
-- except we set Storage_Pool and Procedure_To_Call so
-- it will use the user-defined storage pool.
- Pool_Allocator := Make_Allocator_For_BIP_Return;
+ Pool_Allocator := Make_Allocator_For_Return (Expr_Q);
-- Do not generate the renaming of the build-in-place
-- pool parameter on ZFP because the parameter is not
@@ -8255,7 +8300,7 @@ package body Exp_Ch3 is
-- allocation.
else
- SS_Allocator := Make_Allocator_For_BIP_Return;
+ SS_Allocator := Make_Allocator_For_Return (Expr_Q);
-- The heap and pool allocators are marked as
-- Comes_From_Source since they correspond to an
@@ -8426,7 +8471,10 @@ package body Exp_Ch3 is
-- From now on, the type of the return object is the
-- designated type.
- Set_Etype (Def_Id, Desig_Typ);
+ if Desig_Typ /= Typ then
+ Set_Etype (Def_Id, Desig_Typ);
+ Set_Actual_Subtype (Def_Id, Typ);
+ end if;
-- Remember the local access object for use in the
-- dereference of the renaming created below.
@@ -8473,6 +8521,7 @@ package body Exp_Ch3 is
Alloc_Obj_Decl :=
Make_Object_Declaration (Loc,
Defining_Identifier => Alloc_Obj_Id,
+ Constant_Present => True,
Object_Definition =>
New_Occurrence_Of (Acc_Typ, Loc),
Expression =>
@@ -8491,25 +8540,207 @@ package body Exp_Ch3 is
-- Initialize the object now that it has got its final subtype,
-- but before rewriting it as a renaming.
- if No (Expr_Q) then
- Default_Initialize_Object (Init_After);
+ Initialize_Return_Object
+ (Tag_Assign, Adj_Call, Expr_Q, Init_Stmt, Init_After);
- elsif Is_Delayed_Aggregate (Expr_Q)
- and then not No_Initialization (N)
- then
- Convert_Aggr_In_Object_Decl (N);
+ -- Replace the return object declaration with a renaming of a
+ -- dereference of the access value designating the return object.
- elsif Present (Init_Stmt) then
- Insert_Action_After (Init_After, Init_Stmt);
- Set_Expression (N, Empty);
+ Expr_Q :=
+ Make_Explicit_Dereference (Loc,
+ Prefix => New_Occurrence_Of (Obj_Acc_Formal, Loc));
+ Set_Etype (Expr_Q, Etype (Def_Id));
+
+ Rewrite_As_Renaming := True;
+ end;
+
+ -- If we can rename the initialization expression, we need to make sure
+ -- that we use the proper type in the case of a return object that lives
+ -- on the secondary stack. See other cases below for a similar handling.
+
+ elsif Rewrite_As_Renaming then
+ if Is_Secondary_Stack_Return_Object (Def_Id) then
+ declare
+ Func_Id : constant Entity_Id :=
+ Return_Applies_To (Scope (Def_Id));
+
+ Desig_Typ : constant Entity_Id :=
+ (if Ekind (Typ) = E_Array_Subtype
+ then Etype (Func_Id) else Typ);
+
+ begin
+ -- From now on, the type of the return object is the
+ -- designated type.
+
+ if Desig_Typ /= Typ then
+ Set_Etype (Def_Id, Desig_Typ);
+ Set_Actual_Subtype (Def_Id, Typ);
+ end if;
+ end;
+ end if;
+
+ -- If this is the return object of a function returning on the secondary
+ -- stack, convert the declaration to a renaming of the dereference of ah
+ -- allocator for the secondary stack.
+
+ -- Result : T [:= <expression>];
+
+ -- is converted to
+
+ -- type Txx is access all ...;
+ -- Rxx : constant Txx :=
+ -- new <expression-type>['(<expression>)][storage_pool =
+ -- system__secondary_stack__ss_pool][procedure_to_call =
+ -- system__secondary_stack__ss_allocate];
+
+ -- Result : T renames Rxx.all;
+
+ elsif Is_Secondary_Stack_Return_Object (Def_Id) then
+ declare
+ Func_Id : constant Entity_Id :=
+ Return_Applies_To (Scope (Def_Id));
+
+ Desig_Typ : constant Entity_Id :=
+ (if Ekind (Typ) = E_Array_Subtype
+ then Etype (Func_Id) else Typ);
+ -- Ensure that the we use a fat pointer when allocating
+ -- an unconstrained array on the heap. In this case the
+ -- result object's type is a constrained array type even
+ -- though the function's type is unconstrained.
+
+ Acc_Typ : Entity_Id;
+ Alloc_Obj_Decl : Node_Id;
+ Alloc_Obj_Id : Entity_Id;
+ Ptr_Type_Decl : Node_Id;
+
+ begin
+ -- Create an access type designating the function's
+ -- result subtype.
+
+ Acc_Typ := Make_Temporary (Loc, 'A');
+
+ Ptr_Type_Decl :=
+ Make_Full_Type_Declaration (Loc,
+ Defining_Identifier => Acc_Typ,
+ Type_Definition =>
+ Make_Access_To_Object_Definition (Loc,
+ All_Present => True,
+ Subtype_Indication =>
+ New_Occurrence_Of (Desig_Typ, Loc)));
+
+ Insert_Action (N, Ptr_Type_Decl, Suppress => All_Checks);
+
+ Set_Associated_Storage_Pool (Acc_Typ, RTE (RE_SS_Pool));
+
+ Alloc_Obj_Id := Make_Temporary (Loc, 'R');
+
+ Alloc_Obj_Decl :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Alloc_Obj_Id,
+ Constant_Present => True,
+ Object_Definition =>
+ New_Occurrence_Of (Acc_Typ, Loc),
+ Expression => Make_Allocator_For_Return (Expr_Q));
+
+ Insert_Action (N, Alloc_Obj_Decl, Suppress => All_Checks);
+
+ Set_Uses_Sec_Stack (Func_Id);
+ Set_Uses_Sec_Stack (Scope (Def_Id));
+ Set_Sec_Stack_Needed_For_Return (Scope (Def_Id));
+
+ -- From now on, the type of the return object is the
+ -- designated type.
+
+ if Desig_Typ /= Typ then
+ Set_Etype (Def_Id, Desig_Typ);
+ Set_Actual_Subtype (Def_Id, Typ);
end if;
+ -- Initialize the object now that it has got its final subtype,
+ -- but before rewriting it as a renaming.
+
+ Initialize_Return_Object
+ (Tag_Assign, Adj_Call, Expr_Q, Empty, Init_After);
+
-- Replace the return object declaration with a renaming of a
-- dereference of the access value designating the return object.
Expr_Q :=
Make_Explicit_Dereference (Loc,
- Prefix => New_Occurrence_Of (Obj_Acc_Formal, Loc));
+ Prefix => New_Occurrence_Of (Alloc_Obj_Id, Loc));
+ Set_Etype (Expr_Q, Etype (Def_Id));
+
+ Rewrite_As_Renaming := True;
+ end;
+
+ -- If this is the return object of a function returning a by-reference
+ -- type, convert the declaration to a renaming of the dereference of ah
+ -- allocator for the return stack.
+
+ -- Result : T [:= <expression>];
+
+ -- is converted to
+
+ -- type Txx is access all ...;
+ -- Rxx : constant Txx :=
+ -- new <expression-type>['(<expression>)][storage_pool =
+ -- system__secondary_stack__rs_pool][procedure_to_call =
+ -- system__secondary_stack__rs_allocate];
+
+ -- Result : T renames Rxx.all;
+
+ elsif Back_End_Return_Slot
+ and then Is_By_Reference_Return_Object (Def_Id)
+ then
+ declare
+ Acc_Typ : Entity_Id;
+ Alloc_Obj_Decl : Node_Id;
+ Alloc_Obj_Id : Entity_Id;
+ Ptr_Type_Decl : Node_Id;
+
+ begin
+ -- Create an access type designating the function's
+ -- result subtype.
+
+ Acc_Typ := Make_Temporary (Loc, 'A');
+
+ Ptr_Type_Decl :=
+ Make_Full_Type_Declaration (Loc,
+ Defining_Identifier => Acc_Typ,
+ Type_Definition =>
+ Make_Access_To_Object_Definition (Loc,
+ All_Present => True,
+ Subtype_Indication =>
+ New_Occurrence_Of (Typ, Loc)));
+
+ Insert_Action (N, Ptr_Type_Decl, Suppress => All_Checks);
+
+ Set_Associated_Storage_Pool (Acc_Typ, RTE (RE_RS_Pool));
+
+ Alloc_Obj_Id := Make_Temporary (Loc, 'R');
+
+ Alloc_Obj_Decl :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Alloc_Obj_Id,
+ Constant_Present => True,
+ Object_Definition =>
+ New_Occurrence_Of (Acc_Typ, Loc),
+ Expression => Make_Allocator_For_Return (Expr_Q));
+
+ Insert_Action (N, Alloc_Obj_Decl, Suppress => All_Checks);
+
+ -- Initialize the object now that it has got its final subtype,
+ -- but before rewriting it as a renaming.
+
+ Initialize_Return_Object
+ (Tag_Assign, Adj_Call, Expr_Q, Empty, Init_After);
+
+ -- Replace the return object declaration with a renaming of a
+ -- dereference of the access value designating the return object.
+
+ Expr_Q :=
+ Make_Explicit_Dereference (Loc,
+ Prefix => New_Occurrence_Of (Alloc_Obj_Id, Loc));
Set_Etype (Expr_Q, Etype (Def_Id));
Rewrite_As_Renaming := True;
diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb
index 0a104cd..a8980a6 100644
--- a/gcc/ada/exp_ch4.adb
+++ b/gcc/ada/exp_ch4.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Aspects; use Aspects;
with Atree; use Atree;
with Checks; use Checks;
@@ -33,7 +34,6 @@ with Einfo.Utils; use Einfo.Utils;
with Elists; use Elists;
with Errout; use Errout;
with Exp_Aggr; use Exp_Aggr;
-with Exp_Atag; use Exp_Atag;
with Exp_Ch3; use Exp_Ch3;
with Exp_Ch6; use Exp_Ch6;
with Exp_Ch7; use Exp_Ch7;
@@ -560,219 +560,6 @@ package body Exp_Ch4 is
PtrT : constant Entity_Id := Etype (N);
DesigT : constant Entity_Id := Designated_Type (PtrT);
- procedure Apply_Accessibility_Check
- (Ref : Node_Id;
- Built_In_Place : Boolean := False);
- -- Ada 2005 (AI-344): For an allocator with a class-wide designated
- -- type, generate an accessibility check to verify that the level of the
- -- type of the created object is not deeper than the level of the access
- -- type. If the type of the qualified expression is class-wide, then
- -- always generate the check (except in the case where it is known to be
- -- unnecessary, see comment below). Otherwise, only generate the check
- -- if the level of the qualified expression type is statically deeper
- -- than the access type.
- --
- -- Although the static accessibility will generally have been performed
- -- as a legality check, it won't have been done in cases where the
- -- allocator appears in generic body, so a run-time check is needed in
- -- general. One special case is when the access type is declared in the
- -- same scope as the class-wide allocator, in which case the check can
- -- never fail, so it need not be generated.
- --
- -- As an open issue, there seem to be cases where the static level
- -- associated with the class-wide object's underlying type is not
- -- sufficient to perform the proper accessibility check, such as for
- -- allocators in nested subprograms or accept statements initialized by
- -- class-wide formals when the actual originates outside at a deeper
- -- static level. The nested subprogram case might require passing
- -- accessibility levels along with class-wide parameters, and the task
- -- case seems to be an actual gap in the language rules that needs to
- -- be fixed by the ARG. ???
-
- -------------------------------
- -- Apply_Accessibility_Check --
- -------------------------------
-
- procedure Apply_Accessibility_Check
- (Ref : Node_Id;
- Built_In_Place : Boolean := False)
- is
- Pool_Id : constant Entity_Id := Associated_Storage_Pool (PtrT);
- Cond : Node_Id;
- Fin_Call : Node_Id;
- Free_Stmt : Node_Id;
- Obj_Ref : Node_Id;
- Stmts : List_Id;
-
- begin
- if Ada_Version >= Ada_2005
- and then Is_Class_Wide_Type (DesigT)
- and then Tagged_Type_Expansion
- and then not Scope_Suppress.Suppress (Accessibility_Check)
- and then not No_Dynamic_Accessibility_Checks_Enabled (Ref)
- and then
- (Type_Access_Level (Etype (Exp)) > Type_Access_Level (PtrT)
- or else
- (Is_Class_Wide_Type (Etype (Exp))
- and then Scope (PtrT) /= Current_Scope))
- then
- -- If the allocator was built in place, Ref is already a reference
- -- to the access object initialized to the result of the allocator
- -- (see Exp_Ch6.Make_Build_In_Place_Call_In_Allocator). We call
- -- Remove_Side_Effects for cases where the build-in-place call may
- -- still be the prefix of the reference (to avoid generating
- -- duplicate calls). Otherwise, it is the entity associated with
- -- the object containing the address of the allocated object.
-
- if Built_In_Place then
- Remove_Side_Effects (Ref);
- Obj_Ref := New_Copy_Tree (Ref);
- else
- Obj_Ref := New_Occurrence_Of (Ref, Loc);
- end if;
-
- -- For access to interface types we must generate code to displace
- -- the pointer to the base of the object since the subsequent code
- -- references components located in the TSD of the object (which
- -- is associated with the primary dispatch table --see a-tags.ads)
- -- and also generates code invoking Free, which requires also a
- -- reference to the base of the unallocated object.
-
- if Is_Interface (DesigT) and then Tagged_Type_Expansion then
- Obj_Ref :=
- Unchecked_Convert_To (Etype (Obj_Ref),
- Make_Function_Call (Loc,
- Name =>
- New_Occurrence_Of (RTE (RE_Base_Address), Loc),
- Parameter_Associations => New_List (
- Unchecked_Convert_To (RTE (RE_Address),
- New_Copy_Tree (Obj_Ref)))));
- end if;
-
- -- Step 1: Create the object clean up code
-
- Stmts := New_List;
-
- -- Deallocate the object if the accessibility check fails. This
- -- is done only on targets or profiles that support deallocation.
-
- -- Free (Obj_Ref);
-
- if RTE_Available (RE_Free) then
- Free_Stmt := Make_Free_Statement (Loc, New_Copy_Tree (Obj_Ref));
- Set_Storage_Pool (Free_Stmt, Pool_Id);
-
- Append_To (Stmts, Free_Stmt);
-
- -- The target or profile cannot deallocate objects
-
- else
- Free_Stmt := Empty;
- end if;
-
- -- Finalize the object if applicable. Generate:
-
- -- [Deep_]Finalize (Obj_Ref.all);
-
- if Needs_Finalization (DesigT)
- and then not No_Heap_Finalization (PtrT)
- then
- Fin_Call :=
- Make_Final_Call
- (Obj_Ref =>
- Make_Explicit_Dereference (Loc, New_Copy (Obj_Ref)),
- Typ => DesigT);
-
- -- Guard against a missing [Deep_]Finalize when the designated
- -- type was not properly frozen.
-
- if No (Fin_Call) then
- Fin_Call := Make_Null_Statement (Loc);
- end if;
-
- -- When the target or profile supports deallocation, wrap the
- -- finalization call in a block to ensure proper deallocation
- -- even if finalization fails. Generate:
-
- -- begin
- -- <Fin_Call>
- -- exception
- -- when others =>
- -- <Free_Stmt>
- -- raise;
- -- end;
-
- if Present (Free_Stmt) then
- Fin_Call :=
- Make_Block_Statement (Loc,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Fin_Call),
-
- Exception_Handlers => New_List (
- Make_Exception_Handler (Loc,
- Exception_Choices => New_List (
- Make_Others_Choice (Loc)),
- Statements => New_List (
- New_Copy_Tree (Free_Stmt),
- Make_Raise_Statement (Loc))))));
- end if;
-
- Prepend_To (Stmts, Fin_Call);
- end if;
-
- -- Signal the accessibility failure through a Program_Error
-
- Append_To (Stmts,
- Make_Raise_Program_Error (Loc,
- Reason => PE_Accessibility_Check_Failed));
-
- -- Step 2: Create the accessibility comparison
-
- -- Generate:
- -- Ref'Tag
-
- Obj_Ref :=
- Make_Attribute_Reference (Loc,
- Prefix => Obj_Ref,
- Attribute_Name => Name_Tag);
-
- -- For tagged types, determine the accessibility level by looking
- -- at the type specific data of the dispatch table. Generate:
-
- -- Type_Specific_Data (Address (Ref'Tag)).Access_Level
-
- if Tagged_Type_Expansion then
- Cond := Build_Get_Access_Level (Loc, Obj_Ref);
-
- -- Use a runtime call to determine the accessibility level when
- -- compiling on virtual machine targets. Generate:
-
- -- Get_Access_Level (Ref'Tag)
-
- else
- Cond :=
- Make_Function_Call (Loc,
- Name =>
- New_Occurrence_Of (RTE (RE_Get_Access_Level), Loc),
- Parameter_Associations => New_List (Obj_Ref));
- end if;
-
- Cond :=
- Make_Op_Gt (Loc,
- Left_Opnd => Cond,
- Right_Opnd => Accessibility_Level (N, Dynamic_Level));
-
- -- Due to the complexity and side effects of the check, utilize an
- -- if statement instead of the regular Program_Error circuitry.
-
- Insert_Action (N,
- Make_Implicit_If_Statement (N,
- Condition => Cond,
- Then_Statements => Stmts));
- end if;
- end Apply_Accessibility_Check;
-
-- Local variables
Indic : constant Node_Id := Subtype_Mark (Expression (N));
@@ -884,7 +671,8 @@ package body Exp_Ch4 is
if Is_Build_In_Place_Function_Call (Exp) then
Make_Build_In_Place_Call_In_Allocator (N, Exp);
- Apply_Accessibility_Check (N, Built_In_Place => True);
+ Apply_Accessibility_Check_For_Allocator
+ (N, Exp, N, Built_In_Place => True);
return;
-- Ada 2005 (AI-318-02): Specialization of the previous case for
@@ -896,7 +684,8 @@ package body Exp_Ch4 is
elsif Present (Unqual_BIP_Iface_Function_Call (Exp)) then
Make_Build_In_Place_Iface_Call_In_Allocator (N, Exp);
- Apply_Accessibility_Check (N, Built_In_Place => True);
+ Apply_Accessibility_Check_For_Allocator
+ (N, Exp, N, Built_In_Place => True);
return;
end if;
@@ -1109,6 +898,11 @@ package body Exp_Ch4 is
(Directly_Designated_Type (Etype (N))));
null;
+ -- Likewise if the allocator is made for a special return object
+
+ elsif For_Special_Return_Object (N) then
+ null;
+
elsif Is_Tagged_Type (T) and then not Is_Class_Wide_Type (T) then
TagT := T;
TagR :=
@@ -1157,19 +951,18 @@ package body Exp_Ch4 is
-- Adjust procedure, and the object is built in place. In Ada 95, the
-- object can be limited but not inherently limited if this allocator
-- came from a return statement (we're allocating the result on the
- -- secondary stack). In that case, the object will be moved, so we do
- -- want to Adjust. However, if it's a nonlimited build-in-place
- -- function call, Adjust is not wanted.
- --
- -- Needs_Finalization (DesigT) can differ from Needs_Finalization (T)
+ -- secondary stack); in that case, the object will be moved, so we do
+ -- want to Adjust. But the call is always skipped if the allocator is
+ -- made for a special return object because it's generated elsewhere.
+
+ -- Needs_Finalization (DesigT) may differ from Needs_Finalization (T)
-- if one of the two types is class-wide, and the other is not.
if Needs_Finalization (DesigT)
and then Needs_Finalization (T)
and then not Aggr_In_Place
and then not Is_Limited_View (T)
- and then not Alloc_For_BIP_Return (N)
- and then not Is_Build_In_Place_Function_Call (Expression (N))
+ and then not For_Special_Return_Object (N)
then
-- An unchecked conversion is needed in the classwide case because
-- the designated type can be an ancestor of the subtype mark of
@@ -1191,7 +984,7 @@ package body Exp_Ch4 is
-- Note: the accessibility check must be inserted after the call to
-- [Deep_]Adjust to ensure proper completion of the assignment.
- Apply_Accessibility_Check (Temp);
+ Apply_Accessibility_Check_For_Allocator (N, Exp, Temp);
Rewrite (N, New_Occurrence_Of (Temp, Loc));
Analyze_And_Resolve (N, PtrT);
@@ -2935,6 +2728,7 @@ package body Exp_Ch4 is
Len : Unat;
J : Nat;
Clen : Node_Id;
+ Decl : Node_Id;
Set : Boolean;
-- Start of processing for Expand_Concatenate
@@ -3461,10 +3255,32 @@ package body Exp_Ch4 is
Set_Is_Internal (Ent);
Set_Debug_Info_Needed (Ent);
+ -- If the bound is statically known to be out of range, we do not want
+ -- to abort, we want a warning and a constraint error at run time. Note
+ -- that we have arranged that the result will not be treated as a static
+ -- constant, so we won't get an illegality during the insertion. We also
+ -- enable all checks (in particular range checks) in case the bounds of
+ -- Subtyp_Ind are out of range.
+
+ Decl :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Ent,
+ Object_Definition => Subtyp_Ind);
+ Insert_Action (Cnode, Decl);
+
+ -- If the result of the concatenation appears as the initializing
+ -- expression of an object declaration, we can just rename the
+ -- result, rather than copying it.
+
+ Set_OK_To_Rename (Ent);
+
-- If we are concatenating strings and the current scope already uses
- -- the secondary stack, allocate the resulting string also on the
- -- secondary stack to avoid putting too much pressure on the primary
- -- stack.
+ -- the secondary stack, allocate the result also on the secondary stack
+ -- to avoid putting too much pressure on the primary stack.
+
+ -- We use an unconstrained allocation, i.e. we also allocate the bounds,
+ -- so that the result can be renamed in all contexts.
+
-- Don't do this if -gnatd.h is set, as this will break the wrapping of
-- Cnode in an Expression_With_Actions, see Expand_N_Op_Concat.
@@ -3474,84 +3290,77 @@ package body Exp_Ch4 is
and then not Debug_Flag_Dot_H
then
-- Generate:
- -- subtype Axx is ...;
- -- type Ayy is access Axx;
- -- Rxx : Ayy := new <subtype> [storage_pool = ss_pool];
- -- Sxx : <subtype> renames Rxx.all;
+ -- subtype Axx is String (<low-bound> .. <high-bound>)
+ -- type Ayy is access String;
+ -- Rxx : Ayy := new <Axx> [storage_pool = ss_pool];
+ -- Sxx : String renames Rxx.all;
declare
- Alloc : Node_Id;
ConstrT : constant Entity_Id := Make_Temporary (Loc, 'A');
Acc_Typ : constant Entity_Id := Make_Temporary (Loc, 'A');
+
+ Alloc : Node_Id;
+ Deref : Node_Id;
Temp : Entity_Id;
begin
- Insert_Action (Cnode,
+ Insert_Action (Decl,
Make_Subtype_Declaration (Loc,
Defining_Identifier => ConstrT,
Subtype_Indication => Subtyp_Ind),
Suppress => All_Checks);
- Freeze_Itype (ConstrT, Cnode);
- Insert_Action (Cnode,
+ Freeze_Itype (ConstrT, Decl);
+
+ Insert_Action (Decl,
Make_Full_Type_Declaration (Loc,
Defining_Identifier => Acc_Typ,
Type_Definition =>
Make_Access_To_Object_Definition (Loc,
- Subtype_Indication => New_Occurrence_Of (ConstrT, Loc))),
+ Subtype_Indication => New_Occurrence_Of (Atyp, Loc))),
Suppress => All_Checks);
+
+ Mutate_Ekind (Acc_Typ, E_Access_Type);
+ Set_Associated_Storage_Pool (Acc_Typ, RTE (RE_SS_Pool));
+
Alloc :=
Make_Allocator (Loc,
Expression => New_Occurrence_Of (ConstrT, Loc));
- -- Allocate on the secondary stack. This is currently done
- -- only for type String, which normally doesn't have default
- -- initialization, but we need to Set_No_Initialization in case
- -- of Initialize_Scalars or Normalize_Scalars; otherwise, the
- -- allocator will get transformed and will not use the secondary
- -- stack.
+ -- This is currently done only for type String, which normally
+ -- doesn't have default initialization, but we need to set the
+ -- No_Initialization flag in case of either Initialize_Scalars
+ -- or Normalize_Scalars.
- Set_Storage_Pool (Alloc, RTE (RE_SS_Pool));
- Set_Procedure_To_Call (Alloc, RTE (RE_SS_Allocate));
Set_No_Initialization (Alloc);
Temp := Make_Temporary (Loc, 'R', Alloc);
- Insert_Action (Cnode,
+ Insert_Action (Decl,
Make_Object_Declaration (Loc,
Defining_Identifier => Temp,
Object_Definition => New_Occurrence_Of (Acc_Typ, Loc),
Expression => Alloc),
Suppress => All_Checks);
- Insert_Action (Cnode,
+ Deref :=
+ Make_Explicit_Dereference (Loc,
+ Prefix => New_Occurrence_Of (Temp, Loc));
+ Set_Etype (Deref, Atyp);
+
+ Rewrite (Decl,
Make_Object_Renaming_Declaration (Loc,
Defining_Identifier => Ent,
- Subtype_Mark => New_Occurrence_Of (ConstrT, Loc),
- Name =>
- Make_Explicit_Dereference (Loc,
- Prefix => New_Occurrence_Of (Temp, Loc))),
- Suppress => All_Checks);
- end;
- else
- -- If the bound is statically known to be out of range, we do not
- -- want to abort, we want a warning and a runtime constraint error.
- -- Note that we have arranged that the result will not be treated as
- -- a static constant, so we won't get an illegality during this
- -- insertion.
- -- We also enable checks (in particular range checks) in case the
- -- bounds of Subtyp_Ind are out of range.
-
- Insert_Action (Cnode,
- Make_Object_Declaration (Loc,
- Defining_Identifier => Ent,
- Object_Definition => Subtyp_Ind));
- end if;
+ Subtype_Mark => New_Occurrence_Of (Atyp, Loc),
+ Name => Deref));
- -- If the result of the concatenation appears as the initializing
- -- expression of an object declaration, we can just rename the
- -- result, rather than copying it.
+ -- We do not analyze this renaming declaration because this would
+ -- change the subtype of Ent back to a constrained string.
- Set_OK_To_Rename (Ent);
+ Set_Etype (Ent, Atyp);
+ Set_Renamed_Object (Ent, Deref);
+ Set_Analyzed (Decl);
+ end;
+ end if;
-- Catch the static out of range case now
@@ -6665,15 +6474,15 @@ package body Exp_Ch4 is
Rop : constant Node_Id := Right_Opnd (N);
Static : constant Boolean := Is_OK_Static_Expression (N);
- procedure Substitute_Valid_Check;
+ procedure Substitute_Valid_Test;
-- Replaces node N by Lop'Valid. This is done when we have an explicit
-- test for the left operand being in range of its subtype.
- ----------------------------
- -- Substitute_Valid_Check --
- ----------------------------
+ ---------------------------
+ -- Substitute_Valid_Test --
+ ---------------------------
- procedure Substitute_Valid_Check is
+ procedure Substitute_Valid_Test is
function Is_OK_Object_Reference (Nod : Node_Id) return Boolean;
-- Determine whether arbitrary node Nod denotes a source object that
-- may safely act as prefix of attribute 'Valid.
@@ -6713,7 +6522,7 @@ package body Exp_Ch4 is
return False;
end Is_OK_Object_Reference;
- -- Start of processing for Substitute_Valid_Check
+ -- Start of processing for Substitute_Valid_Test
begin
Rewrite (N,
@@ -6737,7 +6546,7 @@ package body Exp_Ch4 is
Error_Msg_N -- CODEFIX
("\??use ''Valid attribute instead", N);
end if;
- end Substitute_Valid_Check;
+ end Substitute_Valid_Test;
-- Local variables
@@ -6790,7 +6599,7 @@ package body Exp_Ch4 is
-- eliminates the cases where MINIMIZED/ELIMINATED mode overflow
-- checks have changed the type of the left operand.
- and then Nkind (Rop) in N_Has_Entity
+ and then Is_Entity_Name (Rop)
and then Ltyp = Entity (Rop)
-- Skip this for predicated types, where such expressions are a
@@ -6798,7 +6607,7 @@ package body Exp_Ch4 is
and then No (Predicate_Function (Ltyp))
then
- Substitute_Valid_Check;
+ Substitute_Valid_Test;
return;
end if;
@@ -6816,26 +6625,42 @@ package body Exp_Ch4 is
Lo : constant Node_Id := Low_Bound (Rop);
Hi : constant Node_Id := High_Bound (Rop);
- Lo_Orig : constant Node_Id := Original_Node (Lo);
- Hi_Orig : constant Node_Id := Original_Node (Hi);
-
- Lcheck : Compare_Result;
- Ucheck : Compare_Result;
+ Lo_Orig : constant Node_Id := Original_Node (Lo);
+ Hi_Orig : constant Node_Id := Original_Node (Hi);
+ Rop_Orig : constant Node_Id := Original_Node (Rop);
+
+ Comes_From_Simple_Range_In_Source : constant Boolean :=
+ Comes_From_Source (N)
+ and then not
+ (Is_Entity_Name (Rop_Orig)
+ and then Is_Type (Entity (Rop_Orig))
+ and then Present (Predicate_Function (Entity (Rop_Orig))));
+ -- This is true for a membership test present in the source with a
+ -- range or mark for a subtype that is not predicated. As already
+ -- explained a few lines above, we do not want to give warnings on
+ -- a test with a mark for a subtype that is predicated.
Warn : constant Boolean :=
Constant_Condition_Warnings
- and then Comes_From_Source (N)
+ and then Comes_From_Simple_Range_In_Source
and then not In_Instance;
-- This must be true for any of the optimization warnings, we
-- clearly want to give them only for source with the flag on. We
-- also skip these warnings in an instance since it may be the
-- case that different instantiations have different ranges.
+ Lcheck : Compare_Result;
+ Ucheck : Compare_Result;
+
begin
- -- If test is explicit x'First .. x'Last, replace by valid check
+ -- If test is explicit x'First .. x'Last, replace by 'Valid test
if Is_Scalar_Type (Ltyp)
+ -- Only relevant for source comparisons
+
+ and then Comes_From_Simple_Range_In_Source
+
-- And left operand is X'First where X matches left operand
-- type (this eliminates cases of type mismatch, including
-- the cases where ELIMINATED/MINIMIZED mode has changed the
@@ -6843,21 +6668,17 @@ package body Exp_Ch4 is
and then Nkind (Lo_Orig) = N_Attribute_Reference
and then Attribute_Name (Lo_Orig) = Name_First
- and then Nkind (Prefix (Lo_Orig)) in N_Has_Entity
+ and then Is_Entity_Name (Prefix (Lo_Orig))
and then Entity (Prefix (Lo_Orig)) = Ltyp
-- Same tests for right operand
and then Nkind (Hi_Orig) = N_Attribute_Reference
and then Attribute_Name (Hi_Orig) = Name_Last
- and then Nkind (Prefix (Hi_Orig)) in N_Has_Entity
+ and then Is_Entity_Name (Prefix (Hi_Orig))
and then Entity (Prefix (Hi_Orig)) = Ltyp
-
- -- Relevant only for source cases
-
- and then Comes_From_Source (N)
then
- Substitute_Valid_Check;
+ Substitute_Valid_Test;
goto Leave;
end if;
@@ -6866,7 +6687,7 @@ package body Exp_Ch4 is
-- for substituting a valid test. We only do this for discrete
-- types, since it won't arise in practice for float types.
- if Comes_From_Source (N)
+ if Comes_From_Simple_Range_In_Source
and then Is_Discrete_Type (Ltyp)
and then Compile_Time_Known_Value (Type_High_Bound (Ltyp))
and then Compile_Time_Known_Value (Type_Low_Bound (Ltyp))
@@ -6879,7 +6700,7 @@ package body Exp_Ch4 is
-- have a test in the generic that makes sense with some types
-- and not with other types.
- -- Similarly, do not rewrite membership as a validity check if
+ -- Similarly, do not rewrite membership as a 'Valid test if
-- within the predicate function for the type.
-- Finally, if the original bounds are type conversions, even
@@ -6899,7 +6720,7 @@ package body Exp_Ch4 is
null;
else
- Substitute_Valid_Check;
+ Substitute_Valid_Test;
goto Leave;
end if;
end if;
@@ -7034,12 +6855,12 @@ package body Exp_Ch4 is
goto Leave;
-- If type is scalar type, rewrite as x in t'First .. t'Last.
- -- This reason we do this is that the bounds may have the wrong
+ -- The reason we do this is that the bounds may have the wrong
-- type if they come from the original type definition. Also this
-- way we get all the processing above for an explicit range.
- -- Don't do this for predicated types, since in this case we
- -- want to check the predicate.
+ -- Don't do this for predicated types, since in this case we want
+ -- to generate the predicate check at the end of the function.
elsif Is_Scalar_Type (Typ) then
if No (Predicate_Function (Typ)) then
@@ -7054,6 +6875,7 @@ package body Exp_Ch4 is
Make_Attribute_Reference (Loc,
Attribute_Name => Name_Last,
Prefix => New_Occurrence_Of (Typ, Loc))));
+
Analyze_And_Resolve (N, Restyp);
end if;
@@ -7361,6 +7183,24 @@ package body Exp_Ch4 is
and then Current_Scope /= PFunc
and then Nkind (Rop) /= N_Range
then
+ -- First apply the transformation that was skipped above
+
+ if Is_Scalar_Type (Rtyp) then
+ Rewrite (Rop,
+ Make_Range (Loc,
+ Low_Bound =>
+ Make_Attribute_Reference (Loc,
+ Attribute_Name => Name_First,
+ Prefix => New_Occurrence_Of (Rtyp, Loc)),
+
+ High_Bound =>
+ Make_Attribute_Reference (Loc,
+ Attribute_Name => Name_Last,
+ Prefix => New_Occurrence_Of (Rtyp, Loc))));
+
+ Analyze_And_Resolve (N, Restyp);
+ end if;
+
if not In_Range_Check then
-- Indicate via Static_Mem parameter that this predicate
-- evaluation is for a membership test.
@@ -7380,10 +7220,6 @@ package body Exp_Ch4 is
Set_Analyzed (Left_Opnd (N));
Analyze_And_Resolve (N, Standard_Boolean, Suppress => All_Checks);
-
- -- All done, skip attempt at compile time determination of result
-
- return;
end if;
end Predicate_Check;
end Expand_N_In;
diff --git a/gcc/ada/exp_ch5.adb b/gcc/ada/exp_ch5.adb
index 3ea6cbb..d67f788 100644
--- a/gcc/ada/exp_ch5.adb
+++ b/gcc/ada/exp_ch5.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Aspects; use Aspects;
with Atree; use Atree;
with Checks; use Checks;
diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb
index 0fe980c..c026b63 100644
--- a/gcc/ada/exp_ch6.adb
+++ b/gcc/ada/exp_ch6.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Atree; use Atree;
with Aspects; use Aspects;
with Checks; use Checks;
@@ -191,16 +192,6 @@ package body Exp_Ch6 is
-- the activation Chain. Note: Master_Actual can be Empty, but only if
-- there are no tasks.
- procedure Apply_CW_Accessibility_Check (Exp : Node_Id; Func : Entity_Id);
- -- Ada 2005 (AI95-344): If the result type is class-wide, insert a check
- -- that the level of the return expression's underlying type is not deeper
- -- than the level of the master enclosing the function. Always generate the
- -- check when the type of the return expression is class-wide, when it's a
- -- type conversion, or when it's a formal parameter. Otherwise suppress the
- -- check in the case where the return expression has a specific type whose
- -- level is known not to be statically deeper than the result type of the
- -- function.
-
function Caller_Known_Size
(Func_Call : Node_Id;
Result_Subt : Entity_Id) return Boolean;
@@ -5139,10 +5130,15 @@ package body Exp_Ch6 is
end if;
-- Another optimization: if the returned value is used to initialize an
- -- object, and the secondary stack is not involved in the call, then no
- -- need to copy/readjust/finalize, we can just initialize it in place.
-
- if Nkind (Par) = N_Object_Declaration and then not Use_Sec_Stack then
+ -- object, then no need to copy/readjust/finalize, we can initialize it
+ -- in place. However, if the call returns on the secondary stack or this
+ -- is a special return object, then we need the expansion because we'll
+ -- be renaming the temporary as the (permanent) object.
+
+ if Nkind (Par) = N_Object_Declaration
+ and then not Use_Sec_Stack
+ and then not Is_Special_Return_Object (Defining_Entity (Par))
+ then
return;
end if;
@@ -5299,7 +5295,7 @@ package body Exp_Ch6 is
-- Assert that if F says "return R : T := G(...) do..."
-- then F and G are both b-i-p, or neither b-i-p.
- if Nkind (Exp) = N_Function_Call then
+ if Present (Exp) and then Nkind (Exp) = N_Function_Call then
pragma Assert (Ekind (Current_Subprogram) = E_Function);
pragma Assert
(Is_Build_In_Place_Function (Current_Subprogram) =
@@ -5307,16 +5303,6 @@ package body Exp_Ch6 is
null;
end if;
- -- Ada 2005 (AI95-344): If the result type is class-wide, then insert
- -- a check that the level of the return expression's underlying type
- -- is not deeper than the level of the master enclosing the function.
-
- -- AI12-043: The check is made immediately after the return object
- -- is created.
-
- if Present (Exp) and then Is_Class_Wide_Type (Ret_Typ) then
- Apply_CW_Accessibility_Check (Exp, Func_Id);
- end if;
else
Exp := Empty;
end if;
@@ -6528,19 +6514,6 @@ package body Exp_Ch6 is
-- need to reify the return object, so we can build it "in place", and
-- we need a block statement to hang finalization and tasking stuff.
- -- ??? In order to avoid disruption, we avoid translating to extended
- -- return except in the cases where we really need to (Ada 2005 for
- -- inherently limited). We might prefer to do this translation in all
- -- cases (except perhaps for the case of Ada 95 inherently limited),
- -- in order to fully exercise the Expand_N_Extended_Return_Statement
- -- code. This would also allow us to do the build-in-place optimization
- -- for efficiency even in cases where it is semantically not required.
-
- -- As before, we check the type of the return expression rather than the
- -- return type of the function, because the latter may be a limited
- -- class-wide interface type, which is not a limited type, even though
- -- the type of the expression may be.
-
pragma Assert
(Comes_From_Extended_Return_Statement (N)
or else not Is_Build_In_Place_Function_Call (Exp)
@@ -6681,15 +6654,18 @@ package body Exp_Ch6 is
-- type Ann is access R_Type;
-- for Ann'Storage_pool use rs_pool;
- -- Rnn : Ann := new Exp_Typ'(Exp);
+ -- Rnn : constant Ann := new Exp_Typ'(Exp);
-- return Rnn.all;
-- but optimize the case where the result is a function call that
-- also needs finalization. In this case the result can directly be
-- allocated on the return stack of the caller and no further
- -- processing is required.
+ -- processing is required. Likewise if this is a return object.
- if Present (Utyp)
+ if Comes_From_Extended_Return_Statement (N) then
+ null;
+
+ elsif Present (Utyp)
and then Needs_Finalization (Utyp)
and then not (Exp_Is_Function_Call
and then Needs_Finalization (Exp_Typ))
@@ -6732,6 +6708,7 @@ package body Exp_Ch6 is
Make_Object_Declaration (Loc,
Defining_Identifier => Temp,
+ Constant_Present => True,
Object_Definition => New_Occurrence_Of (Acc_Typ, Loc),
Expression => Alloc_Node)));
@@ -6752,11 +6729,16 @@ package body Exp_Ch6 is
Set_Enclosing_Sec_Stack_Return (N);
+ -- Nothing else to do for a return object
+
+ if Comes_From_Extended_Return_Statement (N) then
+ null;
+
-- Optimize the case where the result is a function call that also
-- returns on the secondary stack. In this case the result is already
-- on the secondary stack and no further processing is required.
- if Exp_Is_Function_Call
+ elsif Exp_Is_Function_Call
and then Needs_Secondary_Stack (Exp_Typ)
then
-- Remove side effects from the expression now so that other parts
@@ -6781,7 +6763,7 @@ package body Exp_Ch6 is
-- type Ann is access R_Type;
-- for Ann'Storage_pool use ss_pool;
- -- Rnn : Ann := new Exp_Typ'(Exp);
+ -- Rnn : constant Ann := new Exp_Typ'(Exp);
-- return Rnn.all;
-- And we do the same for class-wide types that are not potentially
@@ -6805,7 +6787,6 @@ package body Exp_Ch6 is
begin
Mutate_Ekind (Acc_Typ, E_Access_Type);
-
Set_Associated_Storage_Pool (Acc_Typ, RTE (RE_SS_Pool));
-- This is an allocator for the secondary stack, and it's fine
@@ -6835,6 +6816,7 @@ package body Exp_Ch6 is
Make_Object_Declaration (Loc,
Defining_Identifier => Temp,
+ Constant_Present => True,
Object_Definition => New_Occurrence_Of (Acc_Typ, Loc),
Expression => Alloc_Node)));
@@ -7570,9 +7552,10 @@ package body Exp_Ch6 is
Remove_Side_Effects (A);
- if Is_Controlling_Actual (A)
- and then Etype (F) /= Etype (A)
- then
+ -- Ensure matching types to avoid reporting spurious errors since
+ -- the called helper may have been built for a parent type.
+
+ if Etype (F) /= Etype (A) then
Append_To (Actuals,
Unchecked_Convert_To (Etype (F), New_Copy_Tree (A)));
else
@@ -7899,6 +7882,16 @@ package body Exp_Ch6 is
and then Is_Build_In_Place_Function (Return_Applies_To (Scope (E)));
end Is_Build_In_Place_Return_Object;
+ -----------------------------------
+ -- Is_By_Reference_Return_Object --
+ -----------------------------------
+
+ function Is_By_Reference_Return_Object (E : Entity_Id) return Boolean is
+ begin
+ return Is_Return_Object (E)
+ and then Is_By_Reference_Type (Etype (Return_Applies_To (Scope (E))));
+ end Is_By_Reference_Return_Object;
+
-----------------------
-- Is_Null_Procedure --
-----------------------
@@ -7958,6 +7951,28 @@ package body Exp_Ch6 is
end if;
end Is_Null_Procedure;
+ --------------------------------------
+ -- Is_Secondary_Stack_Return_Object --
+ --------------------------------------
+
+ function Is_Secondary_Stack_Return_Object (E : Entity_Id) return Boolean is
+ begin
+ return Is_Return_Object (E)
+ and then Needs_Secondary_Stack (Etype (Return_Applies_To (Scope (E))));
+ end Is_Secondary_Stack_Return_Object;
+
+ ------------------------------
+ -- Is_Special_Return_Object --
+ ------------------------------
+
+ function Is_Special_Return_Object (E : Entity_Id) return Boolean is
+ begin
+ return Is_Build_In_Place_Return_Object (E)
+ or else Is_Secondary_Stack_Return_Object (E)
+ or else (Back_End_Return_Slot
+ and then Is_By_Reference_Return_Object (E));
+ end Is_Special_Return_Object;
+
-------------------------------------------
-- Make_Build_In_Place_Call_In_Allocator --
-------------------------------------------
diff --git a/gcc/ada/exp_ch6.ads b/gcc/ada/exp_ch6.ads
index 66888c5..41ddf8d 100644
--- a/gcc/ada/exp_ch6.ads
+++ b/gcc/ada/exp_ch6.ads
@@ -99,6 +99,16 @@ package Exp_Ch6 is
-- Adds Extra_Actual as a named parameter association for the formal
-- Extra_Formal in Subprogram_Call.
+ procedure Apply_CW_Accessibility_Check (Exp : Node_Id; Func : Entity_Id);
+ -- Ada 2005 (AI95-344): If the result type is class-wide, insert a check
+ -- that the level of the return expression's underlying type is not deeper
+ -- than the level of the master enclosing the function. Always generate the
+ -- check when the type of the return expression is class-wide, when it's a
+ -- type conversion, or when it's a formal parameter. Otherwise suppress the
+ -- check in the case where the return expression has a specific type whose
+ -- level is known not to be statically deeper than the result type of the
+ -- function.
+
function BIP_Formal_Suffix (Kind : BIP_Formal_Kind) return String;
-- Ada 2005 (AI-318-02): Returns a string to be used as the suffix of names
-- for build-in-place formal parameters of the given kind.
@@ -158,13 +168,28 @@ package Exp_Ch6 is
-- True in >= Ada 2005 and must be False in Ada 95.
function Is_Build_In_Place_Return_Object (E : Entity_Id) return Boolean;
- -- Ada 2005 (AI-318-02): Return True is E is a return object of a function
+ -- Ada 2005 (AI-318-02): Return True if E is a return object of a function
-- that uses build-in-place protocols.
+ function Is_By_Reference_Return_Object (E : Entity_Id) return Boolean;
+ -- Return True if E is a return object of a function whose return type is
+ -- required to be passed by reference, as defined in (RM 6.2(4-9)).
+
function Is_Null_Procedure (Subp : Entity_Id) return Boolean;
-- Predicate to recognize stubbed procedures and null procedures, which
-- can be inlined unconditionally in all cases.
+ function Is_Secondary_Stack_Return_Object (E : Entity_Id) return Boolean;
+ -- Return True if E is a return object of a function whose return type is
+ -- returned on the secondary stack.
+
+ function Is_Special_Return_Object (E : Entity_Id) return Boolean;
+ -- Return True if E is the return object of a function and is handled in a
+ -- special way by the expander. In most cases, return objects are handled
+ -- like any other variables or constants but, in a few special cases, they
+ -- are further expanded into more elaborate constructs, whose common goal
+ -- is to elide the copy operation associated with the return.
+
procedure Make_Build_In_Place_Call_In_Allocator
(Allocator : Node_Id;
Function_Call : Node_Id);
diff --git a/gcc/ada/exp_ch9.adb b/gcc/ada/exp_ch9.adb
index 70ede15..7d76144 100644
--- a/gcc/ada/exp_ch9.adb
+++ b/gcc/ada/exp_ch9.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Atree; use Atree;
with Aspects; use Aspects;
with Checks; use Checks;
diff --git a/gcc/ada/exp_disp.adb b/gcc/ada/exp_disp.adb
index 41da7a2..e0ad27e 100644
--- a/gcc/ada/exp_disp.adb
+++ b/gcc/ada/exp_disp.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Atree; use Atree;
with Checks; use Checks;
with Debug; use Debug;
diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb
index bcfb39c..84b0c0e 100644
--- a/gcc/ada/exp_util.adb
+++ b/gcc/ada/exp_util.adb
@@ -9166,7 +9166,11 @@ package body Exp_Util is
return
Present (Expr)
and then Nkind (Unqual_Conv (Expr)) = N_Explicit_Dereference
- and then Nkind (Parent (Expr)) = N_Simple_Return_Statement;
+ and then (Nkind (Parent (Expr)) = N_Simple_Return_Statement
+ or else
+ (Nkind (Parent (Expr)) = N_Object_Renaming_Declaration
+ and then
+ Is_Return_Object (Defining_Entity (Parent (Expr)))));
end Is_Related_To_Func_Return;
--------------------------------
diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in
index 45a4168..2acd195 100644
--- a/gcc/ada/gcc-interface/Make-lang.in
+++ b/gcc/ada/gcc-interface/Make-lang.in
@@ -399,6 +399,7 @@ GNAT_ADA_OBJS = \
ada/sem_ch12.o \
ada/sem_ch13.o \
ada/sem_ch2.o \
+ ada/accessibility.o \
ada/sem_ch3.o \
ada/sem_ch4.o \
ada/sem_ch5.o \
diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc
index b9d7c01..59332f9 100644
--- a/gcc/ada/gcc-interface/trans.cc
+++ b/gcc/ada/gcc-interface/trans.cc
@@ -4400,6 +4400,11 @@ get_storage_model_access (Node_Id gnat_node, Entity_Id *gnat_smo)
return;
}
+ /* Now strip any type conversion from GNAT_NODE. */
+ if (Nkind (gnat_node) == N_Type_Conversion
+ || Nkind (gnat_node) == N_Unchecked_Type_Conversion)
+ gnat_node = Expression (gnat_node);
+
while (node_is_component (gnat_node))
gnat_node = Prefix (gnat_node);
@@ -8468,9 +8473,10 @@ gnat_to_gnu (Node_Id gnat_node)
declaration, return the result unmodified because we want to use the
return slot optimization in this case.
- 5. If this is a reference to an unconstrained array which is used as the
- prefix of an attribute reference that requires an lvalue, return the
- result unmodified because we want to return the original bounds.
+ 5. If this is a reference to an unconstrained array which is used either
+ as the prefix of an attribute reference that requires an lvalue or in
+ a return statement, then return the result unmodified because we want
+ to return the original bounds.
6. Finally, if the type of the result is already correct. */
@@ -8534,8 +8540,9 @@ gnat_to_gnu (Node_Id gnat_node)
else if (TREE_CODE (TREE_TYPE (gnu_result)) == UNCONSTRAINED_ARRAY_TYPE
&& Present (Parent (gnat_node))
- && Nkind (Parent (gnat_node)) == N_Attribute_Reference
- && lvalue_required_for_attribute_p (Parent (gnat_node)))
+ && ((Nkind (Parent (gnat_node)) == N_Attribute_Reference
+ && lvalue_required_for_attribute_p (Parent (gnat_node)))
+ || Nkind (Parent (gnat_node)) == N_Simple_Return_Statement))
;
else if (TREE_TYPE (gnu_result) != gnu_result_type)
diff --git a/gcc/ada/gen_il-fields.ads b/gcc/ada/gen_il-fields.ads
index 83c7180..bc424ab 100644
--- a/gcc/ada/gen_il-fields.ads
+++ b/gcc/ada/gen_il-fields.ads
@@ -69,7 +69,6 @@ package Gen_IL.Fields is
Address_Warning_Posted,
Aggregate_Bounds,
Aliased_Present,
- Alloc_For_BIP_Return,
All_Others,
All_Present,
Alternatives,
@@ -98,6 +97,7 @@ package Gen_IL.Fields is
Cleanup_Actions,
Comes_From_Check_Or_Contract,
Comes_From_Extended_Return_Statement,
+ Comes_From_Iterator,
Compile_Time_Known_Aggregate,
Component_Associations,
Component_Clauses,
@@ -188,6 +188,7 @@ package Gen_IL.Fields is
Float_Truncate,
Formal_Type_Definition,
Forwards_OK,
+ For_Special_Return_Object,
From_Aspect_Specification,
From_At_Mod,
From_Conditional_Expression,
diff --git a/gcc/ada/gen_il-gen-gen_nodes.adb b/gcc/ada/gen_il-gen-gen_nodes.adb
index 556326a..ec0eba7 100644
--- a/gcc/ada/gen_il-gen-gen_nodes.adb
+++ b/gcc/ada/gen_il-gen-gen_nodes.adb
@@ -494,7 +494,7 @@ begin -- Gen_IL.Gen.Gen_Nodes
(Sy (Expression, Node_Id, Default_Empty),
Sy (Subpool_Handle_Name, Node_Id, Default_Empty),
Sy (Null_Exclusion_Present, Flag, Default_False),
- Sm (Alloc_For_BIP_Return, Flag),
+ Sm (For_Special_Return_Object, Flag),
Sm (Do_Storage_Check, Flag),
Sm (Is_Dynamic_Coextension, Flag),
Sm (Is_Static_Coextension, Flag),
@@ -906,6 +906,7 @@ begin -- Gen_IL.Gen.Gen_Nodes
Sy (Subtype_Mark, Node_Id, Default_Empty),
Sy (Access_Definition, Node_Id, Default_Empty),
Sy (Name, Node_Id, Default_Empty),
+ Sm (Comes_From_Iterator, Flag),
Sm (Corresponding_Generic_Association, Node_Id)));
Cc (N_Package_Renaming_Declaration, N_Renaming_Declaration,
diff --git a/gcc/ada/gen_il-internals.adb b/gcc/ada/gen_il-internals.adb
index cec5b94..09fe99f 100644
--- a/gcc/ada/gen_il-internals.adb
+++ b/gcc/ada/gen_il-internals.adb
@@ -257,8 +257,6 @@ package body Gen_IL.Internals is
-- Special cases for the same reason as in the above Image
-- function for Opt_Type_Enum.
- when Alloc_For_BIP_Return =>
- return "Alloc_For_BIP_Return";
when Assignment_OK =>
return "Assignment_OK";
when Backwards_OK =>
diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi
index cc18673..ed763f9 100644
--- a/gcc/ada/gnat_rm.texi
+++ b/gcc/ada/gnat_rm.texi
@@ -19,7 +19,7 @@
@copying
@quotation
-GNAT Reference Manual , Nov 18, 2022
+GNAT Reference Manual , Dec 01, 2022
AdaCore
@@ -690,7 +690,7 @@ The GNAT Library
* Ada.Characters.Latin_9 (a-chlat9.ads): Ada Characters Latin_9 a-chlat9 ads.
* Ada.Characters.Wide_Latin_1 (a-cwila1.ads): Ada Characters Wide_Latin_1 a-cwila1 ads.
-* Ada.Characters.Wide_Latin_9 (a-cwila1.ads): Ada Characters Wide_Latin_9 a-cwila1 ads.
+* Ada.Characters.Wide_Latin_9 (a-cwila9.ads): Ada Characters Wide_Latin_9 a-cwila9 ads.
* Ada.Characters.Wide_Wide_Latin_1 (a-chzla1.ads): Ada Characters Wide_Wide_Latin_1 a-chzla1 ads.
* Ada.Characters.Wide_Wide_Latin_9 (a-chzla9.ads): Ada Characters Wide_Wide_Latin_9 a-chzla9 ads.
* Ada.Containers.Bounded_Holders (a-coboho.ads): Ada Containers Bounded_Holders a-coboho ads.
@@ -809,8 +809,8 @@ The GNAT Library
* GNAT.Threads (g-thread.ads): GNAT Threads g-thread ads.
* GNAT.Traceback (g-traceb.ads): GNAT Traceback g-traceb ads.
* GNAT.Traceback.Symbolic (g-trasym.ads): GNAT Traceback Symbolic g-trasym ads.
-* GNAT.UTF_32 (g-table.ads): GNAT UTF_32 g-table ads.
-* GNAT.Wide_Spelling_Checker (g-u3spch.ads): GNAT Wide_Spelling_Checker g-u3spch ads.
+* GNAT.UTF_32 (g-utf_32.ads): GNAT UTF_32 g-utf_32 ads.
+* GNAT.UTF_32_Spelling_Checker (g-u3spch.ads): GNAT UTF_32_Spelling_Checker g-u3spch ads.
* GNAT.Wide_Spelling_Checker (g-wispch.ads): GNAT Wide_Spelling_Checker g-wispch ads.
* GNAT.Wide_String_Split (g-wistsp.ads): GNAT Wide_String_Split g-wistsp ads.
* GNAT.Wide_Wide_Spelling_Checker (g-zspche.ads): GNAT Wide_Wide_Spelling_Checker g-zspche ads.
@@ -9177,7 +9177,7 @@ also be used as a configuration pragma.
The fourth form, with an @code{On|Off} parameter and a string, is used to
control individual messages, based on their text. The string argument
is a pattern that is used to match against the text of individual
-warning messages (not including the initial “warning: “ tag).
+warning messages (not including the initial “warning: ” tag).
The pattern may contain asterisks, which match zero or more characters in
the message. For example, you can use
@@ -23105,7 +23105,7 @@ of GNAT, and will generate a warning message.
@menu
* Ada.Characters.Latin_9 (a-chlat9.ads): Ada Characters Latin_9 a-chlat9 ads.
* Ada.Characters.Wide_Latin_1 (a-cwila1.ads): Ada Characters Wide_Latin_1 a-cwila1 ads.
-* Ada.Characters.Wide_Latin_9 (a-cwila1.ads): Ada Characters Wide_Latin_9 a-cwila1 ads.
+* Ada.Characters.Wide_Latin_9 (a-cwila9.ads): Ada Characters Wide_Latin_9 a-cwila9 ads.
* Ada.Characters.Wide_Wide_Latin_1 (a-chzla1.ads): Ada Characters Wide_Wide_Latin_1 a-chzla1 ads.
* Ada.Characters.Wide_Wide_Latin_9 (a-chzla9.ads): Ada Characters Wide_Wide_Latin_9 a-chzla9 ads.
* Ada.Containers.Bounded_Holders (a-coboho.ads): Ada Containers Bounded_Holders a-coboho ads.
@@ -23224,8 +23224,8 @@ of GNAT, and will generate a warning message.
* GNAT.Threads (g-thread.ads): GNAT Threads g-thread ads.
* GNAT.Traceback (g-traceb.ads): GNAT Traceback g-traceb ads.
* GNAT.Traceback.Symbolic (g-trasym.ads): GNAT Traceback Symbolic g-trasym ads.
-* GNAT.UTF_32 (g-table.ads): GNAT UTF_32 g-table ads.
-* GNAT.Wide_Spelling_Checker (g-u3spch.ads): GNAT Wide_Spelling_Checker g-u3spch ads.
+* GNAT.UTF_32 (g-utf_32.ads): GNAT UTF_32 g-utf_32 ads.
+* GNAT.UTF_32_Spelling_Checker (g-u3spch.ads): GNAT UTF_32_Spelling_Checker g-u3spch ads.
* GNAT.Wide_Spelling_Checker (g-wispch.ads): GNAT Wide_Spelling_Checker g-wispch ads.
* GNAT.Wide_String_Split (g-wistsp.ads): GNAT Wide_String_Split g-wistsp ads.
* GNAT.Wide_Wide_Spelling_Checker (g-zspche.ads): GNAT Wide_Wide_Spelling_Checker g-zspche ads.
@@ -23266,12 +23266,12 @@ of GNAT, and will generate a warning message.
This child of @code{Ada.Characters}
provides a set of definitions corresponding to those in the
RM-defined package @code{Ada.Characters.Latin_1} but with the
-few modifications required for @code{Latin-9}
+few modifications required for @code{Latin-9}.
The provision of such a package
is specifically authorized by the Ada Reference Manual
(RM A.3.3(27)).
-@node Ada Characters Wide_Latin_1 a-cwila1 ads,Ada Characters Wide_Latin_9 a-cwila1 ads,Ada Characters Latin_9 a-chlat9 ads,The GNAT Library
+@node Ada Characters Wide_Latin_1 a-cwila1 ads,Ada Characters Wide_Latin_9 a-cwila9 ads,Ada Characters Latin_9 a-chlat9 ads,The GNAT Library
@anchor{gnat_rm/the_gnat_library ada-characters-wide-latin-1-a-cwila1-ads}@anchor{2d9}@anchor{gnat_rm/the_gnat_library id3}@anchor{2da}
@section @code{Ada.Characters.Wide_Latin_1} (@code{a-cwila1.ads})
@@ -23288,12 +23288,12 @@ instead of @code{Character}. The provision of such a package
is specifically authorized by the Ada Reference Manual
(RM A.3.3(27)).
-@node Ada Characters Wide_Latin_9 a-cwila1 ads,Ada Characters Wide_Wide_Latin_1 a-chzla1 ads,Ada Characters Wide_Latin_1 a-cwila1 ads,The GNAT Library
-@anchor{gnat_rm/the_gnat_library ada-characters-wide-latin-9-a-cwila1-ads}@anchor{2db}@anchor{gnat_rm/the_gnat_library id4}@anchor{2dc}
-@section @code{Ada.Characters.Wide_Latin_9} (@code{a-cwila1.ads})
+@node Ada Characters Wide_Latin_9 a-cwila9 ads,Ada Characters Wide_Wide_Latin_1 a-chzla1 ads,Ada Characters Wide_Latin_1 a-cwila1 ads,The GNAT Library
+@anchor{gnat_rm/the_gnat_library ada-characters-wide-latin-9-a-cwila9-ads}@anchor{2db}@anchor{gnat_rm/the_gnat_library id4}@anchor{2dc}
+@section @code{Ada.Characters.Wide_Latin_9} (@code{a-cwila9.ads})
-@geindex Ada.Characters.Wide_Latin_9 (a-cwila1.ads)
+@geindex Ada.Characters.Wide_Latin_9 (a-cwila9.ads)
@geindex Latin_9 constants for Wide_Character
@@ -23305,7 +23305,7 @@ instead of @code{Character}. The provision of such a package
is specifically authorized by the Ada Reference Manual
(RM A.3.3(27)).
-@node Ada Characters Wide_Wide_Latin_1 a-chzla1 ads,Ada Characters Wide_Wide_Latin_9 a-chzla9 ads,Ada Characters Wide_Latin_9 a-cwila1 ads,The GNAT Library
+@node Ada Characters Wide_Wide_Latin_1 a-chzla1 ads,Ada Characters Wide_Wide_Latin_9 a-chzla9 ads,Ada Characters Wide_Latin_9 a-cwila9 ads,The GNAT Library
@anchor{gnat_rm/the_gnat_library ada-characters-wide-wide-latin-1-a-chzla1-ads}@anchor{2dd}@anchor{gnat_rm/the_gnat_library id5}@anchor{2de}
@section @code{Ada.Characters.Wide_Wide_Latin_1} (@code{a-chzla1.ads})
@@ -23379,8 +23379,8 @@ where this concept makes sense.
This child of @code{Ada.Command_Line}
provides a mechanism for logically removing
arguments from the argument list. Once removed, an argument is not visible
-to further calls on the subprograms in @code{Ada.Command_Line} will not
-see the removed argument.
+to further calls to the subprograms in @code{Ada.Command_Line}. These calls
+will not see the removed argument.
@node Ada Command_Line Response_File a-clrefi ads,Ada Direct_IO C_Streams a-diocst ads,Ada Command_Line Remove a-colire ads,The GNAT Library
@anchor{gnat_rm/the_gnat_library ada-command-line-response-file-a-clrefi-ads}@anchor{2e7}@anchor{gnat_rm/the_gnat_library id10}@anchor{2e8}
@@ -24072,7 +24072,7 @@ obtaining information about exceptions provided by Ada 83 compilers.
@geindex Memory corruption debugging
-Provide a debugging storage pools that helps tracking memory corruption
+Provides a debugging storage pools that helps tracking memory corruption
problems.
See @code{The GNAT Debug_Pool Facility} section in the @cite{GNAT User’s Guide}.
@@ -24285,7 +24285,7 @@ a message from a subprogram in a pure package, since the
necessary types and subprograms are in @code{Ada.Exceptions}
which is not a pure unit. @code{GNAT.Exceptions} provides a
facility for getting around this limitation for a few
-predefined exceptions, and for example allow raising
+predefined exceptions, and for example allows raising
@code{Constraint_Error} with a message from a pure subprogram.
@node GNAT Expect g-expect ads,GNAT Expect TTY g-exptty ads,GNAT Exceptions g-except ads,The GNAT Library
@@ -24340,7 +24340,7 @@ in this package can be used to reestablish the required mode.
@geindex Formatted String
Provides support for C/C++ printf() formatted strings. The format is
-copied from the printf() routine and should therefore gives identical
+copied from the printf() routine and should therefore give identical
output. Some generic routines are provided to be able to use types
derived from Integer, Float or enumerations as values for the
formatted string.
@@ -24557,7 +24557,7 @@ Provides a generator of static minimal perfect hash functions. No
collisions occur and each item can be retrieved from the table in one
probe (perfect property). The hash table size corresponds to the exact
size of the key set and no larger (minimal property). The key set has to
-be know in advance (static property). The hash functions are also order
+be known in advance (static property). The hash functions are also order
preserving. If w2 is inserted after w1 in the generator, their
hashcode are in the same order. These hashing functions are very
convenient for use with realtime applications.
@@ -24642,7 +24642,7 @@ this interface usable for large files or socket streams.
@geindex Secondary Stack Info
-Provide the capability to query the high water mark of the current task’s
+Provides the capability to query the high water mark of the current task’s
secondary stack.
@node GNAT Semaphores g-semaph ads,GNAT Serial_Communications g-sercom ads,GNAT Secondary_Stack_Info g-sestin ads,The GNAT Library
@@ -24757,7 +24757,7 @@ targets.
A high level and portable interface to develop sockets based applications.
This package is based on the sockets thin binding found in
@code{GNAT.Sockets.Thin}. Currently @code{GNAT.Sockets} is implemented
-on all native GNAT ports and on VxWorks cross prots. It is not implemented for
+on all native GNAT ports and on VxWorks cross ports. It is not implemented for
the LynxOS cross port.
@node GNAT Source_Info g-souinf ads,GNAT Spelling_Checker g-speche ads,GNAT Sockets g-socket ads,The GNAT Library
@@ -25017,7 +25017,7 @@ environment which then accesses Ada code.
Provides a facility for obtaining non-symbolic traceback information, useful
in various debugging situations.
-@node GNAT Traceback Symbolic g-trasym ads,GNAT UTF_32 g-table ads,GNAT Traceback g-traceb ads,The GNAT Library
+@node GNAT Traceback Symbolic g-trasym ads,GNAT UTF_32 g-utf_32 ads,GNAT Traceback g-traceb ads,The GNAT Library
@anchor{gnat_rm/the_gnat_library gnat-traceback-symbolic-g-trasym-ads}@anchor{3c6}@anchor{gnat_rm/the_gnat_library id122}@anchor{3c7}
@section @code{GNAT.Traceback.Symbolic} (@code{g-trasym.ads})
@@ -25026,12 +25026,12 @@ in various debugging situations.
@geindex Trace back facilities
-@node GNAT UTF_32 g-table ads,GNAT Wide_Spelling_Checker g-u3spch ads,GNAT Traceback Symbolic g-trasym ads,The GNAT Library
-@anchor{gnat_rm/the_gnat_library gnat-utf-32-g-table-ads}@anchor{3c8}@anchor{gnat_rm/the_gnat_library id123}@anchor{3c9}
-@section @code{GNAT.UTF_32} (@code{g-table.ads})
+@node GNAT UTF_32 g-utf_32 ads,GNAT UTF_32_Spelling_Checker g-u3spch ads,GNAT Traceback Symbolic g-trasym ads,The GNAT Library
+@anchor{gnat_rm/the_gnat_library gnat-utf-32-g-utf-32-ads}@anchor{3c8}@anchor{gnat_rm/the_gnat_library id123}@anchor{3c9}
+@section @code{GNAT.UTF_32} (@code{g-utf_32.ads})
-@geindex GNAT.UTF_32 (g-table.ads)
+@geindex GNAT.UTF_32 (g-utf_32.ads)
@geindex Wide character codes
@@ -25045,12 +25045,12 @@ lexical rules for identifiers and strings, and also a
lower case to upper case fold routine corresponding to
the Ada 2005 rules for identifier equivalence.
-@node GNAT Wide_Spelling_Checker g-u3spch ads,GNAT Wide_Spelling_Checker g-wispch ads,GNAT UTF_32 g-table ads,The GNAT Library
-@anchor{gnat_rm/the_gnat_library gnat-wide-spelling-checker-g-u3spch-ads}@anchor{3ca}@anchor{gnat_rm/the_gnat_library id124}@anchor{3cb}
-@section @code{GNAT.Wide_Spelling_Checker} (@code{g-u3spch.ads})
+@node GNAT UTF_32_Spelling_Checker g-u3spch ads,GNAT Wide_Spelling_Checker g-wispch ads,GNAT UTF_32 g-utf_32 ads,The GNAT Library
+@anchor{gnat_rm/the_gnat_library gnat-utf-32-spelling-checker-g-u3spch-ads}@anchor{3ca}@anchor{gnat_rm/the_gnat_library id124}@anchor{3cb}
+@section @code{GNAT.UTF_32_Spelling_Checker} (@code{g-u3spch.ads})
-@geindex GNAT.Wide_Spelling_Checker (g-u3spch.ads)
+@geindex GNAT.UTF_32_Spelling_Checker (g-u3spch.ads)
@geindex Spell checking
@@ -25058,7 +25058,7 @@ Provides a function for determining whether one wide wide string is a plausible
near misspelling of another wide wide string, where the strings are represented
using the UTF_32_String type defined in System.Wch_Cnv.
-@node GNAT Wide_Spelling_Checker g-wispch ads,GNAT Wide_String_Split g-wistsp ads,GNAT Wide_Spelling_Checker g-u3spch ads,The GNAT Library
+@node GNAT Wide_Spelling_Checker g-wispch ads,GNAT Wide_String_Split g-wistsp ads,GNAT UTF_32_Spelling_Checker g-u3spch ads,The GNAT Library
@anchor{gnat_rm/the_gnat_library gnat-wide-spelling-checker-g-wispch-ads}@anchor{3cc}@anchor{gnat_rm/the_gnat_library id125}@anchor{3cd}
@section @code{GNAT.Wide_Spelling_Checker} (@code{g-wispch.ads})
diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi
index 5224a12..dfe44b0 100644
--- a/gcc/ada/gnat_ugn.texi
+++ b/gcc/ada/gnat_ugn.texi
@@ -19,7 +19,7 @@
@copying
@quotation
-GNAT User's Guide for Native Platforms , Nov 28, 2022
+GNAT User's Guide for Native Platforms , Dec 01, 2022
AdaCore
@@ -19200,13 +19200,9 @@ begin
P2;
end STB;
@end example
-@end quotation
-
-This program will output:
-
-@quotation
@example
+$ gnatmake stb -g -bargs -E -largs -no-pie
$ stb
raised CONSTRAINT_ERROR : stb.adb:12 range check failed
@@ -19350,7 +19346,7 @@ end STB;
@end example
@example
-$ gnatmake -g .\stb -bargs -E
+$ gnatmake -g stb -bargs -E
$ stb
0040149F in stb.p1 at stb.adb:8
@@ -19364,15 +19360,6 @@ $ stb
@end example
@end quotation
-In the above example the @code{.\} syntax in the @code{gnatmake} command
-is currently required by @code{addr2line} for files that are in
-the current working directory.
-Moreover, the exact sequence of linker options may vary from platform
-to platform.
-The above @code{-largs} section is for Windows platforms. By contrast,
-under Unix there is no need for the @code{-largs} section.
-Differences across platforms are due to details of linker implementation.
-
@subsubheading Tracebacks From Anywhere in a Program
diff --git a/gcc/ada/lib-xref.adb b/gcc/ada/lib-xref.adb
index e5dcc85..182ea2f 100644
--- a/gcc/ada/lib-xref.adb
+++ b/gcc/ada/lib-xref.adb
@@ -776,7 +776,7 @@ package body Lib.Xref is
Set_Referenced_As_LHS (E, False);
-- For OUT parameter not covered by the above cases, we simply
- -- regard it as a non-reference.
+ -- regard it as a reference.
else
Set_Referenced_As_Out_Parameter (E);
diff --git a/gcc/ada/libgnat/i-c.adb b/gcc/ada/libgnat/i-c.adb
index 4b50d18..2866021 100644
--- a/gcc/ada/libgnat/i-c.adb
+++ b/gcc/ada/libgnat/i-c.adb
@@ -186,7 +186,7 @@ is
(Item : char_array;
Trim_Nul : Boolean := True) return String
is
- Count : Natural;
+ Count : Natural := 0;
From : size_t;
begin
@@ -1177,7 +1177,7 @@ is
To : size_t;
begin
- if Target'Length < Item'Length then
+ if Target'Length < Item'Length + (if Append_Nul then 1 else 0) then
raise Constraint_Error;
else
@@ -1210,17 +1210,14 @@ is
Target'First + (Item'Length - 1))'Initialized);
if Append_Nul then
- if To > Target'Last then
- raise Constraint_Error;
- else
- Target (To) := char32_nul;
- Count := Item'Length + 1;
- end if;
-
+ Target (To) := char32_nul;
+ Count := Item'Length + 1;
else
Count := Item'Length;
end if;
end if;
end To_C;
+ pragma Annotate (CodePeer, False_Positive, "validity check",
+ "Count is only uninitialized on abnormal return.");
end Interfaces.C;
diff --git a/gcc/ada/sem_aggr.adb b/gcc/ada/sem_aggr.adb
index 3e978f9..433f1ac 100644
--- a/gcc/ada/sem_aggr.adb
+++ b/gcc/ada/sem_aggr.adb
@@ -3242,7 +3242,7 @@ package body Sem_Aggr is
end loop;
end;
- else
+ elsif Present (Assign_Indexed_Subp) then
-- Indexed Aggregate. Positional or indexed component
-- can be present, but not both. Choices must be static
-- values or ranges with static bounds.
diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb
index 4c76b93..7c76f0f 100644
--- a/gcc/ada/sem_attr.adb
+++ b/gcc/ada/sem_attr.adb
@@ -25,6 +25,7 @@
with Ada.Characters.Latin_1; use Ada.Characters.Latin_1;
+with Accessibility; use Accessibility;
with Aspects; use Aspects;
with Atree; use Atree;
with Casing; use Casing;
@@ -3430,7 +3431,34 @@ package body Sem_Attr is
Check_E0;
Address_Checks;
Check_Not_Incomplete_Type;
- Set_Etype (N, RTE (RE_Address));
+
+ -- If the prefix is a dereference of a value whose associated access
+ -- type has been specified with aspect Designated_Storage_Model, then
+ -- use the associated Storage_Model_Type's address type as the type
+ -- of the attribute. Otherwise we use System.Address as usual. This
+ -- isn't normally legit for a predefined attribute, but this is for
+ -- our own extension to addressing and currently requires extensions
+ -- to be enabled (such as with -gnatX0).
+
+ declare
+ Prefix_Obj : constant Node_Id := Get_Referenced_Object (P);
+ Addr_Type : Entity_Id := RTE (RE_Address);
+ begin
+ if Nkind (Prefix_Obj) = N_Explicit_Dereference then
+ declare
+ P_Type : constant Entity_Id := Etype (Prefix (Prefix_Obj));
+
+ use Storage_Model_Support;
+ begin
+ if Has_Designated_Storage_Model_Aspect (P_Type) then
+ Addr_Type := Storage_Model_Address_Type
+ (Storage_Model_Object (P_Type));
+ end if;
+ end;
+ end if;
+
+ Set_Etype (N, Addr_Type);
+ end;
------------------
-- Address_Size --
@@ -10909,72 +10937,12 @@ package body Sem_Attr is
It : Interp;
Nom_Subt : Entity_Id;
- procedure Accessibility_Message;
- -- Error, or warning within an instance, if the static accessibility
- -- rules of 3.10.2 are violated.
-
function Declared_Within_Generic_Unit
(Entity : Entity_Id;
Generic_Unit : Node_Id) return Boolean;
-- Returns True if Declared_Entity is declared within the declarative
-- region of Generic_Unit; otherwise returns False.
- function Prefix_With_Safe_Accessibility_Level return Boolean;
- -- Return True if the prefix does not have a value conversion of an
- -- array because a value conversion is like an aggregate with respect
- -- to determining accessibility level (RM 3.10.2); even if evaluation
- -- of a value conversion is guaranteed to not create a new object,
- -- accessibility rules are defined as if it might.
-
- ---------------------------
- -- Accessibility_Message --
- ---------------------------
-
- procedure Accessibility_Message is
- Indic : Node_Id := Parent (Parent (N));
-
- begin
- -- In an instance, this is a runtime check, but one we
- -- know will fail, so generate an appropriate warning.
-
- if In_Instance_Body then
- Error_Msg_Warn := SPARK_Mode /= On;
- Error_Msg_F
- ("non-local pointer cannot point to local object<<", P);
- Error_Msg_F ("\Program_Error [<<", P);
- Rewrite (N,
- Make_Raise_Program_Error (Loc,
- Reason => PE_Accessibility_Check_Failed));
- Set_Etype (N, Typ);
- return;
-
- else
- Error_Msg_F ("non-local pointer cannot point to local object", P);
-
- -- Check for case where we have a missing access definition
-
- if Is_Record_Type (Current_Scope)
- and then
- Nkind (Parent (N)) in N_Discriminant_Association
- | N_Index_Or_Discriminant_Constraint
- then
- Indic := Parent (Parent (N));
- while Present (Indic)
- and then Nkind (Indic) /= N_Subtype_Indication
- loop
- Indic := Parent (Indic);
- end loop;
-
- if Present (Indic) then
- Error_Msg_NE
- ("\use an access definition for" &
- " the access discriminant of&",
- N, Entity (Subtype_Mark (Indic)));
- end if;
- end if;
- end if;
- end Accessibility_Message;
-
----------------------------------
-- Declared_Within_Generic_Unit --
----------------------------------
@@ -11002,70 +10970,6 @@ package body Sem_Attr is
return False;
end Declared_Within_Generic_Unit;
- ------------------------------------------
- -- Prefix_With_Safe_Accessibility_Level --
- ------------------------------------------
-
- function Prefix_With_Safe_Accessibility_Level return Boolean is
- function Safe_Value_Conversions return Boolean;
- -- Return False if the prefix has a value conversion of an array type
-
- ----------------------------
- -- Safe_Value_Conversions --
- ----------------------------
-
- function Safe_Value_Conversions return Boolean is
- PP : Node_Id := P;
-
- begin
- loop
- if Nkind (PP) in N_Selected_Component | N_Indexed_Component then
- PP := Prefix (PP);
-
- elsif Comes_From_Source (PP)
- and then Nkind (PP) in N_Type_Conversion
- | N_Unchecked_Type_Conversion
- and then Is_Array_Type (Etype (PP))
- then
- return False;
-
- elsif Comes_From_Source (PP)
- and then Nkind (PP) = N_Qualified_Expression
- and then Is_Array_Type (Etype (PP))
- and then Nkind (Original_Node (Expression (PP))) in
- N_Aggregate | N_Extension_Aggregate
- then
- return False;
-
- else
- exit;
- end if;
- end loop;
-
- return True;
- end Safe_Value_Conversions;
-
- -- Start of processing for Prefix_With_Safe_Accessibility_Level
-
- begin
- -- No check required for unchecked and unrestricted access
-
- if Attr_Id = Attribute_Unchecked_Access
- or else Attr_Id = Attribute_Unrestricted_Access
- then
- return True;
-
- -- Check value conversions
-
- elsif Ekind (Btyp) = E_General_Access_Type
- and then not Safe_Value_Conversions
- then
- return False;
- end if;
-
- return True;
- end Prefix_With_Safe_Accessibility_Level;
-
-- Start of processing for Resolve_Attribute
begin
@@ -11751,7 +11655,7 @@ package body Sem_Attr is
Intval (Accessibility_Level (P, Dynamic_Level))
> Deepest_Type_Access_Level (Btyp)
then
- Accessibility_Message;
+ Accessibility_Message (N, Typ);
return;
end if;
end;
@@ -11777,7 +11681,7 @@ package body Sem_Attr is
and then Ekind (Btyp) = E_Access_Protected_Subprogram_Type
and then Attr_Id /= Attribute_Unrestricted_Access
then
- Accessibility_Message;
+ Accessibility_Message (N, Typ);
return;
-- AI05-0225: If the context is not an access to protected
@@ -11936,8 +11840,8 @@ package body Sem_Attr is
-- array type since a value conversion is like an aggregate with
-- respect to determining accessibility level (RM 3.10.2).
- if not Prefix_With_Safe_Accessibility_Level then
- Accessibility_Message;
+ if not Prefix_With_Safe_Accessibility_Level (N, Typ) then
+ Accessibility_Message (N, Typ);
return;
end if;
diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb
index a478274..618f935 100644
--- a/gcc/ada/sem_ch13.adb
+++ b/gcc/ada/sem_ch13.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Aspects; use Aspects;
with Atree; use Atree;
with Checks; use Checks;
@@ -15729,6 +15730,12 @@ package body Sem_Ch13 is
return;
end if;
+ elsif No (Add_Named_Subp)
+ and then No (Add_Unnamed_Subp)
+ and then No (Assign_Indexed_Subp)
+ then
+ Error_Msg_N ("incomplete specification for aggregate", N);
+
elsif Present (New_Indexed_Subp) /= Present (Assign_Indexed_Subp) then
Error_Msg_N ("incomplete specification for indexed aggregate", N);
end if;
diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb
index 61386e2..5334e48 100644
--- a/gcc/ada/sem_ch3.adb
+++ b/gcc/ada/sem_ch3.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Aspects; use Aspects;
with Atree; use Atree;
with Checks; use Checks;
@@ -3780,6 +3781,11 @@ package body Sem_Ch3 is
-- Obj_Decl carrying type Obj_Typ has explicit initialization. Emit
-- a compile-time warning if this is not the case.
+ procedure Check_Return_Subtype_Indication (Obj_Decl : Node_Id);
+ -- Check that the return subtype indication properly matches the result
+ -- subtype of the function in an extended return object declaration, as
+ -- required by RM 6.5(5.1/2-5.3/2).
+
function Count_Tasks (T : Entity_Id) return Uint;
-- This function is called when a non-generic library level object of a
-- task type is declared. Its function is to count the static number of
@@ -3953,6 +3959,134 @@ package body Sem_Ch3 is
Check_Component (Obj_Typ, Obj_Decl);
end Check_For_Null_Excluding_Components;
+ -------------------------------------
+ -- Check_Return_Subtype_Indication --
+ -------------------------------------
+
+ procedure Check_Return_Subtype_Indication (Obj_Decl : Node_Id) is
+ Obj_Id : constant Entity_Id := Defining_Identifier (Obj_Decl);
+ Obj_Typ : constant Entity_Id := Etype (Obj_Id);
+ Func_Id : constant Entity_Id := Return_Applies_To (Scope (Obj_Id));
+ R_Typ : constant Entity_Id := Etype (Func_Id);
+ Indic : constant Node_Id :=
+ Object_Definition (Original_Node (Obj_Decl));
+
+ procedure Error_No_Match (N : Node_Id);
+ -- Output error messages for case where types do not statically
+ -- match. N is the location for the messages.
+
+ --------------------
+ -- Error_No_Match --
+ --------------------
+
+ procedure Error_No_Match (N : Node_Id) is
+ begin
+ Error_Msg_N
+ ("subtype must statically match function result subtype", N);
+
+ if not Predicates_Match (Obj_Typ, R_Typ) then
+ Error_Msg_Node_2 := R_Typ;
+ Error_Msg_NE
+ ("\predicate of& does not match predicate of&",
+ N, Obj_Typ);
+ end if;
+ end Error_No_Match;
+
+ -- Start of processing for Check_Return_Subtype_Indication
+
+ begin
+ -- First, avoid cascaded errors
+
+ if Error_Posted (Obj_Decl) or else Error_Posted (Indic) then
+ return;
+ end if;
+
+ -- "return access T" case; check that the return statement also has
+ -- "access T", and that the subtypes statically match:
+ -- if this is an access to subprogram the signatures must match.
+
+ if Is_Anonymous_Access_Type (R_Typ) then
+ if Is_Anonymous_Access_Type (Obj_Typ) then
+ if Ekind (Designated_Type (Obj_Typ)) /= E_Subprogram_Type
+ then
+ if Base_Type (Designated_Type (Obj_Typ)) /=
+ Base_Type (Designated_Type (R_Typ))
+ or else not Subtypes_Statically_Match (Obj_Typ, R_Typ)
+ then
+ Error_No_Match (Subtype_Mark (Indic));
+ end if;
+
+ else
+ -- For two anonymous access to subprogram types, the types
+ -- themselves must be type conformant.
+
+ if not Conforming_Types
+ (Obj_Typ, R_Typ, Fully_Conformant)
+ then
+ Error_No_Match (Indic);
+ end if;
+ end if;
+
+ else
+ Error_Msg_N ("must use anonymous access type", Indic);
+ end if;
+
+ -- If the return object is of an anonymous access type, then report
+ -- an error if the function's result type is not also anonymous.
+
+ elsif Is_Anonymous_Access_Type (Obj_Typ) then
+ pragma Assert (not Is_Anonymous_Access_Type (R_Typ));
+ Error_Msg_N
+ ("anonymous access not allowed for function with named access "
+ & "result", Indic);
+
+ -- Subtype indication case: check that the return object's type is
+ -- covered by the result type, and that the subtypes statically match
+ -- when the result subtype is constrained. Also handle record types
+ -- with unknown discriminants for which we have built the underlying
+ -- record view. Coverage is needed to allow specific-type return
+ -- objects when the result type is class-wide (see AI05-32).
+
+ elsif Covers (Base_Type (R_Typ), Base_Type (Obj_Typ))
+ or else (Is_Underlying_Record_View (Base_Type (Obj_Typ))
+ and then
+ Covers
+ (Base_Type (R_Typ),
+ Underlying_Record_View (Base_Type (Obj_Typ))))
+ then
+ -- A null exclusion may be present on the return type, on the
+ -- function specification, on the object declaration or on the
+ -- subtype itself.
+
+ if Is_Access_Type (R_Typ)
+ and then
+ (Can_Never_Be_Null (R_Typ)
+ or else Null_Exclusion_Present (Parent (Func_Id))) /=
+ Can_Never_Be_Null (Obj_Typ)
+ then
+ Error_No_Match (Indic);
+ end if;
+
+ -- AI05-103: for elementary types, subtypes must statically match
+
+ if Is_Constrained (R_Typ) or else Is_Access_Type (R_Typ) then
+ if not Subtypes_Statically_Match (Obj_Typ, R_Typ) then
+ Error_No_Match (Indic);
+ end if;
+ end if;
+
+ -- All remaining cases are illegal
+
+ -- Note: previous versions of this subprogram allowed the return
+ -- value to be the ancestor of the return type if the return type
+ -- was a null extension. This was plainly incorrect.
+
+ else
+ Error_Msg_N
+ ("wrong type for return_subtype_indication", Indic);
+ end if;
+ end Check_Return_Subtype_Indication;
+
-----------------
-- Count_Tasks --
-----------------
@@ -5046,6 +5180,12 @@ package body Sem_Ch3 is
end if;
end if;
+ -- Check specific legality rules for a return object
+
+ if Is_Return_Object (Id) then
+ Check_Return_Subtype_Indication (N);
+ end if;
+
-- Some simple constant-propagation: if the expression is a constant
-- string initialized with a literal, share the literal. This avoids
-- a run-time copy.
diff --git a/gcc/ada/sem_ch4.adb b/gcc/ada/sem_ch4.adb
index b724fbe..da5aa5f 100644
--- a/gcc/ada/sem_ch4.adb
+++ b/gcc/ada/sem_ch4.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Aspects; use Aspects;
with Atree; use Atree;
with Debug; use Debug;
@@ -43,6 +44,7 @@ with Opt; use Opt;
with Output; use Output;
with Restrict; use Restrict;
with Rident; use Rident;
+with Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
with Sem_Case; use Sem_Case;
@@ -732,43 +734,16 @@ package body Sem_Ch4 is
end;
end if;
- -- Check for missing initialization. Skip this check if we already
- -- had errors on analyzing the allocator, since in that case these
- -- are probably cascaded errors.
+ -- Check for missing initialization. Skip this check if the allocator
+ -- is made for a special return object or if we already had errors on
+ -- analyzing the allocator since, in that case, these are very likely
+ -- cascaded errors.
if not Is_Definite_Subtype (Type_Id)
+ and then not For_Special_Return_Object (N)
and then Serious_Errors_Detected = Sav_Errs
then
- -- The build-in-place machinery may produce an allocator when
- -- the designated type is indefinite but the underlying type is
- -- not. In this case the unknown discriminants are meaningless
- -- and should not trigger error messages. Check the parent node
- -- because the allocator is marked as coming from source.
-
- if Present (Underlying_Type (Type_Id))
- and then Is_Definite_Subtype (Underlying_Type (Type_Id))
- and then not Comes_From_Source (Parent (N))
- then
- null;
-
- -- An unusual case arises when the parent of a derived type is
- -- a limited record extension with unknown discriminants, and
- -- its full view has no discriminants.
- --
- -- A more general fix might be to create the proper underlying
- -- type for such a derived type, but it is a record type with
- -- no private attributes, so this required extending the
- -- meaning of this attribute. ???
-
- elsif Ekind (Etype (Type_Id)) = E_Record_Type_With_Private
- and then Present (Underlying_Type (Etype (Type_Id)))
- and then
- not Has_Discriminants (Underlying_Type (Etype (Type_Id)))
- and then not Comes_From_Source (Parent (N))
- then
- null;
-
- elsif Is_Class_Wide_Type (Type_Id) then
+ if Is_Class_Wide_Type (Type_Id) then
Error_Msg_N
("initialization required in class-wide allocation", N);
@@ -841,6 +816,27 @@ package body Sem_Ch4 is
Error_Msg_N ("cannot allocate abstract object", E);
end if;
+ Set_Etype (N, Acc_Type);
+
+ -- If this is an allocator for the return stack, then no restriction may
+ -- be violated since it's just a low-level access to the primary stack.
+
+ if Nkind (Parent (N)) = N_Object_Declaration
+ and then Is_Entity_Name (Object_Definition (Parent (N)))
+ and then Is_Access_Type (Entity (Object_Definition (Parent (N))))
+ then
+ declare
+ Pool : constant Entity_Id :=
+ Associated_Storage_Pool
+ (Root_Type (Entity (Object_Definition (Parent (N)))));
+
+ begin
+ if Present (Pool) and then Is_RTE (Pool, RE_RS_Pool) then
+ goto Leave;
+ end if;
+ end;
+ end if;
+
if Has_Task (Designated_Type (Acc_Type)) then
Check_Restriction (No_Tasking, N);
Check_Restriction (Max_Tasks, N);
@@ -892,12 +888,11 @@ package body Sem_Ch4 is
end if;
end if;
- Set_Etype (N, Acc_Type);
-
if not Is_Library_Level_Entity (Acc_Type) then
Check_Restriction (No_Local_Allocators, N);
end if;
+ <<Leave>>
if Serious_Errors_Detected > Sav_Errs then
Set_Error_Posted (N);
Set_Etype (N, Any_Type);
diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb
index b54f270..344b3eb 100644
--- a/gcc/ada/sem_ch5.adb
+++ b/gcc/ada/sem_ch5.adb
@@ -307,7 +307,8 @@ package body Sem_Ch5 is
-- get the actual subtype (needed for the unconstrained case). If the
-- operand is the actual in an entry declaration, then within the
-- accept statement it is replaced with a local renaming, which may
- -- also have an actual subtype.
+ -- also have an actual subtype. Likewise for a return object that
+ -- lives on the secondary stack.
if Is_Entity_Name (Opnd)
and then (Ekind (Entity (Opnd)) in E_Out_Parameter
@@ -318,7 +319,8 @@ package body Sem_Ch5 is
and then Nkind (Parent (Entity (Opnd))) =
N_Object_Renaming_Declaration
and then Nkind (Parent (Parent (Entity (Opnd)))) =
- N_Accept_Statement))
+ N_Accept_Statement)
+ or else Is_Secondary_Stack_Return_Object (Entity (Opnd)))
then
Opnd_Type := Get_Actual_Subtype (Opnd);
@@ -2523,6 +2525,7 @@ package body Sem_Ch5 is
Subtype_Mark => New_Occurrence_Of (Typ, Loc),
Name =>
New_Copy_Tree (Iter_Name, New_Sloc => Loc));
+ Set_Comes_From_Iterator (Decl);
Insert_Actions (Parent (Parent (N)), New_List (Decl));
Rewrite (Name (N), New_Occurrence_Of (Id, Loc));
diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb
index cb982b3..f46ca46 100644
--- a/gcc/ada/sem_ch6.adb
+++ b/gcc/ada/sem_ch6.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Aspects; use Aspects;
with Atree; use Atree;
with Checks; use Checks;
@@ -745,14 +746,6 @@ package body Sem_Ch6 is
-- Ada 2022: Check that the return expression in a No_Return function
-- meets the conditions specified by RM 6.5.1(5.1/5).
- procedure Check_Return_Construct_Accessibility (Return_Stmt : Node_Id);
- -- Apply legality rule of 6.5 (5.9) to the access discriminants of an
- -- aggregate in a return statement.
-
- procedure Check_Return_Subtype_Indication (Obj_Decl : Node_Id);
- -- Check that the return_subtype_indication properly matches the result
- -- subtype of the function, as required by RM-6.5(5.1/2-5.3/2).
-
--------------------------------
-- Check_No_Return_Expression --
--------------------------------
@@ -781,645 +774,6 @@ package body Sem_Ch6 is
Return_Expr);
end Check_No_Return_Expression;
- ------------------------------------------
- -- Check_Return_Construct_Accessibility --
- ------------------------------------------
-
- procedure Check_Return_Construct_Accessibility (Return_Stmt : Node_Id) is
-
- function First_Selector (Assoc : Node_Id) return Node_Id;
- -- Obtain the first selector or choice from a given association
-
- function Is_Formal_Of_Current_Function
- (Assoc_Expr : Entity_Id) return Boolean;
- -- Predicate to test if a given expression associated with a
- -- discriminant is a formal parameter to the function in which the
- -- return construct we checking applies to.
-
- --------------------
- -- First_Selector --
- --------------------
-
- function First_Selector (Assoc : Node_Id) return Node_Id is
- begin
- if Nkind (Assoc) = N_Component_Association then
- return First (Choices (Assoc));
-
- elsif Nkind (Assoc) = N_Discriminant_Association then
- return (First (Selector_Names (Assoc)));
-
- else
- raise Program_Error;
- end if;
- end First_Selector;
-
- -----------------------------------
- -- Is_Formal_Of_Current_Function --
- -----------------------------------
-
- function Is_Formal_Of_Current_Function
- (Assoc_Expr : Entity_Id) return Boolean is
- begin
- return Is_Entity_Name (Assoc_Expr)
- and then Enclosing_Subprogram
- (Entity (Assoc_Expr)) = Scope_Id
- and then Is_Formal (Entity (Assoc_Expr));
- end Is_Formal_Of_Current_Function;
-
- -- Local declarations
-
- Assoc : Node_Id := Empty;
- -- Assoc should perhaps be renamed and declared as a
- -- Node_Or_Entity_Id since it encompasses not only component and
- -- discriminant associations, but also discriminant components within
- -- a type declaration or subtype indication ???
-
- Assoc_Expr : Node_Id;
- Assoc_Present : Boolean := False;
-
- Check_Cond : Node_Id;
- Unseen_Disc_Count : Nat := 0;
- Seen_Discs : Elist_Id;
- Disc : Entity_Id;
- First_Disc : Entity_Id;
-
- Obj_Decl : Node_Id;
- Return_Con : Node_Id;
- Unqual : Node_Id;
-
- -- Start of processing for Check_Return_Construct_Accessibility
-
- begin
- -- Only perform checks on record types with access discriminants and
- -- non-internally generated functions.
-
- if not Is_Record_Type (R_Type)
- or else not Has_Anonymous_Access_Discriminant (R_Type)
- or else not Comes_From_Source (Return_Stmt)
- then
- return;
- end if;
-
- -- We are only interested in return statements
-
- if Nkind (Return_Stmt) not in
- N_Extended_Return_Statement | N_Simple_Return_Statement
- then
- return;
- end if;
-
- -- Fetch the object from the return statement, in the case of a
- -- simple return statement the expression is part of the node.
-
- if Nkind (Return_Stmt) = N_Extended_Return_Statement then
- -- Obtain the object definition from the expanded extended return
-
- Return_Con := First (Return_Object_Declarations (Return_Stmt));
- while Present (Return_Con) loop
- -- Inspect the original node to avoid object declarations
- -- expanded into renamings.
-
- if Nkind (Original_Node (Return_Con)) = N_Object_Declaration
- and then Comes_From_Source (Original_Node (Return_Con))
- then
- exit;
- end if;
-
- Nlists.Next (Return_Con);
- end loop;
-
- pragma Assert (Present (Return_Con));
-
- -- Could be dealing with a renaming
-
- Return_Con := Original_Node (Return_Con);
- else
- Return_Con := Expression (Return_Stmt);
- end if;
-
- -- Obtain the accessibility levels of the expressions associated
- -- with all anonymous access discriminants, then generate a
- -- dynamic check or static error when relevant.
-
- -- Note the repeated use of Original_Node to avoid checking
- -- expanded code.
-
- Unqual := Original_Node (Unqualify (Original_Node (Return_Con)));
-
- -- Get the corresponding declaration based on the return object's
- -- identifier.
-
- if Nkind (Unqual) = N_Identifier
- and then Nkind (Parent (Entity (Unqual)))
- in N_Object_Declaration
- | N_Object_Renaming_Declaration
- then
- Obj_Decl := Original_Node (Parent (Entity (Unqual)));
-
- -- We were passed the object declaration directly, so use it
-
- elsif Nkind (Unqual) in N_Object_Declaration
- | N_Object_Renaming_Declaration
- then
- Obj_Decl := Unqual;
-
- -- Otherwise, we are looking at something else
-
- else
- Obj_Decl := Empty;
-
- end if;
-
- -- Hop up object renamings when present
-
- if Present (Obj_Decl)
- and then Nkind (Obj_Decl) = N_Object_Renaming_Declaration
- then
- while Nkind (Obj_Decl) = N_Object_Renaming_Declaration loop
-
- if Nkind (Name (Obj_Decl)) not in N_Entity then
- -- We may be looking at the expansion of iterators or
- -- some other internally generated construct, so it is safe
- -- to ignore checks ???
-
- if not Comes_From_Source (Obj_Decl) then
- return;
- end if;
-
- Obj_Decl := Original_Node
- (Declaration_Node
- (Ultimate_Prefix (Name (Obj_Decl))));
-
- -- Move up to the next declaration based on the object's name
-
- else
- Obj_Decl := Original_Node
- (Declaration_Node (Name (Obj_Decl)));
- end if;
- end loop;
- end if;
-
- -- Obtain the discriminant values from the return aggregate
-
- -- Do we cover extension aggregates correctly ???
-
- if Nkind (Unqual) = N_Aggregate then
- if Present (Expressions (Unqual)) then
- Assoc := First (Expressions (Unqual));
- else
- Assoc := First (Component_Associations (Unqual));
- end if;
-
- -- There is an object declaration for the return object
-
- elsif Present (Obj_Decl) then
- -- When a subtype indication is present in an object declaration
- -- it must contain the object's discriminants.
-
- if Nkind (Object_Definition (Obj_Decl)) = N_Subtype_Indication then
- Assoc := First
- (Constraints
- (Constraint
- (Object_Definition (Obj_Decl))));
-
- -- The object declaration contains an aggregate
-
- elsif Present (Expression (Obj_Decl)) then
-
- if Nkind (Unqualify (Expression (Obj_Decl))) = N_Aggregate then
- -- Grab the first associated discriminant expresion
-
- if Present
- (Expressions (Unqualify (Expression (Obj_Decl))))
- then
- Assoc := First
- (Expressions
- (Unqualify (Expression (Obj_Decl))));
- else
- Assoc := First
- (Component_Associations
- (Unqualify (Expression (Obj_Decl))));
- end if;
-
- -- Otherwise, this is something else
-
- else
- return;
- end if;
-
- -- There are no supplied discriminants in the object declaration,
- -- so get them from the type definition since they must be default
- -- initialized.
-
- -- Do we handle constrained subtypes correctly ???
-
- elsif Nkind (Unqual) = N_Object_Declaration then
- Assoc := First_Discriminant
- (Etype (Object_Definition (Obj_Decl)));
-
- else
- Assoc := First_Discriminant (Etype (Unqual));
- end if;
-
- -- When we are not looking at an aggregate or an identifier, return
- -- since any other construct (like a function call) is not
- -- applicable since checks will be performed on the side of the
- -- callee.
-
- else
- return;
- end if;
-
- -- Obtain the discriminants so we know the actual type in case the
- -- value of their associated expression gets implicitly converted.
-
- if No (Obj_Decl) then
- pragma Assert (Nkind (Unqual) = N_Aggregate);
-
- Disc := First_Discriminant (Etype (Unqual));
-
- else
- Disc := First_Discriminant
- (Etype (Defining_Identifier (Obj_Decl)));
- end if;
-
- -- Preserve the first discriminant for checking named associations
-
- First_Disc := Disc;
-
- -- Count the number of discriminants for processing an aggregate
- -- which includes an others.
-
- Disc := First_Disc;
- while Present (Disc) loop
- Unseen_Disc_Count := Unseen_Disc_Count + 1;
-
- Next_Discriminant (Disc);
- end loop;
-
- Seen_Discs := New_Elmt_List;
-
- -- Loop through each of the discriminants and check each expression
- -- associated with an anonymous access discriminant.
-
- -- When named associations occur in the return aggregate then
- -- discriminants can be in any order, so we need to ensure we do
- -- not continue to loop when all discriminants have been seen.
-
- Disc := First_Disc;
- while Present (Assoc)
- and then (Present (Disc) or else Assoc_Present)
- and then Unseen_Disc_Count > 0
- loop
- -- Handle named associations by searching through the names of
- -- the relevant discriminant components.
-
- if Nkind (Assoc)
- in N_Component_Association | N_Discriminant_Association
- then
- Assoc_Expr := Expression (Assoc);
- Assoc_Present := True;
-
- -- We currently don't handle box initialized discriminants,
- -- however, since default initialized anonymous access
- -- discriminants are a corner case, this is ok for now ???
-
- if Nkind (Assoc) = N_Component_Association
- and then Box_Present (Assoc)
- then
- if Nkind (First_Selector (Assoc)) = N_Others_Choice then
- Unseen_Disc_Count := 0;
- end if;
-
- -- When others is present we must identify a discriminant we
- -- haven't already seen so as to get the appropriate type for
- -- the static accessibility check.
-
- -- This works because all components within an others clause
- -- must have the same type.
-
- elsif Nkind (First_Selector (Assoc)) = N_Others_Choice then
-
- Disc := First_Disc;
- Outer : while Present (Disc) loop
- declare
- Current_Seen_Disc : Elmt_Id;
- begin
- -- Move through the list of identified discriminants
-
- Current_Seen_Disc := First_Elmt (Seen_Discs);
- while Present (Current_Seen_Disc) loop
- -- Exit the loop when we found a match
-
- exit when
- Chars (Node (Current_Seen_Disc)) = Chars (Disc);
-
- Next_Elmt (Current_Seen_Disc);
- end loop;
-
- -- When we have exited the above loop without finding
- -- a match then we know that Disc has not been seen.
-
- exit Outer when No (Current_Seen_Disc);
- end;
-
- Next_Discriminant (Disc);
- end loop Outer;
-
- -- If we got to an others clause with a non-zero
- -- discriminant count there must be a discriminant left to
- -- check.
-
- pragma Assert (Present (Disc));
-
- -- Set the unseen discriminant count to zero because we know
- -- an others clause sets all remaining components of an
- -- aggregate.
-
- Unseen_Disc_Count := 0;
-
- -- Move through each of the selectors in the named association
- -- and obtain a discriminant for accessibility checking if one
- -- is referenced in the list. Also track which discriminants
- -- are referenced for the purpose of handling an others clause.
-
- else
- declare
- Assoc_Choice : Node_Id;
- Curr_Disc : Node_Id;
- begin
-
- Disc := Empty;
- Curr_Disc := First_Disc;
- while Present (Curr_Disc) loop
- -- Check each of the choices in the associations for a
- -- match to the name of the current discriminant.
-
- Assoc_Choice := First_Selector (Assoc);
- while Present (Assoc_Choice) loop
- -- When the name matches we track that we have seen
- -- the discriminant, but instead of exiting the
- -- loop we continue iterating to make sure all the
- -- discriminants within the named association get
- -- tracked.
-
- if Chars (Assoc_Choice) = Chars (Curr_Disc) then
- Append_Elmt (Curr_Disc, Seen_Discs);
-
- Disc := Curr_Disc;
- Unseen_Disc_Count := Unseen_Disc_Count - 1;
- end if;
-
- Next (Assoc_Choice);
- end loop;
-
- Next_Discriminant (Curr_Disc);
- end loop;
- end;
- end if;
-
- -- Unwrap the associated expression if we are looking at a default
- -- initialized type declaration. In this case Assoc is not really
- -- an association, but a component declaration. Should Assoc be
- -- renamed in some way to be more clear ???
-
- -- This occurs when the return object does not initialize
- -- discriminant and instead relies on the type declaration for
- -- their supplied values.
-
- elsif Nkind (Assoc) in N_Entity
- and then Ekind (Assoc) = E_Discriminant
- then
- Append_Elmt (Disc, Seen_Discs);
-
- Assoc_Expr := Discriminant_Default_Value (Assoc);
- Unseen_Disc_Count := Unseen_Disc_Count - 1;
-
- -- Otherwise, there is nothing to do because Assoc is an
- -- expression within the return aggregate itself.
-
- else
- Append_Elmt (Disc, Seen_Discs);
-
- Assoc_Expr := Assoc;
- Unseen_Disc_Count := Unseen_Disc_Count - 1;
- end if;
-
- -- Check the accessibility level of the expression when the
- -- discriminant is of an anonymous access type.
-
- if Present (Assoc_Expr)
- and then Present (Disc)
- and then Ekind (Etype (Disc)) = E_Anonymous_Access_Type
-
- -- We disable the check when we have a tagged return type and
- -- the associated expression for the discriminant is a formal
- -- parameter since the check would require us to compare the
- -- accessibility level of Assoc_Expr to the level of the
- -- Extra_Accessibility_Of_Result of the function - which is
- -- currently disabled for functions with tagged return types.
- -- This may change in the future ???
-
- -- See Needs_Result_Accessibility_Level for details.
-
- and then not
- (No (Extra_Accessibility_Of_Result (Scope_Id))
- and then Is_Formal_Of_Current_Function (Assoc_Expr)
- and then Is_Tagged_Type (Etype (Scope_Id)))
- then
- -- Generate a dynamic check based on the extra accessibility of
- -- the result or the scope of the current function.
-
- Check_Cond :=
- Make_Op_Gt (Loc,
- Left_Opnd => Accessibility_Level
- (Expr => Assoc_Expr,
- Level => Dynamic_Level,
- In_Return_Context => True),
- Right_Opnd =>
- (if Present (Extra_Accessibility_Of_Result (Scope_Id))
-
- -- When Assoc_Expr is a formal we have to look at the
- -- extra accessibility-level formal associated with
- -- the result.
-
- and then Is_Formal_Of_Current_Function (Assoc_Expr)
- then
- New_Occurrence_Of
- (Extra_Accessibility_Of_Result (Scope_Id), Loc)
-
- -- Otherwise, we compare the level of Assoc_Expr to the
- -- scope of the current function.
-
- else
- Make_Integer_Literal
- (Loc, Scope_Depth (Scope (Scope_Id)))));
-
- Insert_Before_And_Analyze (Return_Stmt,
- Make_Raise_Program_Error (Loc,
- Condition => Check_Cond,
- Reason => PE_Accessibility_Check_Failed));
-
- -- If constant folding has happened on the condition for the
- -- generated error, then warn about it being unconditional when
- -- we know an error will be raised.
-
- if Nkind (Check_Cond) = N_Identifier
- and then Entity (Check_Cond) = Standard_True
- then
- Error_Msg_N
- ("access discriminant in return object would be a dangling"
- & " reference", Return_Stmt);
- end if;
- end if;
-
- -- Iterate over the discriminants, except when we have encountered
- -- a named association since the discriminant order becomes
- -- irrelevant in that case.
-
- if not Assoc_Present then
- Next_Discriminant (Disc);
- end if;
-
- -- Iterate over associations
-
- if not Is_List_Member (Assoc) then
- exit;
- else
- Nlists.Next (Assoc);
- end if;
- end loop;
- end Check_Return_Construct_Accessibility;
-
- -------------------------------------
- -- Check_Return_Subtype_Indication --
- -------------------------------------
-
- procedure Check_Return_Subtype_Indication (Obj_Decl : Node_Id) is
- Return_Obj : constant Node_Id := Defining_Identifier (Obj_Decl);
-
- R_Stm_Type : constant Entity_Id := Etype (Return_Obj);
- -- Subtype given in the extended return statement (must match R_Type)
-
- Subtype_Ind : constant Node_Id :=
- Object_Definition (Original_Node (Obj_Decl));
-
- procedure Error_No_Match (N : Node_Id);
- -- Output error messages for case where types do not statically
- -- match. N is the location for the messages.
-
- --------------------
- -- Error_No_Match --
- --------------------
-
- procedure Error_No_Match (N : Node_Id) is
- begin
- Error_Msg_N
- ("subtype must statically match function result subtype", N);
-
- if not Predicates_Match (R_Stm_Type, R_Type) then
- Error_Msg_Node_2 := R_Type;
- Error_Msg_NE
- ("\predicate of& does not match predicate of&",
- N, R_Stm_Type);
- end if;
- end Error_No_Match;
-
- -- Start of processing for Check_Return_Subtype_Indication
-
- begin
- -- First, avoid cascaded errors
-
- if Error_Posted (Obj_Decl) or else Error_Posted (Subtype_Ind) then
- return;
- end if;
-
- -- "return access T" case; check that the return statement also has
- -- "access T", and that the subtypes statically match:
- -- if this is an access to subprogram the signatures must match.
-
- if Is_Anonymous_Access_Type (R_Type) then
- if Is_Anonymous_Access_Type (R_Stm_Type) then
- if Ekind (Designated_Type (R_Stm_Type)) /= E_Subprogram_Type
- then
- if Base_Type (Designated_Type (R_Stm_Type)) /=
- Base_Type (Designated_Type (R_Type))
- or else not Subtypes_Statically_Match (R_Stm_Type, R_Type)
- then
- Error_No_Match (Subtype_Mark (Subtype_Ind));
- end if;
-
- else
- -- For two anonymous access to subprogram types, the types
- -- themselves must be type conformant.
-
- if not Conforming_Types
- (R_Stm_Type, R_Type, Fully_Conformant)
- then
- Error_No_Match (Subtype_Ind);
- end if;
- end if;
-
- else
- Error_Msg_N ("must use anonymous access type", Subtype_Ind);
- end if;
-
- -- If the return object is of an anonymous access type, then report
- -- an error if the function's result type is not also anonymous.
-
- elsif Is_Anonymous_Access_Type (R_Stm_Type) then
- pragma Assert (not Is_Anonymous_Access_Type (R_Type));
- Error_Msg_N
- ("anonymous access not allowed for function with named access "
- & "result", Subtype_Ind);
-
- -- Subtype indication case: check that the return object's type is
- -- covered by the result type, and that the subtypes statically match
- -- when the result subtype is constrained. Also handle record types
- -- with unknown discriminants for which we have built the underlying
- -- record view. Coverage is needed to allow specific-type return
- -- objects when the result type is class-wide (see AI05-32).
-
- elsif Covers (Base_Type (R_Type), Base_Type (R_Stm_Type))
- or else (Is_Underlying_Record_View (Base_Type (R_Stm_Type))
- and then
- Covers
- (Base_Type (R_Type),
- Underlying_Record_View (Base_Type (R_Stm_Type))))
- then
- -- A null exclusion may be present on the return type, on the
- -- function specification, on the object declaration or on the
- -- subtype itself.
-
- if Is_Access_Type (R_Type)
- and then
- (Can_Never_Be_Null (R_Type)
- or else Null_Exclusion_Present (Parent (Scope_Id))) /=
- Can_Never_Be_Null (R_Stm_Type)
- then
- Error_No_Match (Subtype_Ind);
- end if;
-
- -- AI05-103: for elementary types, subtypes must statically match
-
- if Is_Constrained (R_Type) or else Is_Access_Type (R_Type) then
- if not Subtypes_Statically_Match (R_Stm_Type, R_Type) then
- Error_No_Match (Subtype_Ind);
- end if;
- end if;
-
- -- All remaining cases are illegal
-
- -- Note: previous versions of this subprogram allowed the return
- -- value to be the ancestor of the return type if the return type
- -- was a null extension. This was plainly incorrect.
-
- else
- Error_Msg_N
- ("wrong type for return_subtype_indication", Subtype_Ind);
- end if;
- end Check_Return_Subtype_Indication;
-
---------------------
-- Local Variables --
---------------------
@@ -1495,7 +849,7 @@ package body Sem_Ch6 is
Resolve (Expr, R_Type);
Check_Limited_Return (N, Expr, R_Type);
- Check_Return_Construct_Accessibility (N);
+ Check_Return_Construct_Accessibility (N, Stm_Entity);
-- Ada 2022 (AI12-0269): Any return statement that applies to a
-- nonreturning function shall be a simple_return_statement with
@@ -1529,8 +883,6 @@ package body Sem_Ch6 is
Set_Is_Return_Object (Defining_Identifier (Obj_Decl));
Analyze (Obj_Decl);
- Check_Return_Subtype_Indication (Obj_Decl);
-
if Present (HSS) then
Analyze (HSS);
@@ -1551,7 +903,7 @@ package body Sem_Ch6 is
Check_References (Stm_Entity);
- Check_Return_Construct_Accessibility (N);
+ Check_Return_Construct_Accessibility (N, Stm_Entity);
-- Check RM 6.5 (5.9/3)
diff --git a/gcc/ada/sem_ch9.adb b/gcc/ada/sem_ch9.adb
index e43e3ae..aad86fa 100644
--- a/gcc/ada/sem_ch9.adb
+++ b/gcc/ada/sem_ch9.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Aspects; use Aspects;
with Atree; use Atree;
with Checks; use Checks;
diff --git a/gcc/ada/sem_elab.adb b/gcc/ada/sem_elab.adb
index a1e8f1e..9bf8614 100644
--- a/gcc/ada/sem_elab.adb
+++ b/gcc/ada/sem_elab.adb
@@ -881,6 +881,10 @@ package body Sem_Elab is
-- The subprogram body traversal mode. Once set, this value should not
-- be changed.
+ Within_Freezing_Actions : Boolean := False;
+ -- This flag is set when the Processing phase is currently examining a
+ -- scenario which was reached from the actions of a freeze node.
+
Within_Generic : Boolean := False;
-- This flag is set when the Processing phase is currently within a
-- generic unit.
@@ -5353,6 +5357,7 @@ package body Sem_Elab is
Subp_Id : constant Entity_Id := Target (Call_Rep);
Subp_Rep : constant Target_Rep_Id :=
Target_Representation_Of (Subp_Id, In_State);
+ Body_Decl : constant Node_Id := Body_Declaration (Subp_Rep);
Subp_Decl : constant Node_Id := Spec_Declaration (Subp_Rep);
SPARK_Rules_On : constant Boolean :=
@@ -5452,6 +5457,16 @@ package body Sem_Elab is
or else not Elaboration_Warnings_OK (Call_Rep)
or else not Elaboration_Warnings_OK (Subp_Rep);
+ -- The call occurs in freezing actions context when a prior scenario
+ -- is already in that mode, or when the target is a subprogram whose
+ -- body has been generated as a freezing action. Update the state of
+ -- the Processing phase to reflect this.
+
+ New_In_State.Within_Freezing_Actions :=
+ New_In_State.Within_Freezing_Actions
+ or else (Present (Body_Decl)
+ and then Nkind (Parent (Body_Decl)) = N_Freeze_Entity);
+
-- The call occurs in an initial condition context when a prior
-- scenario is already in that mode, or when the target is an
-- Initial_Condition procedure. Update the state of the Processing
@@ -5502,7 +5517,7 @@ package body Sem_Elab is
In_State => New_In_State);
Traverse_Conditional_ABE_Body
- (N => Body_Declaration (Subp_Rep),
+ (N => Body_Decl,
In_State => New_In_State);
end Process_Conditional_ABE_Call;
@@ -5721,6 +5736,13 @@ package body Sem_Elab is
if In_State.Suppress_Warnings then
null;
+ -- Do not emit any ABE diagnostics when the call occurs in a
+ -- freezing actions context because this leads to incorrect
+ -- diagnostics.
+
+ elsif In_State.Within_Freezing_Actions then
+ null;
+
-- Do not emit any ABE diagnostics when the call occurs in an
-- initial condition context because this leads to incorrect
-- diagnostics.
diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb
index 27bd879..f3c23ca 100644
--- a/gcc/ada/sem_prag.adb
+++ b/gcc/ada/sem_prag.adb
@@ -2116,9 +2116,16 @@ package body Sem_Prag is
First (Pragma_Argument_Associations (N));
Obj_Decl : constant Node_Id := Find_Related_Context (N);
Obj_Id : constant Entity_Id := Defining_Entity (Obj_Decl);
+ Obj_Typ : Entity_Id;
Expr : Node_Id;
begin
+ if Is_Type (Obj_Id) then
+ Obj_Typ := Obj_Id;
+ else
+ Obj_Typ := Etype (Obj_Id);
+ end if;
+
-- Ensure that the Boolean expression (if present) is static. A missing
-- argument defaults the value to True (SPARK RM 7.1.2(5)).
@@ -2153,9 +2160,7 @@ package body Sem_Prag is
if Prag_Id /= Pragma_No_Caching
and then not Is_Effectively_Volatile (Obj_Id)
then
- if Ekind (Obj_Id) = E_Variable
- and then No_Caching_Enabled (Obj_Id)
- then
+ if No_Caching_Enabled (Obj_Id) then
if Expr_Val then -- Confirming value of False is allowed
SPARK_Msg_N
("illegal combination of external property % and property "
@@ -2167,15 +2172,16 @@ package body Sem_Prag is
N);
end if;
- -- Pragma No_Caching should only apply to volatile variables of
+ -- Pragma No_Caching should only apply to volatile types or variables of
-- a non-effectively volatile type (SPARK RM 7.1.2).
elsif Prag_Id = Pragma_No_Caching then
- if Is_Effectively_Volatile (Etype (Obj_Id)) then
- SPARK_Msg_N ("property % must not apply to an object of "
+ if Is_Effectively_Volatile (Obj_Typ) then
+ SPARK_Msg_N ("property % must not apply to a type or object of "
& "an effectively volatile type", N);
elsif not Is_Volatile (Obj_Id) then
- SPARK_Msg_N ("property % must apply to a volatile object", N);
+ SPARK_Msg_N
+ ("property % must apply to a volatile type or object", N);
end if;
end if;
@@ -13484,22 +13490,19 @@ package body Sem_Prag is
Obj_Or_Type_Decl := Find_Related_Context (N, Do_Checks => True);
-- Pragma must apply to a object declaration or to a type
- -- declaration (only the former in the No_Caching case).
- -- Original_Node is necessary to account for untagged derived
- -- types that are rewritten as subtypes of their
- -- respective root types.
-
- if Nkind (Obj_Or_Type_Decl) /= N_Object_Declaration then
- if Prag_Id = Pragma_No_Caching
- or else Nkind (Original_Node (Obj_Or_Type_Decl)) not in
- N_Full_Type_Declaration |
- N_Private_Type_Declaration |
- N_Formal_Type_Declaration |
- N_Task_Type_Declaration |
- N_Protected_Type_Declaration
- then
- Pragma_Misplaced;
- end if;
+ -- declaration. Original_Node is necessary to account for
+ -- untagged derived types that are rewritten as subtypes of
+ -- their respective root types.
+
+ if Nkind (Obj_Or_Type_Decl) /= N_Object_Declaration
+ and then Nkind (Original_Node (Obj_Or_Type_Decl)) not in
+ N_Full_Type_Declaration |
+ N_Private_Type_Declaration |
+ N_Formal_Type_Declaration |
+ N_Task_Type_Declaration |
+ N_Protected_Type_Declaration
+ then
+ Pragma_Misplaced;
end if;
Obj_Or_Type_Id := Defining_Entity (Obj_Or_Type_Decl);
diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb
index e702df6..b54ed93 100644
--- a/gcc/ada/sem_res.adb
+++ b/gcc/ada/sem_res.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Aspects; use Aspects;
with Atree; use Atree;
with Checks; use Checks;
@@ -5621,7 +5622,7 @@ package body Sem_Res is
-- caller does use an allocator, it will be caught at the call site.
if No_Pool_Assigned (Typ)
- and then not Alloc_For_BIP_Return (N)
+ and then not For_Special_Return_Object (N)
then
Error_Msg_N ("allocation from empty storage pool!", N);
@@ -10104,6 +10105,55 @@ package body Sem_Res is
then
T := Etype (R);
+ -- If the type of the left operand is universal_integer and that of the
+ -- right operand is smaller, then we do not resolve the operands to the
+ -- tested type but to universal_integer instead. If not conforming to
+ -- the letter, it's conforming to the spirit of the specification of
+ -- membership tests, which are typically used to guard an operation and
+ -- ought not to fail a check in doing so. Without this, in the case of
+
+ -- type Small_Length is range 1 .. 16;
+
+ -- function Is_Small_String (S : String) return Boolean is
+ -- begin
+ -- return S'Length in Small_Length;
+ -- end;
+
+ -- the function Is_Small_String would fail a range check for strings
+ -- larger than 127 characters.
+
+ -- The test on the size is required in GNAT because universal_integer
+ -- does not cover all the values of all the supported integer types,
+ -- for example the large values of Long_Long_Long_Unsigned.
+
+ elsif not Is_Overloaded (L)
+ and then Etype (L) = Universal_Integer
+ and then (Is_Overloaded (R)
+ or else RM_Size (Etype (R)) < RM_Size (Universal_Integer))
+ then
+ T := Etype (L);
+
+ -- If the right operand is 'Range, we first need to resolve it (to
+ -- the tested type) so that it is rewritten as an N_Range, before
+ -- converting its bounds and resolving it again below.
+
+ if Nkind (R) = N_Attribute_Reference
+ and then Attribute_Name (R) = Name_Range
+ then
+ Resolve (R);
+ end if;
+
+ -- If the right operand is an N_Range, we convert its bounds to the
+ -- universal type before resolving it.
+
+ if Nkind (R) = N_Range then
+ Rewrite (R,
+ Make_Range (Sloc (R),
+ Low_Bound => Convert_To (T, Low_Bound (R)),
+ High_Bound => Convert_To (T, High_Bound (R))));
+ Analyze (R);
+ end if;
+
-- Ada 2005 (AI-251): Support the following case:
-- type I is interface;
@@ -10123,6 +10173,7 @@ package body Sem_Res is
and then not Is_Interface (Etype (R))
then
return;
+
else
T := Intersect_Types (L, R);
end if;
diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb
index a13d9eb..a1cebb0 100644
--- a/gcc/ada/sem_util.adb
+++ b/gcc/ada/sem_util.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Casing; use Casing;
with Checks; use Checks;
with Debug; use Debug;
@@ -30,7 +31,6 @@ with Einfo.Utils; use Einfo.Utils;
with Elists; use Elists;
with Errout; use Errout;
with Erroutc; use Erroutc;
-with Exp_Ch3; use Exp_Ch3;
with Exp_Ch6; use Exp_Ch6;
with Exp_Ch11; use Exp_Ch11;
with Exp_Util; use Exp_Util;
@@ -255,740 +255,6 @@ package body Sem_Util is
return Interface_List (Nod);
end Abstract_Interface_List;
- -------------------------
- -- Accessibility_Level --
- -------------------------
-
- function Accessibility_Level
- (Expr : Node_Id;
- Level : Accessibility_Level_Kind;
- In_Return_Context : Boolean := False;
- Allow_Alt_Model : Boolean := True) return Node_Id
- is
- Loc : constant Source_Ptr := Sloc (Expr);
-
- function Accessibility_Level (Expr : Node_Id) return Node_Id
- is (Accessibility_Level (Expr, Level, In_Return_Context));
- -- Renaming of the enclosing function to facilitate recursive calls
-
- function Make_Level_Literal (Level : Uint) return Node_Id;
- -- Construct an integer literal representing an accessibility level
- -- with its type set to Natural.
-
- function Innermost_Master_Scope_Depth (N : Node_Id) return Uint;
- -- Returns the scope depth of the given node's innermost enclosing
- -- scope (effectively the accessibility level of the innermost
- -- enclosing master).
-
- function Function_Call_Or_Allocator_Level (N : Node_Id) return Node_Id;
- -- Centralized processing of subprogram calls which may appear in
- -- prefix notation.
-
- function Typ_Access_Level (Typ : Entity_Id) return Uint
- is (Type_Access_Level (Typ, Allow_Alt_Model));
- -- Renaming of Type_Access_Level with Allow_Alt_Model specified to avoid
- -- passing the parameter specifically in every call.
-
- ----------------------------------
- -- Innermost_Master_Scope_Depth --
- ----------------------------------
-
- function Innermost_Master_Scope_Depth (N : Node_Id) return Uint is
- Encl_Scop : Entity_Id;
- Ent : Entity_Id;
- Node_Par : Node_Id := Parent (N);
- Master_Lvl_Modifier : Int := 0;
-
- begin
- -- Locate the nearest enclosing node (by traversing Parents)
- -- that Defining_Entity can be applied to, and return the
- -- depth of that entity's nearest enclosing scope.
-
- -- The rules that define what a master are defined in
- -- RM 7.6.1 (3), and include statements and conditions for loops
- -- among other things. These cases are detected properly ???
-
- while Present (Node_Par) loop
- Ent := Defining_Entity_Or_Empty (Node_Par);
-
- if Present (Ent) then
- Encl_Scop := Find_Enclosing_Scope (Ent);
-
- -- Ignore transient scopes made during expansion
-
- if Comes_From_Source (Node_Par) then
- -- Note that in some rare cases the scope depth may not be
- -- set, for example, when we are in the middle of analyzing
- -- a type and the enclosing scope is said type. So, instead,
- -- continue to move up the parent chain since the scope
- -- depth of the type's parent is the same as that of the
- -- type.
-
- if not Scope_Depth_Set (Encl_Scop) then
- pragma Assert (Nkind (Parent (Encl_Scop))
- = N_Full_Type_Declaration);
- else
- return
- Scope_Depth (Encl_Scop) + Master_Lvl_Modifier;
- end if;
- end if;
-
- -- For a return statement within a function, return
- -- the depth of the function itself. This is not just
- -- a small optimization, but matters when analyzing
- -- the expression in an expression function before
- -- the body is created.
-
- elsif Nkind (Node_Par) in N_Extended_Return_Statement
- | N_Simple_Return_Statement
- then
- return Scope_Depth (Enclosing_Subprogram (Node_Par));
-
- -- Statements are counted as masters
-
- elsif Is_Master (Node_Par) then
- Master_Lvl_Modifier := Master_Lvl_Modifier + 1;
-
- end if;
-
- Node_Par := Parent (Node_Par);
- end loop;
-
- -- Should never reach the following return
-
- pragma Assert (False);
-
- return Scope_Depth (Current_Scope) + 1;
- end Innermost_Master_Scope_Depth;
-
- ------------------------
- -- Make_Level_Literal --
- ------------------------
-
- function Make_Level_Literal (Level : Uint) return Node_Id is
- Result : constant Node_Id := Make_Integer_Literal (Loc, Level);
-
- begin
- Set_Etype (Result, Standard_Natural);
- return Result;
- end Make_Level_Literal;
-
- --------------------------------------
- -- Function_Call_Or_Allocator_Level --
- --------------------------------------
-
- function Function_Call_Or_Allocator_Level (N : Node_Id) return Node_Id is
- Par : Node_Id;
- Prev_Par : Node_Id;
- begin
- -- Results of functions are objects, so we either get the
- -- accessibility of the function or, in case of a call which is
- -- indirect, the level of the access-to-subprogram type.
-
- -- This code looks wrong ???
-
- if Nkind (N) = N_Function_Call
- and then Ada_Version < Ada_2005
- then
- if Is_Entity_Name (Name (N)) then
- return Make_Level_Literal
- (Subprogram_Access_Level (Entity (Name (N))));
- else
- return Make_Level_Literal
- (Typ_Access_Level (Etype (Prefix (Name (N)))));
- end if;
-
- -- We ignore coextensions as they cannot be implemented under the
- -- "small-integer" model.
-
- elsif Nkind (N) = N_Allocator
- and then (Is_Static_Coextension (N)
- or else Is_Dynamic_Coextension (N))
- then
- return Make_Level_Literal (Scope_Depth (Standard_Standard));
- end if;
-
- -- Named access types have a designated level
-
- if Is_Named_Access_Type (Etype (N)) then
- return Make_Level_Literal (Typ_Access_Level (Etype (N)));
-
- -- Otherwise, the level is dictated by RM 3.10.2 (10.7/3)
-
- else
- -- Check No_Dynamic_Accessibility_Checks restriction override for
- -- alternative accessibility model.
-
- if Allow_Alt_Model
- and then No_Dynamic_Accessibility_Checks_Enabled (N)
- and then Is_Anonymous_Access_Type (Etype (N))
- then
- -- In the alternative model the level is that of the
- -- designated type.
-
- if Debug_Flag_Underscore_B then
- return Make_Level_Literal (Typ_Access_Level (Etype (N)));
-
- -- For function calls the level is that of the innermost
- -- master, otherwise (for allocators etc.) we get the level
- -- of the corresponding anonymous access type, which is
- -- calculated through the normal path of execution.
-
- elsif Nkind (N) = N_Function_Call then
- return Make_Level_Literal
- (Innermost_Master_Scope_Depth (Expr));
- end if;
- end if;
-
- if Nkind (N) = N_Function_Call then
- -- Dynamic checks are generated when we are within a return
- -- value or we are in a function call within an anonymous
- -- access discriminant constraint of a return object (signified
- -- by In_Return_Context) on the side of the callee.
-
- -- So, in this case, return accessibility level of the
- -- enclosing subprogram.
-
- if In_Return_Value (N)
- or else In_Return_Context
- then
- return Make_Level_Literal
- (Subprogram_Access_Level (Current_Subprogram));
- end if;
- end if;
-
- -- When the call is being dereferenced the level is that of the
- -- enclosing master of the dereferenced call.
-
- if Nkind (Parent (N)) in N_Explicit_Dereference
- | N_Indexed_Component
- | N_Selected_Component
- then
- return Make_Level_Literal
- (Innermost_Master_Scope_Depth (Expr));
- end if;
-
- -- Find any relevant enclosing parent nodes that designate an
- -- object being initialized.
-
- -- Note: The above is only relevant if the result is used "in its
- -- entirety" as RM 3.10.2 (10.2/3) states. However, this is
- -- accounted for in the case statement in the main body of
- -- Accessibility_Level for N_Selected_Component.
-
- Par := Parent (Expr);
- Prev_Par := Empty;
- while Present (Par) loop
- -- Detect an expanded implicit conversion, typically this
- -- occurs on implicitly converted actuals in calls.
-
- -- Does this catch all implicit conversions ???
-
- if Nkind (Par) = N_Type_Conversion
- and then Is_Named_Access_Type (Etype (Par))
- then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (Par)));
- end if;
-
- -- Jump out when we hit an object declaration or the right-hand
- -- side of an assignment, or a construct such as an aggregate
- -- subtype indication which would be the result is not used
- -- "in its entirety."
-
- exit when Nkind (Par) in N_Object_Declaration
- or else (Nkind (Par) = N_Assignment_Statement
- and then Name (Par) /= Prev_Par);
-
- Prev_Par := Par;
- Par := Parent (Par);
- end loop;
-
- -- Assignment statements are handled in a similar way in
- -- accordance to the left-hand part. However, strictly speaking,
- -- this is illegal according to the RM, but this change is needed
- -- to pass an ACATS C-test and is useful in general ???
-
- case Nkind (Par) is
- when N_Object_Declaration =>
- return Make_Level_Literal
- (Scope_Depth
- (Scope (Defining_Identifier (Par))));
-
- when N_Assignment_Statement =>
- -- Return the accessibility level of the left-hand part
-
- return Accessibility_Level
- (Expr => Name (Par),
- Level => Object_Decl_Level,
- In_Return_Context => In_Return_Context);
-
- when others =>
- return Make_Level_Literal
- (Innermost_Master_Scope_Depth (Expr));
- end case;
- end if;
- end Function_Call_Or_Allocator_Level;
-
- -- Local variables
-
- E : Node_Id := Original_Node (Expr);
- Pre : Node_Id;
-
- -- Start of processing for Accessibility_Level
-
- begin
- -- We could be looking at a reference to a formal due to the expansion
- -- of entries and other cases, so obtain the renaming if necessary.
-
- if Present (Param_Entity (Expr)) then
- E := Param_Entity (Expr);
- end if;
-
- -- Extract the entity
-
- if Nkind (E) in N_Has_Entity and then Present (Entity (E)) then
- E := Entity (E);
-
- -- Deal with a possible renaming of a private protected component
-
- if Ekind (E) in E_Constant | E_Variable and then Is_Prival (E) then
- E := Prival_Link (E);
- end if;
- end if;
-
- -- Perform the processing on the expression
-
- case Nkind (E) is
- -- The level of an aggregate is that of the innermost master that
- -- evaluates it as defined in RM 3.10.2 (10/4).
-
- when N_Aggregate =>
- return Make_Level_Literal (Innermost_Master_Scope_Depth (Expr));
-
- -- The accessibility level is that of the access type, except for an
- -- anonymous allocators which have special rules defined in RM 3.10.2
- -- (14/3).
-
- when N_Allocator =>
- return Function_Call_Or_Allocator_Level (E);
-
- -- We could reach this point for two reasons. Either the expression
- -- applies to a special attribute ('Loop_Entry, 'Result, or 'Old), or
- -- we are looking at the access attributes directly ('Access,
- -- 'Address, or 'Unchecked_Access).
-
- when N_Attribute_Reference =>
- Pre := Original_Node (Prefix (E));
-
- -- Regular 'Access attribute presence means we have to look at the
- -- prefix.
-
- if Attribute_Name (E) = Name_Access then
- return Accessibility_Level (Prefix (E));
-
- -- Unchecked or unrestricted attributes have unlimited depth
-
- elsif Attribute_Name (E) in Name_Address
- | Name_Unchecked_Access
- | Name_Unrestricted_Access
- then
- return Make_Level_Literal (Scope_Depth (Standard_Standard));
-
- -- 'Access can be taken further against other special attributes,
- -- so handle these cases explicitly.
-
- elsif Attribute_Name (E)
- in Name_Old | Name_Loop_Entry | Name_Result
- then
- -- Named access types
-
- if Is_Named_Access_Type (Etype (Pre)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (Pre)));
-
- -- Anonymous access types
-
- elsif Nkind (Pre) in N_Has_Entity
- and then Ekind (Entity (Pre)) not in Subprogram_Kind
- and then Present (Get_Dynamic_Accessibility (Entity (Pre)))
- and then Level = Dynamic_Level
- then
- return New_Occurrence_Of
- (Get_Dynamic_Accessibility (Entity (Pre)), Loc);
-
- -- Otherwise the level is treated in a similar way as
- -- aggregates according to RM 6.1.1 (35.1/4) which concerns
- -- an implicit constant declaration - in turn defining the
- -- accessibility level to be that of the implicit constant
- -- declaration.
-
- else
- return Make_Level_Literal
- (Innermost_Master_Scope_Depth (Expr));
- end if;
-
- else
- raise Program_Error;
- end if;
-
- -- This is the "base case" for accessibility level calculations which
- -- means we are near the end of our recursive traversal.
-
- when N_Defining_Identifier =>
- -- A dynamic check is performed on the side of the callee when we
- -- are within a return statement, so return a library-level
- -- accessibility level to null out checks on the side of the
- -- caller.
-
- if Is_Explicitly_Aliased (E)
- and then (In_Return_Context
- or else (Level /= Dynamic_Level
- and then In_Return_Value (Expr)))
- then
- return Make_Level_Literal (Scope_Depth (Standard_Standard));
-
- -- Something went wrong and an extra accessibility formal has not
- -- been generated when one should have ???
-
- elsif Is_Formal (E)
- and then No (Get_Dynamic_Accessibility (E))
- and then Ekind (Etype (E)) = E_Anonymous_Access_Type
- then
- return Make_Level_Literal (Scope_Depth (Standard_Standard));
-
- -- Stand-alone object of an anonymous access type "SAOAAT"
-
- elsif (Is_Formal (E)
- or else Ekind (E) in E_Variable
- | E_Constant)
- and then Present (Get_Dynamic_Accessibility (E))
- and then (Level = Dynamic_Level
- or else Level = Zero_On_Dynamic_Level)
- then
- if Level = Zero_On_Dynamic_Level then
- return Make_Level_Literal
- (Scope_Depth (Standard_Standard));
- end if;
-
- -- No_Dynamic_Accessibility_Checks restriction override for
- -- alternative accessibility model.
-
- if Allow_Alt_Model
- and then No_Dynamic_Accessibility_Checks_Enabled (E)
- then
- -- In the alternative model the level is that of the
- -- designated type entity's context.
-
- if Debug_Flag_Underscore_B then
- return Make_Level_Literal (Typ_Access_Level (Etype (E)));
-
- -- Otherwise the level depends on the entity's context
-
- elsif Is_Formal (E) then
- return Make_Level_Literal
- (Subprogram_Access_Level
- (Enclosing_Subprogram (E)));
- else
- return Make_Level_Literal
- (Scope_Depth (Enclosing_Dynamic_Scope (E)));
- end if;
- end if;
-
- -- Return the dynamic level in the normal case
-
- return New_Occurrence_Of
- (Get_Dynamic_Accessibility (E), Loc);
-
- -- Initialization procedures have a special extra accessibility
- -- parameter associated with the level at which the object
- -- being initialized exists
-
- elsif Ekind (E) = E_Record_Type
- and then Is_Limited_Record (E)
- and then Current_Scope = Init_Proc (E)
- and then Present (Init_Proc_Level_Formal (Current_Scope))
- then
- return New_Occurrence_Of
- (Init_Proc_Level_Formal (Current_Scope), Loc);
-
- -- Current instance of the type is deeper than that of the type
- -- according to RM 3.10.2 (21).
-
- elsif Is_Type (E) then
- -- When restriction No_Dynamic_Accessibility_Checks is active
- -- along with -gnatd_b.
-
- if Allow_Alt_Model
- and then No_Dynamic_Accessibility_Checks_Enabled (E)
- and then Debug_Flag_Underscore_B
- then
- return Make_Level_Literal (Typ_Access_Level (E));
- end if;
-
- -- Normal path
-
- return Make_Level_Literal (Typ_Access_Level (E) + 1);
-
- -- Move up the renamed entity or object if it came from source
- -- since expansion may have created a dummy renaming under
- -- certain circumstances.
-
- -- Note: We check if the original node of the renaming comes
- -- from source because the node may have been rewritten.
-
- elsif Present (Renamed_Entity_Or_Object (E))
- and then Comes_From_Source
- (Original_Node (Renamed_Entity_Or_Object (E)))
- then
- return Accessibility_Level (Renamed_Entity_Or_Object (E));
-
- -- Named access types get their level from their associated type
-
- elsif Is_Named_Access_Type (Etype (E)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (E)));
-
- -- Check if E is an expansion-generated renaming of an iterator
- -- by examining Related_Expression. If so, determine the
- -- accessibility level based on the original expression.
-
- elsif Ekind (E) in E_Constant | E_Variable
- and then Present (Related_Expression (E))
- then
- return Accessibility_Level (Related_Expression (E));
-
- elsif Level = Dynamic_Level
- and then Ekind (E) in E_In_Parameter | E_In_Out_Parameter
- and then Present (Init_Proc_Level_Formal (Scope (E)))
- then
- return New_Occurrence_Of
- (Init_Proc_Level_Formal (Scope (E)), Loc);
-
- -- Normal object - get the level of the enclosing scope
-
- else
- return Make_Level_Literal
- (Scope_Depth (Enclosing_Dynamic_Scope (E)));
- end if;
-
- -- Handle indexed and selected components including the special cases
- -- whereby there is an implicit dereference, a component of a
- -- composite type, or a function call in prefix notation.
-
- -- We don't handle function calls in prefix notation correctly ???
-
- when N_Indexed_Component | N_Selected_Component | N_Slice =>
- Pre := Prefix (E);
-
- -- Fetch the original node when the prefix comes from the result
- -- of expanding a function call since we want to find the level
- -- of the original source call.
-
- if not Comes_From_Source (Pre)
- and then Nkind (Original_Node (Pre)) = N_Function_Call
- then
- Pre := Original_Node (Pre);
- end if;
-
- -- When E is an indexed component or selected component and
- -- the current Expr is a function call, we know that we are
- -- looking at an expanded call in prefix notation.
-
- if Nkind (Expr) = N_Function_Call then
- return Function_Call_Or_Allocator_Level (Expr);
-
- -- If the prefix is a named access type, then we are dealing
- -- with an implicit deferences. In that case the level is that
- -- of the named access type in the prefix.
-
- elsif Is_Named_Access_Type (Etype (Pre)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (Pre)));
-
- -- The current expression is a named access type, so there is no
- -- reason to look at the prefix. Instead obtain the level of E's
- -- named access type.
-
- elsif Is_Named_Access_Type (Etype (E)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (E)));
-
- -- A nondiscriminant selected component where the component
- -- is an anonymous access type means that its associated
- -- level is that of the containing type - see RM 3.10.2 (16).
-
- -- Note that when restriction No_Dynamic_Accessibility_Checks is
- -- in effect we treat discriminant components as regular
- -- components.
-
- elsif
- (Nkind (E) = N_Selected_Component
- and then Ekind (Etype (E)) = E_Anonymous_Access_Type
- and then Ekind (Etype (Pre)) /= E_Anonymous_Access_Type
- and then (not (Nkind (Selector_Name (E)) in N_Has_Entity
- and then Ekind (Entity (Selector_Name (E)))
- = E_Discriminant)
-
- -- The alternative accessibility models both treat
- -- discriminants as regular components.
-
- or else (No_Dynamic_Accessibility_Checks_Enabled (E)
- and then Allow_Alt_Model)))
-
- -- Arrays featuring components of anonymous access components
- -- get their corresponding level from their containing type's
- -- declaration.
-
- or else
- (Nkind (E) = N_Indexed_Component
- and then Ekind (Etype (E)) = E_Anonymous_Access_Type
- and then Ekind (Etype (Pre)) in Array_Kind
- and then Ekind (Component_Type (Base_Type (Etype (Pre))))
- = E_Anonymous_Access_Type)
- then
- -- When restriction No_Dynamic_Accessibility_Checks is active
- -- and -gnatd_b set, the level is that of the designated type.
-
- if Allow_Alt_Model
- and then No_Dynamic_Accessibility_Checks_Enabled (E)
- and then Debug_Flag_Underscore_B
- then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (E)));
- end if;
-
- -- Otherwise proceed normally
-
- return Make_Level_Literal
- (Typ_Access_Level (Etype (Prefix (E))));
-
- -- The accessibility calculation routine that handles function
- -- calls (Function_Call_Level) assumes, in the case the
- -- result is of an anonymous access type, that the result will be
- -- used "in its entirety" when the call is present within an
- -- assignment or object declaration.
-
- -- To properly handle cases where the result is not used in its
- -- entirety, we test if the prefix of the component in question is
- -- a function call, which tells us that one of its components has
- -- been identified and is being accessed. Therefore we can
- -- conclude that the result is not used "in its entirety"
- -- according to RM 3.10.2 (10.2/3).
-
- elsif Nkind (Pre) = N_Function_Call
- and then not Is_Named_Access_Type (Etype (Pre))
- then
- -- Dynamic checks are generated when we are within a return
- -- value or we are in a function call within an anonymous
- -- access discriminant constraint of a return object (signified
- -- by In_Return_Context) on the side of the callee.
-
- -- So, in this case, return a library accessibility level to
- -- null out the check on the side of the caller.
-
- if (In_Return_Value (E)
- or else In_Return_Context)
- and then Level /= Dynamic_Level
- then
- return Make_Level_Literal
- (Scope_Depth (Standard_Standard));
- end if;
-
- return Make_Level_Literal
- (Innermost_Master_Scope_Depth (Expr));
-
- -- Otherwise, continue recursing over the expression prefixes
-
- else
- return Accessibility_Level (Prefix (E));
- end if;
-
- -- Qualified expressions
-
- when N_Qualified_Expression =>
- if Is_Named_Access_Type (Etype (E)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (E)));
- else
- return Accessibility_Level (Expression (E));
- end if;
-
- -- Handle function calls
-
- when N_Function_Call =>
- return Function_Call_Or_Allocator_Level (E);
-
- -- Explicit dereference accessibility level calculation
-
- when N_Explicit_Dereference =>
- Pre := Original_Node (Prefix (E));
-
- -- The prefix is a named access type so the level is taken from
- -- its type.
-
- if Is_Named_Access_Type (Etype (Pre)) then
- return Make_Level_Literal (Typ_Access_Level (Etype (Pre)));
-
- -- Otherwise, recurse deeper
-
- else
- return Accessibility_Level (Prefix (E));
- end if;
-
- -- Type conversions
-
- when N_Type_Conversion | N_Unchecked_Type_Conversion =>
- -- View conversions are special in that they require use to
- -- inspect the expression of the type conversion.
-
- -- Allocators of anonymous access types are internally generated,
- -- so recurse deeper in that case as well.
-
- if Is_View_Conversion (E)
- or else Ekind (Etype (E)) = E_Anonymous_Access_Type
- then
- return Accessibility_Level (Expression (E));
-
- -- We don't care about the master if we are looking at a named
- -- access type.
-
- elsif Is_Named_Access_Type (Etype (E)) then
- return Make_Level_Literal
- (Typ_Access_Level (Etype (E)));
-
- -- In section RM 3.10.2 (10/4) the accessibility rules for
- -- aggregates and value conversions are outlined. Are these
- -- followed in the case of initialization of an object ???
-
- -- Should use Innermost_Master_Scope_Depth ???
-
- else
- return Accessibility_Level (Current_Scope);
- end if;
-
- -- Default to the type accessibility level for the type of the
- -- expression's entity.
-
- when others =>
- return Make_Level_Literal (Typ_Access_Level (Etype (E)));
- end case;
- end Accessibility_Level;
-
- --------------------------------
- -- Static_Accessibility_Level --
- --------------------------------
-
- function Static_Accessibility_Level
- (Expr : Node_Id;
- Level : Static_Accessibility_Level_Kind;
- In_Return_Context : Boolean := False) return Uint
- is
- begin
- return Intval
- (Accessibility_Level (Expr, Level, In_Return_Context));
- end Static_Accessibility_Level;
-
----------------------------------
-- Acquire_Warning_Match_String --
----------------------------------
@@ -7431,47 +6697,6 @@ package body Sem_Util is
return Is_Class_Wide_Type (Typ) or else Needs_Finalization (Typ);
end CW_Or_Needs_Finalization;
- -------------------------------
- -- Deepest_Type_Access_Level --
- -------------------------------
-
- function Deepest_Type_Access_Level
- (Typ : Entity_Id;
- Allow_Alt_Model : Boolean := True) return Uint
- is
- begin
- if Ekind (Typ) = E_Anonymous_Access_Type
- and then not Is_Local_Anonymous_Access (Typ)
- and then Nkind (Associated_Node_For_Itype (Typ)) = N_Object_Declaration
- then
- -- No_Dynamic_Accessibility_Checks override for alternative
- -- accessibility model.
-
- if Allow_Alt_Model
- and then No_Dynamic_Accessibility_Checks_Enabled (Typ)
- then
- return Type_Access_Level (Typ, Allow_Alt_Model);
- end if;
-
- -- Typ is the type of an Ada 2012 stand-alone object of an anonymous
- -- access type.
-
- return
- Scope_Depth (Enclosing_Dynamic_Scope
- (Defining_Identifier
- (Associated_Node_For_Itype (Typ))));
-
- -- For generic formal type, return Int'Last (infinite).
- -- See comment preceding Is_Generic_Type call in Type_Access_Level.
-
- elsif Is_Generic_Type (Root_Type (Typ)) then
- return UI_From_Int (Int'Last);
-
- else
- return Type_Access_Level (Typ, Allow_Alt_Model);
- end if;
- end Deepest_Type_Access_Level;
-
---------------------
-- Defining_Entity --
---------------------
@@ -8182,21 +7407,6 @@ package body Sem_Util is
return False;
end Discriminated_Size;
- -----------------------------------
- -- Effective_Extra_Accessibility --
- -----------------------------------
-
- function Effective_Extra_Accessibility (Id : Entity_Id) return Entity_Id is
- begin
- if Present (Renamed_Object (Id))
- and then Is_Entity_Name (Renamed_Object (Id))
- then
- return Effective_Extra_Accessibility (Entity (Renamed_Object (Id)));
- else
- return Extra_Accessibility (Id);
- end if;
- end Effective_Extra_Accessibility;
-
-----------------------------
-- Effective_Reads_Enabled --
-----------------------------
@@ -10776,30 +9986,6 @@ package body Sem_Util is
end if;
end Gather_Components;
- -------------------------------
- -- Get_Dynamic_Accessibility --
- -------------------------------
-
- function Get_Dynamic_Accessibility (E : Entity_Id) return Entity_Id is
- begin
- -- When minimum accessibility is set for E then we utilize it - except
- -- in a few edge cases like the expansion of select statements where
- -- generated subprogram may attempt to unnecessarily use a minimum
- -- accessibility object declared outside of scope.
-
- -- To avoid these situations where expansion may get complex we verify
- -- that the minimum accessibility object is within scope.
-
- if Is_Formal (E)
- and then Present (Minimum_Accessibility (E))
- and then In_Open_Scopes (Scope (Minimum_Accessibility (E)))
- then
- return Minimum_Accessibility (E);
- end if;
-
- return Extra_Accessibility (E);
- end Get_Dynamic_Accessibility;
-
------------------------
-- Get_Actual_Subtype --
------------------------
@@ -12006,85 +11192,6 @@ package body Sem_Util is
end if;
end Get_Views;
- -----------------------
- -- Has_Access_Values --
- -----------------------
-
- function Has_Access_Values (T : Entity_Id) return Boolean
- is
- Typ : constant Entity_Id := Underlying_Type (T);
-
- begin
- -- Case of a private type which is not completed yet. This can only
- -- happen in the case of a generic formal type appearing directly, or
- -- as a component of the type to which this function is being applied
- -- at the top level. Return False in this case, since we certainly do
- -- not know that the type contains access types.
-
- if No (Typ) then
- return False;
-
- elsif Is_Access_Type (Typ) then
- return True;
-
- elsif Is_Array_Type (Typ) then
- return Has_Access_Values (Component_Type (Typ));
-
- elsif Is_Record_Type (Typ) then
- declare
- Comp : Entity_Id;
-
- begin
- -- Loop to check components
-
- Comp := First_Component_Or_Discriminant (Typ);
- while Present (Comp) loop
-
- -- Check for access component, tag field does not count, even
- -- though it is implemented internally using an access type.
-
- if Has_Access_Values (Etype (Comp))
- and then Chars (Comp) /= Name_uTag
- then
- return True;
- end if;
-
- Next_Component_Or_Discriminant (Comp);
- end loop;
- end;
-
- return False;
-
- else
- return False;
- end if;
- end Has_Access_Values;
-
- ---------------------------------------
- -- Has_Anonymous_Access_Discriminant --
- ---------------------------------------
-
- function Has_Anonymous_Access_Discriminant (Typ : Entity_Id) return Boolean
- is
- Disc : Node_Id;
-
- begin
- if not Has_Discriminants (Typ) then
- return False;
- end if;
-
- Disc := First_Discriminant (Typ);
- while Present (Disc) loop
- if Ekind (Etype (Disc)) = E_Anonymous_Access_Type then
- return True;
- end if;
-
- Next_Discriminant (Disc);
- end loop;
-
- return False;
- end Has_Anonymous_Access_Discriminant;
-
------------------------------
-- Has_Compatible_Alignment --
------------------------------
@@ -14382,32 +13489,6 @@ package body Sem_Util is
end if;
end Has_Tagged_Component;
- --------------------------------------------
- -- Has_Unconstrained_Access_Discriminants --
- --------------------------------------------
-
- function Has_Unconstrained_Access_Discriminants
- (Subtyp : Entity_Id) return Boolean
- is
- Discr : Entity_Id;
-
- begin
- if Has_Discriminants (Subtyp)
- and then not Is_Constrained (Subtyp)
- then
- Discr := First_Discriminant (Subtyp);
- while Present (Discr) loop
- if Ekind (Etype (Discr)) = E_Anonymous_Access_Type then
- return True;
- end if;
-
- Next_Discriminant (Discr);
- end loop;
- end if;
-
- return False;
- end Has_Unconstrained_Access_Discriminants;
-
-----------------------------
-- Has_Undefined_Reference --
-----------------------------
@@ -14449,6 +13530,36 @@ package body Sem_Util is
return Has_Undef_Ref;
end Has_Undefined_Reference;
+ ----------------------------------------
+ -- Has_Effectively_Volatile_Component --
+ ----------------------------------------
+
+ function Has_Effectively_Volatile_Component
+ (Typ : Entity_Id) return Boolean
+ is
+ Comp : Entity_Id;
+
+ begin
+ if Has_Volatile_Components (Typ) then
+ return True;
+
+ elsif Is_Array_Type (Typ) then
+ return Is_Effectively_Volatile (Component_Type (Typ));
+
+ elsif Is_Record_Type (Typ) then
+ Comp := First_Component (Typ);
+ while Present (Comp) loop
+ if Is_Effectively_Volatile (Etype (Comp)) then
+ return True;
+ end if;
+
+ Next_Component (Comp);
+ end loop;
+ end if;
+
+ return False;
+ end Has_Effectively_Volatile_Component;
+
----------------------------
-- Has_Volatile_Component --
----------------------------
@@ -15989,28 +15100,6 @@ package body Sem_Util is
end if;
end Invalid_Scalar_Value;
- --------------------------------
- -- Is_Anonymous_Access_Actual --
- --------------------------------
-
- function Is_Anonymous_Access_Actual (N : Node_Id) return Boolean is
- Par : Node_Id;
- begin
- if Ekind (Etype (N)) /= E_Anonymous_Access_Type then
- return False;
- end if;
-
- Par := Parent (N);
- while Present (Par)
- and then Nkind (Par) in N_Case_Expression
- | N_If_Expression
- | N_Parameter_Association
- loop
- Par := Parent (Par);
- end loop;
- return Nkind (Par) in N_Subprogram_Call;
- end Is_Anonymous_Access_Actual;
-
------------------------
-- Is_Access_Variable --
------------------------
@@ -17604,9 +16693,11 @@ package body Sem_Util is
if Is_Type (Id) then
-- An arbitrary type is effectively volatile when it is subject to
- -- pragma Atomic or Volatile.
+ -- pragma Atomic or Volatile, unless No_Caching is enabled.
- if Is_Volatile (Id) then
+ if Is_Volatile (Id)
+ and then not No_Caching_Enabled (Id)
+ then
return True;
-- An array type is effectively volatile when it is subject to pragma
@@ -21224,38 +20315,6 @@ package body Sem_Util is
and then Is_Single_Concurrent_Type (Etype (Id));
end Is_Single_Task_Object;
- --------------------------------------
- -- Is_Special_Aliased_Formal_Access --
- --------------------------------------
-
- function Is_Special_Aliased_Formal_Access
- (Exp : Node_Id;
- In_Return_Context : Boolean := False) return Boolean
- is
- Scop : constant Entity_Id := Current_Subprogram;
- begin
- -- Verify the expression is an access reference to 'Access within a
- -- return statement as this is the only time an explicitly aliased
- -- formal has different semantics.
-
- if Nkind (Exp) /= N_Attribute_Reference
- or else Get_Attribute_Id (Attribute_Name (Exp)) /= Attribute_Access
- or else not (In_Return_Value (Exp)
- or else In_Return_Context)
- or else not Needs_Result_Accessibility_Level (Scop)
- then
- return False;
- end if;
-
- -- Check if the prefix of the reference is indeed an explicitly aliased
- -- formal parameter for the function Scop. Additionally, we must check
- -- that Scop returns an anonymous access type, otherwise the special
- -- rules dictating a need for a dynamic check are not in effect.
-
- return Is_Entity_Name (Prefix (Exp))
- and then Is_Explicitly_Aliased (Entity (Prefix (Exp)));
- end Is_Special_Aliased_Formal_Access;
-
-----------------------------
-- Is_Specific_Tagged_Type --
-----------------------------
@@ -23228,144 +22287,6 @@ package body Sem_Util is
end if;
end Needs_One_Actual;
- --------------------------------------
- -- Needs_Result_Accessibility_Level --
- --------------------------------------
-
- function Needs_Result_Accessibility_Level
- (Func_Id : Entity_Id) return Boolean
- is
- Func_Typ : constant Entity_Id := Underlying_Type (Etype (Func_Id));
-
- function Has_Unconstrained_Access_Discriminant_Component
- (Comp_Typ : Entity_Id) return Boolean;
- -- Returns True if any component of the type has an unconstrained access
- -- discriminant.
-
- -----------------------------------------------------
- -- Has_Unconstrained_Access_Discriminant_Component --
- -----------------------------------------------------
-
- function Has_Unconstrained_Access_Discriminant_Component
- (Comp_Typ : Entity_Id) return Boolean
- is
- begin
- if not Is_Limited_Type (Comp_Typ) then
- return False;
-
- -- Only limited types can have access discriminants with
- -- defaults.
-
- elsif Has_Unconstrained_Access_Discriminants (Comp_Typ) then
- return True;
-
- elsif Is_Array_Type (Comp_Typ) then
- return Has_Unconstrained_Access_Discriminant_Component
- (Underlying_Type (Component_Type (Comp_Typ)));
-
- elsif Is_Record_Type (Comp_Typ) then
- declare
- Comp : Entity_Id;
-
- begin
- Comp := First_Component (Comp_Typ);
- while Present (Comp) loop
- if Has_Unconstrained_Access_Discriminant_Component
- (Underlying_Type (Etype (Comp)))
- then
- return True;
- end if;
-
- Next_Component (Comp);
- end loop;
- end;
- end if;
-
- return False;
- end Has_Unconstrained_Access_Discriminant_Component;
-
- Disable_Tagged_Cases : constant Boolean := True;
- -- Flag used to temporarily disable a "True" result for tagged types.
- -- See comments further below for details.
-
- -- Start of processing for Needs_Result_Accessibility_Level
-
- begin
- -- False if completion unavailable, which can happen when we are
- -- analyzing an abstract subprogram or if the subprogram has
- -- delayed freezing.
-
- if No (Func_Typ) then
- return False;
-
- -- False if not a function, also handle enum-lit renames case
-
- elsif Func_Typ = Standard_Void_Type
- or else Is_Scalar_Type (Func_Typ)
- then
- return False;
-
- -- Handle a corner case, a cross-dialect subp renaming. For example,
- -- an Ada 2012 renaming of an Ada 2005 subprogram. This can occur when
- -- an Ada 2005 (or earlier) unit references predefined run-time units.
-
- elsif Present (Alias (Func_Id)) then
-
- -- Unimplemented: a cross-dialect subp renaming which does not set
- -- the Alias attribute (e.g., a rename of a dereference of an access
- -- to subprogram value). ???
-
- return Present (Extra_Accessibility_Of_Result (Alias (Func_Id)));
-
- -- Remaining cases require Ada 2012 mode, unless they are dispatching
- -- operations, since they may be overridden by Ada_2012 primitives.
-
- elsif Ada_Version < Ada_2012
- and then not Is_Dispatching_Operation (Func_Id)
- then
- return False;
-
- -- Handle the situation where a result is an anonymous access type
- -- RM 3.10.2 (10.3/3).
-
- elsif Ekind (Func_Typ) = E_Anonymous_Access_Type then
- return True;
-
- -- In the case of, say, a null tagged record result type, the need for
- -- this extra parameter might not be obvious so this function returns
- -- True for all tagged types for compatibility reasons.
-
- -- A function with, say, a tagged null controlling result type might
- -- be overridden by a primitive of an extension having an access
- -- discriminant and the overrider and overridden must have compatible
- -- calling conventions (including implicitly declared parameters).
-
- -- Similarly, values of one access-to-subprogram type might designate
- -- both a primitive subprogram of a given type and a function which is,
- -- for example, not a primitive subprogram of any type. Again, this
- -- requires calling convention compatibility. It might be possible to
- -- solve these issues by introducing wrappers, but that is not the
- -- approach that was chosen.
-
- -- Note: Despite the reasoning noted above, the extra accessibility
- -- parameter for tagged types is disabled for performance reasons.
-
- elsif Is_Tagged_Type (Func_Typ) then
- return not Disable_Tagged_Cases;
-
- elsif Has_Unconstrained_Access_Discriminants (Func_Typ) then
- return True;
-
- elsif Has_Unconstrained_Access_Discriminant_Component (Func_Typ) then
- return True;
-
- -- False for all other cases
-
- else
- return False;
- end if;
- end Needs_Result_Accessibility_Level;
-
----------------------------
-- Needs_Secondary_Stack --
----------------------------
@@ -25690,7 +24611,6 @@ package body Sem_Util is
------------------------
function No_Caching_Enabled (Id : Entity_Id) return Boolean is
- pragma Assert (Ekind (Id) = E_Variable);
Prag : constant Node_Id := Get_Pragma (Id, Pragma_No_Caching);
Arg1 : Node_Id;
@@ -29179,19 +28099,6 @@ package body Sem_Util is
and then Has_Loop_Entry_Attributes (Entity (Identifier (Stmt)));
end Subject_To_Loop_Entry_Attributes;
- -----------------------------
- -- Subprogram_Access_Level --
- -----------------------------
-
- function Subprogram_Access_Level (Subp : Entity_Id) return Uint is
- begin
- if Present (Alias (Subp)) then
- return Subprogram_Access_Level (Alias (Subp));
- else
- return Scope_Depth (Enclosing_Dynamic_Scope (Subp));
- end if;
- end Subprogram_Access_Level;
-
---------------------
-- Subprogram_Name --
---------------------
@@ -29651,179 +28558,6 @@ package body Sem_Util is
Discard := Traverse (Node);
end Traverse_More_Proc;
- -----------------------
- -- Type_Access_Level --
- -----------------------
-
- function Type_Access_Level
- (Typ : Entity_Id;
- Allow_Alt_Model : Boolean := True;
- Assoc_Ent : Entity_Id := Empty) return Uint
- is
- Btyp : Entity_Id := Base_Type (Typ);
- Def_Ent : Entity_Id;
-
- begin
- -- Ada 2005 (AI-230): For most cases of anonymous access types, we
- -- simply use the level where the type is declared. This is true for
- -- stand-alone object declarations, and for anonymous access types
- -- associated with components the level is the same as that of the
- -- enclosing composite type. However, special treatment is needed for
- -- the cases of access parameters, return objects of an anonymous access
- -- type, and, in Ada 95, access discriminants of limited types.
-
- if Is_Access_Type (Btyp) then
- if Ekind (Btyp) = E_Anonymous_Access_Type then
- -- No_Dynamic_Accessibility_Checks restriction override for
- -- alternative accessibility model.
-
- if Allow_Alt_Model
- and then No_Dynamic_Accessibility_Checks_Enabled (Btyp)
- then
- -- In the -gnatd_b model, the level of an anonymous access
- -- type is always that of the designated type.
-
- if Debug_Flag_Underscore_B then
- return Type_Access_Level
- (Designated_Type (Btyp), Allow_Alt_Model);
- end if;
-
- -- When an anonymous access type's Assoc_Ent is specified,
- -- calculate the result based on the general accessibility
- -- level routine.
-
- -- We would like to use Associated_Node_For_Itype here instead,
- -- but in some cases it is not fine grained enough ???
-
- if Present (Assoc_Ent) then
- return Static_Accessibility_Level
- (Assoc_Ent, Object_Decl_Level);
- end if;
-
- -- Otherwise take the context of the anonymous access type into
- -- account.
-
- -- Obtain the defining entity for the internally generated
- -- anonymous access type.
-
- Def_Ent := Defining_Entity_Or_Empty
- (Associated_Node_For_Itype (Typ));
-
- if Present (Def_Ent) then
- -- When the defining entity is a subprogram then we know the
- -- anonymous access type Typ has been generated to either
- -- describe an anonymous access type formal or an anonymous
- -- access result type.
-
- -- Since we are only interested in the formal case, avoid
- -- the anonymous access result type.
-
- if Is_Subprogram (Def_Ent)
- and then not (Ekind (Def_Ent) = E_Function
- and then Etype (Def_Ent) = Typ)
- then
- -- When the type comes from an anonymous access
- -- parameter, the level is that of the subprogram
- -- declaration.
-
- return Scope_Depth (Def_Ent);
-
- -- When the type is an access discriminant, the level is
- -- that of the type.
-
- elsif Ekind (Def_Ent) = E_Discriminant then
- return Scope_Depth (Scope (Def_Ent));
- end if;
- end if;
-
- -- If the type is a nonlocal anonymous access type (such as for
- -- an access parameter) we treat it as being declared at the
- -- library level to ensure that names such as X.all'access don't
- -- fail static accessibility checks.
-
- elsif not Is_Local_Anonymous_Access (Typ) then
- return Scope_Depth (Standard_Standard);
-
- -- If this is a return object, the accessibility level is that of
- -- the result subtype of the enclosing function. The test here is
- -- little complicated, because we have to account for extended
- -- return statements that have been rewritten as blocks, in which
- -- case we have to find and the Is_Return_Object attribute of the
- -- itype's associated object. It would be nice to find a way to
- -- simplify this test, but it doesn't seem worthwhile to add a new
- -- flag just for purposes of this test. ???
-
- elsif Ekind (Scope (Btyp)) = E_Return_Statement
- or else
- (Is_Itype (Btyp)
- and then Nkind (Associated_Node_For_Itype (Btyp)) =
- N_Object_Declaration
- and then Is_Return_Object
- (Defining_Identifier
- (Associated_Node_For_Itype (Btyp))))
- then
- declare
- Scop : Entity_Id;
-
- begin
- Scop := Scope (Scope (Btyp));
- while Present (Scop) loop
- exit when Ekind (Scop) = E_Function;
- Scop := Scope (Scop);
- end loop;
-
- -- Treat the return object's type as having the level of the
- -- function's result subtype (as per RM05-6.5(5.3/2)).
-
- return Type_Access_Level (Etype (Scop), Allow_Alt_Model);
- end;
- end if;
- end if;
-
- Btyp := Root_Type (Btyp);
-
- -- The accessibility level of anonymous access types associated with
- -- discriminants is that of the current instance of the type, and
- -- that's deeper than the type itself (AARM 3.10.2 (12.3.21)).
-
- -- AI-402: access discriminants have accessibility based on the
- -- object rather than the type in Ada 2005, so the above paragraph
- -- doesn't apply.
-
- -- ??? Needs completion with rules from AI-416
-
- if Ada_Version <= Ada_95
- and then Ekind (Typ) = E_Anonymous_Access_Type
- and then Present (Associated_Node_For_Itype (Typ))
- and then Nkind (Associated_Node_For_Itype (Typ)) =
- N_Discriminant_Specification
- then
- return Scope_Depth (Enclosing_Dynamic_Scope (Btyp)) + 1;
- end if;
- end if;
-
- -- Return library level for a generic formal type. This is done because
- -- RM(10.3.2) says that "The statically deeper relationship does not
- -- apply to ... a descendant of a generic formal type". Rather than
- -- checking at each point where a static accessibility check is
- -- performed to see if we are dealing with a formal type, this rule is
- -- implemented by having Type_Access_Level and Deepest_Type_Access_Level
- -- return extreme values for a formal type; Deepest_Type_Access_Level
- -- returns Int'Last. By calling the appropriate function from among the
- -- two, we ensure that the static accessibility check will pass if we
- -- happen to run into a formal type. More specifically, we should call
- -- Deepest_Type_Access_Level instead of Type_Access_Level whenever the
- -- call occurs as part of a static accessibility check and the error
- -- case is the case where the type's level is too shallow (as opposed
- -- to too deep).
-
- if Is_Generic_Type (Root_Type (Btyp)) then
- return Scope_Depth (Standard_Standard);
- end if;
-
- return Scope_Depth (Enclosing_Dynamic_Scope (Btyp));
- end Type_Access_Level;
-
------------------------------------
-- Type_Without_Stream_Operation --
------------------------------------
diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads
index e651b20..b647e68 100644
--- a/gcc/ada/sem_util.ads
+++ b/gcc/ada/sem_util.ads
@@ -44,40 +44,6 @@ package Sem_Util is
-- including the cases where there can't be any because e.g. the type is
-- not tagged.
- type Accessibility_Level_Kind is
- (Dynamic_Level,
- Object_Decl_Level,
- Zero_On_Dynamic_Level);
- -- Accessibility_Level_Kind is an enumerated type which captures the
- -- different modes in which an accessibility level could be obtained for
- -- a given expression.
-
- -- When in the context of the function Accessibility_Level,
- -- Accessibility_Level_Kind signals what type of accessibility level to
- -- obtain. For example, when Level is Dynamic_Level, a defining identifier
- -- associated with a SAOOAAT may be returned or an N_Integer_Literal node.
- -- When the level is Object_Decl_Level, an N_Integer_Literal node is
- -- returned containing the level of the declaration of the object if
- -- relevant (be it a SAOOAAT or otherwise). Finally, Zero_On_Dynamic_Level
- -- returns library level for all cases where the accessibility level is
- -- dynamic (used to bypass static accessibility checks in dynamic cases).
-
- function Accessibility_Level
- (Expr : Node_Id;
- Level : Accessibility_Level_Kind;
- In_Return_Context : Boolean := False;
- Allow_Alt_Model : Boolean := True) return Node_Id;
- -- Centralized accessibility level calculation routine for finding the
- -- accessibility level of a given expression Expr.
-
- -- In_Return_Context forces the Accessibility_Level calculations to be
- -- carried out "as if" Expr existed in a return value. This is useful for
- -- calculating the accessibility levels for discriminant associations
- -- and return aggregates.
-
- -- The Allow_Alt_Model parameter allows the alternative level calculation
- -- under the restriction No_Dynamic_Accessibility_Checks to be performed.
-
function Acquire_Warning_Match_String (Str_Lit : Node_Id) return String;
-- Used by pragma Warnings (Off, string), and Warn_As_Error (string) to get
-- the given string argument, adding leading and trailing asterisks if they
@@ -696,22 +662,6 @@ package Sem_Util is
-- as Needs_Finalization except with pragma Restrictions (No_Finalization),
-- in which case we know that class-wide objects do not need finalization.
- function Deepest_Type_Access_Level
- (Typ : Entity_Id;
- Allow_Alt_Model : Boolean := True) return Uint;
-
- -- Same as Type_Access_Level, except that if the type is the type of an Ada
- -- 2012 stand-alone object of an anonymous access type, then return the
- -- static accessibility level of the object. In that case, the dynamic
- -- accessibility level of the object may take on values in a range. The low
- -- bound of that range is returned by Type_Access_Level; this function
- -- yields the high bound of that range. Also differs from Type_Access_Level
- -- in the case of a descendant of a generic formal type (returns Int'Last
- -- instead of 0).
-
- -- The Allow_Alt_Model parameter allows the alternative level calculation
- -- under the restriction No_Dynamic_Accessibility_Checks to be performed.
-
function Defining_Entity (N : Node_Id) return Entity_Id;
-- Given a declaration N, returns the associated defining entity. If the
-- declaration has a specification, the entity is obtained from the
@@ -786,10 +736,6 @@ package Sem_Util is
-- private components of protected objects, but is generally useful when
-- restriction No_Implicit_Heap_Allocation is active.
- function Effective_Extra_Accessibility (Id : Entity_Id) return Entity_Id;
- -- Same as Einfo.Extra_Accessibility except thtat object renames
- -- are looked through.
-
function Effective_Reads_Enabled (Id : Entity_Id) return Boolean;
-- Id should be the entity of a state abstraction, an object, or a type.
-- Returns True iff Id is subject to external property Effective_Reads.
@@ -1146,10 +1092,6 @@ package Sem_Util is
-- discriminants. Otherwise all components of the parent must be included
-- in the subtype for semantic analysis.
- function Get_Dynamic_Accessibility (E : Entity_Id) return Entity_Id;
- -- Obtain the accessibility level for a given entity formal taking into
- -- account both extra and minimum accessibility.
-
function Get_Actual_Subtype (N : Node_Id) return Entity_Id;
-- Given a node for an expression, obtain the actual subtype of the
-- expression. In the case of a parameter where the formal is an
@@ -1393,18 +1335,6 @@ package Sem_Util is
-- don't look inside packed array types. If Recurse is False, just
-- go down one level (so it's no longer the "fullest" view).
- function Has_Access_Values (T : Entity_Id) return Boolean;
- -- Returns true if the underlying type of T is an access type, or has a
- -- component (at any recursive level) that is an access type. This is a
- -- conservative predicate, if it is not known whether or not T contains
- -- access values (happens for generic formals in some cases), then False is
- -- returned. Note that tagged types return False. Even though the tag is
- -- implemented as an access type internally, this function tests only for
- -- access types known to the programmer. See also Has_Tagged_Component.
-
- function Has_Anonymous_Access_Discriminant (Typ : Entity_Id) return Boolean;
- -- Returns True if Typ has one or more anonymous access discriminants
-
type Alignment_Result is (Known_Compatible, Unknown, Known_Incompatible);
-- Result of Has_Compatible_Alignment test, description found below. Note
-- that the values are arranged in increasing order of problematicness.
@@ -1544,20 +1474,6 @@ package Sem_Util is
-- Return True if the loop has no side effect and can therefore be
-- marked for removal. Return False if N is not a N_Loop_Statement.
- subtype Static_Accessibility_Level_Kind
- is Accessibility_Level_Kind range Object_Decl_Level
- .. Zero_On_Dynamic_Level;
- -- Restrict the reange of Accessibility_Level_Kind to be non-dynamic for
- -- use in the static version of Accessibility_Level below.
-
- function Static_Accessibility_Level
- (Expr : Node_Id;
- Level : Static_Accessibility_Level_Kind;
- In_Return_Context : Boolean := False) return Uint;
- -- Overloaded version of Accessibility_Level which returns a universal
- -- integer for use in compile-time checking. Note: Level is restricted to
- -- be non-dynamic.
-
function Is_Newly_Constructed
(Exp : Node_Id; Context_Requires_NC : Boolean) return Boolean;
-- Indicates whether a given expression is "newly constructed" (RM 4.4).
@@ -1644,15 +1560,15 @@ package Sem_Util is
-- a tagged type or has a subcomponent that is tagged. Returns False for a
-- noncomposite type, or if no tagged subcomponents are present.
- function Has_Unconstrained_Access_Discriminants
- (Subtyp : Entity_Id) return Boolean;
- -- Returns True if the given subtype is unconstrained and has one or more
- -- access discriminants.
-
function Has_Undefined_Reference (Expr : Node_Id) return Boolean;
-- Given arbitrary expression Expr, determine whether it contains at
-- least one name whose entity is Any_Id.
+ function Has_Effectively_Volatile_Component
+ (Typ : Entity_Id) return Boolean;
+ -- Given arbitrary type Typ, determine whether it contains at least one
+ -- effectively volatile component.
+
function Has_Volatile_Component (Typ : Entity_Id) return Boolean;
-- Given arbitrary type Typ, determine whether it contains at least one
-- volatile component.
@@ -1822,10 +1738,6 @@ package Sem_Util is
-- pragma Initialize_Scalars or by the binder. Return an expression created
-- at source location Loc, which denotes the invalid value.
- function Is_Anonymous_Access_Actual (N : Node_Id) return Boolean;
- -- Determine if N is used as an actual for a call whose corresponding
- -- formal is of an anonymous access type.
-
function Is_Access_Subprogram_Wrapper (E : Entity_Id) return Boolean;
-- True if E is the constructed wrapper for an access_to_subprogram
-- type with Pre/Postconditions.
@@ -2400,21 +2312,6 @@ package Sem_Util is
-- Determine whether arbitrary entity Id denotes the anonymous object
-- created for a single task type.
- function Is_Special_Aliased_Formal_Access
- (Exp : Node_Id;
- In_Return_Context : Boolean := False) return Boolean;
- -- Determines whether a dynamic check must be generated for explicitly
- -- aliased formals within a function Scop for the expression Exp.
-
- -- In_Return_Context forces Is_Special_Aliased_Formal_Access to assume
- -- that Exp is within a return value which is useful for checking
- -- expressions within discriminant associations of return objects.
-
- -- More specially, Is_Special_Aliased_Formal_Access checks that Exp is a
- -- 'Access attribute reference within a return statement where the ultimate
- -- prefix is an aliased formal of Scop and that Scop returns an anonymous
- -- access type. See RM 3.10.2 for more details.
-
function Is_Specific_Tagged_Type (Typ : Entity_Id) return Boolean;
-- Determine whether an arbitrary [private] type is specifically tagged
@@ -2692,12 +2589,6 @@ package Sem_Util is
-- syntactic ambiguity that results from an indexing of a function call
-- that returns an array, so that Obj.F (X, Y) may mean F (Ob) (X, Y).
- function Needs_Result_Accessibility_Level
- (Func_Id : Entity_Id) return Boolean;
- -- Ada 2012 (AI05-0234): Return True if the function needs an implicit
- -- parameter to identify the accessibility level of the function result
- -- "determined by the point of call".
-
function Needs_Secondary_Stack (Id : Entity_Id) return Boolean;
-- Return true if functions whose result type is Id must return on the
-- secondary stack, i.e. allocate the return object on this stack.
@@ -2872,9 +2763,9 @@ package Sem_Util is
-- inline this procedural form, but not the functional form above.
function No_Caching_Enabled (Id : Entity_Id) return Boolean;
- -- Given the entity of a variable, determine whether Id is subject to
- -- volatility property No_Caching and if it is, the related expression
- -- evaluates to True.
+ -- Given any entity Id, determine whether Id is subject to volatility
+ -- property No_Caching and if it is, the related expression evaluates
+ -- to True.
function No_Heap_Finalization (Typ : Entity_Id) return Boolean;
-- Determine whether type Typ is subject to pragma No_Heap_Finalization
@@ -3340,9 +3231,6 @@ package Sem_Util is
-- Determine whether node N is a loop statement subject to at least one
-- 'Loop_Entry attribute.
- function Subprogram_Access_Level (Subp : Entity_Id) return Uint;
- -- Return the accessibility level of the view denoted by Subp
-
function Support_Atomic_Primitives (Typ : Entity_Id) return Boolean;
-- Return True if Typ supports the GCC built-in atomic operations (i.e. if
-- Typ is properly sized and aligned).
@@ -3373,19 +3261,6 @@ package Sem_Util is
-- returned, i.e. Traverse_More_Func is called and the result is simply
-- discarded.
- function Type_Access_Level
- (Typ : Entity_Id;
- Allow_Alt_Model : Boolean := True;
- Assoc_Ent : Entity_Id := Empty) return Uint;
- -- Return the accessibility level of Typ
-
- -- The Allow_Alt_Model parameter allows the alternative level calculation
- -- under the restriction No_Dynamic_Accessibility_Checks to be performed.
-
- -- Assoc_Ent allows for the optional specification of the entity associated
- -- with Typ. This gets utilized mostly for anonymous access type
- -- processing, where context matters in interpreting Typ's level.
-
function Type_Without_Stream_Operation
(T : Entity_Id;
Op : TSS_Name_Type := TSS_Null) return Entity_Id;
diff --git a/gcc/ada/sem_warn.adb b/gcc/ada/sem_warn.adb
index cbfabd2..cb2a381 100644
--- a/gcc/ada/sem_warn.adb
+++ b/gcc/ada/sem_warn.adb
@@ -23,6 +23,7 @@
-- --
------------------------------------------------------------------------------
+with Accessibility; use Accessibility;
with Atree; use Atree;
with Debug; use Debug;
with Einfo; use Einfo;
@@ -3289,6 +3290,44 @@ package body Sem_Warn is
Left : constant Node_Id := Left_Opnd (Op);
Right : constant Node_Id := Right_Opnd (Op);
+ function Comes_From_Simple_Condition_In_Source
+ (Op : Node_Id) return Boolean;
+ -- Return True if Op comes from a simple condition present in the source
+
+ -------------------------------------------
+ -- Comes_From_Simple_Condition_In_Source --
+ -------------------------------------------
+
+ function Comes_From_Simple_Condition_In_Source
+ (Op : Node_Id) return Boolean
+ is
+ Orig_Op : constant Node_Id := Original_Node (Op);
+
+ begin
+ if not Comes_From_Source (Orig_Op) then
+ return False;
+ end if;
+
+ -- We do not want to give warnings on a membership test with a mark
+ -- for a subtype that is predicated, see also Exp_Ch4.Expand_N_In.
+
+ if Nkind (Orig_Op) = N_In then
+ declare
+ Orig_Rop : constant Node_Id :=
+ Original_Node (Right_Opnd (Orig_Op));
+ begin
+ if Is_Entity_Name (Orig_Rop)
+ and then Is_Type (Entity (Orig_Rop))
+ and then Present (Predicate_Function (Entity (Orig_Rop)))
+ then
+ return False;
+ end if;
+ end;
+ end if;
+
+ return True;
+ end Comes_From_Simple_Condition_In_Source;
+
True_Result : Boolean;
False_Result : Boolean;
@@ -3297,7 +3336,7 @@ package body Sem_Warn is
-- scalar operands are valid.
if Constant_Condition_Warnings
- and then Comes_From_Source (Original_Node (Op))
+ and then Comes_From_Simple_Condition_In_Source (Op)
and then Is_Scalar_Type (Etype (Left))
and then Is_Scalar_Type (Etype (Right))
diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads
index c41b0f2..104ee66 100644
--- a/gcc/ada/sinfo.ads
+++ b/gcc/ada/sinfo.ads
@@ -842,10 +842,6 @@ package Sinfo is
-- known at compile time, this field points to an N_Range node with those
-- bounds. Otherwise Empty.
- -- Alloc_For_BIP_Return
- -- Present in N_Allocator nodes. True if the allocator is one of those
- -- generated for a build-in-place return statement.
-
-- All_Others
-- Present in an N_Others_Choice node. This flag is set for an others
-- exception where all exceptions are to be caught, even those that are
@@ -953,6 +949,11 @@ package Sinfo is
-- Present in N_Simple_Return_Statement nodes. True if this node was
-- constructed as part of the N_Extended_Return_Statement expansion.
+ -- Comes_From_Iterator
+ -- Present in N_Object_Renaming_Declaration nodes. True if this node was
+ -- was constructed as part of the expansion of an iterator
+ -- specification.
+
-- Compile_Time_Known_Aggregate
-- Present in N_Aggregate nodes. Set for aggregates which can be fully
-- evaluated at compile time without raising constraint error. Such
@@ -1339,6 +1340,10 @@ package Sinfo is
-- cannot figure it out. If both flags Forwards_OK and Backwards_OK are
-- set, it means that the front end can assure no overlap of operands.
+ -- For_Special_Return_Object
+ -- Present in N_Allocator nodes. True if the allocator is generated for
+ -- the initialization of a special return object.
+
-- From_Aspect_Specification
-- Processing of aspect specifications typically results in insertion in
-- the tree of corresponding pragma or attribute definition clause nodes.
@@ -4772,7 +4777,7 @@ package Sinfo is
-- Subpool_Handle_Name (set to Empty if not present)
-- Storage_Pool
-- Procedure_To_Call
- -- Alloc_For_BIP_Return
+ -- For_Special_Return_Object
-- Null_Exclusion_Present
-- No_Initialization
-- Is_Static_Coextension
diff --git a/gcc/ada/treepr.adb b/gcc/ada/treepr.adb
index a9f4088..a0f45c4 100644
--- a/gcc/ada/treepr.adb
+++ b/gcc/ada/treepr.adb
@@ -269,8 +269,9 @@ package body Treepr is
function Image (F : Node_Or_Entity_Field) return String is
begin
case F is
- when F_Alloc_For_BIP_Return =>
- return "Alloc_For_BIP_Return";
+ -- We special case the following; otherwise the compiler will use
+ -- the usual Mixed_Case convention.
+
when F_Assignment_OK =>
return "Assignment_OK";
when F_Backwards_OK =>
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog
index aa7ce88..9a4bb25 100644
--- a/gcc/analyzer/ChangeLog
+++ b/gcc/analyzer/ChangeLog
@@ -1,3 +1,332 @@
+2022-12-06 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/107882
+ * region-model.cc (region_model::get_store_value): Return an
+ unknown value for empty regions.
+ (region_model::set_value): Bail on empty regions.
+ * region.cc (region::empty_p): New.
+ * region.h (region::empty_p): New decl.
+ * state-purge.cc (same_binding_p): Bail if either region is empty.
+ * store.cc (binding_key::make): Assert that a concrete binding's
+ bit_size must be > 0.
+ (binding_cluster::mark_region_as_unknown): Bail on empty regions.
+ (binding_cluster::get_binding): Likewise.
+ (binding_cluster::remove_overlapping_bindings): Likewise.
+ (binding_cluster::on_unknown_fncall): Don't conjure values for
+ empty regions.
+ (store::fill_region): Bail on empty regions.
+ * store.h (class concrete_binding): Update comment to reflect that
+ the range of bits must be non-empty.
+ (concrete_binding::concrete_binding): Assert that bit range is
+ non-empty.
+
+2022-12-06 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106325
+ * region-model-manager.cc
+ (region_model_manager::get_or_create_null_ptr): New.
+ * region-model-manager.h
+ (region_model_manager::get_or_create_null_ptr): New decl.
+ * region-model.cc (region_model::on_top_level_param): Add
+ "nonnull" param and make use of it.
+ (region_model::push_frame): When handling a top-level entrypoint
+ to the analysis, determine which params __attribute__((nonnull))
+ applies to, and pass to on_top_level_param.
+ * region-model.h (region_model::on_top_level_param): Add "nonnull"
+ param.
+
+2022-12-06 David Malcolm <dmalcolm@redhat.com>
+
+ * analyzer.h (register_known_analyzer_functions): New decl.
+ (register_known_functions_lang_cp): New decl.
+ * call-details.cc: New file, split out from
+ region-model-impl-calls.cc.
+ * call-details.h: New file, split out from region-model.h.
+ * call-info.cc: Include "analyzer/call-details.h".
+ * call-summary.h: Likewise.
+ * kf-analyzer.cc: New file, split out from
+ region-model-impl-calls.cc.
+ * kf-lang-cp.cc: Likewise.
+ * known-function-manager.cc: Include "analyzer/call-details.h".
+ * region-model-impl-calls.cc: Move definitions of call_details's
+ member functions to call-details.cc. Move class kf_analyzer_* to
+ kf-analyzer.cc. Move kf_operator_new and kf_operator_delete to
+ kf-lang-cp.cc. Refresh #includes accordingly.
+ (register_known_functions): Replace registration of __analyzer_*
+ functions with a call to register_known_analyzer_functions.
+ Replace registration of C++ support functions with a call to
+ register_known_functions_lang_cp.
+ * region-model.h (class call_details): Move to new call-details.h.
+ * sm-fd.cc: Include "analyzer/call-details.h".
+ * sm-file.cc: Likewise.
+ * sm-malloc.cc: Likewise.
+ * varargs.cc: Likewise.
+
+2022-12-02 David Malcolm <dmalcolm@redhat.com>
+
+ * analyzer.h (struct event_loc_info): New forward decl.
+ * bounds-checking.cc: Use event_loc_info throughout to bundle the
+ loc, fndecl, depth triples.
+ * call-info.cc: Likewise.
+ * checker-event.cc: Likewise.
+ * checker-event.h (struct event_loc_info): New decl. Use it
+ throughout to bundle the loc, fndecl, depth triples.
+ * checker-path.cc: Likewise.
+ * checker-path.h: Likewise.
+ * diagnostic-manager.cc: Likewise.
+ * engine.cc: Likewise.
+ * infinite-recursion.cc: Likewise.
+ * pending-diagnostic.cc: Likewise.
+ * pending-diagnostic.h: Likewise.
+ * region-model.cc: Likewise.
+ * sm-signal.cc: Likewise.
+ * varargs.cc: Likewise.
+
+2022-12-02 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/107851
+ * analyzer.cc (make_label_text_n): Convert param "n" from int to
+ unsigned HOST_WIDE_INT.
+ * analyzer.h (make_label_text_n): Likewise for decl.
+ * bounds-checking.cc: Include "analyzer/checker-event.h" and
+ "analyzer/checker-path.h".
+ (out_of_bounds::add_region_creation_events): New.
+ (concrete_past_the_end::describe_region_creation_event): Replace
+ with...
+ (concrete_past_the_end::add_region_creation_events): ...this.
+ (symbolic_past_the_end::describe_region_creation_event): Delete.
+ * checker-event.cc (region_creation_event::region_creation_event):
+ Update for dropping all member data.
+ (region_creation_event::get_desc): Delete, splitting out into
+ region_creation_event_memory_space::get_desc,
+ region_creation_event_capacity::get_desc, and
+ region_creation_event_debug::get_desc.
+ (region_creation_event_memory_space::get_desc): New.
+ (region_creation_event_capacity::get_desc): New.
+ (region_creation_event_allocation_size::get_desc): New.
+ (region_creation_event_debug::get_desc): New.
+ * checker-event.h: Include "analyzer/program-state.h".
+ (enum rce_kind): Delete.
+ (class region_creation_event): Drop all member data.
+ (region_creation_event::region_creation_event): Make protected.
+ (region_creation_event::get_desc): Delete.
+ (class region_creation_event_memory_space): New.
+ (class region_creation_event_capacity): New.
+ (class region_creation_event_allocation_size): New.
+ (class region_creation_event_debug): New.
+ * checker-path.cc (checker_path::add_region_creation_events): Add
+ "pd" param. Call pending_diangnostic::add_region_creation_events.
+ Update for conversion of RCE_DEBUG to region_creation_event_debug.
+ * checker-path.h (checker_path::add_region_creation_events): Add
+ "pd" param.
+ * diagnostic-manager.cc (diagnostic_manager::build_emission_path):
+ Pass pending_diagnostic to
+ emission_path::add_region_creation_events.
+ (diagnostic_manager::build_emission_path): Pass path_builder to
+ add_event_on_final_node.
+ (diagnostic_manager::add_event_on_final_node): Add "pb" param.
+ Pass pending_diagnostic to
+ emission_path::add_region_creation_events.
+ (diagnostic_manager::add_events_for_eedge): Pass
+ pending_diagnostic to emission_path::add_region_creation_events.
+ * diagnostic-manager.h
+ (diagnostic_manager::add_event_on_final_node): Add "pb" param.
+ * pending-diagnostic.cc
+ (pending_diagnostic::add_region_creation_events): New.
+ * pending-diagnostic.h (struct region_creation): Delete.
+ (pending_diagnostic::describe_region_creation_event): Delete.
+ (pending_diagnostic::add_region_creation_events): New vfunc.
+ * region-model.cc: Include "analyzer/checker-event.h" and
+ "analyzer/checker-path.h".
+ (dubious_allocation_size::dubious_allocation_size): Initialize
+ m_has_allocation_event.
+ (dubious_allocation_size::describe_region_creation_event): Delete.
+ (dubious_allocation_size::describe_final_event): Update for
+ replacement of m_allocation_event with m_has_allocation_event.
+ (dubious_allocation_size::add_region_creation_events): New.
+ (dubious_allocation_size::m_allocation_event): Replace with...
+ (dubious_allocation_size::m_has_allocation_event): ...this.
+
+2022-12-02 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/107948
+ * region-model-manager.cc
+ (region_model_manager::maybe_fold_binop): Fold (0 - VAL) to -VAL.
+ * region-model.cc (region_model::eval_condition): Handle e.g.
+ "-X <= 0" as equivalent to X >= 0".
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106626
+ * bounds-checking.cc
+ (symbolic_past_the_end::describe_final_event): Delete, moving to
+ symbolic_buffer_overflow::describe_final_event and
+ symbolic_buffer_over_read::describe_final_event, eliminating
+ composition of text strings via "byte_str" and "m_dir_str".
+ (symbolic_past_the_end::m_dir_str): Delete field.
+ (symbolic_buffer_overflow::symbolic_buffer_overflow): Drop
+ m_dir_str.
+ (symbolic_buffer_overflow::describe_final_event): New, as noted
+ above.
+ (symbolic_buffer_over_read::symbolic_buffer_overflow): Drop
+ m_dir_str.
+ (symbolic_buffer_over_read::describe_final_event): New, as noted
+ above.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ * bounds-checking.cc (class out_of_bounds): Split out from...
+ (class concrete_out_of_bounds): New abstract subclass.
+ (class past_the_end): Rename to...
+ (class concrete_past_the_end): ...this, and make a subclass of
+ concrete_out_of_bounds.
+ (class buffer_overflow): Rename to...
+ (class concrete_buffer_overflow): ...this, and make a subclass of
+ concrete_past_the_end.
+ (class buffer_over_read): Rename to...
+ (class concrete_buffer_over_read): ...this, and make a subclass of
+ concrete_past_the_end.
+ (class buffer_underwrite): Rename to...
+ (class concrete_buffer_underwrite): ...this, and make a subclass
+ of concrete_out_of_bounds.
+ (class buffer_under_read): Rename to...
+ (class concrete_buffer_under_read): ...this, and make a subclass
+ of concrete_out_of_bounds.
+ (class symbolic_past_the_end): Convert to a subclass of
+ out_of_bounds.
+ (symbolic_buffer_overflow::get_kind): New.
+ (symbolic_buffer_over_read::get_kind): New.
+ (region_model::check_region_bounds): Update for renamings.
+ * engine.cc (impl_sm_context::set_next_state): Eliminate
+ "new_ctxt", passing NULL to get_rvalue instead.
+ (impl_sm_context::warn): Likewise.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106626
+ * bounds-checking.cc (out_of_bounds::get_memory_space): New.
+ (buffer_overflow::emit): Use it.
+ (class buffer_overread): Rename to...
+ (class buffer_over_read): ...this.
+ (buffer_over_read::emit): Specify which memory space the read is
+ from, where known. Change "overread" to "over-read".
+ (class buffer_underflow): Rename to...
+ (class buffer_underwrite): ...this.
+ (buffer_underwrite::emit): Specify which memory space the write is
+ to, where known. Change "underflow" to "underwrite".
+ (class buffer_underread): Rename to...
+ (class buffer_under_read): Rename to...
+ (buffer_under_read::emit): Specify which memory space the read is
+ from, where known. Change "underread" to "under-read".
+ (symbolic_past_the_end::get_memory_space): New.
+ (symbolic_buffer_overflow::emit): Use it.
+ (class symbolic_buffer_overread): Rename to...
+ (class symbolic_buffer_over_read): ...this.
+ (symbolic_buffer_over_read::emit): Specify which memory space the
+ read is from, where known. Change "overread" to "over-read".
+ (region_model::check_symbolic_bounds): Update for class renaming.
+ (region_model::check_region_bounds): Likewise.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106626
+ * bounds-checking.cc (out_of_bounds::maybe_describe_array_bounds):
+ New.
+ (buffer_overflow::emit): Call maybe_describe_array_bounds.
+ (buffer_overread::emit): Likewise.
+ (buffer_underflow::emit): Likewise.
+ (buffer_underread::emit): Likewise.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106626
+ * bounds-checking.cc (buffer_overflow::emit): Use inform_n.
+ Update wording to clarify that we're talking about the size of
+ the bad access, rather than its position.
+ (buffer_overread::emit): Likewise.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ * bounds-checking.cc: New file, taken from region-model.cc.
+ * region-model.cc (class out_of_bounds): Move to
+ bounds-checking.cc.
+ (class past_the_end): Likewise.
+ (class buffer_overflow): Likewise.
+ (class buffer_overread): Likewise.
+ (class buffer_underflow): Likewise.
+ (class buffer_underread): Likewise.
+ (class symbolic_past_the_end): Likewise.
+ (class symbolic_buffer_overflow): Likewise.
+ (class symbolic_buffer_overread): Likewise.
+ (region_model::check_symbolic_bounds): Likewise.
+ (maybe_get_integer_cst_tree): Likewise.
+ (region_model::check_region_bounds): Likewise.
+ * region-model.h: Add comment.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/107928
+ * sm-fd.cc (fd_state_machine::on_bind): Handle m_constant_fd in
+ the "success" outcome.
+ (fd_state_machine::on_connect): Likewise.
+ * sm-fd.dot: Add "constant_fd" state and its transitions.
+
+2022-11-30 David Malcolm <dmalcolm@redhat.com>
+
+ * region-model-impl-calls.cc (class kf_fgets): Move to sm-file.cc.
+ (kf_fgets::impl_call_pre): Likewise.
+ (class kf_fread): Likewise.
+ (kf_fread::impl_call_pre): Likewise.
+ (class kf_getchar): Likewise.
+ (class kf_stdio_output_fn): Likewise.
+ (register_known_functions): Move registration of
+ BUILT_IN_FPRINTF, BUILT_IN_FPRINTF_UNLOCKED, BUILT_IN_FPUTC,
+ BUILT_IN_FPUTC_UNLOCKED, BUILT_IN_FPUTS, BUILT_IN_FPUTS_UNLOCKED,
+ BUILT_IN_FWRITE, BUILT_IN_FWRITE_UNLOCKED, BUILT_IN_PRINTF,
+ BUILT_IN_PRINTF_UNLOCKED, BUILT_IN_PUTC, BUILT_IN_PUTCHAR,
+ BUILT_IN_PUTCHAR_UNLOCKED, BUILT_IN_PUTC_UNLOCKED, BUILT_IN_PUTS,
+ BUILT_IN_PUTS_UNLOCKED, BUILT_IN_VFPRINTF, BUILT_IN_VPRINTF,
+ "getchar", "fgets", "fgets_unlocked", and "fread" to
+ register_known_file_functions.
+ * sm-file.cc (class kf_stdio_output_fn): Move here from
+ region-model-impl-calls.cc.
+ (class kf_fgets): Likewise.
+ (class kf_fread): Likewise.
+ (class kf_getchar): Likewise.
+ (register_known_file_functions): Move registration of
+ BUILT_IN_FPRINTF, BUILT_IN_FPRINTF_UNLOCKED, BUILT_IN_FPUTC,
+ BUILT_IN_FPUTC_UNLOCKED, BUILT_IN_FPUTS, BUILT_IN_FPUTS_UNLOCKED,
+ BUILT_IN_FWRITE, BUILT_IN_FWRITE_UNLOCKED, BUILT_IN_PRINTF,
+ BUILT_IN_PRINTF_UNLOCKED, BUILT_IN_PUTC, BUILT_IN_PUTCHAR,
+ BUILT_IN_PUTCHAR_UNLOCKED, BUILT_IN_PUTC_UNLOCKED, BUILT_IN_PUTS,
+ BUILT_IN_PUTS_UNLOCKED, BUILT_IN_VFPRINTF, BUILT_IN_VPRINTF,
+ "fgets", "fgets_unlocked", "fread", and "getchar" to here from
+ register_known_functions.
+
+2022-11-30 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/103546
+ * analyzer.h (register_known_file_functions): New decl.
+ * program-state.cc (sm_state_map::replay_call_summary): Rejct
+ attempts to store sm-state for caller_sval that can't have
+ associated state.
+ * region-model-impl-calls.cc (register_known_functions): Call
+ register_known_file_functions.
+ * sm-fd.cc (class kf_isatty): New.
+ (register_known_fd_functions): Register it.
+ * sm-file.cc (class kf_ferror): New.
+ (class kf_fileno): New.
+ (class kf_getc): New.
+ (register_known_file_functions): New.
+
+2022-11-30 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/105784
+ * region-model-manager.cc
+ (region_model_manager::maybe_fold_binop): For POINTER_PLUS_EXPR,
+ PLUS_EXPR and MINUS_EXPR, eliminate requirement that the final
+ type matches that of arg0 in favor of a cast.
+
2022-11-24 Martin Liska <mliska@suse.cz>
* varargs.cc: Fix Clang warnings.
diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
index 96497dc..77d622d 100644
--- a/gcc/analyzer/analyzer.cc
+++ b/gcc/analyzer/analyzer.cc
@@ -449,7 +449,7 @@ make_label_text (bool can_colorize, const char *fmt, ...)
/* As above, but with singular vs plural. */
label_text
-make_label_text_n (bool can_colorize, int n,
+make_label_text_n (bool can_colorize, unsigned HOST_WIDE_INT n,
const char *singular_fmt,
const char *plural_fmt, ...)
{
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index 35c71f3..418d421 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -92,6 +92,7 @@ class bounded_ranges_manager;
class pending_diagnostic;
class pending_note;
+struct event_loc_info;
class state_change_event;
class checker_path;
class extrinsic_state;
@@ -258,8 +259,10 @@ public:
};
extern void register_known_functions (known_function_manager &mgr);
+extern void register_known_analyzer_functions (known_function_manager &kfm);
extern void register_known_fd_functions (known_function_manager &kfm);
extern void register_known_file_functions (known_function_manager &kfm);
+extern void register_known_functions_lang_cp (known_function_manager &kfm);
extern void register_varargs_builtins (known_function_manager &kfm);
/* Passed by pointer to PLUGIN_ANALYZER_INIT callbacks. */
@@ -359,7 +362,8 @@ extern const char *get_user_facing_name (const gcall *call);
extern void register_analyzer_pass ();
extern label_text make_label_text (bool can_colorize, const char *fmt, ...);
-extern label_text make_label_text_n (bool can_colorize, int n,
+extern label_text make_label_text_n (bool can_colorize,
+ unsigned HOST_WIDE_INT n,
const char *singular_fmt,
const char *plural_fmt, ...);
diff --git a/gcc/analyzer/bounds-checking.cc b/gcc/analyzer/bounds-checking.cc
new file mode 100644
index 0000000..4b43c43
--- /dev/null
+++ b/gcc/analyzer/bounds-checking.cc
@@ -0,0 +1,943 @@
+/* Bounds-checking of reads and writes to memory regions.
+ Copyright (C) 2019-2022 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#define INCLUDE_MEMORY
+#include "system.h"
+#include "coretypes.h"
+#include "make-unique.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "diagnostic-core.h"
+#include "diagnostic-metadata.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/region-model.h"
+#include "analyzer/checker-event.h"
+#include "analyzer/checker-path.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* Abstract base class for all out-of-bounds warnings. */
+
+class out_of_bounds : public pending_diagnostic
+{
+public:
+ out_of_bounds (const region *reg, tree diag_arg)
+ : m_reg (reg), m_diag_arg (diag_arg)
+ {}
+
+ bool subclass_equal_p (const pending_diagnostic &base_other) const override
+ {
+ const out_of_bounds &other
+ (static_cast <const out_of_bounds &>(base_other));
+ return (m_reg == other.m_reg
+ && pending_diagnostic::same_tree_p (m_diag_arg, other.m_diag_arg));
+ }
+
+ int get_controlling_option () const final override
+ {
+ return OPT_Wanalyzer_out_of_bounds;
+ }
+
+ void mark_interesting_stuff (interesting_t *interest) final override
+ {
+ interest->add_region_creation (m_reg);
+ }
+
+ void add_region_creation_events (const region *,
+ tree capacity,
+ const event_loc_info &loc_info,
+ checker_path &emission_path) override
+ {
+ /* The memory space is described in the diagnostic message itself,
+ so we don't need an event for that. */
+ if (capacity)
+ emission_path.add_event
+ (make_unique<region_creation_event_capacity> (capacity, loc_info));
+ }
+
+protected:
+ enum memory_space get_memory_space () const
+ {
+ return m_reg->get_memory_space ();
+ }
+
+ /* Potentially add a note about valid ways to index this array, such
+ as (given "int arr[10];"):
+ note: valid subscripts for 'arr' are '[0]' to '[9]'
+ We print the '[' and ']' characters so as to express the valid
+ subscripts using C syntax, rather than just as byte ranges,
+ which hopefully is more clear to the user. */
+ void
+ maybe_describe_array_bounds (location_t loc) const
+ {
+ if (!m_diag_arg)
+ return;
+ tree t = TREE_TYPE (m_diag_arg);
+ if (!t)
+ return;
+ if (TREE_CODE (t) != ARRAY_TYPE)
+ return;
+ tree domain = TYPE_DOMAIN (t);
+ if (!domain)
+ return;
+ tree max_idx = TYPE_MAX_VALUE (domain);
+ if (!max_idx)
+ return;
+ tree min_idx = TYPE_MIN_VALUE (domain);
+ inform (loc,
+ "valid subscripts for %qE are %<[%E]%> to %<[%E]%>",
+ m_diag_arg, min_idx, max_idx);
+ }
+
+ const region *m_reg;
+ tree m_diag_arg;
+};
+
+/* Abstract base class for all out-of-bounds warnings where the
+ out-of-bounds range is concrete. */
+
+class concrete_out_of_bounds : public out_of_bounds
+{
+public:
+ concrete_out_of_bounds (const region *reg, tree diag_arg,
+ byte_range out_of_bounds_range)
+ : out_of_bounds (reg, diag_arg),
+ m_out_of_bounds_range (out_of_bounds_range)
+ {}
+
+ bool subclass_equal_p (const pending_diagnostic &base_other) const override
+ {
+ const concrete_out_of_bounds &other
+ (static_cast <const concrete_out_of_bounds &>(base_other));
+ return (out_of_bounds::subclass_equal_p (other)
+ && m_out_of_bounds_range == other.m_out_of_bounds_range);
+ }
+
+protected:
+ byte_range m_out_of_bounds_range;
+};
+
+/* Abstract subclass to complaing about concrete out-of-bounds
+ past the end of the buffer. */
+
+class concrete_past_the_end : public concrete_out_of_bounds
+{
+public:
+ concrete_past_the_end (const region *reg, tree diag_arg, byte_range range,
+ tree byte_bound)
+ : concrete_out_of_bounds (reg, diag_arg, range), m_byte_bound (byte_bound)
+ {}
+
+ bool
+ subclass_equal_p (const pending_diagnostic &base_other) const final override
+ {
+ const concrete_past_the_end &other
+ (static_cast <const concrete_past_the_end &>(base_other));
+ return (concrete_out_of_bounds::subclass_equal_p (other)
+ && pending_diagnostic::same_tree_p (m_byte_bound,
+ other.m_byte_bound));
+ }
+
+ void add_region_creation_events (const region *,
+ tree,
+ const event_loc_info &loc_info,
+ checker_path &emission_path) final override
+ {
+ if (m_byte_bound && TREE_CODE (m_byte_bound) == INTEGER_CST)
+ emission_path.add_event
+ (make_unique<region_creation_event_capacity> (m_byte_bound, loc_info));
+ }
+
+protected:
+ tree m_byte_bound;
+};
+
+/* Concrete subclass to complain about buffer overflows. */
+
+class concrete_buffer_overflow : public concrete_past_the_end
+{
+public:
+ concrete_buffer_overflow (const region *reg, tree diag_arg,
+ byte_range range, tree byte_bound)
+ : concrete_past_the_end (reg, diag_arg, range, byte_bound)
+ {}
+
+ const char *get_kind () const final override
+ {
+ return "concrete_buffer_overflow";
+ }
+
+ bool emit (rich_location *rich_loc) final override
+ {
+ diagnostic_metadata m;
+ bool warned;
+ switch (get_memory_space ())
+ {
+ default:
+ m.add_cwe (787);
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "buffer overflow");
+ break;
+ case MEMSPACE_STACK:
+ m.add_cwe (121);
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "stack-based buffer overflow");
+ break;
+ case MEMSPACE_HEAP:
+ m.add_cwe (122);
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "heap-based buffer overflow");
+ break;
+ }
+
+ if (warned)
+ {
+ if (wi::fits_uhwi_p (m_out_of_bounds_range.m_size_in_bytes))
+ {
+ unsigned HOST_WIDE_INT num_bad_bytes
+ = m_out_of_bounds_range.m_size_in_bytes.to_uhwi ();
+ if (m_diag_arg)
+ inform_n (rich_loc->get_loc (),
+ num_bad_bytes,
+ "write of %wu byte to beyond the end of %qE",
+ "write of %wu bytes to beyond the end of %qE",
+ num_bad_bytes,
+ m_diag_arg);
+ else
+ inform_n (rich_loc->get_loc (),
+ num_bad_bytes,
+ "write of %wu byte to beyond the end of the region",
+ "write of %wu bytes to beyond the end of the region",
+ num_bad_bytes);
+ }
+ else if (m_diag_arg)
+ inform (rich_loc->get_loc (),
+ "write to beyond the end of %qE",
+ m_diag_arg);
+
+ maybe_describe_array_bounds (rich_loc->get_loc ());
+ }
+
+ return warned;
+ }
+
+ label_text describe_final_event (const evdesc::final_event &ev)
+ final override
+ {
+ byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
+ byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
+ char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
+ print_dec (start, start_buf, SIGNED);
+ char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
+ print_dec (end, end_buf, SIGNED);
+
+ if (start == end)
+ {
+ if (m_diag_arg)
+ return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
+ " ends at byte %E", start_buf, m_diag_arg,
+ m_byte_bound);
+ return ev.formatted_print ("out-of-bounds write at byte %s but region"
+ " ends at byte %E", start_buf,
+ m_byte_bound);
+ }
+ else
+ {
+ if (m_diag_arg)
+ return ev.formatted_print ("out-of-bounds write from byte %s till"
+ " byte %s but %qE ends at byte %E",
+ start_buf, end_buf, m_diag_arg,
+ m_byte_bound);
+ return ev.formatted_print ("out-of-bounds write from byte %s till"
+ " byte %s but region ends at byte %E",
+ start_buf, end_buf, m_byte_bound);
+ }
+ }
+};
+
+/* Concrete subclass to complain about buffer over-reads. */
+
+class concrete_buffer_over_read : public concrete_past_the_end
+{
+public:
+ concrete_buffer_over_read (const region *reg, tree diag_arg,
+ byte_range range, tree byte_bound)
+ : concrete_past_the_end (reg, diag_arg, range, byte_bound)
+ {}
+
+ const char *get_kind () const final override
+ {
+ return "concrete_buffer_over_read";
+ }
+
+ bool emit (rich_location *rich_loc) final override
+ {
+ diagnostic_metadata m;
+ bool warned;
+ m.add_cwe (126);
+ switch (get_memory_space ())
+ {
+ default:
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "buffer over-read");
+ break;
+ case MEMSPACE_STACK:
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "stack-based buffer over-read");
+ break;
+ case MEMSPACE_HEAP:
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "heap-based buffer over-read");
+ break;
+ }
+
+ if (warned)
+ {
+ if (wi::fits_uhwi_p (m_out_of_bounds_range.m_size_in_bytes))
+ {
+ unsigned HOST_WIDE_INT num_bad_bytes
+ = m_out_of_bounds_range.m_size_in_bytes.to_uhwi ();
+ if (m_diag_arg)
+ inform_n (rich_loc->get_loc (),
+ num_bad_bytes,
+ "read of %wu byte from after the end of %qE",
+ "read of %wu bytes from after the end of %qE",
+ num_bad_bytes,
+ m_diag_arg);
+ else
+ inform_n (rich_loc->get_loc (),
+ num_bad_bytes,
+ "read of %wu byte from after the end of the region",
+ "read of %wu bytes from after the end of the region",
+ num_bad_bytes);
+ }
+ else if (m_diag_arg)
+ inform (rich_loc->get_loc (),
+ "read from after the end of %qE",
+ m_diag_arg);
+
+ maybe_describe_array_bounds (rich_loc->get_loc ());
+ }
+
+ return warned;
+ }
+
+ label_text describe_final_event (const evdesc::final_event &ev)
+ final override
+ {
+ byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
+ byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
+ char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
+ print_dec (start, start_buf, SIGNED);
+ char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
+ print_dec (end, end_buf, SIGNED);
+
+ if (start == end)
+ {
+ if (m_diag_arg)
+ return ev.formatted_print ("out-of-bounds read at byte %s but %qE"
+ " ends at byte %E", start_buf, m_diag_arg,
+ m_byte_bound);
+ return ev.formatted_print ("out-of-bounds read at byte %s but region"
+ " ends at byte %E", start_buf,
+ m_byte_bound);
+ }
+ else
+ {
+ if (m_diag_arg)
+ return ev.formatted_print ("out-of-bounds read from byte %s till"
+ " byte %s but %qE ends at byte %E",
+ start_buf, end_buf, m_diag_arg,
+ m_byte_bound);
+ return ev.formatted_print ("out-of-bounds read from byte %s till"
+ " byte %s but region ends at byte %E",
+ start_buf, end_buf, m_byte_bound);
+ }
+ }
+};
+
+/* Concrete subclass to complain about buffer underwrites. */
+
+class concrete_buffer_underwrite : public concrete_out_of_bounds
+{
+public:
+ concrete_buffer_underwrite (const region *reg, tree diag_arg,
+ byte_range range)
+ : concrete_out_of_bounds (reg, diag_arg, range)
+ {}
+
+ const char *get_kind () const final override
+ {
+ return "concrete_buffer_underwrite";
+ }
+
+ bool emit (rich_location *rich_loc) final override
+ {
+ diagnostic_metadata m;
+ bool warned;
+ m.add_cwe (124);
+ switch (get_memory_space ())
+ {
+ default:
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "buffer underwrite");
+ break;
+ case MEMSPACE_STACK:
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "stack-based buffer underwrite");
+ break;
+ case MEMSPACE_HEAP:
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "heap-based buffer underwrite");
+ break;
+ }
+ if (warned)
+ maybe_describe_array_bounds (rich_loc->get_loc ());
+ return warned;
+ }
+
+ label_text describe_final_event (const evdesc::final_event &ev)
+ final override
+ {
+ byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
+ byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
+ char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
+ print_dec (start, start_buf, SIGNED);
+ char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
+ print_dec (end, end_buf, SIGNED);
+
+ if (start == end)
+ {
+ if (m_diag_arg)
+ return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
+ " starts at byte 0", start_buf,
+ m_diag_arg);
+ return ev.formatted_print ("out-of-bounds write at byte %s but region"
+ " starts at byte 0", start_buf);
+ }
+ else
+ {
+ if (m_diag_arg)
+ return ev.formatted_print ("out-of-bounds write from byte %s till"
+ " byte %s but %qE starts at byte 0",
+ start_buf, end_buf, m_diag_arg);
+ return ev.formatted_print ("out-of-bounds write from byte %s till"
+ " byte %s but region starts at byte 0",
+ start_buf, end_buf);;
+ }
+ }
+};
+
+/* Concrete subclass to complain about buffer under-reads. */
+
+class concrete_buffer_under_read : public concrete_out_of_bounds
+{
+public:
+ concrete_buffer_under_read (const region *reg, tree diag_arg,
+ byte_range range)
+ : concrete_out_of_bounds (reg, diag_arg, range)
+ {}
+
+ const char *get_kind () const final override
+ {
+ return "concrete_buffer_under_read";
+ }
+
+ bool emit (rich_location *rich_loc) final override
+ {
+ diagnostic_metadata m;
+ bool warned;
+ m.add_cwe (127);
+ switch (get_memory_space ())
+ {
+ default:
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "buffer under-read");
+ break;
+ case MEMSPACE_STACK:
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "stack-based buffer under-read");
+ break;
+ case MEMSPACE_HEAP:
+ warned = warning_meta (rich_loc, m, get_controlling_option (),
+ "heap-based buffer under-read");
+ break;
+ }
+ if (warned)
+ maybe_describe_array_bounds (rich_loc->get_loc ());
+ return warned;
+ }
+
+ label_text describe_final_event (const evdesc::final_event &ev)
+ final override
+ {
+ byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
+ byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
+ char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
+ print_dec (start, start_buf, SIGNED);
+ char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
+ print_dec (end, end_buf, SIGNED);
+
+ if (start == end)
+ {
+ if (m_diag_arg)
+ return ev.formatted_print ("out-of-bounds read at byte %s but %qE"
+ " starts at byte 0", start_buf,
+ m_diag_arg);
+ return ev.formatted_print ("out-of-bounds read at byte %s but region"
+ " starts at byte 0", start_buf);
+ }
+ else
+ {
+ if (m_diag_arg)
+ return ev.formatted_print ("out-of-bounds read from byte %s till"
+ " byte %s but %qE starts at byte 0",
+ start_buf, end_buf, m_diag_arg);
+ return ev.formatted_print ("out-of-bounds read from byte %s till"
+ " byte %s but region starts at byte 0",
+ start_buf, end_buf);;
+ }
+ }
+};
+
+/* Abstract class to complain about out-of-bounds read/writes where
+ the values are symbolic. */
+
+class symbolic_past_the_end : public out_of_bounds
+{
+public:
+ symbolic_past_the_end (const region *reg, tree diag_arg, tree offset,
+ tree num_bytes, tree capacity)
+ : out_of_bounds (reg, diag_arg),
+ m_offset (offset),
+ m_num_bytes (num_bytes),
+ m_capacity (capacity)
+ {}
+
+ bool
+ subclass_equal_p (const pending_diagnostic &base_other) const final override
+ {
+ const symbolic_past_the_end &other
+ (static_cast <const symbolic_past_the_end &>(base_other));
+ return (out_of_bounds::subclass_equal_p (other)
+ && pending_diagnostic::same_tree_p (m_offset, other.m_offset)
+ && pending_diagnostic::same_tree_p (m_num_bytes, other.m_num_bytes)
+ && pending_diagnostic::same_tree_p (m_capacity, other.m_capacity));
+ }
+
+protected:
+ tree m_offset;
+ tree m_num_bytes;
+ tree m_capacity;
+};
+
+/* Concrete subclass to complain about overflows with symbolic values. */
+
+class symbolic_buffer_overflow : public symbolic_past_the_end
+{
+public:
+ symbolic_buffer_overflow (const region *reg, tree diag_arg, tree offset,
+ tree num_bytes, tree capacity)
+ : symbolic_past_the_end (reg, diag_arg, offset, num_bytes, capacity)
+ {
+ }
+
+ const char *get_kind () const final override
+ {
+ return "symbolic_buffer_overflow";
+ }
+
+ bool emit (rich_location *rich_loc) final override
+ {
+ diagnostic_metadata m;
+ switch (get_memory_space ())
+ {
+ default:
+ m.add_cwe (787);
+ return warning_meta (rich_loc, m, get_controlling_option (),
+ "buffer overflow");
+ case MEMSPACE_STACK:
+ m.add_cwe (121);
+ return warning_meta (rich_loc, m, get_controlling_option (),
+ "stack-based buffer overflow");
+ case MEMSPACE_HEAP:
+ m.add_cwe (122);
+ return warning_meta (rich_loc, m, get_controlling_option (),
+ "heap-based buffer overflow");
+ }
+ }
+
+ label_text
+ describe_final_event (const evdesc::final_event &ev) final override
+ {
+ if (m_offset)
+ {
+ /* Known offset. */
+ if (m_num_bytes)
+ {
+ /* Known offset, known size. */
+ if (TREE_CODE (m_num_bytes) == INTEGER_CST)
+ {
+ /* Known offset, known constant size. */
+ if (pending_diagnostic::same_tree_p (m_num_bytes,
+ integer_one_node))
+ {
+ /* Singular m_num_bytes. */
+ if (m_diag_arg)
+ return ev.formatted_print
+ ("write of %E byte at offset %qE exceeds %qE",
+ m_num_bytes, m_offset, m_diag_arg);
+ else
+ return ev.formatted_print
+ ("write of %E byte at offset %qE exceeds the buffer",
+ m_num_bytes, m_offset);
+ }
+ else
+ {
+ /* Plural m_num_bytes. */
+ if (m_diag_arg)
+ return ev.formatted_print
+ ("write of %E bytes at offset %qE exceeds %qE",
+ m_num_bytes, m_offset, m_diag_arg);
+ else
+ return ev.formatted_print
+ ("write of %E bytes at offset %qE exceeds the buffer",
+ m_num_bytes, m_offset);
+ }
+ }
+ else
+ {
+ /* Known offset, known symbolic size. */
+ if (m_diag_arg)
+ return ev.formatted_print
+ ("write of %qE bytes at offset %qE exceeds %qE",
+ m_num_bytes, m_offset, m_diag_arg);
+ else
+ return ev.formatted_print
+ ("write of %qE bytes at offset %qE exceeds the buffer",
+ m_num_bytes, m_offset);
+ }
+ }
+ else
+ {
+ /* Known offset, unknown size. */
+ if (m_diag_arg)
+ return ev.formatted_print ("write at offset %qE exceeds %qE",
+ m_offset, m_diag_arg);
+ else
+ return ev.formatted_print ("write at offset %qE exceeds the"
+ " buffer", m_offset);
+ }
+ }
+ /* Unknown offset. */
+ if (m_diag_arg)
+ return ev.formatted_print ("out-of-bounds write on %qE",
+ m_diag_arg);
+ return ev.formatted_print ("out-of-bounds write");
+ }
+};
+
+/* Concrete subclass to complain about over-reads with symbolic values. */
+
+class symbolic_buffer_over_read : public symbolic_past_the_end
+{
+public:
+ symbolic_buffer_over_read (const region *reg, tree diag_arg, tree offset,
+ tree num_bytes, tree capacity)
+ : symbolic_past_the_end (reg, diag_arg, offset, num_bytes, capacity)
+ {
+ }
+
+ const char *get_kind () const final override
+ {
+ return "symbolic_buffer_over_read";
+ }
+
+ bool emit (rich_location *rich_loc) final override
+ {
+ diagnostic_metadata m;
+ m.add_cwe (126);
+ switch (get_memory_space ())
+ {
+ default:
+ m.add_cwe (787);
+ return warning_meta (rich_loc, m, get_controlling_option (),
+ "buffer over-read");
+ case MEMSPACE_STACK:
+ m.add_cwe (121);
+ return warning_meta (rich_loc, m, get_controlling_option (),
+ "stack-based buffer over-read");
+ case MEMSPACE_HEAP:
+ m.add_cwe (122);
+ return warning_meta (rich_loc, m, get_controlling_option (),
+ "heap-based buffer over-read");
+ }
+ }
+
+ label_text
+ describe_final_event (const evdesc::final_event &ev) final override
+ {
+ if (m_offset)
+ {
+ /* Known offset. */
+ if (m_num_bytes)
+ {
+ /* Known offset, known size. */
+ if (TREE_CODE (m_num_bytes) == INTEGER_CST)
+ {
+ /* Known offset, known constant size. */
+ if (pending_diagnostic::same_tree_p (m_num_bytes,
+ integer_one_node))
+ {
+ /* Singular m_num_bytes. */
+ if (m_diag_arg)
+ return ev.formatted_print
+ ("read of %E byte at offset %qE exceeds %qE",
+ m_num_bytes, m_offset, m_diag_arg);
+ else
+ return ev.formatted_print
+ ("read of %E byte at offset %qE exceeds the buffer",
+ m_num_bytes, m_offset);
+ }
+ else
+ {
+ /* Plural m_num_bytes. */
+ if (m_diag_arg)
+ return ev.formatted_print
+ ("read of %E bytes at offset %qE exceeds %qE",
+ m_num_bytes, m_offset, m_diag_arg);
+ else
+ return ev.formatted_print
+ ("read of %E bytes at offset %qE exceeds the buffer",
+ m_num_bytes, m_offset);
+ }
+ }
+ else
+ {
+ /* Known offset, known symbolic size. */
+ if (m_diag_arg)
+ return ev.formatted_print
+ ("read of %qE bytes at offset %qE exceeds %qE",
+ m_num_bytes, m_offset, m_diag_arg);
+ else
+ return ev.formatted_print
+ ("read of %qE bytes at offset %qE exceeds the buffer",
+ m_num_bytes, m_offset);
+ }
+ }
+ else
+ {
+ /* Known offset, unknown size. */
+ if (m_diag_arg)
+ return ev.formatted_print ("read at offset %qE exceeds %qE",
+ m_offset, m_diag_arg);
+ else
+ return ev.formatted_print ("read at offset %qE exceeds the"
+ " buffer", m_offset);
+ }
+ }
+ /* Unknown offset. */
+ if (m_diag_arg)
+ return ev.formatted_print ("out-of-bounds read on %qE",
+ m_diag_arg);
+ return ev.formatted_print ("out-of-bounds read");
+ }
+};
+
+/* Check whether an access is past the end of the BASE_REG. */
+
+void
+region_model::check_symbolic_bounds (const region *base_reg,
+ const svalue *sym_byte_offset,
+ const svalue *num_bytes_sval,
+ const svalue *capacity,
+ enum access_direction dir,
+ region_model_context *ctxt) const
+{
+ gcc_assert (ctxt);
+
+ const svalue *next_byte
+ = m_mgr->get_or_create_binop (num_bytes_sval->get_type (), PLUS_EXPR,
+ sym_byte_offset, num_bytes_sval);
+
+ if (eval_condition (next_byte, GT_EXPR, capacity).is_true ())
+ {
+ tree diag_arg = get_representative_tree (base_reg);
+ tree offset_tree = get_representative_tree (sym_byte_offset);
+ tree num_bytes_tree = get_representative_tree (num_bytes_sval);
+ tree capacity_tree = get_representative_tree (capacity);
+ switch (dir)
+ {
+ default:
+ gcc_unreachable ();
+ break;
+ case DIR_READ:
+ ctxt->warn (make_unique<symbolic_buffer_over_read> (base_reg,
+ diag_arg,
+ offset_tree,
+ num_bytes_tree,
+ capacity_tree));
+ break;
+ case DIR_WRITE:
+ ctxt->warn (make_unique<symbolic_buffer_overflow> (base_reg,
+ diag_arg,
+ offset_tree,
+ num_bytes_tree,
+ capacity_tree));
+ break;
+ }
+ }
+}
+
+static tree
+maybe_get_integer_cst_tree (const svalue *sval)
+{
+ tree cst_tree = sval->maybe_get_constant ();
+ if (cst_tree && TREE_CODE (cst_tree) == INTEGER_CST)
+ return cst_tree;
+
+ return NULL_TREE;
+}
+
+/* May complain when the access on REG is out-of-bounds. */
+
+void
+region_model::check_region_bounds (const region *reg,
+ enum access_direction dir,
+ region_model_context *ctxt) const
+{
+ gcc_assert (ctxt);
+
+ /* Get the offset. */
+ region_offset reg_offset = reg->get_offset (m_mgr);
+ const region *base_reg = reg_offset.get_base_region ();
+
+ /* Bail out on symbolic regions.
+ (e.g. because the analyzer did not see previous offsets on the latter,
+ it might think that a negative access is before the buffer). */
+ if (base_reg->symbolic_p ())
+ return;
+
+ /* Find out how many bytes were accessed. */
+ const svalue *num_bytes_sval = reg->get_byte_size_sval (m_mgr);
+ tree num_bytes_tree = maybe_get_integer_cst_tree (num_bytes_sval);
+ /* Bail out if 0 bytes are accessed. */
+ if (num_bytes_tree && zerop (num_bytes_tree))
+ return;
+
+ /* Get the capacity of the buffer. */
+ const svalue *capacity = get_capacity (base_reg);
+ tree cst_capacity_tree = maybe_get_integer_cst_tree (capacity);
+
+ /* The constant offset from a pointer is represented internally as a sizetype
+ but should be interpreted as a signed value here. The statement below
+ converts the offset from bits to bytes and then to a signed integer with
+ the same precision the sizetype has on the target system.
+
+ For example, this is needed for out-of-bounds-3.c test1 to pass when
+ compiled with a 64-bit gcc build targeting 32-bit systems. */
+ byte_offset_t offset;
+ if (!reg_offset.symbolic_p ())
+ offset = wi::sext (reg_offset.get_bit_offset () >> LOG2_BITS_PER_UNIT,
+ TYPE_PRECISION (size_type_node));
+
+ /* If either the offset or the number of bytes accessed are symbolic,
+ we have to reason about symbolic values. */
+ if (reg_offset.symbolic_p () || !num_bytes_tree)
+ {
+ const svalue* byte_offset_sval;
+ if (!reg_offset.symbolic_p ())
+ {
+ tree offset_tree = wide_int_to_tree (integer_type_node, offset);
+ byte_offset_sval
+ = m_mgr->get_or_create_constant_svalue (offset_tree);
+ }
+ else
+ byte_offset_sval = reg_offset.get_symbolic_byte_offset ();
+ check_symbolic_bounds (base_reg, byte_offset_sval, num_bytes_sval,
+ capacity, dir, ctxt);
+ return;
+ }
+
+ /* Otherwise continue to check with concrete values. */
+ byte_range out (0, 0);
+ /* NUM_BYTES_TREE should always be interpreted as unsigned. */
+ byte_offset_t num_bytes_unsigned = wi::to_offset (num_bytes_tree);
+ byte_range read_bytes (offset, num_bytes_unsigned);
+ /* If read_bytes has a subset < 0, we do have an underwrite. */
+ if (read_bytes.falls_short_of_p (0, &out))
+ {
+ tree diag_arg = get_representative_tree (base_reg);
+ switch (dir)
+ {
+ default:
+ gcc_unreachable ();
+ break;
+ case DIR_READ:
+ ctxt->warn (make_unique<concrete_buffer_under_read> (reg, diag_arg,
+ out));
+ break;
+ case DIR_WRITE:
+ ctxt->warn (make_unique<concrete_buffer_underwrite> (reg, diag_arg,
+ out));
+ break;
+ }
+ }
+
+ /* For accesses past the end, we do need a concrete capacity. No need to
+ do a symbolic check here because the inequality check does not reason
+ whether constants are greater than symbolic values. */
+ if (!cst_capacity_tree)
+ return;
+
+ byte_range buffer (0, wi::to_offset (cst_capacity_tree));
+ /* If READ_BYTES exceeds BUFFER, we do have an overflow. */
+ if (read_bytes.exceeds_p (buffer, &out))
+ {
+ tree byte_bound = wide_int_to_tree (size_type_node,
+ buffer.get_next_byte_offset ());
+ tree diag_arg = get_representative_tree (base_reg);
+
+ switch (dir)
+ {
+ default:
+ gcc_unreachable ();
+ break;
+ case DIR_READ:
+ ctxt->warn (make_unique<concrete_buffer_over_read> (reg, diag_arg,
+ out, byte_bound));
+ break;
+ case DIR_WRITE:
+ ctxt->warn (make_unique<concrete_buffer_overflow> (reg, diag_arg,
+ out, byte_bound));
+ break;
+ }
+ }
+}
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/call-details.cc b/gcc/analyzer/call-details.cc
new file mode 100644
index 0000000..b63b8a3
--- /dev/null
+++ b/gcc/analyzer/call-details.cc
@@ -0,0 +1,231 @@
+/* Helper class for handling a call with specific arguments.
+ Copyright (C) 2020-2022 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#define INCLUDE_MEMORY
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "diagnostic-core.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/analyzer-logging.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h" /* for default_tree_printer. */
+#include "gimple-pretty-print.h"
+#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* class call_details. */
+
+/* call_details's ctor. */
+
+call_details::call_details (const gcall *call, region_model *model,
+ region_model_context *ctxt)
+: m_call (call), m_model (model), m_ctxt (ctxt),
+ m_lhs_type (NULL_TREE), m_lhs_region (NULL)
+{
+ m_lhs_type = NULL_TREE;
+ if (tree lhs = gimple_call_lhs (call))
+ {
+ m_lhs_region = model->get_lvalue (lhs, ctxt);
+ m_lhs_type = TREE_TYPE (lhs);
+ }
+}
+
+/* Get the manager from m_model. */
+
+region_model_manager *
+call_details::get_manager () const
+{
+ return m_model->get_manager ();
+}
+
+/* Get any logger associated with this object. */
+
+logger *
+call_details::get_logger () const
+{
+ if (m_ctxt)
+ return m_ctxt->get_logger ();
+ else
+ return NULL;
+}
+
+/* Get any uncertainty_t associated with the region_model_context. */
+
+uncertainty_t *
+call_details::get_uncertainty () const
+{
+ if (m_ctxt)
+ return m_ctxt->get_uncertainty ();
+ else
+ return NULL;
+}
+
+/* If the callsite has a left-hand-side region, set it to RESULT
+ and return true.
+ Otherwise do nothing and return false. */
+
+bool
+call_details::maybe_set_lhs (const svalue *result) const
+{
+ gcc_assert (result);
+ if (m_lhs_region)
+ {
+ m_model->set_value (m_lhs_region, result, m_ctxt);
+ return true;
+ }
+ else
+ return false;
+}
+
+/* Return the number of arguments used by the call statement. */
+
+unsigned
+call_details::num_args () const
+{
+ return gimple_call_num_args (m_call);
+}
+
+/* Return true if argument IDX is a size_t (or compatible with it). */
+
+bool
+call_details::arg_is_size_p (unsigned idx) const
+{
+ return types_compatible_p (get_arg_type (idx), size_type_node);
+}
+
+/* Get the location of the call statement. */
+
+location_t
+call_details::get_location () const
+{
+ return m_call->location;
+}
+
+/* Get argument IDX at the callsite as a tree. */
+
+tree
+call_details::get_arg_tree (unsigned idx) const
+{
+ return gimple_call_arg (m_call, idx);
+}
+
+/* Get the type of argument IDX. */
+
+tree
+call_details::get_arg_type (unsigned idx) const
+{
+ return TREE_TYPE (gimple_call_arg (m_call, idx));
+}
+
+/* Get argument IDX at the callsite as an svalue. */
+
+const svalue *
+call_details::get_arg_svalue (unsigned idx) const
+{
+ tree arg = get_arg_tree (idx);
+ return m_model->get_rvalue (arg, m_ctxt);
+}
+
+/* Attempt to get the string literal for argument IDX, or return NULL
+ otherwise.
+ For use when implementing "__analyzer_*" functions that take
+ string literals. */
+
+const char *
+call_details::get_arg_string_literal (unsigned idx) const
+{
+ const svalue *str_arg = get_arg_svalue (idx);
+ if (const region *pointee = str_arg->maybe_get_region ())
+ if (const string_region *string_reg = pointee->dyn_cast_string_region ())
+ {
+ tree string_cst = string_reg->get_string_cst ();
+ return TREE_STRING_POINTER (string_cst);
+ }
+ return NULL;
+}
+
+/* Attempt to get the fndecl used at this call, if known, or NULL_TREE
+ otherwise. */
+
+tree
+call_details::get_fndecl_for_call () const
+{
+ return m_model->get_fndecl_for_call (m_call, m_ctxt);
+}
+
+/* Dump a multiline representation of this call to PP. */
+
+void
+call_details::dump_to_pp (pretty_printer *pp, bool simple) const
+{
+ pp_string (pp, "gcall: ");
+ pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */);
+ pp_newline (pp);
+ pp_string (pp, "return region: ");
+ if (m_lhs_region)
+ m_lhs_region->dump_to_pp (pp, simple);
+ else
+ pp_string (pp, "NULL");
+ pp_newline (pp);
+ for (unsigned i = 0; i < gimple_call_num_args (m_call); i++)
+ {
+ const svalue *arg_sval = get_arg_svalue (i);
+ pp_printf (pp, "arg %i: ", i);
+ arg_sval->dump_to_pp (pp, simple);
+ pp_newline (pp);
+ }
+}
+
+/* Dump a multiline representation of this call to stderr. */
+
+DEBUG_FUNCTION void
+call_details::dump (bool simple) const
+{
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_show_color (&pp) = pp_show_color (global_dc->printer);
+ pp.buffer->stream = stderr;
+ dump_to_pp (&pp, simple);
+ pp_flush (&pp);
+}
+
+/* Get a conjured_svalue for this call for REG,
+ and purge any state already relating to that conjured_svalue. */
+
+const svalue *
+call_details::get_or_create_conjured_svalue (const region *reg) const
+{
+ region_model_manager *mgr = m_model->get_manager ();
+ return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg,
+ conjured_purge (m_model, m_ctxt));
+}
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/call-details.h b/gcc/analyzer/call-details.h
new file mode 100644
index 0000000..144ca0c
--- /dev/null
+++ b/gcc/analyzer/call-details.h
@@ -0,0 +1,77 @@
+/* Helper class for handling a call with specific arguments.
+ Copyright (C) 2019-2022 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_ANALYZER_CALL_DETAILS_H
+#define GCC_ANALYZER_CALL_DETAILS_H
+
+namespace ana {
+
+/* Helper class for handling calls to functions with known behavior. */
+
+class call_details
+{
+public:
+ call_details (const gcall *call, region_model *model,
+ region_model_context *ctxt);
+
+ region_model *get_model () const { return m_model; }
+ region_model_manager *get_manager () const;
+ region_model_context *get_ctxt () const { return m_ctxt; }
+ logger *get_logger () const;
+
+ uncertainty_t *get_uncertainty () const;
+ tree get_lhs_type () const { return m_lhs_type; }
+ const region *get_lhs_region () const { return m_lhs_region; }
+
+ bool maybe_set_lhs (const svalue *result) const;
+
+ unsigned num_args () const;
+ bool arg_is_pointer_p (unsigned idx) const
+ {
+ return POINTER_TYPE_P (get_arg_type (idx));
+ }
+ bool arg_is_size_p (unsigned idx) const;
+
+ const gcall *get_call_stmt () const { return m_call; }
+ location_t get_location () const;
+
+ tree get_arg_tree (unsigned idx) const;
+ tree get_arg_type (unsigned idx) const;
+ const svalue *get_arg_svalue (unsigned idx) const;
+ const char *get_arg_string_literal (unsigned idx) const;
+
+ tree get_fndecl_for_call () const;
+
+ void dump_to_pp (pretty_printer *pp, bool simple) const;
+ void dump (bool simple) const;
+
+ const svalue *get_or_create_conjured_svalue (const region *) const;
+
+private:
+ const gcall *m_call;
+ region_model *m_model;
+ region_model_context *m_ctxt;
+ tree m_lhs_type;
+ const region *m_lhs_region;
+};
+
+} // namespace ana
+
+#endif /* GCC_ANALYZER_CALL_DETAILS_H */
diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc
index 7a1c4ed..cbd21f7 100644
--- a/gcc/analyzer/call-info.cc
+++ b/gcc/analyzer/call-info.cc
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/checker-path.h"
#include "analyzer/diagnostic-manager.h"
#include "analyzer/exploded-graph.h"
+#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
#include "make-unique.h"
@@ -94,10 +95,10 @@ call_info::add_events_to_path (checker_path *emission_path,
class call_event : public custom_event
{
public:
- call_event (location_t loc, tree fndecl, int depth,
+ call_event (const event_loc_info &loc_info,
const call_info *call_info)
- : custom_event (loc, fndecl, depth),
- m_call_info (call_info)
+ : custom_event (loc_info),
+ m_call_info (call_info)
{}
label_text get_desc (bool can_colorize) const final override
@@ -114,10 +115,11 @@ call_info::add_events_to_path (checker_path *emission_path,
tree caller_fndecl = src_point.get_fndecl ();
const int stack_depth = src_point.get_stack_depth ();
- emission_path->add_event (make_unique<call_event> (get_call_stmt ()->location,
- caller_fndecl,
- stack_depth,
- this));
+ emission_path->add_event
+ (make_unique<call_event> (event_loc_info (get_call_stmt ()->location,
+ caller_fndecl,
+ stack_depth),
+ this));
}
/* Recreate a call_details instance from this call_info. */
diff --git a/gcc/analyzer/call-summary.h b/gcc/analyzer/call-summary.h
index 07cd3f5..73f21ac 100644
--- a/gcc/analyzer/call-summary.h
+++ b/gcc/analyzer/call-summary.h
@@ -20,6 +20,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_CALL_SUMMARY_H
#define GCC_ANALYZER_CALL_SUMMARY_H
+#include "call-details.h"
+
namespace ana {
/* A class summarizing one particular outcome of a function that
diff --git a/gcc/analyzer/checker-event.cc b/gcc/analyzer/checker-event.cc
index a3e0433..4985f63 100644
--- a/gcc/analyzer/checker-event.cc
+++ b/gcc/analyzer/checker-event.cc
@@ -151,17 +151,19 @@ private:
/* checker_event's ctor. */
checker_event::checker_event (enum event_kind kind,
- location_t loc, tree fndecl, int depth)
-: m_kind (kind), m_loc (loc),
- m_original_fndecl (fndecl), m_effective_fndecl (fndecl),
- m_original_depth (depth), m_effective_depth (depth),
+ const event_loc_info &loc_info)
+: m_kind (kind), m_loc (loc_info.m_loc),
+ m_original_fndecl (loc_info.m_fndecl),
+ m_effective_fndecl (loc_info.m_fndecl),
+ m_original_depth (loc_info.m_depth),
+ m_effective_depth (loc_info.m_depth),
m_pending_diagnostic (NULL), m_emission_id (),
- m_logical_loc (fndecl)
+ m_logical_loc (loc_info.m_fndecl)
{
/* Update effective fndecl and depth if inlining has been recorded. */
if (flag_analyzer_undo_inlining)
{
- inlining_info info (loc);
+ inlining_info info (m_loc);
if (info.get_inner_fndecl ())
{
m_effective_fndecl = info.get_inner_fndecl ();
@@ -272,7 +274,8 @@ precanned_custom_event::get_desc (bool) const
statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
const program_state &dst_state)
-: checker_event (EK_STMT, gimple_location (stmt), fndecl, depth),
+: checker_event (EK_STMT,
+ event_loc_info (gimple_location (stmt), fndecl, depth)),
m_stmt (stmt),
m_dst_state (dst_state)
{
@@ -293,93 +296,85 @@ statement_event::get_desc (bool) const
/* class region_creation_event : public checker_event. */
-region_creation_event::region_creation_event (const region *reg,
- tree capacity,
- enum rce_kind kind,
- location_t loc,
- tree fndecl,
- int depth)
-: checker_event (EK_REGION_CREATION, loc, fndecl, depth),
- m_reg (reg),
- m_capacity (capacity),
- m_rce_kind (kind)
+region_creation_event::region_creation_event (const event_loc_info &loc_info)
+: checker_event (EK_REGION_CREATION, loc_info)
{
- if (m_rce_kind == RCE_CAPACITY)
- gcc_assert (capacity);
}
-/* Implementation of diagnostic_event::get_desc vfunc for
- region_creation_event.
- There are effectively 3 kinds of region_region_event, to
- avoid combinatorial explosion by trying to convy the
- information in a single message. */
+/* The various region_creation_event subclasses' get_desc
+ implementations. */
label_text
-region_creation_event::get_desc (bool can_colorize) const
+region_creation_event_memory_space::get_desc (bool) const
{
- if (m_pending_diagnostic)
+ switch (m_mem_space)
{
- label_text custom_desc
- = m_pending_diagnostic->describe_region_creation_event
- (evdesc::region_creation (can_colorize, m_reg));
- if (custom_desc.get ())
- return custom_desc;
+ default:
+ return label_text::borrow ("region created here");
+ case MEMSPACE_STACK:
+ return label_text::borrow ("region created on stack here");
+ case MEMSPACE_HEAP:
+ return label_text::borrow ("region created on heap here");
}
+}
- switch (m_rce_kind)
+label_text
+region_creation_event_capacity::get_desc (bool can_colorize) const
+{
+ gcc_assert (m_capacity);
+ if (TREE_CODE (m_capacity) == INTEGER_CST)
{
- default:
- gcc_unreachable ();
-
- case RCE_MEM_SPACE:
- switch (m_reg->get_memory_space ())
- {
- default:
- return label_text::borrow ("region created here");
- case MEMSPACE_STACK:
- return label_text::borrow ("region created on stack here");
- case MEMSPACE_HEAP:
- return label_text::borrow ("region created on heap here");
- }
- break;
+ unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
+ return make_label_text_n (can_colorize,
+ hwi,
+ "capacity: %wu byte",
+ "capacity: %wu bytes",
+ hwi);
+ }
+ else
+ return make_label_text (can_colorize,
+ "capacity: %qE bytes", m_capacity);
+}
- case RCE_CAPACITY:
- gcc_assert (m_capacity);
+label_text
+region_creation_event_allocation_size::get_desc (bool can_colorize) const
+{
+ if (m_capacity)
+ {
if (TREE_CODE (m_capacity) == INTEGER_CST)
- {
- unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
- if (hwi == 1)
- return make_label_text (can_colorize,
- "capacity: %wu byte", hwi);
- else
- return make_label_text (can_colorize,
- "capacity: %wu bytes", hwi);
- }
+ return make_label_text_n (can_colorize,
+ tree_to_uhwi (m_capacity),
+ "allocated %E byte here",
+ "allocated %E bytes here",
+ m_capacity);
else
return make_label_text (can_colorize,
- "capacity: %qE bytes", m_capacity);
-
- case RCE_DEBUG:
- {
- pretty_printer pp;
- pp_format_decoder (&pp) = default_tree_printer;
- pp_string (&pp, "region creation: ");
- m_reg->dump_to_pp (&pp, true);
- if (m_capacity)
- pp_printf (&pp, " capacity: %qE", m_capacity);
- return label_text::take (xstrdup (pp_formatted_text (&pp)));
- }
- break;
+ "allocated %qE bytes here",
+ m_capacity);
}
+ return make_label_text (can_colorize, "allocated here");
+}
+
+label_text
+region_creation_event_debug::get_desc (bool) const
+{
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_string (&pp, "region creation: ");
+ m_reg->dump_to_pp (&pp, true);
+ if (m_capacity)
+ pp_printf (&pp, " capacity: %qE", m_capacity);
+ return label_text::take (xstrdup (pp_formatted_text (&pp)));
}
/* class function_entry_event : public checker_event. */
function_entry_event::function_entry_event (const program_point &dst_point)
: checker_event (EK_FUNCTION_ENTRY,
- dst_point.get_supernode ()->get_start_location (),
- dst_point.get_fndecl (),
- dst_point.get_stack_depth ())
+ event_loc_info (dst_point.get_supernode
+ ()->get_start_location (),
+ dst_point.get_fndecl (),
+ dst_point.get_stack_depth ()))
{
}
@@ -417,8 +412,9 @@ state_change_event::state_change_event (const supernode *node,
const svalue *origin,
const program_state &dst_state)
: checker_event (EK_STATE_CHANGE,
- stmt->location, node->m_fun->decl,
- stack_depth),
+ event_loc_info (stmt->location,
+ node->m_fun->decl,
+ stack_depth)),
m_node (node), m_stmt (stmt), m_sm (sm),
m_sval (sval), m_from (from), m_to (to),
m_origin (origin),
@@ -585,8 +581,8 @@ superedge_event::should_filter_p (int verbosity) const
superedge_event::superedge_event (enum event_kind kind,
const exploded_edge &eedge,
- location_t loc, tree fndecl, int depth)
-: checker_event (kind, loc, fndecl, depth),
+ const event_loc_info &loc_info)
+: checker_event (kind, loc_info),
m_eedge (eedge), m_sedge (eedge.m_sedge),
m_var (NULL_TREE), m_critical_state (0)
{
@@ -606,8 +602,8 @@ cfg_edge_event::get_cfg_superedge () const
cfg_edge_event::cfg_edge_event (enum event_kind kind,
const exploded_edge &eedge,
- location_t loc, tree fndecl, int depth)
-: superedge_event (kind, eedge, loc, fndecl, depth)
+ const event_loc_info &loc_info)
+: superedge_event (kind, eedge, loc_info)
{
gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
}
@@ -822,8 +818,8 @@ start_cfg_edge_event::should_print_expr_p (tree expr)
/* call_event's ctor. */
call_event::call_event (const exploded_edge &eedge,
- location_t loc, tree fndecl, int depth)
-: superedge_event (EK_CALL_EDGE, eedge, loc, fndecl, depth)
+ const event_loc_info &loc_info)
+: superedge_event (EK_CALL_EDGE, eedge, loc_info)
{
if (eedge.m_sedge)
gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
@@ -901,8 +897,8 @@ call_event::get_callee_fndecl () const
/* return_event's ctor. */
return_event::return_event (const exploded_edge &eedge,
- location_t loc, tree fndecl, int depth)
-: superedge_event (EK_RETURN_EDGE, eedge, loc, fndecl, depth)
+ const event_loc_info &loc_info)
+: superedge_event (EK_RETURN_EDGE, eedge, loc_info)
{
if (eedge.m_sedge)
gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
@@ -1052,9 +1048,9 @@ rewind_event::get_setjmp_caller () const
rewind_event::rewind_event (const exploded_edge *eedge,
enum event_kind kind,
- location_t loc, tree fndecl, int depth,
+ const event_loc_info &loc_info,
const rewind_info_t *rewind_info)
-: checker_event (kind, loc, fndecl, depth),
+: checker_event (kind, loc_info),
m_rewind_info (rewind_info),
m_eedge (eedge)
{
diff --git a/gcc/analyzer/checker-event.h b/gcc/analyzer/checker-event.h
index 18c44e6..6dac647 100644
--- a/gcc/analyzer/checker-event.h
+++ b/gcc/analyzer/checker-event.h
@@ -22,9 +22,23 @@ along with GCC; see the file COPYING3. If not see
#define GCC_ANALYZER_CHECKER_EVENT_H
#include "tree-logical-location.h"
+#include "analyzer/program-state.h"
namespace ana {
+/* A bundle of location information for a checker_event. */
+
+struct event_loc_info
+{
+ event_loc_info (location_t loc, tree fndecl, int depth)
+ : m_loc (loc), m_fndecl (fndecl), m_depth (depth)
+ {}
+
+ location_t m_loc;
+ tree m_fndecl;
+ int m_depth;
+};
+
/* An enum for discriminating between the concrete subclasses of
checker_event. */
@@ -124,7 +138,7 @@ public:
protected:
checker_event (enum event_kind kind,
- location_t loc, tree fndecl, int depth);
+ const event_loc_info &loc_info);
public:
const enum event_kind m_kind;
@@ -145,9 +159,10 @@ protected:
class debug_event : public checker_event
{
public:
- debug_event (location_t loc, tree fndecl, int depth,
- const char *desc)
- : checker_event (EK_DEBUG, loc, fndecl, depth),
+
+ debug_event (const event_loc_info &loc_info,
+ const char *desc)
+ : checker_event (EK_DEBUG, loc_info),
m_desc (xstrdup (desc))
{
}
@@ -168,8 +183,8 @@ private:
class custom_event : public checker_event
{
protected:
- custom_event (location_t loc, tree fndecl, int depth)
- : checker_event (EK_CUSTOM, loc, fndecl, depth)
+ custom_event (const event_loc_info &loc_info)
+ : checker_event (EK_CUSTOM, loc_info)
{
}
};
@@ -179,9 +194,9 @@ protected:
class precanned_custom_event : public custom_event
{
public:
- precanned_custom_event (location_t loc, tree fndecl, int depth,
+ precanned_custom_event (const event_loc_info &loc_info,
const char *desc)
- : custom_event (loc, fndecl, depth),
+ : custom_event (loc_info),
m_desc (xstrdup (desc))
{
}
@@ -211,43 +226,105 @@ public:
const program_state m_dst_state;
};
-/* There are too many combinations to express region creation in one message,
+/* An abstract event subclass describing the creation of a region that
+ is significant for a diagnostic.
+
+ There are too many combinations to express region creation in one message,
so we emit multiple region_creation_event instances when each pertinent
region is created.
- This enum distinguishes between the different messages. */
+ The events are created by pending_diagnostic's add_region_creation_events
+ vfunc, which by default creates a region_creation_event_memory_space, and
+ if a capacity is known, a region_creation_event_capacity, giving e.g.:
+ (1) region created on stack here
+ (2) capacity: 100 bytes
+ but this vfunc can be overridden to create other events if other wordings
+ are more appropriate foa a given pending_diagnostic. */
+
+class region_creation_event : public checker_event
+{
+protected:
+ region_creation_event (const event_loc_info &loc_info);
+};
+
+/* Concrete subclass of region_creation_event.
+ Generates a message based on the memory space of the region
+ e.g. "region created on stack here". */
-enum rce_kind
+class region_creation_event_memory_space : public region_creation_event
{
- /* Generate a message based on the memory space of the region
- e.g. "region created on stack here". */
- RCE_MEM_SPACE,
+public:
+ region_creation_event_memory_space (enum memory_space mem_space,
+ const event_loc_info &loc_info)
+ : region_creation_event (loc_info),
+ m_mem_space (mem_space)
+ {
+ }
- /* Generate a message based on the capacity of the region
- e.g. "capacity: 100 bytes". */
- RCE_CAPACITY,
+ label_text get_desc (bool can_colorize) const final override;
- /* Generate a debug message. */
- RCE_DEBUG
+private:
+ enum memory_space m_mem_space;
};
-/* A concrete event subclass describing the creation of a region that
- is significant for a diagnostic. */
+/* Concrete subclass of region_creation_event.
+ Generates a message based on the capacity of the region
+ e.g. "capacity: 100 bytes". */
-class region_creation_event : public checker_event
+class region_creation_event_capacity : public region_creation_event
+{
+public:
+ region_creation_event_capacity (tree capacity,
+ const event_loc_info &loc_info)
+ : region_creation_event (loc_info),
+ m_capacity (capacity)
+ {
+ gcc_assert (m_capacity);
+ }
+
+ label_text get_desc (bool can_colorize) const final override;
+
+private:
+ tree m_capacity;
+};
+
+/* Concrete subclass of region_creation_event.
+ Generates a message based on the capacity of the region
+ e.g. "allocated 100 bytes here". */
+
+class region_creation_event_allocation_size : public region_creation_event
+{
+public:
+ region_creation_event_allocation_size (tree capacity,
+ const event_loc_info &loc_info)
+ : region_creation_event (loc_info),
+ m_capacity (capacity)
+ {}
+
+ label_text get_desc (bool can_colorize) const final override;
+
+private:
+ tree m_capacity;
+};
+
+/* Concrete subclass of region_creation_event.
+ Generates a debug message intended for analyzer developers. */
+
+class region_creation_event_debug : public region_creation_event
{
public:
- region_creation_event (const region *reg,
- tree capacity,
- enum rce_kind kind,
- location_t loc, tree fndecl, int depth);
+ region_creation_event_debug (const region *reg, tree capacity,
+ const event_loc_info &loc_info)
+ : region_creation_event (loc_info),
+ m_reg (reg), m_capacity (capacity)
+ {
+ }
label_text get_desc (bool can_colorize) const final override;
private:
const region *m_reg;
tree m_capacity;
- enum rce_kind m_rce_kind;
};
/* An event subclass describing the entry to a function. */
@@ -255,8 +332,8 @@ private:
class function_entry_event : public checker_event
{
public:
- function_entry_event (location_t loc, tree fndecl, int depth)
- : checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth)
+ function_entry_event (const event_loc_info &loc_info)
+ : checker_event (EK_FUNCTION_ENTRY, loc_info)
{
}
@@ -322,7 +399,7 @@ public:
protected:
superedge_event (enum event_kind kind, const exploded_edge &eedge,
- location_t loc, tree fndecl, int depth);
+ const event_loc_info &loc_info);
public:
const exploded_edge &m_eedge;
@@ -344,7 +421,7 @@ public:
protected:
cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
- location_t loc, tree fndecl, int depth);
+ const event_loc_info &loc_info);
};
/* A concrete event subclass for the start of a CFG edge
@@ -354,8 +431,8 @@ class start_cfg_edge_event : public cfg_edge_event
{
public:
start_cfg_edge_event (const exploded_edge &eedge,
- location_t loc, tree fndecl, int depth)
- : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc, fndecl, depth)
+ const event_loc_info &loc_info)
+ : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc_info)
{
}
@@ -378,8 +455,8 @@ class end_cfg_edge_event : public cfg_edge_event
{
public:
end_cfg_edge_event (const exploded_edge &eedge,
- location_t loc, tree fndecl, int depth)
- : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc, fndecl, depth)
+ const event_loc_info &loc_info)
+ : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc_info)
{
}
@@ -395,7 +472,7 @@ class call_event : public superedge_event
{
public:
call_event (const exploded_edge &eedge,
- location_t loc, tree fndecl, int depth);
+ const event_loc_info &loc_info);
label_text get_desc (bool can_colorize) const override;
meaning get_meaning () const override;
@@ -416,7 +493,7 @@ class return_event : public superedge_event
{
public:
return_event (const exploded_edge &eedge,
- location_t loc, tree fndecl, int depth);
+ const event_loc_info &loc_info);
label_text get_desc (bool can_colorize) const final override;
meaning get_meaning () const override;
@@ -433,9 +510,9 @@ public:
class start_consolidated_cfg_edges_event : public checker_event
{
public:
- start_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth,
+ start_consolidated_cfg_edges_event (const event_loc_info &loc_info,
bool edge_sense)
- : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth),
+ : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc_info),
m_edge_sense (edge_sense)
{
}
@@ -453,8 +530,8 @@ public:
class end_consolidated_cfg_edges_event : public checker_event
{
public:
- end_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth)
- : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth)
+ end_consolidated_cfg_edges_event (const event_loc_info &loc_info)
+ : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc_info)
{
}
@@ -475,9 +552,10 @@ public:
tree apparent_caller_fndecl,
int actual_depth,
int stack_depth_adjustment)
- : checker_event (EK_INLINED_CALL, loc,
- apparent_caller_fndecl,
- actual_depth + stack_depth_adjustment),
+ : checker_event (EK_INLINED_CALL,
+ event_loc_info (loc,
+ apparent_caller_fndecl,
+ actual_depth + stack_depth_adjustment)),
m_apparent_callee_fndecl (apparent_callee_fndecl),
m_apparent_caller_fndecl (apparent_caller_fndecl)
{
@@ -497,9 +575,10 @@ private:
class setjmp_event : public checker_event
{
public:
- setjmp_event (location_t loc, const exploded_node *enode,
- tree fndecl, int depth, const gcall *setjmp_call)
- : checker_event (EK_SETJMP, loc, fndecl, depth),
+ setjmp_event (const event_loc_info &loc_info,
+ const exploded_node *enode,
+ const gcall *setjmp_call)
+ : checker_event (EK_SETJMP, loc_info),
m_enode (enode), m_setjmp_call (setjmp_call)
{
}
@@ -531,7 +610,7 @@ public:
protected:
rewind_event (const exploded_edge *eedge,
enum event_kind kind,
- location_t loc, tree fndecl, int depth,
+ const event_loc_info &loc_info,
const rewind_info_t *rewind_info);
const rewind_info_t *m_rewind_info;
@@ -546,9 +625,9 @@ class rewind_from_longjmp_event : public rewind_event
{
public:
rewind_from_longjmp_event (const exploded_edge *eedge,
- location_t loc, tree fndecl, int depth,
+ const event_loc_info &loc_info,
const rewind_info_t *rewind_info)
- : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc, fndecl, depth,
+ : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc_info,
rewind_info)
{
}
@@ -563,9 +642,9 @@ class rewind_to_setjmp_event : public rewind_event
{
public:
rewind_to_setjmp_event (const exploded_edge *eedge,
- location_t loc, tree fndecl, int depth,
+ const event_loc_info &loc_info,
const rewind_info_t *rewind_info)
- : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth,
+ : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc_info,
rewind_info)
{
}
@@ -588,10 +667,10 @@ private:
class warning_event : public checker_event
{
public:
- warning_event (location_t loc, tree fndecl, int depth,
+ warning_event (const event_loc_info &loc_info,
const state_machine *sm,
tree var, state_machine::state_t state)
- : checker_event (EK_WARNING, loc, fndecl, depth),
+ : checker_event (EK_WARNING, loc_info),
m_sm (sm), m_var (var), m_state (state)
{
}
diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc
index 221042e..c229e46 100644
--- a/gcc/analyzer/checker-path.cc
+++ b/gcc/analyzer/checker-path.cc
@@ -141,10 +141,10 @@ checker_path::debug () const
If DEBUG is true, also create an RCE_DEBUG event. */
void
-checker_path::add_region_creation_events (const region *reg,
+checker_path::add_region_creation_events (pending_diagnostic *pd,
+ const region *reg,
const region_model *model,
- location_t loc,
- tree fndecl, int depth,
+ const event_loc_info &loc_info,
bool debug)
{
tree capacity = NULL_TREE;
@@ -152,16 +152,11 @@ checker_path::add_region_creation_events (const region *reg,
if (const svalue *capacity_sval = model->get_capacity (reg))
capacity = model->get_representative_tree (capacity_sval);
- add_event (make_unique<region_creation_event> (reg, capacity, RCE_MEM_SPACE,
- loc, fndecl, depth));
-
- if (capacity)
- add_event (make_unique<region_creation_event> (reg, capacity, RCE_CAPACITY,
- loc, fndecl, depth));
+ pd->add_region_creation_events (reg, capacity, loc_info, *this);
if (debug)
- add_event (make_unique<region_creation_event> (reg, capacity, RCE_DEBUG,
- loc, fndecl, depth));
+ add_event (make_unique<region_creation_event_debug> (reg, capacity,
+ loc_info));
}
void
diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h
index 55bf1e3..de1f620 100644
--- a/gcc/analyzer/checker-path.h
+++ b/gcc/analyzer/checker-path.h
@@ -76,10 +76,10 @@ public:
m_events[idx] = new_event;
}
- void add_region_creation_events (const region *reg,
+ void add_region_creation_events (pending_diagnostic *pd,
+ const region *reg,
const region_model *model,
- location_t loc,
- tree fndecl, int depth,
+ const event_loc_info &loc_info,
bool debug);
/* After all event-pruning, a hook for notifying each event what
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index 1b19e58..9cc02da 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -1447,10 +1447,11 @@ diagnostic_manager::build_emission_path (const path_builder &pb,
&& DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
{
emission_path->add_region_creation_events
- (reg, NULL,
- DECL_SOURCE_LOCATION (decl),
- NULL_TREE,
- 0,
+ (pb.get_pending_diagnostic (),
+ reg, NULL,
+ event_loc_info (DECL_SOURCE_LOCATION (decl),
+ NULL_TREE,
+ 0),
m_verbosity > 3);
}
}
@@ -1463,7 +1464,8 @@ diagnostic_manager::build_emission_path (const path_builder &pb,
const exploded_edge *eedge = epath.m_edges[i];
add_events_for_eedge (pb, *eedge, emission_path, &interest);
}
- add_event_on_final_node (epath.get_final_enode (), emission_path, &interest);
+ add_event_on_final_node (pb, epath.get_final_enode (),
+ emission_path, &interest);
}
/* Emit a region_creation_event when requested on the last statement in
@@ -1475,7 +1477,8 @@ diagnostic_manager::build_emission_path (const path_builder &pb,
*/
void
-diagnostic_manager::add_event_on_final_node (const exploded_node *final_enode,
+diagnostic_manager::add_event_on_final_node (const path_builder &pb,
+ const exploded_node *final_enode,
checker_path *emission_path,
interesting_t *interest) const
{
@@ -1512,11 +1515,12 @@ diagnostic_manager::add_event_on_final_node (const exploded_node *final_enode,
case RK_HEAP_ALLOCATED:
case RK_ALLOCA:
emission_path->add_region_creation_events
- (reg,
+ (pb.get_pending_diagnostic (),
+ reg,
dst_model,
- src_point.get_location (),
- src_point.get_fndecl (),
- src_stack_depth,
+ event_loc_info (src_point.get_location (),
+ src_point.get_fndecl (),
+ src_stack_depth),
false);
emitted = true;
break;
@@ -1940,10 +1944,11 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
&& DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
{
emission_path->add_region_creation_events
- (reg, dst_state.m_region_model,
- DECL_SOURCE_LOCATION (decl),
- dst_point.get_fndecl (),
- dst_stack_depth,
+ (pb.get_pending_diagnostic (),
+ reg, dst_state.m_region_model,
+ event_loc_info (DECL_SOURCE_LOCATION (decl),
+ dst_point.get_fndecl (),
+ dst_stack_depth),
m_verbosity > 3);
}
}
@@ -1956,10 +1961,10 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
const gcall *call = dyn_cast <const gcall *> (stmt);
if (call && is_setjmp_call_p (call))
emission_path->add_event
- (make_unique<setjmp_event> (stmt->location,
+ (make_unique<setjmp_event> (event_loc_info (stmt->location,
+ dst_point.get_fndecl (),
+ dst_stack_depth),
dst_node,
- dst_point.get_fndecl (),
- dst_stack_depth,
call));
else
emission_path->add_event
@@ -2036,10 +2041,11 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
case RK_HEAP_ALLOCATED:
case RK_ALLOCA:
emission_path->add_region_creation_events
- (reg, dst_model,
- src_point.get_location (),
- src_point.get_fndecl (),
- src_stack_depth,
+ (pb.get_pending_diagnostic (),
+ reg, dst_model,
+ event_loc_info (src_point.get_location (),
+ src_point.get_fndecl (),
+ src_stack_depth),
m_verbosity > 3);
break;
}
@@ -2058,9 +2064,9 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
pb.get_feasibility_problem ()->dump_to_pp (&pp);
emission_path->add_event
(make_unique<precanned_custom_event>
- (dst_point.get_location (),
- dst_point.get_fndecl (),
- dst_stack_depth,
+ (event_loc_info (dst_point.get_location (),
+ dst_point.get_fndecl (),
+ dst_stack_depth),
pp_formatted_text (&pp)));
}
}
@@ -2172,18 +2178,17 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb,
case SUPEREDGE_CFG_EDGE:
{
emission_path->add_event
- (make_unique<start_cfg_edge_event> (eedge,
- (last_stmt
- ? last_stmt->location
- : UNKNOWN_LOCATION),
- src_point.get_fndecl (),
- src_stack_depth));
+ (make_unique<start_cfg_edge_event>
+ (eedge,
+ event_loc_info (last_stmt ? last_stmt->location : UNKNOWN_LOCATION,
+ src_point.get_fndecl (),
+ src_stack_depth)));
emission_path->add_event
(make_unique<end_cfg_edge_event>
(eedge,
- dst_point.get_supernode ()->get_start_location (),
- dst_point.get_fndecl (),
- dst_stack_depth));
+ event_loc_info (dst_point.get_supernode ()->get_start_location (),
+ dst_point.get_fndecl (),
+ dst_stack_depth)));
}
break;
@@ -2196,11 +2201,11 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb,
/* TODO: add a subclass for this, or generate events for the
summary. */
emission_path->add_event
- (make_unique<debug_event> ((last_stmt
- ? last_stmt->location
- : UNKNOWN_LOCATION),
- src_point.get_fndecl (),
- src_stack_depth,
+ (make_unique<debug_event> (event_loc_info (last_stmt
+ ? last_stmt->location
+ : UNKNOWN_LOCATION,
+ src_point.get_fndecl (),
+ src_stack_depth),
"call summary"));
}
break;
@@ -2213,11 +2218,11 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb,
const gcall *call_stmt = return_edge->get_call_stmt ();
emission_path->add_event
(make_unique<return_event> (eedge,
- (call_stmt
- ? call_stmt->location
- : UNKNOWN_LOCATION),
- dst_point.get_fndecl (),
- dst_stack_depth));
+ event_loc_info (call_stmt
+ ? call_stmt->location
+ : UNKNOWN_LOCATION,
+ dst_point.get_fndecl (),
+ dst_stack_depth)));
}
break;
}
@@ -2759,15 +2764,15 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const
start_idx, next_idx - 1, start_idx, start_idx +1);
start_consolidated_cfg_edges_event *new_start_ev
= new start_consolidated_cfg_edges_event
- (old_start_ev->get_location (),
- old_start_ev->get_fndecl (),
- old_start_ev->get_stack_depth (),
+ (event_loc_info (old_start_ev->get_location (),
+ old_start_ev->get_fndecl (),
+ old_start_ev->get_stack_depth ()),
edge_sense);
checker_event *new_end_ev
= new end_consolidated_cfg_edges_event
- (old_end_ev->get_location (),
- old_end_ev->get_fndecl (),
- old_end_ev->get_stack_depth ());
+ (event_loc_info (old_end_ev->get_location (),
+ old_end_ev->get_fndecl (),
+ old_end_ev->get_stack_depth ()));
path->replace_event (start_idx, new_start_ev);
path->replace_event (start_idx + 1, new_end_ev);
path->delete_events (start_idx + 2, next_idx - (start_idx + 2));
diff --git a/gcc/analyzer/diagnostic-manager.h b/gcc/analyzer/diagnostic-manager.h
index 4862cf4..56a233b 100644
--- a/gcc/analyzer/diagnostic-manager.h
+++ b/gcc/analyzer/diagnostic-manager.h
@@ -148,7 +148,8 @@ private:
const exploded_path &epath,
checker_path *emission_path) const;
- void add_event_on_final_node (const exploded_node *final_enode,
+ void add_event_on_final_node (const path_builder &pb,
+ const exploded_node *final_enode,
checker_path *emission_path,
interesting_t *interest) const;
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 0c49bb2..b3b81cc 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -310,21 +310,17 @@ public:
}
- void set_next_state (const gimple *stmt,
+ void set_next_state (const gimple *,
tree var,
state_machine::state_t to,
tree origin) final override
{
logger * const logger = get_logger ();
LOG_FUNC (logger);
- impl_region_model_context new_ctxt (m_eg, m_enode_for_diag,
- m_old_state, m_new_state,
- NULL, NULL,
- stmt);
const svalue *var_new_sval
- = m_new_state->m_region_model->get_rvalue (var, &new_ctxt);
+ = m_new_state->m_region_model->get_rvalue (var, NULL);
const svalue *origin_new_sval
- = m_new_state->m_region_model->get_rvalue (origin, &new_ctxt);
+ = m_new_state->m_region_model->get_rvalue (origin, NULL);
/* We use the new sval here to avoid issues with uninitialized values. */
state_machine::state_t current
@@ -350,12 +346,8 @@ public:
(m_eg, m_enode_for_diag, NULL, NULL, NULL/*m_enode->get_state ()*/,
NULL, stmt);
- impl_region_model_context new_ctxt (m_eg, m_enode_for_diag,
- m_old_state, m_new_state,
- NULL, NULL,
- stmt);
const svalue *origin_new_sval
- = m_new_state->m_region_model->get_rvalue (origin, &new_ctxt);
+ = m_new_state->m_region_model->get_rvalue (origin, NULL);
state_machine::state_t current
= m_old_smap->get_state (sval, m_eg.get_ext_state ());
@@ -380,11 +372,8 @@ public:
{
LOG_FUNC (get_logger ());
gcc_assert (d);
- impl_region_model_context old_ctxt
- (m_eg, m_enode_for_diag, m_old_state, m_new_state, NULL, NULL, NULL);
-
const svalue *var_old_sval
- = m_old_state->m_region_model->get_rvalue (var, &old_ctxt);
+ = m_old_state->m_region_model->get_rvalue (var, NULL);
state_machine::state_t current
= (var
? m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ())
@@ -400,9 +389,6 @@ public:
{
LOG_FUNC (get_logger ());
gcc_assert (d);
- impl_region_model_context old_ctxt
- (m_eg, m_enode_for_diag, m_old_state, m_new_state, NULL, NULL, NULL);
-
state_machine::state_t current
= (sval
? m_old_smap->get_state (sval, m_eg.get_ext_state ())
@@ -1803,9 +1789,9 @@ public:
/* Compare with diagnostic_manager::add_events_for_superedge. */
const int src_stack_depth = src_point.get_stack_depth ();
m_stack_pop_event = new precanned_custom_event
- (src_point.get_location (),
- src_point.get_fndecl (),
- src_stack_depth,
+ (event_loc_info (src_point.get_location (),
+ src_point.get_fndecl (),
+ src_stack_depth),
"stack frame is popped here, invalidating saved environment");
emission_path->add_event
(std::unique_ptr<custom_event> (m_stack_pop_event));
@@ -2059,19 +2045,19 @@ dynamic_call_info_t::add_events_to_path (checker_path *emission_path,
if (m_is_returning_call)
emission_path->add_event
(make_unique<return_event> (eedge,
- (m_dynamic_call
- ? m_dynamic_call->location
- : UNKNOWN_LOCATION),
- dest_point.get_fndecl (),
- dest_stack_depth));
+ event_loc_info (m_dynamic_call
+ ? m_dynamic_call->location
+ : UNKNOWN_LOCATION,
+ dest_point.get_fndecl (),
+ dest_stack_depth)));
else
emission_path->add_event
(make_unique<call_event> (eedge,
- (m_dynamic_call
- ? m_dynamic_call->location
- : UNKNOWN_LOCATION),
- src_point.get_fndecl (),
- src_stack_depth));
+ event_loc_info (m_dynamic_call
+ ? m_dynamic_call->location
+ : UNKNOWN_LOCATION,
+ src_point.get_fndecl (),
+ src_stack_depth)));
}
/* class rewind_info_t : public custom_edge_info. */
@@ -2117,14 +2103,18 @@ rewind_info_t::add_events_to_path (checker_path *emission_path,
emission_path->add_event
(make_unique<rewind_from_longjmp_event>
- (&eedge, get_longjmp_call ()->location,
- src_point.get_fndecl (),
- src_stack_depth, this));
+ (&eedge,
+ event_loc_info (get_longjmp_call ()->location,
+ src_point.get_fndecl (),
+ src_stack_depth),
+ this));
emission_path->add_event
(make_unique<rewind_to_setjmp_event>
- (&eedge, get_setjmp_call ()->location,
- dst_point.get_fndecl (),
- dst_stack_depth, this));
+ (&eedge,
+ event_loc_info (get_setjmp_call ()->location,
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ this));
}
/* class exploded_edge : public dedge<eg_traits>. */
@@ -2665,9 +2655,9 @@ mark_params_as_tainted (program_state *state, tree fndecl,
class tainted_args_function_custom_event : public custom_event
{
public:
- tainted_args_function_custom_event (location_t loc, tree fndecl, int depth)
- : custom_event (loc, fndecl, depth),
- m_fndecl (fndecl)
+ tainted_args_function_custom_event (const event_loc_info &loc_info)
+ : custom_event (loc_info),
+ m_fndecl (loc_info.m_fndecl)
{
}
@@ -2711,7 +2701,7 @@ public:
{
emission_path->add_event
(make_unique<tainted_args_function_custom_event>
- (DECL_SOURCE_LOCATION (m_fndecl), m_fndecl, 0));
+ (event_loc_info (DECL_SOURCE_LOCATION (m_fndecl), m_fndecl, 0)));
}
private:
@@ -3083,7 +3073,7 @@ class tainted_args_field_custom_event : public custom_event
{
public:
tainted_args_field_custom_event (tree field)
- : custom_event (DECL_SOURCE_LOCATION (field), NULL_TREE, 0),
+ : custom_event (event_loc_info (DECL_SOURCE_LOCATION (field), NULL_TREE, 0)),
m_field (field)
{
}
@@ -3107,9 +3097,9 @@ private:
class tainted_args_callback_custom_event : public custom_event
{
public:
- tainted_args_callback_custom_event (location_t loc, tree fndecl, int depth,
- tree field)
- : custom_event (loc, fndecl, depth),
+ tainted_args_callback_custom_event (const event_loc_info &loc_info,
+ tree field)
+ : custom_event (loc_info),
m_field (field)
{
}
@@ -3162,8 +3152,9 @@ public:
"(2) function 'gadget_dev_desc_UDC_store' used as initializer
for field 'store' marked with '__attribute__((tainted_args))'". */
emission_path->add_event
- (make_unique<tainted_args_callback_custom_event> (m_loc, m_fndecl,
- 0, m_field));
+ (make_unique<tainted_args_callback_custom_event>
+ (event_loc_info (m_loc, m_fndecl, 0),
+ m_field));
}
private:
diff --git a/gcc/analyzer/infinite-recursion.cc b/gcc/analyzer/infinite-recursion.cc
index 7055926..1a17d31f 100644
--- a/gcc/analyzer/infinite-recursion.cc
+++ b/gcc/analyzer/infinite-recursion.cc
@@ -191,9 +191,10 @@ public:
gcc_assert (m_new_entry_enode);
emission_path->add_event
(make_unique<warning_event>
- (m_new_entry_enode->get_supernode ()->get_start_location (),
- m_callee_fndecl,
- m_new_entry_enode->get_stack_depth (),
+ (event_loc_info (m_new_entry_enode->get_supernode
+ ()->get_start_location (),
+ m_callee_fndecl,
+ m_new_entry_enode->get_stack_depth ()),
NULL, NULL, NULL));
}
diff --git a/gcc/analyzer/kf-analyzer.cc b/gcc/analyzer/kf-analyzer.cc
new file mode 100644
index 0000000..b233418
--- /dev/null
+++ b/gcc/analyzer/kf-analyzer.cc
@@ -0,0 +1,386 @@
+/* Handling for the various __analyzer_* known functions.
+ Copyright (C) 2020-2022 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#define INCLUDE_MEMORY
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "diagnostic-core.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/analyzer-logging.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h" /* for default_tree_printer. */
+#include "analyzer/region-model.h"
+#include "analyzer/pending-diagnostic.h"
+#include "analyzer/call-details.h"
+#include "make-unique.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* Handle calls to "__analyzer_break" by triggering a breakpoint within
+ the analyzer. */
+
+class kf_analyzer_break : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+ void impl_call_pre (const call_details &) const final override
+ {
+ /* TODO: is there a good cross-platform way to do this? */
+ raise (SIGINT);
+ }
+};
+
+/* Handler for calls to "__analyzer_describe".
+
+ Emit a warning describing the 2nd argument (which can be of any
+ type), at the given verbosity level. This is for use when
+ debugging, and may be of use in DejaGnu tests. */
+
+class kf_analyzer_describe : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 2;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ if (!cd.get_ctxt ())
+ return;
+ tree t_verbosity = cd.get_arg_tree (0);
+ const svalue *sval = cd.get_arg_svalue (1);
+ bool simple = zerop (t_verbosity);
+ label_text desc = sval->get_desc (simple);
+ warning_at (cd.get_location (), 0, "svalue: %qs", desc.get ());
+ }
+};
+
+/* Handler for calls to "__analyzer_dump_capacity".
+
+ Emit a warning describing the capacity of the base region of
+ the region pointed to by the 1st argument.
+ This is for use when debugging, and may be of use in DejaGnu tests. */
+
+class kf_analyzer_dump_capacity : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return (cd.num_args () == 1
+ && cd.arg_is_pointer_p (0));
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+ region_model *model = cd.get_model ();
+ tree t_ptr = cd.get_arg_tree (0);
+ const svalue *sval_ptr = model->get_rvalue (t_ptr, ctxt);
+ const region *reg = model->deref_rvalue (sval_ptr, t_ptr, ctxt);
+ const region *base_reg = reg->get_base_region ();
+ const svalue *capacity = model->get_capacity (base_reg);
+ label_text desc = capacity->get_desc (true);
+ warning_at (cd.get_call_stmt ()->location, 0,
+ "capacity: %qs", desc.get ());
+ }
+};
+
+/* Compare D1 and D2 using their names, and then IDs to order them. */
+
+static int
+cmp_decls (tree d1, tree d2)
+{
+ gcc_assert (DECL_P (d1));
+ gcc_assert (DECL_P (d2));
+ if (DECL_NAME (d1) && DECL_NAME (d2))
+ if (int cmp = strcmp (IDENTIFIER_POINTER (DECL_NAME (d1)),
+ IDENTIFIER_POINTER (DECL_NAME (d2))))
+ return cmp;
+ return (int)DECL_UID (d1) - (int)DECL_UID (d2);
+}
+
+/* Comparator for use by vec<tree>::qsort,
+ using their names, and then IDs to order them. */
+
+static int
+cmp_decls_ptr_ptr (const void *p1, const void *p2)
+{
+ tree const *d1 = (tree const *)p1;
+ tree const *d2 = (tree const *)p2;
+
+ return cmp_decls (*d1, *d2);
+}
+
+/* Handler for calls to "__analyzer_dump_escaped".
+
+ Emit a warning giving the number of decls that have escaped, followed
+ by a comma-separated list of their names, in alphabetical order.
+
+ This is for use when debugging, and may be of use in DejaGnu tests. */
+
+class kf_analyzer_dump_escaped : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+ region_model *model = cd.get_model ();
+
+ auto_vec<tree> escaped_decls;
+ for (auto iter : *model->get_store ())
+ {
+ const binding_cluster *c = iter.second;
+ if (!c->escaped_p ())
+ continue;
+ if (tree decl = c->get_base_region ()->maybe_get_decl ())
+ escaped_decls.safe_push (decl);
+ }
+
+ /* Sort them into deterministic order; alphabetical is
+ probably most user-friendly. */
+ escaped_decls.qsort (cmp_decls_ptr_ptr);
+
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_show_color (&pp) = pp_show_color (global_dc->printer);
+ bool first = true;
+ for (auto iter : escaped_decls)
+ {
+ if (first)
+ first = false;
+ else
+ pp_string (&pp, ", ");
+ pp_printf (&pp, "%qD", iter);
+ }
+ /* Print the number to make it easier to write DejaGnu tests for
+ the "nothing has escaped" case. */
+ warning_at (cd.get_location (), 0, "escaped: %i: %s",
+ escaped_decls.length (),
+ pp_formatted_text (&pp));
+ }
+};
+
+/* Placeholder handler for calls to "__analyzer_dump_exploded_nodes".
+ This is a no-op; the real implementation happens when the
+ exploded_graph is postprocessed. */
+
+class kf_analyzer_dump_exploded_nodes : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 1;
+ }
+};
+
+/* Handler for calls to "__analyzer_dump_named_constant".
+
+ Look up the given name, and emit a warning describing the
+ state of the corresponding stashed value.
+
+ This is for use when debugging, and for DejaGnu tests. */
+
+class kf_analyzer_dump_named_constant : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 1;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+
+ const char *name = cd.get_arg_string_literal (0);
+ if (!name)
+ {
+ error_at (cd.get_location (), "cannot determine name");
+ return;
+ }
+ tree value = get_stashed_constant_by_name (name);
+ if (value)
+ warning_at (cd.get_location (), 0, "named constant %qs has value %qE",
+ name, value);
+ else
+ warning_at (cd.get_location (), 0, "named constant %qs has unknown value",
+ name);
+ }
+};
+
+/* A pending_diagnostic subclass for implementing "__analyzer_dump_path". */
+
+class dump_path_diagnostic
+ : public pending_diagnostic_subclass<dump_path_diagnostic>
+{
+public:
+ int get_controlling_option () const final override
+ {
+ return 0;
+ }
+
+ bool emit (rich_location *richloc) final override
+ {
+ inform (richloc, "path");
+ return true;
+ }
+
+ const char *get_kind () const final override
+ {
+ return "dump_path_diagnostic";
+ }
+
+ bool operator== (const dump_path_diagnostic &) const
+ {
+ return true;
+ }
+};
+
+/* Handle calls to "__analyzer_dump_path" by queuing a diagnostic at this
+ exploded_node. */
+
+class kf_analyzer_dump_path : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+ ctxt->warn (make_unique<dump_path_diagnostic> ());
+ }
+};
+
+/* Handle calls to "__analyzer_dump_region_model" by dumping
+ the region model's state to stderr. */
+
+class kf_analyzer_dump_region_model : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+ region_model *model = cd.get_model ();
+ model->dump (false);
+ }
+};
+
+/* Handle a call to "__analyzer_eval" by evaluating the input
+ and dumping as a dummy warning, so that test cases can use
+ dg-warning to validate the result (and so unexpected warnings will
+ lead to DejaGnu failures).
+ Broken out as a subroutine to make it easier to put a breakpoint on it
+ - though typically this doesn't help, as we have an SSA name as the arg,
+ and what's more interesting is usually the def stmt for that name. */
+
+class kf_analyzer_eval : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 1;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_context *ctxt = cd.get_ctxt ();
+ if (!ctxt)
+ return;
+ region_model *model = cd.get_model ();
+
+ tree t_arg = cd.get_arg_tree (0);
+ tristate t = model->eval_condition (t_arg, NE_EXPR, integer_zero_node,
+ ctxt);
+ warning_at (cd.get_location (), 0, "%s", t.as_string ());
+ }
+};
+
+/* Handler for "__analyzer_get_unknown_ptr". */
+
+class kf_analyzer_get_unknown_ptr : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model_manager *mgr = cd.get_manager ();
+ const svalue *ptr_sval
+ = mgr->get_or_create_unknown_svalue (cd.get_lhs_type ());
+ cd.maybe_set_lhs (ptr_sval);
+ }
+};
+
+/* Populate KFM with instances of known functions used for debugging the
+ analyzer and for writing DejaGnu tests, all with a "__analyzer_" prefix. */
+
+void
+register_known_analyzer_functions (known_function_manager &kfm)
+{
+ kfm.add ("__analyzer_break", make_unique<kf_analyzer_break> ());
+ kfm.add ("__analyzer_describe", make_unique<kf_analyzer_describe> ());
+ kfm.add ("__analyzer_dump_capacity",
+ make_unique<kf_analyzer_dump_capacity> ());
+ kfm.add ("__analyzer_dump_escaped", make_unique<kf_analyzer_dump_escaped> ());
+ kfm.add ("__analyzer_dump_exploded_nodes",
+ make_unique<kf_analyzer_dump_exploded_nodes> ());
+ kfm.add ("__analyzer_dump_named_constant",
+ make_unique<kf_analyzer_dump_named_constant> ());
+ kfm.add ("__analyzer_dump_path", make_unique<kf_analyzer_dump_path> ());
+ kfm.add ("__analyzer_dump_region_model",
+ make_unique<kf_analyzer_dump_region_model> ());
+ kfm.add ("__analyzer_eval", make_unique<kf_analyzer_eval> ());
+ kfm.add ("__analyzer_get_unknown_ptr",
+ make_unique<kf_analyzer_get_unknown_ptr> ());
+}
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/kf-lang-cp.cc b/gcc/analyzer/kf-lang-cp.cc
new file mode 100644
index 0000000..9dca366
--- /dev/null
+++ b/gcc/analyzer/kf-lang-cp.cc
@@ -0,0 +1,111 @@
+/* Handling for the known behavior of various functions specific to C++.
+ Copyright (C) 2020-2022 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#define INCLUDE_MEMORY
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "analyzer/analyzer.h"
+#include "analyzer/analyzer-logging.h"
+#include "diagnostic.h"
+#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
+#include "make-unique.h"
+
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* Implementations of specific functions. */
+
+/* Handler for "operator new" and "operator new []". */
+
+class kf_operator_new : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 1;
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model *model = cd.get_model ();
+ region_model_manager *mgr = cd.get_manager ();
+ const svalue *size_sval = cd.get_arg_svalue (0);
+ const region *new_reg
+ = model->get_or_create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
+ if (cd.get_lhs_type ())
+ {
+ const svalue *ptr_sval
+ = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
+ cd.maybe_set_lhs (ptr_sval);
+ }
+ }
+};
+
+/* Handler for "operator delete", both the sized and unsized variants
+ (2 arguments and 1 argument respectively), and for "operator delete []" */
+
+class kf_operator_delete : public known_function
+{
+public:
+ kf_operator_delete (unsigned num_args) : m_num_args (num_args) {}
+
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == m_num_args;
+ }
+
+ void impl_call_post (const call_details &cd) const final override
+ {
+ region_model *model = cd.get_model ();
+ const svalue *ptr_sval = cd.get_arg_svalue (0);
+ if (const region *freed_reg = ptr_sval->maybe_get_region ())
+ {
+ /* If the ptr points to an underlying heap region, delete it,
+ poisoning pointers. */
+ model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
+ }
+ }
+
+private:
+ unsigned m_num_args;
+};
+
+/* Populate KFM with instances of known functions relating to C++. */
+
+void
+register_known_functions_lang_cp (known_function_manager &kfm)
+{
+ kfm.add ("operator new", make_unique<kf_operator_new> ());
+ kfm.add ("operator new []", make_unique<kf_operator_new> ());
+ kfm.add ("operator delete", make_unique<kf_operator_delete> (1));
+ kfm.add ("operator delete", make_unique<kf_operator_delete> (2));
+ kfm.add ("operator delete []", make_unique<kf_operator_delete> (1));
+}
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
diff --git a/gcc/analyzer/known-function-manager.cc b/gcc/analyzer/known-function-manager.cc
index c1074bc..dc514a7 100644
--- a/gcc/analyzer/known-function-manager.cc
+++ b/gcc/analyzer/known-function-manager.cc
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple.h"
#include "analyzer/known-function-manager.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/pending-diagnostic.cc b/gcc/analyzer/pending-diagnostic.cc
index 53cab20..5ff32c0 100644
--- a/gcc/analyzer/pending-diagnostic.cc
+++ b/gcc/analyzer/pending-diagnostic.cc
@@ -192,11 +192,29 @@ pending_diagnostic::add_call_event (const exploded_edge &eedge,
const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
emission_path->add_event
(make_unique<call_event> (eedge,
- (last_stmt
- ? last_stmt->location
- : UNKNOWN_LOCATION),
- src_point.get_fndecl (),
- src_stack_depth));
+ event_loc_info (last_stmt
+ ? last_stmt->location
+ : UNKNOWN_LOCATION,
+ src_point.get_fndecl (),
+ src_stack_depth)));
+}
+
+/* Base implementation of pending_diagnostic::add_region_creation_events.
+ See the comment for class region_creation_event. */
+
+void
+pending_diagnostic::add_region_creation_events (const region *reg,
+ tree capacity,
+ const event_loc_info &loc_info,
+ checker_path &emission_path)
+{
+ emission_path.add_event
+ (make_unique<region_creation_event_memory_space> (reg->get_memory_space (),
+ loc_info));
+
+ if (capacity)
+ emission_path.add_event
+ (make_unique<region_creation_event_capacity> (capacity, loc_info));
}
/* Base implementation of pending_diagnostic::add_final_event.
@@ -210,11 +228,11 @@ pending_diagnostic::add_final_event (const state_machine *sm,
checker_path *emission_path)
{
emission_path->add_event
- (make_unique<warning_event> (get_stmt_location (stmt,
- enode->get_function ()),
- enode->get_function ()->decl,
- enode->get_stack_depth (),
- sm, var, state));
+ (make_unique<warning_event>
+ (event_loc_info (get_stmt_location (stmt, enode->get_function ()),
+ enode->get_function ()->decl,
+ enode->get_stack_depth ()),
+ sm, var, state));
}
} // namespace ana
diff --git a/gcc/analyzer/pending-diagnostic.h b/gcc/analyzer/pending-diagnostic.h
index 5d5d126..be446a4 100644
--- a/gcc/analyzer/pending-diagnostic.h
+++ b/gcc/analyzer/pending-diagnostic.h
@@ -59,17 +59,6 @@ struct event_desc
bool m_colorize;
};
-/* For use by pending_diagnostic::describe_region_creation. */
-
-struct region_creation : public event_desc
-{
- region_creation (bool colorize, const region *reg)
- : event_desc (colorize), m_reg (reg)
- {}
-
- const region *m_reg;
-};
-
/* For use by pending_diagnostic::describe_state_change. */
struct state_change : public event_desc
@@ -219,23 +208,6 @@ class pending_diagnostic
for the diagnostic, and FALSE for events in their paths. */
virtual location_t fixup_location (location_t loc, bool primary) const;
- /* For greatest precision-of-wording, the various following "describe_*"
- virtual functions give the pending diagnostic a way to describe events
- in a diagnostic_path in terms that make sense for that diagnostic.
-
- In each case, return a non-NULL label_text to give the event a custom
- description; NULL otherwise (falling back on a more generic
- description). */
-
- /* Precision-of-wording vfunc for describing a region creation event
- triggered by the mark_interesting_stuff vfunc. */
- virtual label_text
- describe_region_creation_event (const evdesc::region_creation &)
- {
- /* Default no-op implementation. */
- return label_text ();
- }
-
/* Precision-of-wording vfunc for describing a critical state change
within the diagnostic_path.
@@ -338,6 +310,14 @@ class pending_diagnostic
virtual void add_call_event (const exploded_edge &,
checker_path *);
+ /* Vfunc for adding any events for the creation of regions identified
+ by the mark_interesting_stuff vfunc.
+ See the comment for class region_creation_event. */
+ virtual void add_region_creation_events (const region *reg,
+ tree capacity,
+ const event_loc_info &loc_info,
+ checker_path &emission_path);
+
/* Vfunc for adding the final warning_event to a checker_path, so that e.g.
the infinite recursion diagnostic can have its diagnostic appear at
the callsite, but the final event in the path be at the entrypoint
diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc
index 8ba644c..6aeb928 100644
--- a/gcc/analyzer/region-model-impl-calls.cc
+++ b/gcc/analyzer/region-model-impl-calls.cc
@@ -26,228 +26,20 @@ along with GCC; see the file COPYING3. If not see
#include "function.h"
#include "basic-block.h"
#include "gimple.h"
-#include "gimple-iterator.h"
#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "diagnostic-color.h"
#include "diagnostic-metadata.h"
-#include "bitmap.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
-#include "ordered-hash-map.h"
-#include "options.h"
-#include "analyzer/supergraph.h"
-#include "sbitmap.h"
-#include "analyzer/call-string.h"
-#include "analyzer/program-point.h"
-#include "analyzer/store.h"
+#include "diagnostic.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
-#include "analyzer/sm.h"
-#include "diagnostic-path.h"
-#include "analyzer/pending-diagnostic.h"
-#include "gimple-pretty-print.h"
#include "make-unique.h"
#if ENABLE_ANALYZER
namespace ana {
-/* class call_details. */
-
-/* call_details's ctor. */
-
-call_details::call_details (const gcall *call, region_model *model,
- region_model_context *ctxt)
-: m_call (call), m_model (model), m_ctxt (ctxt),
- m_lhs_type (NULL_TREE), m_lhs_region (NULL)
-{
- m_lhs_type = NULL_TREE;
- if (tree lhs = gimple_call_lhs (call))
- {
- m_lhs_region = model->get_lvalue (lhs, ctxt);
- m_lhs_type = TREE_TYPE (lhs);
- }
-}
-
-/* Get the manager from m_model. */
-
-region_model_manager *
-call_details::get_manager () const
-{
- return m_model->get_manager ();
-}
-
-/* Get any logger associated with this object. */
-
-logger *
-call_details::get_logger () const
-{
- if (m_ctxt)
- return m_ctxt->get_logger ();
- else
- return NULL;
-}
-
-/* Get any uncertainty_t associated with the region_model_context. */
-
-uncertainty_t *
-call_details::get_uncertainty () const
-{
- if (m_ctxt)
- return m_ctxt->get_uncertainty ();
- else
- return NULL;
-}
-
-/* If the callsite has a left-hand-side region, set it to RESULT
- and return true.
- Otherwise do nothing and return false. */
-
-bool
-call_details::maybe_set_lhs (const svalue *result) const
-{
- gcc_assert (result);
- if (m_lhs_region)
- {
- m_model->set_value (m_lhs_region, result, m_ctxt);
- return true;
- }
- else
- return false;
-}
-
-/* Return the number of arguments used by the call statement. */
-
-unsigned
-call_details::num_args () const
-{
- return gimple_call_num_args (m_call);
-}
-
-/* Return true if argument IDX is a size_t (or compatible with it). */
-
-bool
-call_details::arg_is_size_p (unsigned idx) const
-{
- return types_compatible_p (get_arg_type (idx), size_type_node);
-}
-
-/* Get the location of the call statement. */
-
-location_t
-call_details::get_location () const
-{
- return m_call->location;
-}
-
-/* Get argument IDX at the callsite as a tree. */
-
-tree
-call_details::get_arg_tree (unsigned idx) const
-{
- return gimple_call_arg (m_call, idx);
-}
-
-/* Get the type of argument IDX. */
-
-tree
-call_details::get_arg_type (unsigned idx) const
-{
- return TREE_TYPE (gimple_call_arg (m_call, idx));
-}
-
-/* Get argument IDX at the callsite as an svalue. */
-
-const svalue *
-call_details::get_arg_svalue (unsigned idx) const
-{
- tree arg = get_arg_tree (idx);
- return m_model->get_rvalue (arg, m_ctxt);
-}
-
-/* Attempt to get the string literal for argument IDX, or return NULL
- otherwise.
- For use when implementing "__analyzer_*" functions that take
- string literals. */
-
-const char *
-call_details::get_arg_string_literal (unsigned idx) const
-{
- const svalue *str_arg = get_arg_svalue (idx);
- if (const region *pointee = str_arg->maybe_get_region ())
- if (const string_region *string_reg = pointee->dyn_cast_string_region ())
- {
- tree string_cst = string_reg->get_string_cst ();
- return TREE_STRING_POINTER (string_cst);
- }
- return NULL;
-}
-
-/* Attempt to get the fndecl used at this call, if known, or NULL_TREE
- otherwise. */
-
-tree
-call_details::get_fndecl_for_call () const
-{
- return m_model->get_fndecl_for_call (m_call, m_ctxt);
-}
-
-/* Dump a multiline representation of this call to PP. */
-
-void
-call_details::dump_to_pp (pretty_printer *pp, bool simple) const
-{
- pp_string (pp, "gcall: ");
- pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */);
- pp_newline (pp);
- pp_string (pp, "return region: ");
- if (m_lhs_region)
- m_lhs_region->dump_to_pp (pp, simple);
- else
- pp_string (pp, "NULL");
- pp_newline (pp);
- for (unsigned i = 0; i < gimple_call_num_args (m_call); i++)
- {
- const svalue *arg_sval = get_arg_svalue (i);
- pp_printf (pp, "arg %i: ", i);
- arg_sval->dump_to_pp (pp, simple);
- pp_newline (pp);
- }
-}
-
-/* Dump a multiline representation of this call to stderr. */
-
-DEBUG_FUNCTION void
-call_details::dump (bool simple) const
-{
- pretty_printer pp;
- pp_format_decoder (&pp) = default_tree_printer;
- pp_show_color (&pp) = pp_show_color (global_dc->printer);
- pp.buffer->stream = stderr;
- dump_to_pp (&pp, simple);
- pp_flush (&pp);
-}
-
-/* Get a conjured_svalue for this call for REG,
- and purge any state already relating to that conjured_svalue. */
-
-const svalue *
-call_details::get_or_create_conjured_svalue (const region *reg) const
-{
- region_model_manager *mgr = m_model->get_manager ();
- return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg,
- conjured_purge (m_model, m_ctxt));
-}
-
/* Implementations of specific functions. */
/* Handler for "alloca". */
@@ -277,324 +69,6 @@ kf_alloca::impl_call_pre (const call_details &cd) const
cd.maybe_set_lhs (ptr_sval);
}
-/* Handle calls to "__analyzer_break" by triggering a breakpoint within
- the analyzer. */
-
-class kf_analyzer_break : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 0;
- }
- void impl_call_pre (const call_details &) const final override
- {
- /* TODO: is there a good cross-platform way to do this? */
- raise (SIGINT);
- }
-};
-
-/* Handler for calls to "__analyzer_describe".
-
- Emit a warning describing the 2nd argument (which can be of any
- type), at the given verbosity level. This is for use when
- debugging, and may be of use in DejaGnu tests. */
-
-class kf_analyzer_describe : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 2;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- if (!cd.get_ctxt ())
- return;
- tree t_verbosity = cd.get_arg_tree (0);
- const svalue *sval = cd.get_arg_svalue (1);
- bool simple = zerop (t_verbosity);
- label_text desc = sval->get_desc (simple);
- warning_at (cd.get_location (), 0, "svalue: %qs", desc.get ());
- }
-};
-
-/* Handler for calls to "__analyzer_dump_capacity".
-
- Emit a warning describing the capacity of the base region of
- the region pointed to by the 1st argument.
- This is for use when debugging, and may be of use in DejaGnu tests. */
-
-class kf_analyzer_dump_capacity : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return (cd.num_args () == 1
- && cd.arg_is_pointer_p (0));
- }
-
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
- region_model *model = cd.get_model ();
- tree t_ptr = cd.get_arg_tree (0);
- const svalue *sval_ptr = model->get_rvalue (t_ptr, ctxt);
- const region *reg = model->deref_rvalue (sval_ptr, t_ptr, ctxt);
- const region *base_reg = reg->get_base_region ();
- const svalue *capacity = model->get_capacity (base_reg);
- label_text desc = capacity->get_desc (true);
- warning_at (cd.get_call_stmt ()->location, 0,
- "capacity: %qs", desc.get ());
- }
-};
-
-/* Compare D1 and D2 using their names, and then IDs to order them. */
-
-static int
-cmp_decls (tree d1, tree d2)
-{
- gcc_assert (DECL_P (d1));
- gcc_assert (DECL_P (d2));
- if (DECL_NAME (d1) && DECL_NAME (d2))
- if (int cmp = strcmp (IDENTIFIER_POINTER (DECL_NAME (d1)),
- IDENTIFIER_POINTER (DECL_NAME (d2))))
- return cmp;
- return (int)DECL_UID (d1) - (int)DECL_UID (d2);
-}
-
-/* Comparator for use by vec<tree>::qsort,
- using their names, and then IDs to order them. */
-
-static int
-cmp_decls_ptr_ptr (const void *p1, const void *p2)
-{
- tree const *d1 = (tree const *)p1;
- tree const *d2 = (tree const *)p2;
-
- return cmp_decls (*d1, *d2);
-}
-
-/* Handler for calls to "__analyzer_dump_escaped".
-
- Emit a warning giving the number of decls that have escaped, followed
- by a comma-separated list of their names, in alphabetical order.
-
- This is for use when debugging, and may be of use in DejaGnu tests. */
-
-class kf_analyzer_dump_escaped : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 0;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
- region_model *model = cd.get_model ();
-
- auto_vec<tree> escaped_decls;
- for (auto iter : *model->get_store ())
- {
- const binding_cluster *c = iter.second;
- if (!c->escaped_p ())
- continue;
- if (tree decl = c->get_base_region ()->maybe_get_decl ())
- escaped_decls.safe_push (decl);
- }
-
- /* Sort them into deterministic order; alphabetical is
- probably most user-friendly. */
- escaped_decls.qsort (cmp_decls_ptr_ptr);
-
- pretty_printer pp;
- pp_format_decoder (&pp) = default_tree_printer;
- pp_show_color (&pp) = pp_show_color (global_dc->printer);
- bool first = true;
- for (auto iter : escaped_decls)
- {
- if (first)
- first = false;
- else
- pp_string (&pp, ", ");
- pp_printf (&pp, "%qD", iter);
- }
- /* Print the number to make it easier to write DejaGnu tests for
- the "nothing has escaped" case. */
- warning_at (cd.get_location (), 0, "escaped: %i: %s",
- escaped_decls.length (),
- pp_formatted_text (&pp));
- }
-};
-
-/* Placeholder handler for calls to "__analyzer_dump_exploded_nodes".
- This is a no-op; the real implementation happens when the
- exploded_graph is postprocessed. */
-
-class kf_analyzer_dump_exploded_nodes : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 1;
- }
-};
-
-/* Handler for calls to "__analyzer_dump_named_constant".
-
- Look up the given name, and emit a warning describing the
- state of the corresponding stashed value.
-
- This is for use when debugging, and for DejaGnu tests. */
-
-class kf_analyzer_dump_named_constant : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 1;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
-
- const char *name = cd.get_arg_string_literal (0);
- if (!name)
- {
- error_at (cd.get_location (), "cannot determine name");
- return;
- }
- tree value = get_stashed_constant_by_name (name);
- if (value)
- warning_at (cd.get_location (), 0, "named constant %qs has value %qE",
- name, value);
- else
- warning_at (cd.get_location (), 0, "named constant %qs has unknown value",
- name);
- }
-};
-
-/* A pending_diagnostic subclass for implementing "__analyzer_dump_path". */
-
-class dump_path_diagnostic
- : public pending_diagnostic_subclass<dump_path_diagnostic>
-{
-public:
- int get_controlling_option () const final override
- {
- return 0;
- }
-
- bool emit (rich_location *richloc) final override
- {
- inform (richloc, "path");
- return true;
- }
-
- const char *get_kind () const final override
- {
- return "dump_path_diagnostic";
- }
-
- bool operator== (const dump_path_diagnostic &) const
- {
- return true;
- }
-};
-
-/* Handle calls to "__analyzer_dump_path" by queuing a diagnostic at this
- exploded_node. */
-
-class kf_analyzer_dump_path : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 0;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
- ctxt->warn (make_unique<dump_path_diagnostic> ());
- }
-};
-
-/* Handle calls to "__analyzer_dump_region_model" by dumping
- the region model's state to stderr. */
-
-class kf_analyzer_dump_region_model : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 0;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
- region_model *model = cd.get_model ();
- model->dump (false);
- }
-};
-
-/* Handle a call to "__analyzer_eval" by evaluating the input
- and dumping as a dummy warning, so that test cases can use
- dg-warning to validate the result (and so unexpected warnings will
- lead to DejaGnu failures).
- Broken out as a subroutine to make it easier to put a breakpoint on it
- - though typically this doesn't help, as we have an SSA name as the arg,
- and what's more interesting is usually the def stmt for that name. */
-
-class kf_analyzer_eval : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 1;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_context *ctxt = cd.get_ctxt ();
- if (!ctxt)
- return;
- region_model *model = cd.get_model ();
-
- tree t_arg = cd.get_arg_tree (0);
- tristate t = model->eval_condition (t_arg, NE_EXPR, integer_zero_node,
- ctxt);
- warning_at (cd.get_location (), 0, "%s", t.as_string ());
- }
-};
-
-/* Handler for "__analyzer_get_unknown_ptr". */
-
-class kf_analyzer_get_unknown_ptr : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 0;
- }
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model_manager *mgr = cd.get_manager ();
- const svalue *ptr_sval
- = mgr->get_or_create_unknown_svalue (cd.get_lhs_type ());
- cd.maybe_set_lhs (ptr_sval);
- }
-};
-
/* Handler for "__builtin_expect" etc. */
class kf_expect : public internal_known_function
@@ -977,61 +451,6 @@ public:
}
};
-/* Handler for "operator new" and "operator new []". */
-
-class kf_operator_new : public known_function
-{
-public:
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == 1;
- }
-
- void impl_call_pre (const call_details &cd) const final override
- {
- region_model *model = cd.get_model ();
- region_model_manager *mgr = cd.get_manager ();
- const svalue *size_sval = cd.get_arg_svalue (0);
- const region *new_reg
- = model->get_or_create_region_for_heap_alloc (size_sval, cd.get_ctxt ());
- if (cd.get_lhs_type ())
- {
- const svalue *ptr_sval
- = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
- cd.maybe_set_lhs (ptr_sval);
- }
- }
-};
-
-/* Handler for "operator delete", both the sized and unsized variants
- (2 arguments and 1 argument respectively), and for "operator delete []" */
-
-class kf_operator_delete : public known_function
-{
-public:
- kf_operator_delete (unsigned num_args) : m_num_args (num_args) {}
-
- bool matches_call_types_p (const call_details &cd) const final override
- {
- return cd.num_args () == m_num_args;
- }
-
- void impl_call_post (const call_details &cd) const final override
- {
- region_model *model = cd.get_model ();
- const svalue *ptr_sval = cd.get_arg_svalue (0);
- if (const region *freed_reg = ptr_sval->maybe_get_region ())
- {
- /* If the ptr points to an underlying heap region, delete it,
- poisoning pointers. */
- model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
- }
- }
-
-private:
- unsigned m_num_args;
-};
-
/* Handler for "realloc":
void *realloc(void *ptr, size_t size);
@@ -1490,6 +909,9 @@ region_model::impl_deallocation_call (const call_details &cd)
void
register_known_functions (known_function_manager &kfm)
{
+ /* Debugging/test support functions, all with a "__analyzer_" prefix. */
+ register_known_analyzer_functions (kfm);
+
/* Internal fns the analyzer has known_functions for. */
{
kfm.add (IFN_BUILTIN_EXPECT, make_unique<kf_expect> ());
@@ -1520,27 +942,6 @@ register_known_functions (known_function_manager &kfm)
register_varargs_builtins (kfm);
}
- /* Debugging/test support functions, all with a "__analyzer_" prefix. */
- {
- kfm.add ("__analyzer_break", make_unique<kf_analyzer_break> ());
- kfm.add ("__analyzer_describe", make_unique<kf_analyzer_describe> ());
- kfm.add ("__analyzer_dump_capacity",
- make_unique<kf_analyzer_dump_capacity> ());
- kfm.add ("__analyzer_dump_escaped",
- make_unique<kf_analyzer_dump_escaped> ());
- kfm.add ("__analyzer_dump_exploded_nodes",
- make_unique<kf_analyzer_dump_exploded_nodes> ());
- kfm.add ("__analyzer_dump_named_constant",
- make_unique<kf_analyzer_dump_named_constant> ());
- kfm.add ("__analyzer_dump_path", make_unique<kf_analyzer_dump_path> ());
- kfm.add ("__analyzer_dump_region_model",
- make_unique<kf_analyzer_dump_region_model> ());
- kfm.add ("__analyzer_eval",
- make_unique<kf_analyzer_eval> ());
- kfm.add ("__analyzer_get_unknown_ptr",
- make_unique<kf_analyzer_get_unknown_ptr> ());
- }
-
/* Known builtins and C standard library functions. */
{
kfm.add ("memset", make_unique<kf_memset> ());
@@ -1575,14 +976,8 @@ register_known_functions (known_function_manager &kfm)
kfm.add ("__error", make_unique<kf_errno_location> ());
}
- /* C++ support functions. */
- {
- kfm.add ("operator new", make_unique<kf_operator_new> ());
- kfm.add ("operator new []", make_unique<kf_operator_new> ());
- kfm.add ("operator delete", make_unique<kf_operator_delete> (1));
- kfm.add ("operator delete", make_unique<kf_operator_delete> (2));
- kfm.add ("operator delete []", make_unique<kf_operator_delete> (1));
- }
+ /* Language-specific support functions. */
+ register_known_functions_lang_cp (kfm);
}
} // namespace ana
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index ae63c66..0fb9638 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -237,6 +237,17 @@ region_model_manager::get_or_create_int_cst (tree type, poly_int64 val)
return get_or_create_constant_svalue (tree_cst);
}
+/* Return the svalue * for the constant_svalue for the NULL pointer
+ of POINTER_TYPE, creating it if necessary. */
+
+const svalue *
+region_model_manager::get_or_create_null_ptr (tree pointer_type)
+{
+ gcc_assert (pointer_type);
+ gcc_assert (POINTER_TYPE_P (pointer_type));
+ return get_or_create_int_cst (pointer_type, 0);
+}
+
/* Return the svalue * for a unknown_svalue for TYPE (which can be NULL),
creating it if necessary.
The unknown_svalue instances are reused, based on pointer equality
@@ -620,6 +631,9 @@ region_model_manager::maybe_fold_binop (tree type, enum tree_code op,
/* (VAL - 0) -> VAL. */
if (cst1 && zerop (cst1))
return get_or_create_cast (type, arg0);
+ /* (0 - VAL) -> -VAL. */
+ if (cst0 && zerop (cst0))
+ return get_or_create_unaryop (type, NEGATE_EXPR, arg1);
break;
case MULT_EXPR:
/* (VAL * 0). */
diff --git a/gcc/analyzer/region-model-manager.h b/gcc/analyzer/region-model-manager.h
index 22f9800..13fbe48 100644
--- a/gcc/analyzer/region-model-manager.h
+++ b/gcc/analyzer/region-model-manager.h
@@ -43,6 +43,7 @@ public:
/* svalue consolidation. */
const svalue *get_or_create_constant_svalue (tree cst_expr);
const svalue *get_or_create_int_cst (tree type, poly_int64);
+ const svalue *get_or_create_null_ptr (tree pointer_type);
const svalue *get_or_create_unknown_svalue (tree type);
const svalue *get_or_create_setjmp_svalue (const setjmp_record &r,
tree type);
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 7f2c0b6..18eaf22 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -74,6 +74,8 @@ along with GCC; see the file COPYING3. If not see
#include "calls.h"
#include "is-a.h"
#include "gcc-rich-location.h"
+#include "analyzer/checker-event.h"
+#include "analyzer/checker-path.h"
#if ENABLE_ANALYZER
@@ -1212,659 +1214,6 @@ region_model::on_stmt_pre (const gimple *stmt,
}
}
-/* Abstract base class for all out-of-bounds warnings with concrete values. */
-
-class out_of_bounds : public pending_diagnostic_subclass<out_of_bounds>
-{
-public:
- out_of_bounds (const region *reg, tree diag_arg,
- byte_range out_of_bounds_range)
- : m_reg (reg), m_diag_arg (diag_arg),
- m_out_of_bounds_range (out_of_bounds_range)
- {}
-
- const char *get_kind () const final override
- {
- return "out_of_bounds_diagnostic";
- }
-
- bool operator== (const out_of_bounds &other) const
- {
- return m_reg == other.m_reg
- && m_out_of_bounds_range == other.m_out_of_bounds_range
- && pending_diagnostic::same_tree_p (m_diag_arg, other.m_diag_arg);
- }
-
- int get_controlling_option () const final override
- {
- return OPT_Wanalyzer_out_of_bounds;
- }
-
- void mark_interesting_stuff (interesting_t *interest) final override
- {
- interest->add_region_creation (m_reg);
- }
-
-protected:
- const region *m_reg;
- tree m_diag_arg;
- byte_range m_out_of_bounds_range;
-};
-
-/* Abstract subclass to complaing about out-of-bounds
- past the end of the buffer. */
-
-class past_the_end : public out_of_bounds
-{
-public:
- past_the_end (const region *reg, tree diag_arg, byte_range range,
- tree byte_bound)
- : out_of_bounds (reg, diag_arg, range), m_byte_bound (byte_bound)
- {}
-
- bool operator== (const past_the_end &other) const
- {
- return out_of_bounds::operator== (other)
- && pending_diagnostic::same_tree_p (m_byte_bound,
- other.m_byte_bound);
- }
-
- label_text
- describe_region_creation_event (const evdesc::region_creation &ev) final
- override
- {
- if (m_byte_bound && TREE_CODE (m_byte_bound) == INTEGER_CST)
- return ev.formatted_print ("capacity is %E bytes", m_byte_bound);
-
- return label_text ();
- }
-
-protected:
- tree m_byte_bound;
-};
-
-/* Concrete subclass to complain about buffer overflows. */
-
-class buffer_overflow : public past_the_end
-{
-public:
- buffer_overflow (const region *reg, tree diag_arg,
- byte_range range, tree byte_bound)
- : past_the_end (reg, diag_arg, range, byte_bound)
- {}
-
- bool emit (rich_location *rich_loc) final override
- {
- diagnostic_metadata m;
- bool warned;
- switch (m_reg->get_memory_space ())
- {
- default:
- m.add_cwe (787);
- warned = warning_meta (rich_loc, m, get_controlling_option (),
- "buffer overflow");
- break;
- case MEMSPACE_STACK:
- m.add_cwe (121);
- warned = warning_meta (rich_loc, m, get_controlling_option (),
- "stack-based buffer overflow");
- break;
- case MEMSPACE_HEAP:
- m.add_cwe (122);
- warned = warning_meta (rich_loc, m, get_controlling_option (),
- "heap-based buffer overflow");
- break;
- }
-
- if (warned)
- {
- char num_bytes_past_buf[WIDE_INT_PRINT_BUFFER_SIZE];
- print_dec (m_out_of_bounds_range.m_size_in_bytes,
- num_bytes_past_buf, UNSIGNED);
- if (m_diag_arg)
- inform (rich_loc->get_loc (), "write is %s bytes past the end"
- " of %qE", num_bytes_past_buf,
- m_diag_arg);
- else
- inform (rich_loc->get_loc (), "write is %s bytes past the end"
- "of the region",
- num_bytes_past_buf);
- }
-
- return warned;
- }
-
- label_text describe_final_event (const evdesc::final_event &ev)
- final override
- {
- byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
- byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
- char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
- print_dec (start, start_buf, SIGNED);
- char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
- print_dec (end, end_buf, SIGNED);
-
- if (start == end)
- {
- if (m_diag_arg)
- return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
- " ends at byte %E", start_buf, m_diag_arg,
- m_byte_bound);
- return ev.formatted_print ("out-of-bounds write at byte %s but region"
- " ends at byte %E", start_buf,
- m_byte_bound);
- }
- else
- {
- if (m_diag_arg)
- return ev.formatted_print ("out-of-bounds write from byte %s till"
- " byte %s but %qE ends at byte %E",
- start_buf, end_buf, m_diag_arg,
- m_byte_bound);
- return ev.formatted_print ("out-of-bounds write from byte %s till"
- " byte %s but region ends at byte %E",
- start_buf, end_buf, m_byte_bound);
- }
- }
-};
-
-/* Concrete subclass to complain about buffer overreads. */
-
-class buffer_overread : public past_the_end
-{
-public:
- buffer_overread (const region *reg, tree diag_arg,
- byte_range range, tree byte_bound)
- : past_the_end (reg, diag_arg, range, byte_bound)
- {}
-
- bool emit (rich_location *rich_loc) final override
- {
- diagnostic_metadata m;
- m.add_cwe (126);
- bool warned = warning_meta (rich_loc, m, get_controlling_option (),
- "buffer overread");
-
- if (warned)
- {
- char num_bytes_past_buf[WIDE_INT_PRINT_BUFFER_SIZE];
- print_dec (m_out_of_bounds_range.m_size_in_bytes,
- num_bytes_past_buf, UNSIGNED);
- if (m_diag_arg)
- inform (rich_loc->get_loc (), "read is %s bytes past the end"
- " of %qE", num_bytes_past_buf,
- m_diag_arg);
- else
- inform (rich_loc->get_loc (), "read is %s bytes past the end"
- "of the region",
- num_bytes_past_buf);
- }
-
- return warned;
- }
-
- label_text describe_final_event (const evdesc::final_event &ev)
- final override
- {
- byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
- byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
- char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
- print_dec (start, start_buf, SIGNED);
- char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
- print_dec (end, end_buf, SIGNED);
-
- if (start == end)
- {
- if (m_diag_arg)
- return ev.formatted_print ("out-of-bounds read at byte %s but %qE"
- " ends at byte %E", start_buf, m_diag_arg,
- m_byte_bound);
- return ev.formatted_print ("out-of-bounds read at byte %s but region"
- " ends at byte %E", start_buf,
- m_byte_bound);
- }
- else
- {
- if (m_diag_arg)
- return ev.formatted_print ("out-of-bounds read from byte %s till"
- " byte %s but %qE ends at byte %E",
- start_buf, end_buf, m_diag_arg,
- m_byte_bound);
- return ev.formatted_print ("out-of-bounds read from byte %s till"
- " byte %s but region ends at byte %E",
- start_buf, end_buf, m_byte_bound);
- }
- }
-};
-
-/* Concrete subclass to complain about buffer underflows. */
-
-class buffer_underflow : public out_of_bounds
-{
-public:
- buffer_underflow (const region *reg, tree diag_arg, byte_range range)
- : out_of_bounds (reg, diag_arg, range)
- {}
-
- bool emit (rich_location *rich_loc) final override
- {
- diagnostic_metadata m;
- m.add_cwe (124);
- return warning_meta (rich_loc, m, get_controlling_option (),
- "buffer underflow");
- }
-
- label_text describe_final_event (const evdesc::final_event &ev)
- final override
- {
- byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
- byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
- char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
- print_dec (start, start_buf, SIGNED);
- char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
- print_dec (end, end_buf, SIGNED);
-
- if (start == end)
- {
- if (m_diag_arg)
- return ev.formatted_print ("out-of-bounds write at byte %s but %qE"
- " starts at byte 0", start_buf,
- m_diag_arg);
- return ev.formatted_print ("out-of-bounds write at byte %s but region"
- " starts at byte 0", start_buf);
- }
- else
- {
- if (m_diag_arg)
- return ev.formatted_print ("out-of-bounds write from byte %s till"
- " byte %s but %qE starts at byte 0",
- start_buf, end_buf, m_diag_arg);
- return ev.formatted_print ("out-of-bounds write from byte %s till"
- " byte %s but region starts at byte 0",
- start_buf, end_buf);;
- }
- }
-};
-
-/* Concrete subclass to complain about buffer underreads. */
-
-class buffer_underread : public out_of_bounds
-{
-public:
- buffer_underread (const region *reg, tree diag_arg, byte_range range)
- : out_of_bounds (reg, diag_arg, range)
- {}
-
- bool emit (rich_location *rich_loc) final override
- {
- diagnostic_metadata m;
- m.add_cwe (127);
- return warning_meta (rich_loc, m, get_controlling_option (),
- "buffer underread");
- }
-
- label_text describe_final_event (const evdesc::final_event &ev)
- final override
- {
- byte_size_t start = m_out_of_bounds_range.get_start_byte_offset ();
- byte_size_t end = m_out_of_bounds_range.get_last_byte_offset ();
- char start_buf[WIDE_INT_PRINT_BUFFER_SIZE];
- print_dec (start, start_buf, SIGNED);
- char end_buf[WIDE_INT_PRINT_BUFFER_SIZE];
- print_dec (end, end_buf, SIGNED);
-
- if (start == end)
- {
- if (m_diag_arg)
- return ev.formatted_print ("out-of-bounds read at byte %s but %qE"
- " starts at byte 0", start_buf,
- m_diag_arg);
- return ev.formatted_print ("out-of-bounds read at byte %s but region"
- " starts at byte 0", start_buf);
- }
- else
- {
- if (m_diag_arg)
- return ev.formatted_print ("out-of-bounds read from byte %s till"
- " byte %s but %qE starts at byte 0",
- start_buf, end_buf, m_diag_arg);
- return ev.formatted_print ("out-of-bounds read from byte %s till"
- " byte %s but region starts at byte 0",
- start_buf, end_buf);;
- }
- }
-};
-
-/* Abstract class to complain about out-of-bounds read/writes where
- the values are symbolic. */
-
-class symbolic_past_the_end
- : public pending_diagnostic_subclass<symbolic_past_the_end>
-{
-public:
- symbolic_past_the_end (const region *reg, tree diag_arg, tree offset,
- tree num_bytes, tree capacity)
- : m_reg (reg), m_diag_arg (diag_arg), m_offset (offset),
- m_num_bytes (num_bytes), m_capacity (capacity)
- {}
-
- const char *get_kind () const final override
- {
- return "symbolic_past_the_end";
- }
-
- bool operator== (const symbolic_past_the_end &other) const
- {
- return m_reg == other.m_reg
- && pending_diagnostic::same_tree_p (m_diag_arg, other.m_diag_arg)
- && pending_diagnostic::same_tree_p (m_offset, other.m_offset)
- && pending_diagnostic::same_tree_p (m_num_bytes, other.m_num_bytes)
- && pending_diagnostic::same_tree_p (m_capacity, other.m_capacity);
- }
-
- int get_controlling_option () const final override
- {
- return OPT_Wanalyzer_out_of_bounds;
- }
-
- void mark_interesting_stuff (interesting_t *interest) final override
- {
- interest->add_region_creation (m_reg);
- }
-
- label_text
- describe_region_creation_event (const evdesc::region_creation &ev) final
- override
- {
- if (m_capacity)
- return ev.formatted_print ("capacity is %qE bytes", m_capacity);
-
- return label_text ();
- }
-
- label_text
- describe_final_event (const evdesc::final_event &ev) final override
- {
- const char *byte_str;
- if (pending_diagnostic::same_tree_p (m_num_bytes, integer_one_node))
- byte_str = "byte";
- else
- byte_str = "bytes";
-
- if (m_offset)
- {
- if (m_num_bytes && TREE_CODE (m_num_bytes) == INTEGER_CST)
- {
- if (m_diag_arg)
- return ev.formatted_print ("%s of %E %s at offset %qE"
- " exceeds %qE", m_dir_str,
- m_num_bytes, byte_str,
- m_offset, m_diag_arg);
- else
- return ev.formatted_print ("%s of %E %s at offset %qE"
- " exceeds the buffer", m_dir_str,
- m_num_bytes, byte_str, m_offset);
- }
- else if (m_num_bytes)
- {
- if (m_diag_arg)
- return ev.formatted_print ("%s of %qE %s at offset %qE"
- " exceeds %qE", m_dir_str,
- m_num_bytes, byte_str,
- m_offset, m_diag_arg);
- else
- return ev.formatted_print ("%s of %qE %s at offset %qE"
- " exceeds the buffer", m_dir_str,
- m_num_bytes, byte_str, m_offset);
- }
- else
- {
- if (m_diag_arg)
- return ev.formatted_print ("%s at offset %qE exceeds %qE",
- m_dir_str, m_offset, m_diag_arg);
- else
- return ev.formatted_print ("%s at offset %qE exceeds the"
- " buffer", m_dir_str, m_offset);
- }
- }
- if (m_diag_arg)
- return ev.formatted_print ("out-of-bounds %s on %qE",
- m_dir_str, m_diag_arg);
- return ev.formatted_print ("out-of-bounds %s", m_dir_str);
- }
-
-protected:
- const region *m_reg;
- tree m_diag_arg;
- tree m_offset;
- tree m_num_bytes;
- tree m_capacity;
- const char *m_dir_str;
-};
-
-/* Concrete subclass to complain about overflows with symbolic values. */
-
-class symbolic_buffer_overflow : public symbolic_past_the_end
-{
-public:
- symbolic_buffer_overflow (const region *reg, tree diag_arg, tree offset,
- tree num_bytes, tree capacity)
- : symbolic_past_the_end (reg, diag_arg, offset, num_bytes, capacity)
- {
- m_dir_str = "write";
- }
-
- bool emit (rich_location *rich_loc) final override
- {
- diagnostic_metadata m;
- switch (m_reg->get_memory_space ())
- {
- default:
- m.add_cwe (787);
- return warning_meta (rich_loc, m, get_controlling_option (),
- "buffer overflow");
- case MEMSPACE_STACK:
- m.add_cwe (121);
- return warning_meta (rich_loc, m, get_controlling_option (),
- "stack-based buffer overflow");
- case MEMSPACE_HEAP:
- m.add_cwe (122);
- return warning_meta (rich_loc, m, get_controlling_option (),
- "heap-based buffer overflow");
- }
- }
-};
-
-/* Concrete subclass to complain about overreads with symbolic values. */
-
-class symbolic_buffer_overread : public symbolic_past_the_end
-{
-public:
- symbolic_buffer_overread (const region *reg, tree diag_arg, tree offset,
- tree num_bytes, tree capacity)
- : symbolic_past_the_end (reg, diag_arg, offset, num_bytes, capacity)
- {
- m_dir_str = "read";
- }
-
- bool emit (rich_location *rich_loc) final override
- {
- diagnostic_metadata m;
- m.add_cwe (126);
- return warning_meta (rich_loc, m, get_controlling_option (),
- "buffer overread");
- }
-};
-
-/* Check whether an access is past the end of the BASE_REG. */
-
-void
-region_model::check_symbolic_bounds (const region *base_reg,
- const svalue *sym_byte_offset,
- const svalue *num_bytes_sval,
- const svalue *capacity,
- enum access_direction dir,
- region_model_context *ctxt) const
-{
- gcc_assert (ctxt);
-
- const svalue *next_byte
- = m_mgr->get_or_create_binop (num_bytes_sval->get_type (), PLUS_EXPR,
- sym_byte_offset, num_bytes_sval);
-
- if (eval_condition (next_byte, GT_EXPR, capacity).is_true ())
- {
- tree diag_arg = get_representative_tree (base_reg);
- tree offset_tree = get_representative_tree (sym_byte_offset);
- tree num_bytes_tree = get_representative_tree (num_bytes_sval);
- tree capacity_tree = get_representative_tree (capacity);
- switch (dir)
- {
- default:
- gcc_unreachable ();
- break;
- case DIR_READ:
- ctxt->warn (make_unique<symbolic_buffer_overread> (base_reg,
- diag_arg,
- offset_tree,
- num_bytes_tree,
- capacity_tree));
- break;
- case DIR_WRITE:
- ctxt->warn (make_unique<symbolic_buffer_overflow> (base_reg,
- diag_arg,
- offset_tree,
- num_bytes_tree,
- capacity_tree));
- break;
- }
- }
-}
-
-static tree
-maybe_get_integer_cst_tree (const svalue *sval)
-{
- tree cst_tree = sval->maybe_get_constant ();
- if (cst_tree && TREE_CODE (cst_tree) == INTEGER_CST)
- return cst_tree;
-
- return NULL_TREE;
-}
-
-/* May complain when the access on REG is out-of-bounds. */
-
-void
-region_model::check_region_bounds (const region *reg,
- enum access_direction dir,
- region_model_context *ctxt) const
-{
- gcc_assert (ctxt);
-
- /* Get the offset. */
- region_offset reg_offset = reg->get_offset (m_mgr);
- const region *base_reg = reg_offset.get_base_region ();
-
- /* Bail out on symbolic regions.
- (e.g. because the analyzer did not see previous offsets on the latter,
- it might think that a negative access is before the buffer). */
- if (base_reg->symbolic_p ())
- return;
-
- /* Find out how many bytes were accessed. */
- const svalue *num_bytes_sval = reg->get_byte_size_sval (m_mgr);
- tree num_bytes_tree = maybe_get_integer_cst_tree (num_bytes_sval);
- /* Bail out if 0 bytes are accessed. */
- if (num_bytes_tree && zerop (num_bytes_tree))
- return;
-
- /* Get the capacity of the buffer. */
- const svalue *capacity = get_capacity (base_reg);
- tree cst_capacity_tree = maybe_get_integer_cst_tree (capacity);
-
- /* The constant offset from a pointer is represented internally as a sizetype
- but should be interpreted as a signed value here. The statement below
- converts the offset from bits to bytes and then to a signed integer with
- the same precision the sizetype has on the target system.
-
- For example, this is needed for out-of-bounds-3.c test1 to pass when
- compiled with a 64-bit gcc build targeting 32-bit systems. */
- byte_offset_t offset;
- if (!reg_offset.symbolic_p ())
- offset = wi::sext (reg_offset.get_bit_offset () >> LOG2_BITS_PER_UNIT,
- TYPE_PRECISION (size_type_node));
-
- /* If either the offset or the number of bytes accessed are symbolic,
- we have to reason about symbolic values. */
- if (reg_offset.symbolic_p () || !num_bytes_tree)
- {
- const svalue* byte_offset_sval;
- if (!reg_offset.symbolic_p ())
- {
- tree offset_tree = wide_int_to_tree (integer_type_node, offset);
- byte_offset_sval
- = m_mgr->get_or_create_constant_svalue (offset_tree);
- }
- else
- byte_offset_sval = reg_offset.get_symbolic_byte_offset ();
- check_symbolic_bounds (base_reg, byte_offset_sval, num_bytes_sval,
- capacity, dir, ctxt);
- return;
- }
-
- /* Otherwise continue to check with concrete values. */
- byte_range out (0, 0);
- /* NUM_BYTES_TREE should always be interpreted as unsigned. */
- byte_offset_t num_bytes_unsigned = wi::to_offset (num_bytes_tree);
- byte_range read_bytes (offset, num_bytes_unsigned);
- /* If read_bytes has a subset < 0, we do have an underflow. */
- if (read_bytes.falls_short_of_p (0, &out))
- {
- tree diag_arg = get_representative_tree (base_reg);
- switch (dir)
- {
- default:
- gcc_unreachable ();
- break;
- case DIR_READ:
- ctxt->warn (make_unique<buffer_underread> (reg, diag_arg, out));
- break;
- case DIR_WRITE:
- ctxt->warn (make_unique<buffer_underflow> (reg, diag_arg, out));
- break;
- }
- }
-
- /* For accesses past the end, we do need a concrete capacity. No need to
- do a symbolic check here because the inequality check does not reason
- whether constants are greater than symbolic values. */
- if (!cst_capacity_tree)
- return;
-
- byte_range buffer (0, wi::to_offset (cst_capacity_tree));
- /* If READ_BYTES exceeds BUFFER, we do have an overflow. */
- if (read_bytes.exceeds_p (buffer, &out))
- {
- tree byte_bound = wide_int_to_tree (size_type_node,
- buffer.get_next_byte_offset ());
- tree diag_arg = get_representative_tree (base_reg);
-
- switch (dir)
- {
- default:
- gcc_unreachable ();
- break;
- case DIR_READ:
- ctxt->warn (make_unique<buffer_overread> (reg, diag_arg,
- out, byte_bound));
- break;
- case DIR_WRITE:
- ctxt->warn (make_unique<buffer_overflow> (reg, diag_arg,
- out, byte_bound));
- break;
- }
- }
-}
-
/* Ensure that all arguments at the call described by CD are checked
for poisoned values, by calling get_rvalue on each argument. */
@@ -2972,6 +2321,10 @@ const svalue *
region_model::get_store_value (const region *reg,
region_model_context *ctxt) const
{
+ /* Getting the value of an empty region gives an unknown_svalue. */
+ if (reg->empty_p ())
+ return m_mgr->get_or_create_unknown_svalue (reg->get_type ());
+
check_region_for_read (reg, ctxt);
/* Special-case: handle var_decls in the constant pool. */
@@ -3430,12 +2783,14 @@ class dubious_allocation_size
{
public:
dubious_allocation_size (const region *lhs, const region *rhs)
- : m_lhs (lhs), m_rhs (rhs), m_expr (NULL_TREE)
+ : m_lhs (lhs), m_rhs (rhs), m_expr (NULL_TREE),
+ m_has_allocation_event (false)
{}
dubious_allocation_size (const region *lhs, const region *rhs,
tree expr)
- : m_lhs (lhs), m_rhs (rhs), m_expr (expr)
+ : m_lhs (lhs), m_rhs (rhs), m_expr (expr),
+ m_has_allocation_event (false)
{}
const char *get_kind () const final override
@@ -3464,34 +2819,17 @@ public:
" of the pointee's size");
}
- label_text
- describe_region_creation_event (const evdesc::region_creation &ev) final
- override
- {
- m_allocation_event = &ev;
- if (m_expr)
- {
- if (TREE_CODE (m_expr) == INTEGER_CST)
- return ev.formatted_print ("allocated %E bytes here", m_expr);
- else
- return ev.formatted_print ("allocated %qE bytes here", m_expr);
- }
-
- return ev.formatted_print ("allocated here");
- }
-
label_text describe_final_event (const evdesc::final_event &ev) final
override
{
tree pointee_type = TREE_TYPE (m_lhs->get_type ());
- if (m_allocation_event)
- /* Fallback: Typically, we should always
- see an m_allocation_event before. */
+ if (m_has_allocation_event)
return ev.formatted_print ("assigned to %qT here;"
" %<sizeof (%T)%> is %qE",
m_lhs->get_type (), pointee_type,
size_in_bytes (pointee_type));
-
+ /* Fallback: Typically, we should always see an allocation_event
+ before. */
if (m_expr)
{
if (TREE_CODE (m_expr) == INTEGER_CST)
@@ -3512,6 +2850,18 @@ public:
size_in_bytes (pointee_type));
}
+ void
+ add_region_creation_events (const region *,
+ tree capacity,
+ const event_loc_info &loc_info,
+ checker_path &emission_path) final override
+ {
+ emission_path.add_event
+ (make_unique<region_creation_event_allocation_size> (capacity, loc_info));
+
+ m_has_allocation_event = true;
+ }
+
void mark_interesting_stuff (interesting_t *interest) final override
{
interest->add_region_creation (m_rhs);
@@ -3521,7 +2871,7 @@ private:
const region *m_lhs;
const region *m_rhs;
const tree m_expr;
- const evdesc::region_creation *m_allocation_event;
+ bool m_has_allocation_event;
};
/* Return true on dubious allocation sizes for constant sizes. */
@@ -3813,6 +3163,10 @@ region_model::set_value (const region *lhs_reg, const svalue *rhs_sval,
gcc_assert (lhs_reg);
gcc_assert (rhs_sval);
+ /* Setting the value of an empty region is a no-op. */
+ if (lhs_reg->empty_p ())
+ return;
+
check_region_size (lhs_reg, rhs_sval, ctxt);
check_region_for_write (lhs_reg, ctxt);
@@ -3992,6 +3346,19 @@ region_model::eval_condition (const svalue *lhs,
return lhs_ts;
}
}
+ else if (const unaryop_svalue *unaryop
+ = lhs->dyn_cast_unaryop_svalue ())
+ {
+ if (unaryop->get_op () == NEGATE_EXPR)
+ {
+ /* e.g. "-X <= 0" is equivalent to X >= 0". */
+ tristate lhs_ts = eval_condition (unaryop->get_arg (),
+ swap_tree_comparison (op),
+ rhs);
+ if (lhs_ts.is_known ())
+ return lhs_ts;
+ }
+ }
}
/* Handle rejection of equality for comparisons of the initial values of
@@ -5026,11 +4393,13 @@ region_model::apply_constraints_for_exception (const gimple *last_stmt,
PARAM has a defined but unknown initial value.
Anything it points to has escaped, since the calling context "knows"
the pointer, and thus calls to unknown functions could read/write into
- the region. */
+ the region.
+ If NONNULL is true, then assume that PARAM must be non-NULL. */
void
region_model::on_top_level_param (tree param,
- region_model_context *ctxt)
+ bool nonnull,
+ region_model_context *ctxt)
{
if (POINTER_TYPE_P (TREE_TYPE (param)))
{
@@ -5039,6 +4408,12 @@ region_model::on_top_level_param (tree param,
= m_mgr->get_or_create_initial_value (param_reg);
const region *pointee_reg = m_mgr->get_symbolic_region (init_ptr_sval);
m_store.mark_as_escaped (pointee_reg);
+ if (nonnull)
+ {
+ const svalue *null_ptr_sval
+ = m_mgr->get_or_create_null_ptr (TREE_TYPE (param));
+ add_constraint (init_ptr_sval, NE_EXPR, null_ptr_sval, ctxt);
+ }
}
}
@@ -5094,14 +4469,27 @@ region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
have defined but unknown initial values.
Anything they point to has escaped. */
tree fndecl = fun->decl;
+
+ /* Handle "__attribute__((nonnull))". */
+ tree fntype = TREE_TYPE (fndecl);
+ bitmap nonnull_args = get_nonnull_args (fntype);
+
+ unsigned parm_idx = 0;
for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
iter_parm = DECL_CHAIN (iter_parm))
{
+ bool non_null = (nonnull_args
+ ? (bitmap_empty_p (nonnull_args)
+ || bitmap_bit_p (nonnull_args, parm_idx))
+ : false);
if (tree parm_default_ssa = ssa_default_def (fun, iter_parm))
- on_top_level_param (parm_default_ssa, ctxt);
+ on_top_level_param (parm_default_ssa, non_null, ctxt);
else
- on_top_level_param (iter_parm, ctxt);
+ on_top_level_param (iter_parm, non_null, ctxt);
+ parm_idx++;
}
+
+ BITMAP_FREE (nonnull_args);
}
return m_current_frame;
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 86c42a2..291bb2f 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -236,56 +236,6 @@ public:
struct append_regions_cb_data;
-/* Helper class for handling calls to functions with known behavior.
- Implemented in region-model-impl-calls.c. */
-
-class call_details
-{
-public:
- call_details (const gcall *call, region_model *model,
- region_model_context *ctxt);
-
- region_model *get_model () const { return m_model; }
- region_model_manager *get_manager () const;
- region_model_context *get_ctxt () const { return m_ctxt; }
- logger *get_logger () const;
-
- uncertainty_t *get_uncertainty () const;
- tree get_lhs_type () const { return m_lhs_type; }
- const region *get_lhs_region () const { return m_lhs_region; }
-
- bool maybe_set_lhs (const svalue *result) const;
-
- unsigned num_args () const;
- bool arg_is_pointer_p (unsigned idx) const
- {
- return POINTER_TYPE_P (get_arg_type (idx));
- }
- bool arg_is_size_p (unsigned idx) const;
-
- const gcall *get_call_stmt () const { return m_call; }
- location_t get_location () const;
-
- tree get_arg_tree (unsigned idx) const;
- tree get_arg_type (unsigned idx) const;
- const svalue *get_arg_svalue (unsigned idx) const;
- const char *get_arg_string_literal (unsigned idx) const;
-
- tree get_fndecl_for_call () const;
-
- void dump_to_pp (pretty_printer *pp, bool simple) const;
- void dump (bool simple) const;
-
- const svalue *get_or_create_conjured_svalue (const region *) const;
-
-private:
- const gcall *m_call;
- region_model *m_model;
- region_model_context *m_ctxt;
- tree m_lhs_type;
- const region *m_lhs_region;
-};
-
/* A region_model encapsulates a representation of the state of memory, with
a tree of regions, along with their associated values.
The representation is graph-like because values can be pointers to
@@ -580,7 +530,9 @@ private:
int poison_any_pointers_to_descendents (const region *reg,
enum poison_kind pkind);
- void on_top_level_param (tree param, region_model_context *ctxt);
+ void on_top_level_param (tree param,
+ bool nonnull,
+ region_model_context *ctxt);
bool called_from_main_p () const;
const svalue *get_initial_value_for_global (const region *reg) const;
@@ -606,6 +558,8 @@ private:
region_model_context *ctxt) const;
void check_region_size (const region *lhs_reg, const svalue *rhs_sval,
region_model_context *ctxt) const;
+
+ /* Implemented in bounds-checking.cc */
void check_symbolic_bounds (const region *base_reg,
const svalue *sym_byte_offset,
const svalue *num_bytes_sval,
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index 6d97590..67ba948 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -671,6 +671,18 @@ region::symbolic_p () const
return get_kind () == RK_SYMBOLIC;
}
+/* Return true if this region is known to be zero bits in size. */
+
+bool
+region::empty_p () const
+{
+ bit_size_t num_bits;
+ if (get_bit_size (&num_bits))
+ if (num_bits == 0)
+ return true;
+ return false;
+}
+
/* Return true if this is a region for a decl with name DECL_NAME.
Intended for use when debugging (for assertions and conditional
breakpoints). */
diff --git a/gcc/analyzer/region.h b/gcc/analyzer/region.h
index ecae887..6d8bcfb 100644
--- a/gcc/analyzer/region.h
+++ b/gcc/analyzer/region.h
@@ -233,6 +233,8 @@ public:
bool is_named_decl_p (const char *decl_name) const;
+ bool empty_p () const;
+
protected:
region (complexity c, unsigned id, const region *parent, tree type);
diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc
index 794733e..50e1313 100644
--- a/gcc/analyzer/sm-fd.cc
+++ b/gcc/analyzer/sm-fd.cc
@@ -47,6 +47,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-state.h"
#include "analyzer/supergraph.h"
#include "analyzer/analyzer-language.h"
+#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
#if ENABLE_ANALYZER
@@ -1861,7 +1862,8 @@ fd_state_machine::on_bind (const call_details &cd,
next_state = m_bound_datagram_socket;
else if (old_state == m_new_unknown_socket)
next_state = m_bound_unknown_socket;
- else if (old_state == m_start)
+ else if (old_state == m_start
+ || old_state == m_constant_fd)
next_state = m_bound_unknown_socket;
else if (old_state == m_stop)
next_state = m_stop;
@@ -2116,7 +2118,8 @@ fd_state_machine::on_connect (const call_details &cd,
next_state = m_new_datagram_socket;
else if (old_state == m_new_unknown_socket)
next_state = m_stop;
- else if (old_state == m_start)
+ else if (old_state == m_start
+ || old_state == m_constant_fd)
next_state = m_stop;
else if (old_state == m_stop)
next_state = m_stop;
diff --git a/gcc/analyzer/sm-fd.dot b/gcc/analyzer/sm-fd.dot
index da925b0..d7676b1 100644
--- a/gcc/analyzer/sm-fd.dot
+++ b/gcc/analyzer/sm-fd.dot
@@ -27,6 +27,9 @@ digraph "fd" {
/* Start state. */
start;
+ /* State for a constant file descriptor (>= 0). */
+ constant_fd;
+
/* States representing a file descriptor that hasn't yet been
checked for validity after opening, for three different
access modes. */
@@ -129,6 +132,7 @@ digraph "fd" {
/* On "bind". */
start -> bound_unknown_socket [label="when 'bind(X, ...)' succeeds"];
+ constant_fd -> bound_unknown_socket [label="when 'bind(X, ...)' succeeds"];
new_stream_socket -> bound_stream_socket [label="when 'bind(X, ...)' succeeds"];
new_datagram_socket -> bound_datagram_socket [label="when 'bind(X, ...)' succeeds"];
new_unknown_socket -> bound_unknown_socket [label="when 'bind(X, ...)' succeeds"];
@@ -140,12 +144,14 @@ digraph "fd" {
/* On "accept". */
start -> connected_stream_socket [label="when 'accept(OTHER, ...)' succeeds on a listening_stream_socket"];
+ constant_fd -> connected_stream_socket [label="when 'accept(OTHER, ...)' succeeds on a listening_stream_socket"];
/* On "connect". */
new_stream_socket -> connected_stream_socket [label="when 'connect(X, ...)' succeeds"];
new_datagram_socket -> new_datagram_socket [label="when 'connect(X, ...)' succeeds"];
new_unknown_socket -> stop [label="when 'connect(X, ...)' succeeds"];
start -> stop [label="when 'connect(X, ...)' succeeds"];
+ constant_fd -> stop [label="when 'connect(X, ...)' succeeds"];
/* on_condition. */
unchecked_read_write -> valid_read_write [label="on 'X >= 0'"];
diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc
index d2dcb43..1bd594b 100644
--- a/gcc/analyzer/sm-file.cc
+++ b/gcc/analyzer/sm-file.cc
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
index 94ca295..b520c9b 100644
--- a/gcc/analyzer/sm-malloc.cc
+++ b/gcc/analyzer/sm-malloc.cc
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#include "stringpool.h"
#include "attribs.h"
#include "analyzer/function-set.h"
diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc
index 87e21a4..38db6c0 100644
--- a/gcc/analyzer/sm-signal.cc
+++ b/gcc/analyzer/sm-signal.cc
@@ -235,7 +235,7 @@ public:
{
emission_path->add_event
(make_unique<precanned_custom_event>
- (UNKNOWN_LOCATION, NULL_TREE, 0,
+ (event_loc_info (UNKNOWN_LOCATION, NULL_TREE, 0),
"later on,"
" when the signal is delivered to the process"));
}
diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc
index 6fac18a..e9bcb4b 100644
--- a/gcc/analyzer/state-purge.cc
+++ b/gcc/analyzer/state-purge.cc
@@ -813,7 +813,11 @@ same_binding_p (const region *reg_a, const region *reg_b,
{
if (reg_a->get_base_region () != reg_b->get_base_region ())
return false;
+ if (reg_a->empty_p ())
+ return false;
const binding_key *bind_key_a = binding_key::make (store_mgr, reg_a);
+ if (reg_b->empty_p ())
+ return false;
const binding_key *bind_key_b = binding_key::make (store_mgr, reg_b);
return bind_key_a == bind_key_b;
}
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index 99939b7..dd8ebaa 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -127,8 +127,12 @@ binding_key::make (store_manager *mgr, const region *r)
{
bit_size_t bit_size;
if (r->get_bit_size (&bit_size))
- return mgr->get_concrete_binding (offset.get_bit_offset (),
- bit_size);
+ {
+ /* Must be non-empty. */
+ gcc_assert (bit_size > 0);
+ return mgr->get_concrete_binding (offset.get_bit_offset (),
+ bit_size);
+ }
else
return mgr->get_symbolic_binding (r);
}
@@ -1464,6 +1468,9 @@ binding_cluster::mark_region_as_unknown (store_manager *mgr,
const region *reg_for_overlap,
uncertainty_t *uncertainty)
{
+ if (reg_to_bind->empty_p ())
+ return;
+
remove_overlapping_bindings (mgr, reg_for_overlap, uncertainty);
/* Add a default binding to "unknown". */
@@ -1516,6 +1523,8 @@ const svalue *
binding_cluster::get_binding (store_manager *mgr,
const region *reg) const
{
+ if (reg->empty_p ())
+ return NULL;
const binding_key *reg_binding = binding_key::make (mgr, reg);
const svalue *sval = m_map.get (reg_binding);
if (sval)
@@ -1800,6 +1809,8 @@ binding_cluster::remove_overlapping_bindings (store_manager *mgr,
const region *reg,
uncertainty_t *uncertainty)
{
+ if (reg->empty_p ())
+ return;
const binding_key *reg_binding = binding_key::make (mgr, reg);
const region *cluster_base_reg = get_base_region ();
@@ -2007,11 +2018,14 @@ binding_cluster::on_unknown_fncall (const gcall *call,
{
m_map.empty ();
- /* Bind it to a new "conjured" value using CALL. */
- const svalue *sval
- = mgr->get_svalue_manager ()->get_or_create_conjured_svalue
+ if (!m_base_region->empty_p ())
+ {
+ /* Bind it to a new "conjured" value using CALL. */
+ const svalue *sval
+ = mgr->get_svalue_manager ()->get_or_create_conjured_svalue
(m_base_region->get_type (), call, m_base_region, p);
- bind (mgr, m_base_region, sval);
+ bind (mgr, m_base_region, sval);
+ }
m_touched = true;
}
@@ -2742,6 +2756,10 @@ store::purge_region (store_manager *mgr, const region *reg)
void
store::fill_region (store_manager *mgr, const region *reg, const svalue *sval)
{
+ /* Filling an empty region is a no-op. */
+ if (reg->empty_p ())
+ return;
+
const region *base_reg = reg->get_base_region ();
if (base_reg->symbolic_for_unknown_ptr_p ()
|| !base_reg->tracked_p ())
diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
index 6243ec6..30284eb 100644
--- a/gcc/analyzer/store.h
+++ b/gcc/analyzer/store.h
@@ -356,8 +356,8 @@ struct byte_range
byte_size_t m_size_in_bytes;
};
-/* Concrete subclass of binding_key, for describing a concrete range of
- bits within the binding_map (e.g. "bits 8-15"). */
+/* Concrete subclass of binding_key, for describing a non-empty
+ concrete range of bits within the binding_map (e.g. "bits 8-15"). */
class concrete_binding : public binding_key
{
@@ -367,7 +367,9 @@ public:
concrete_binding (bit_offset_t start_bit_offset, bit_size_t size_in_bits)
: m_bit_range (start_bit_offset, size_in_bits)
- {}
+ {
+ gcc_assert (!m_bit_range.empty_p ());
+ }
bool concrete_p () const final override { return true; }
hashval_t hash () const
diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc
index daa937d..1a3bdde 100644
--- a/gcc/analyzer/varargs.cc
+++ b/gcc/analyzer/varargs.cc
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/diagnostic-manager.h"
#include "analyzer/exploded-graph.h"
#include "diagnostic-metadata.h"
+#include "analyzer/call-details.h"
#if ENABLE_ANALYZER
@@ -777,9 +778,9 @@ public:
{
public:
va_arg_call_event (const exploded_edge &eedge,
- location_t loc, tree fndecl, int depth,
+ const event_loc_info &loc_info,
int num_variadic_arguments)
- : call_event (eedge, loc, fndecl, depth),
+ : call_event (eedge, loc_info),
m_num_variadic_arguments (num_variadic_arguments)
{
}
@@ -812,13 +813,12 @@ public:
= get_num_variadic_arguments (dst_node->get_function ()->decl,
call_stmt);
emission_path->add_event
- (make_unique<va_arg_call_event> (eedge,
- (last_stmt
- ? last_stmt->location
- : UNKNOWN_LOCATION),
- src_point.get_fndecl (),
- src_stack_depth,
- num_variadic_arguments));
+ (make_unique<va_arg_call_event>
+ (eedge,
+ event_loc_info (last_stmt ? last_stmt->location : UNKNOWN_LOCATION,
+ src_point.get_fndecl (),
+ src_stack_depth),
+ num_variadic_arguments));
}
else
pending_diagnostic::add_call_event (eedge, emission_path);
diff --git a/gcc/attribs.cc b/gcc/attribs.cc
index 27dea74..095def4 100644
--- a/gcc/attribs.cc
+++ b/gcc/attribs.cc
@@ -2456,6 +2456,36 @@ init_attr_rdwr_indices (rdwr_map *rwm, tree attrs)
}
}
+/* Get the LEVEL of the strict_flex_array for the ARRAY_FIELD based on the
+ values of attribute strict_flex_array and the flag_strict_flex_arrays. */
+unsigned int
+strict_flex_array_level_of (tree array_field)
+{
+ gcc_assert (TREE_CODE (array_field) == FIELD_DECL);
+ unsigned int strict_flex_array_level = flag_strict_flex_arrays;
+
+ tree attr_strict_flex_array
+ = lookup_attribute ("strict_flex_array", DECL_ATTRIBUTES (array_field));
+ /* If there is a strict_flex_array attribute attached to the field,
+ override the flag_strict_flex_arrays. */
+ if (attr_strict_flex_array)
+ {
+ /* Get the value of the level first from the attribute. */
+ unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
+ gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
+ attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
+ gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
+ attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
+ gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
+ attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
+
+ /* The attribute has higher priority than flag_struct_flex_array. */
+ strict_flex_array_level = attr_strict_flex_array_level;
+ }
+ return strict_flex_array_level;
+}
+
+
/* Return the access specification for a function parameter PARM
or null if the current function has no such specification. */
diff --git a/gcc/attribs.h b/gcc/attribs.h
index 1dc16e4..742811e 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -398,4 +398,6 @@ extern void init_attr_rdwr_indices (rdwr_map *, tree);
extern attr_access *get_parm_access (rdwr_map &, tree,
tree = current_function_decl);
+extern unsigned int strict_flex_array_level_of (tree);
+
#endif // GCC_ATTRIBS_H
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index e53acbd..3fb66a7 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,23 @@
+2022-12-02 Andrew MacLeod <amacleod@redhat.com>
+
+ * c-attribs.cc (handle_deprecated_attribute): Use type when
+ using TYPE_NAME.
+
+2022-12-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/84469
+ * c-omp.cc (c_omp_is_loop_iterator): For range for with structured
+ binding return TREE_VEC_LENGTH (d->declv) even if decl is equal
+ to any of the structured binding decls.
+
+2022-11-30 Iskander Shakirzyanov <iskander@ispras.ru>
+ Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
+
+ PR driver/107787
+ * c-common.cc (fold_offsetof,
+ convert_vector_to_array_for_subscript): Use OPT_Warray_bounds_
+ instead of OPT_Warray_bounds.
+
2022-11-24 Jakub Jelinek <jakub@redhat.com>
* c.opt (fcontract-role=, fcontract-semantic=): Terminate descriptions
diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 07bca68..b36dd97 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -4240,7 +4240,7 @@ handle_deprecated_attribute (tree *node, tree name,
if (type && TYPE_NAME (type))
{
if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- what = TYPE_NAME (*node);
+ what = TYPE_NAME (type);
else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
&& DECL_NAME (TYPE_NAME (type)))
what = DECL_NAME (TYPE_NAME (type));
diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc
index 5bb1035..2ab9911 100644
--- a/gcc/c-family/c-omp.cc
+++ b/gcc/c-family/c-omp.cc
@@ -1311,10 +1311,11 @@ c_omp_is_loop_iterator (tree decl, struct c_omp_check_loop_iv_data *d)
else if (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST
&& TREE_CHAIN (TREE_VEC_ELT (d->declv, i))
&& (TREE_CODE (TREE_CHAIN (TREE_VEC_ELT (d->declv, i)))
- == TREE_VEC)
- && decl == TREE_VEC_ELT (TREE_CHAIN (TREE_VEC_ELT (d->declv,
- i)), 2))
- return TREE_VEC_LENGTH (d->declv);
+ == TREE_VEC))
+ for (int j = 2;
+ j < TREE_VEC_LENGTH (TREE_CHAIN (TREE_VEC_ELT (d->declv, i))); j++)
+ if (decl == TREE_VEC_ELT (TREE_CHAIN (TREE_VEC_ELT (d->declv, i)), j))
+ return TREE_VEC_LENGTH (d->declv);
return -1;
}
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 956e47c..758b130 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,8 @@
+2022-12-06 Qing Zhao <qing.zhao@oracle.com>
+
+ * c-decl.cc (is_flexible_array_member_p): Call new function
+ strict_flex_array_level_of.
+
2022-11-24 Florian Weimer <fweimer@redhat.com>
PR c/107805
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 4adb89e..111f05e 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9067,26 +9067,7 @@ is_flexible_array_member_p (bool is_last_field,
bool is_one_element_array = one_element_array_type_p (TREE_TYPE (x));
bool is_flexible_array = flexible_array_member_type_p (TREE_TYPE (x));
- unsigned int strict_flex_array_level = flag_strict_flex_arrays;
-
- tree attr_strict_flex_array = lookup_attribute ("strict_flex_array",
- DECL_ATTRIBUTES (x));
- /* If there is a strict_flex_array attribute attached to the field,
- override the flag_strict_flex_arrays. */
- if (attr_strict_flex_array)
- {
- /* Get the value of the level first from the attribute. */
- unsigned HOST_WIDE_INT attr_strict_flex_array_level = 0;
- gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
- attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
- gcc_assert (TREE_VALUE (attr_strict_flex_array) != NULL_TREE);
- attr_strict_flex_array = TREE_VALUE (attr_strict_flex_array);
- gcc_assert (tree_fits_uhwi_p (attr_strict_flex_array));
- attr_strict_flex_array_level = tree_to_uhwi (attr_strict_flex_array);
-
- /* The attribute has higher priority than flag_struct_flex_array. */
- strict_flex_array_level = attr_strict_flex_array_level;
- }
+ unsigned int strict_flex_array_level = strict_flex_array_level_of (x);
switch (strict_flex_array_level)
{
diff --git a/gcc/cfghooks.cc b/gcc/cfghooks.cc
index 29ded57..f8fa13c 100644
--- a/gcc/cfghooks.cc
+++ b/gcc/cfghooks.cc
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-core.h"
#include "dumpfile.h"
#include "cfganal.h"
+#include "tree.h"
#include "tree-ssa.h"
#include "cfgloop.h"
#include "sreal.h"
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 4be93c9..f3d847e 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -756,7 +756,7 @@ void aarch64_post_cfi_startproc (void);
poly_int64 aarch64_initial_elimination_offset (unsigned, unsigned);
int aarch64_get_condition_code (rtx);
bool aarch64_address_valid_for_prefetch_p (rtx, bool);
-bool aarch64_bitmask_imm (HOST_WIDE_INT val, machine_mode);
+bool aarch64_bitmask_imm (unsigned HOST_WIDE_INT val, machine_mode);
unsigned HOST_WIDE_INT aarch64_and_split_imm1 (HOST_WIDE_INT val_in);
unsigned HOST_WIDE_INT aarch64_and_split_imm2 (HOST_WIDE_INT val_in);
bool aarch64_and_bitmask_imm (unsigned HOST_WIDE_INT val_in, machine_mode mode);
@@ -793,7 +793,7 @@ bool aarch64_masks_and_shift_for_bfi_p (scalar_int_mode, unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT,
unsigned HOST_WIDE_INT);
bool aarch64_zero_extend_const_eq (machine_mode, rtx, machine_mode, rtx);
-bool aarch64_move_imm (HOST_WIDE_INT, machine_mode);
+bool aarch64_move_imm (unsigned HOST_WIDE_INT, machine_mode);
machine_mode aarch64_sve_int_mode (machine_mode);
opt_machine_mode aarch64_sve_pred_mode (unsigned int);
machine_mode aarch64_sve_pred_mode (machine_mode);
@@ -843,8 +843,9 @@ bool aarch64_sve_float_arith_immediate_p (rtx, bool);
bool aarch64_sve_float_mul_immediate_p (rtx);
bool aarch64_split_dimode_const_store (rtx, rtx);
bool aarch64_symbolic_address_p (rtx);
-bool aarch64_uimm12_shift (HOST_WIDE_INT);
+bool aarch64_uimm12_shift (unsigned HOST_WIDE_INT);
int aarch64_movk_shift (const wide_int_ref &, const wide_int_ref &);
+bool aarch64_is_mov_xn_imm (unsigned HOST_WIDE_INT);
bool aarch64_use_return_insn_p (void);
const char *aarch64_output_casesi (rtx *);
diff --git a/gcc/config/aarch64/aarch64-sve-builtins-base.cc b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
index 6347407..d52ec08 100644
--- a/gcc/config/aarch64/aarch64-sve-builtins-base.cc
+++ b/gcc/config/aarch64/aarch64-sve-builtins-base.cc
@@ -45,6 +45,7 @@
#include "aarch64-sve-builtins-base.h"
#include "aarch64-sve-builtins-functions.h"
#include "ssa.h"
+#include "gimple-fold.h"
using namespace aarch64_sve;
@@ -1209,7 +1210,8 @@ public:
vectype is the corresponding ADVSIMD type. */
if (!BYTES_BIG_ENDIAN
- && integer_all_onesp (arg0))
+ && integer_all_onesp (arg0)
+ && !flag_non_call_exceptions)
{
tree lhs = gimple_call_lhs (f.call);
tree lhs_type = TREE_TYPE (lhs);
@@ -1232,7 +1234,9 @@ public:
tree mem_ref_op = fold_build2 (MEM_REF, access_type, arg1, zero);
gimple *mem_ref_stmt
= gimple_build_assign (mem_ref_lhs, mem_ref_op);
- gsi_insert_before (f.gsi, mem_ref_stmt, GSI_SAME_STMT);
+
+ gimple_seq stmts = NULL;
+ gimple_seq_add_stmt_without_update (&stmts, mem_ref_stmt);
int source_nelts = TYPE_VECTOR_SUBPARTS (access_type).to_constant ();
vec_perm_builder sel (lhs_len, source_nelts, 1);
@@ -1245,8 +1249,11 @@ public:
indices));
tree mask_type = build_vector_type (ssizetype, lhs_len);
tree mask = vec_perm_indices_to_tree (mask_type, indices);
- return gimple_build_assign (lhs, VEC_PERM_EXPR,
- mem_ref_lhs, mem_ref_lhs, mask);
+ gimple *g2 = gimple_build_assign (lhs, VEC_PERM_EXPR,
+ mem_ref_lhs, mem_ref_lhs, mask);
+ gimple_seq_add_stmt_without_update (&stmts, g2);
+ gsi_replace_with_seq_vops (f.gsi, stmts);
+ return g2;
}
return NULL;
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index e97f3b3..27a814d 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -5625,12 +5625,10 @@ aarch64_bitmask_imm (unsigned HOST_WIDE_INT val)
/* Return true if VAL is a valid bitmask immediate for MODE. */
bool
-aarch64_bitmask_imm (HOST_WIDE_INT val_in, machine_mode mode)
+aarch64_bitmask_imm (unsigned HOST_WIDE_INT val, machine_mode mode)
{
if (mode == DImode)
- return aarch64_bitmask_imm (val_in);
-
- unsigned HOST_WIDE_INT val = val_in;
+ return aarch64_bitmask_imm (val);
if (mode == SImode)
return aarch64_bitmask_imm ((val & 0xffffffff) | (val << 32));
@@ -5669,51 +5667,55 @@ aarch64_check_bitmask (unsigned HOST_WIDE_INT val,
}
-/* Return true if val is an immediate that can be loaded into a
- register by a MOVZ instruction. */
-static bool
-aarch64_movw_imm (HOST_WIDE_INT val, scalar_int_mode mode)
+/* Return true if VAL is a valid MOVZ immediate. */
+static inline bool
+aarch64_is_movz (unsigned HOST_WIDE_INT val)
{
- if (GET_MODE_SIZE (mode) > 4)
- {
- if ((val & (((HOST_WIDE_INT) 0xffff) << 32)) == val
- || (val & (((HOST_WIDE_INT) 0xffff) << 48)) == val)
- return 1;
- }
- else
- {
- /* Ignore sign extension. */
- val &= (HOST_WIDE_INT) 0xffffffff;
- }
- return ((val & (((HOST_WIDE_INT) 0xffff) << 0)) == val
- || (val & (((HOST_WIDE_INT) 0xffff) << 16)) == val);
+ return (val >> (ctz_hwi (val) & 48)) < 65536;
}
-/* Return true if VAL is an immediate that can be loaded into a
- register in a single instruction. */
+/* Return true if immediate VAL can be created by a 64-bit MOVI/MOVN/MOVZ. */
bool
-aarch64_move_imm (HOST_WIDE_INT val, machine_mode mode)
+aarch64_is_mov_xn_imm (unsigned HOST_WIDE_INT val)
{
- scalar_int_mode int_mode;
- if (!is_a <scalar_int_mode> (mode, &int_mode))
- return false;
+ return aarch64_is_movz (val) || aarch64_is_movz (~val)
+ || aarch64_bitmask_imm (val);
+}
- if (aarch64_movw_imm (val, int_mode) || aarch64_movw_imm (~val, int_mode))
- return 1;
- return aarch64_bitmask_imm (val, int_mode);
+
+/* Return true if VAL is an immediate that can be created by a single
+ MOV instruction. */
+bool
+aarch64_move_imm (unsigned HOST_WIDE_INT val, machine_mode mode)
+{
+ gcc_assert (mode == SImode || mode == DImode);
+
+ if (val < 65536)
+ return true;
+
+ unsigned HOST_WIDE_INT mask =
+ (val >> 32) == 0 || mode == SImode ? 0xffffffff : HOST_WIDE_INT_M1U;
+
+ if (aarch64_is_movz (val & mask) || aarch64_is_movz (~val & mask))
+ return true;
+
+ val = (val & mask) | ((val << 32) & ~mask);
+ return aarch64_bitmask_imm (val);
}
static int
aarch64_internal_mov_immediate (rtx dest, rtx imm, bool generate,
- scalar_int_mode mode)
+ machine_mode mode)
{
int i;
unsigned HOST_WIDE_INT val, val2, mask;
int one_match, zero_match;
int num_insns;
+ gcc_assert (mode == SImode || mode == DImode);
+
val = INTVAL (imm);
if (aarch64_move_imm (val, mode))
@@ -5723,31 +5725,6 @@ aarch64_internal_mov_immediate (rtx dest, rtx imm, bool generate,
return 1;
}
- /* Check to see if the low 32 bits are either 0xffffXXXX or 0xXXXXffff
- (with XXXX non-zero). In that case check to see if the move can be done in
- a smaller mode. */
- val2 = val & 0xffffffff;
- if (mode == DImode
- && aarch64_move_imm (val2, SImode)
- && (((val >> 32) & 0xffff) == 0 || (val >> 48) == 0))
- {
- if (generate)
- emit_insn (gen_rtx_SET (dest, GEN_INT (val2)));
-
- /* Check if we have to emit a second instruction by checking to see
- if any of the upper 32 bits of the original DI mode value is set. */
- if (val == val2)
- return 1;
-
- i = (val >> 48) ? 48 : 32;
-
- if (generate)
- emit_insn (gen_insv_immdi (dest, GEN_INT (i),
- GEN_INT ((val >> i) & 0xffff)));
-
- return 2;
- }
-
if ((val >> 32) == 0 || mode == SImode)
{
if (generate)
@@ -5771,24 +5748,31 @@ aarch64_internal_mov_immediate (rtx dest, rtx imm, bool generate,
one_match = ((~val & mask) == 0) + ((~val & (mask << 16)) == 0) +
((~val & (mask << 32)) == 0) + ((~val & (mask << 48)) == 0);
+ /* Try a bitmask immediate and a movk to generate the immediate
+ in 2 instructions. */
+
if (zero_match < 2 && one_match < 2)
{
- /* Try emitting a bitmask immediate with a movk replacing 16 bits.
- For a 64-bit bitmask try whether changing 16 bits to all ones or
- zeroes creates a valid bitmask. To check any repeated bitmask,
- try using 16 bits from the other 32-bit half of val. */
-
for (i = 0; i < 64; i += 16)
- if (aarch64_check_bitmask (val, val2, mask << i))
- {
- if (generate)
- {
- emit_insn (gen_rtx_SET (dest, GEN_INT (val2)));
- emit_insn (gen_insv_immdi (dest, GEN_INT (i),
- GEN_INT ((val >> i) & 0xffff)));
- }
- return 2;
- }
+ {
+ if (aarch64_check_bitmask (val, val2, mask << i))
+ break;
+
+ val2 = val & ~(mask << i);
+ if ((val2 >> 32) == 0 && aarch64_move_imm (val2, DImode))
+ break;
+ }
+
+ if (i != 64)
+ {
+ if (generate)
+ {
+ emit_insn (gen_rtx_SET (dest, GEN_INT (val2)));
+ emit_insn (gen_insv_immdi (dest, GEN_INT (i),
+ GEN_INT ((val >> i) & 0xffff)));
+ }
+ return 2;
+ }
}
/* Try a bitmask plus 2 movk to generate the immediate in 3 instructions. */
@@ -5857,26 +5841,24 @@ aarch64_mov128_immediate (rtx imm)
/* Return true if val can be encoded as a 12-bit unsigned immediate with
a left shift of 0 or 12 bits. */
bool
-aarch64_uimm12_shift (HOST_WIDE_INT val)
+aarch64_uimm12_shift (unsigned HOST_WIDE_INT val)
{
- return ((val & (((HOST_WIDE_INT) 0xfff) << 0)) == val
- || (val & (((HOST_WIDE_INT) 0xfff) << 12)) == val
- );
+ return val < 4096 || (val & 0xfff000) == val;
}
/* Returns the nearest value to VAL that will fit as a 12-bit unsigned immediate
that can be created with a left shift of 0 or 12. */
static HOST_WIDE_INT
-aarch64_clamp_to_uimm12_shift (HOST_WIDE_INT val)
+aarch64_clamp_to_uimm12_shift (unsigned HOST_WIDE_INT val)
{
/* Check to see if the value fits in 24 bits, as that is the maximum we can
handle correctly. */
- gcc_assert ((val & 0xffffff) == val);
+ gcc_assert (val < 0x1000000);
- if (((val & 0xfff) << 0) == val)
+ if (val < 4096)
return val;
- return val & (0xfff << 12);
+ return val & 0xfff000;
}
@@ -6531,7 +6513,8 @@ aarch64_expand_sve_const_vector (rtx target, rtx src)
/* If the integer can be moved into a general register by a
single instruction, do that and duplicate the result. */
if (CONST_INT_P (elt_value)
- && aarch64_move_imm (INTVAL (elt_value), elt_mode))
+ && aarch64_move_imm (INTVAL (elt_value),
+ encoded_bits <= 32 ? SImode : DImode))
{
elt_value = force_reg (elt_mode, elt_value);
return expand_vector_broadcast (mode, elt_value);
@@ -7024,8 +7007,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm)
return;
}
- aarch64_internal_mov_immediate (dest, imm, true,
- as_a <scalar_int_mode> (mode));
+ aarch64_internal_mov_immediate (dest, imm, true, mode);
}
/* Return the MEM rtx that provides the canary value that should be used
@@ -11197,9 +11179,7 @@ aarch64_float_const_rtx_p (rtx x)
&& SCALAR_FLOAT_MODE_P (mode)
&& aarch64_reinterpret_float_as_int (x, &ival))
{
- scalar_int_mode imode = (mode == HFmode
- ? SImode
- : int_mode_for_mode (mode).require ());
+ machine_mode imode = known_eq (GET_MODE_SIZE (mode), 8) ? DImode : SImode;
int num_instr = aarch64_internal_mov_immediate
(NULL_RTX, gen_int_mode (ival, imode), false, imode);
return num_instr < 3;
@@ -13857,10 +13837,10 @@ aarch64_rtx_costs (rtx x, machine_mode mode, int outer ATTRIBUTE_UNUSED,
proportionally expensive to the number of instructions
required to build that constant. This is true whether we
are compiling for SPEED or otherwise. */
- if (!is_a <scalar_int_mode> (mode, &int_mode))
- int_mode = word_mode;
+ machine_mode imode = known_le (GET_MODE_SIZE (mode), 4)
+ ? SImode : DImode;
*cost = COSTS_N_INSNS (aarch64_internal_mov_immediate
- (NULL_RTX, x, false, int_mode));
+ (NULL_RTX, x, false, imode));
}
return true;
@@ -13876,9 +13856,8 @@ aarch64_rtx_costs (rtx x, machine_mode mode, int outer ATTRIBUTE_UNUSED,
bool succeed = aarch64_reinterpret_float_as_int (x, &ival);
gcc_assert (succeed);
- scalar_int_mode imode = (mode == HFmode
- ? SImode
- : int_mode_for_mode (mode).require ());
+ machine_mode imode = known_eq (GET_MODE_SIZE (mode), 8)
+ ? DImode : SImode;
int ncost = aarch64_internal_mov_immediate
(NULL_RTX, gen_int_mode (ival, imode), false, imode);
*cost += COSTS_N_INSNS (ncost);
@@ -22058,6 +22037,38 @@ aarch64_expand_vector_init (rtx target, rtx vals)
return;
}
+ /* Check for interleaving case.
+ For eg if initializer is (int16x8_t) {x, y, x, y, x, y, x, y}.
+ Generate following code:
+ dup v0.h, x
+ dup v1.h, y
+ zip1 v0.h, v0.h, v1.h
+ for "large enough" initializer. */
+
+ if (n_elts >= 8)
+ {
+ int i;
+ for (i = 2; i < n_elts; i++)
+ if (!rtx_equal_p (XVECEXP (vals, 0, i), XVECEXP (vals, 0, i % 2)))
+ break;
+
+ if (i == n_elts)
+ {
+ machine_mode mode = GET_MODE (target);
+ rtx dest[2];
+
+ for (int i = 0; i < 2; i++)
+ {
+ rtx x = expand_vector_broadcast (mode, XVECEXP (vals, 0, i));
+ dest[i] = force_reg (mode, x);
+ }
+
+ rtvec v = gen_rtvec (2, dest[0], dest[1]);
+ emit_set_insn (target, gen_rtx_UNSPEC (mode, v, UNSPEC_ZIP1));
+ return;
+ }
+ }
+
enum insn_code icode = optab_handler (vec_set_optab, mode);
gcc_assert (icode != CODE_FOR_nothing);
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 8a18405..82cc716 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -1309,16 +1309,15 @@
)
(define_insn_and_split "*movdi_aarch64"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,k,r,r,r,r,r, r,w, m,m, r, r, r, w,r,w, w")
- (match_operand:DI 1 "aarch64_mov_operand" " r,r,k,N,M,n,Usv,m,m,rZ,w,Usw,Usa,Ush,rZ,w,w,Dd"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,k,r,r,r,r, r,w, m,m, r, r, r, w,r,w, w")
+ (match_operand:DI 1 "aarch64_mov_operand" " r,r,k,O,n,Usv,m,m,rZ,w,Usw,Usa,Ush,rZ,w,w,Dd"))]
"(register_operand (operands[0], DImode)
|| aarch64_reg_or_zero (operands[1], DImode))"
"@
mov\\t%x0, %x1
mov\\t%0, %x1
mov\\t%x0, %1
- mov\\t%x0, %1
- mov\\t%w0, %1
+ * return aarch64_is_mov_xn_imm (INTVAL (operands[1])) ? \"mov\\t%x0, %1\" : \"mov\\t%w0, %1\";
#
* return aarch64_output_sve_cnt_immediate (\"cnt\", \"%x0\", operands[1]);
ldr\\t%x0, %1
@@ -1340,11 +1339,11 @@
DONE;
}"
;; The "mov_imm" type for CNTD is just a placeholder.
- [(set_attr "type" "mov_reg,mov_reg,mov_reg,mov_imm,mov_imm,mov_imm,mov_imm,
+ [(set_attr "type" "mov_reg,mov_reg,mov_reg,mov_imm,mov_imm,mov_imm,
load_8,load_8,store_8,store_8,load_8,adr,adr,f_mcr,f_mrc,
fmov,neon_move")
- (set_attr "arch" "*,*,*,*,*,*,sve,*,fp,*,fp,*,*,*,fp,fp,fp,simd")
- (set_attr "length" "4,4,4,4,4,*, 4,4, 4,4, 4,8,4,4, 4, 4, 4, 4")]
+ (set_attr "arch" "*,*,*,*,*,sve,*,fp,*,fp,*,*,*,fp,fp,fp,simd")
+ (set_attr "length" "4,4,4,4,*, 4,4, 4,4, 4,8,4,4, 4, 4, 4, 4")]
)
(define_insn "insv_imm<mode>"
@@ -1508,7 +1507,7 @@
(define_insn "*mov<mode>_aarch64"
[(set (match_operand:DFD 0 "nonimmediate_operand" "=w, w ,?r,w,w ,w ,w,m,r,m ,r,r")
- (match_operand:DFD 1 "general_operand" "Y , ?rY, w,w,Ufc,Uvi,m,w,m,rY,r,N"))]
+ (match_operand:DFD 1 "general_operand" "Y , ?rY, w,w,Ufc,Uvi,m,w,m,rY,r,O"))]
"TARGET_FLOAT && (register_operand (operands[0], <MODE>mode)
|| aarch64_reg_or_fp_zero (operands[1], <MODE>mode))"
"@
@@ -1523,7 +1522,7 @@
ldr\\t%x0, %1
str\\t%x1, %0
mov\\t%x0, %x1
- mov\\t%x0, %1"
+ * return aarch64_is_mov_xn_imm (INTVAL (operands[1])) ? \"mov\\t%x0, %1\" : \"mov\\t%w0, %1\";"
[(set_attr "type" "neon_move,f_mcr,f_mrc,fmov,fconstd,neon_move,\
f_loadd,f_stored,load_8,store_8,mov_reg,\
fconstd")
diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md
index 29efb6c..ad2e5e0 100644
--- a/gcc/config/aarch64/constraints.md
+++ b/gcc/config/aarch64/constraints.md
@@ -107,6 +107,11 @@
(define_constraint "N"
"A constant that can be used with a 64-bit MOV immediate operation."
(and (match_code "const_int")
+ (match_test "aarch64_is_mov_xn_imm (ival)")))
+
+(define_constraint "O"
+ "A constant that can be used with a 32 or 64-bit MOV immediate operation."
+ (and (match_code "const_int")
(match_test "aarch64_move_imm (ival, DImode)")))
(define_constraint "Uti"
diff --git a/gcc/config/arm/mve.md b/gcc/config/arm/mve.md
index b5e6da4..3fe9db8 100644
--- a/gcc/config/arm/mve.md
+++ b/gcc/config/arm/mve.md
@@ -841,8 +841,9 @@
(define_insn "mve_vcmp<mve_cmp_op>q_n_<mode>"
[
(set (match_operand:<MVE_VPRED> 0 "vpr_register_operand" "=Up")
- (MVE_COMPARISONS:<MVE_VPRED> (match_operand:MVE_2 1 "s_register_operand" "w")
- (match_operand:<V_elem> 2 "s_register_operand" "r")))
+ (MVE_COMPARISONS:<MVE_VPRED>
+ (match_operand:MVE_2 1 "s_register_operand" "w")
+ (vec_duplicate:MVE_2 (match_operand:<V_elem> 2 "s_register_operand" "r"))))
]
"TARGET_HAVE_MVE"
"vcmp.<mve_cmp_type>%#<V_sz_elem> <mve_cmp_op>, %q1, %2"
@@ -1931,8 +1932,9 @@
(define_insn "@mve_vcmp<mve_cmp_op>q_n_f<mode>"
[
(set (match_operand:<MVE_VPRED> 0 "vpr_register_operand" "=Up")
- (MVE_FP_COMPARISONS:<MVE_VPRED> (match_operand:MVE_0 1 "s_register_operand" "w")
- (match_operand:<V_elem> 2 "s_register_operand" "r")))
+ (MVE_FP_COMPARISONS:<MVE_VPRED>
+ (match_operand:MVE_0 1 "s_register_operand" "w")
+ (vec_duplicate:MVE_0 (match_operand:<V_elem> 2 "s_register_operand" "r"))))
]
"TARGET_HAVE_MVE && TARGET_HAVE_MVE_FLOAT"
"vcmp.f%#<V_sz_elem> <mve_cmp_op>, %q1, %2"
diff --git a/gcc/config/gcn/gcn-opts.h b/gcc/config/gcn/gcn-opts.h
index b62dfb4..b54eae7 100644
--- a/gcc/config/gcn/gcn-opts.h
+++ b/gcc/config/gcn/gcn-opts.h
@@ -27,6 +27,12 @@ enum processor_type
PROCESSOR_GFX90a
};
+#define TARGET_FIJI (gcn_arch == PROCESSOR_FIJI)
+#define TARGET_VEGA10 (gcn_arch == PROCESSOR_VEGA10)
+#define TARGET_VEGA20 (gcn_arch == PROCESSOR_VEGA20)
+#define TARGET_GFX908 (gcn_arch == PROCESSOR_GFX908)
+#define TARGET_GFX90a (gcn_arch == PROCESSOR_GFX90a)
+
/* Set in gcn_option_override. */
extern enum gcn_isa {
ISA_UNKNOWN,
diff --git a/gcc/config/gcn/gcn.h b/gcc/config/gcn/gcn.h
index 38f7212..1cc5981 100644
--- a/gcc/config/gcn/gcn.h
+++ b/gcc/config/gcn/gcn.h
@@ -16,20 +16,32 @@
#include "config/gcn/gcn-opts.h"
-#define TARGET_CPU_CPP_BUILTINS() \
- do \
- { \
- builtin_define ("__AMDGCN__"); \
- if (TARGET_GCN3) \
- builtin_define ("__GCN3__"); \
- else if (TARGET_GCN5) \
- builtin_define ("__GCN5__"); \
- else if (TARGET_CDNA1) \
- builtin_define ("__CDNA1__"); \
- else if (TARGET_CDNA2) \
- builtin_define ("__CDNA2__"); \
- } \
- while(0)
+#define TARGET_CPU_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define ("__AMDGCN__"); \
+ if (TARGET_GCN3) \
+ builtin_define ("__GCN3__"); \
+ else if (TARGET_GCN5) \
+ builtin_define ("__GCN5__"); \
+ else if (TARGET_CDNA1) \
+ builtin_define ("__CDNA1__"); \
+ else if (TARGET_CDNA2) \
+ builtin_define ("__CDNA2__"); \
+ if (TARGET_FIJI) \
+ { \
+ builtin_define ("__fiji__"); \
+ builtin_define ("__gfx803__"); \
+ } \
+ else if (TARGET_VEGA10) \
+ builtin_define ("__gfx900__"); \
+ else if (TARGET_VEGA20) \
+ builtin_define ("__gfx906__"); \
+ else if (TARGET_GFX908) \
+ builtin_define ("__gfx908__"); \
+ else if (TARGET_GFX90a) \
+ builtin_define ("__gfx90a__"); \
+ } while (0)
/* Support for a compile-time default architecture and tuning.
The rules are:
diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index d26e7e4..b920cfb 100644
--- a/gcc/config/i386/i386-expand.cc
+++ b/gcc/config/i386/i386-expand.cc
@@ -173,6 +173,33 @@ split_double_concat (machine_mode mode, rtx dst, rtx lo, rtx hi)
rtx dlo, dhi;
int deleted_move_count = 0;
split_double_mode (mode, &dst, 1, &dlo, &dhi);
+ /* Constraints ensure that if both lo and hi are MEMs, then
+ dst has early-clobber and thus addresses of MEMs don't use
+ dlo/dhi registers. Otherwise if at least one of li and hi are MEMs,
+ dlo/dhi are registers. */
+ if (MEM_P (lo)
+ && rtx_equal_p (dlo, hi)
+ && reg_overlap_mentioned_p (dhi, lo))
+ {
+ /* If dlo is same as hi and lo's address uses dhi register,
+ code below would first emit_move_insn (dhi, hi)
+ and then emit_move_insn (dlo, lo). But the former
+ would invalidate lo's address. Load into dhi first,
+ then swap. */
+ emit_move_insn (dhi, lo);
+ lo = dhi;
+ }
+ else if (MEM_P (hi)
+ && !MEM_P (lo)
+ && !rtx_equal_p (dlo, lo)
+ && reg_overlap_mentioned_p (dlo, hi))
+ {
+ /* In this case, code below would first emit_move_insn (dlo, lo)
+ and then emit_move_insn (dhi, hi). But the former would
+ invalidate hi's address. Load into dhi first. */
+ emit_move_insn (dhi, hi);
+ hi = dhi;
+ }
if (!rtx_equal_p (dlo, hi))
{
if (!rtx_equal_p (dlo, lo))
@@ -12476,7 +12503,7 @@ ix86_expand_vec_set_builtin (tree exp)
op1 = expand_expr (arg1, NULL_RTX, mode1, EXPAND_NORMAL);
elt = get_element_number (TREE_TYPE (arg0), arg2);
- if (GET_MODE (op1) != mode1 && GET_MODE (op1) != VOIDmode)
+ if (GET_MODE (op1) != mode1)
op1 = convert_modes (mode1, GET_MODE (op1), op1, true);
op0 = force_reg (tmode, op0);
@@ -15160,6 +15187,10 @@ ix86_vector_duplicate_value (machine_mode mode, rtx target, rtx val)
bool ok;
rtx_insn *insn;
rtx dup;
+ /* Save/restore recog_data in case this is called from splitters
+ or other routines where recog_data needs to stay valid across
+ force_reg. See PR106577. */
+ recog_data_d recog_data_save = recog_data;
/* First attempt to recognize VAL as-is. */
dup = gen_vec_duplicate (mode, val);
@@ -15185,6 +15216,7 @@ ix86_vector_duplicate_value (machine_mode mode, rtx target, rtx val)
ok = recog_memoized (insn) >= 0;
gcc_assert (ok);
}
+ recog_data = recog_data_save;
return true;
}
@@ -24155,14 +24187,13 @@ ix86_expand_fast_convert_bf_to_sf (rtx val)
/* FLOAT_EXTEND simplification will fail if VAL is a sNaN. */
ret = gen_reg_rtx (SImode);
emit_move_insn (ret, GEN_INT (INTVAL (op) & 0xffff));
+ emit_insn (gen_ashlsi3 (ret, ret, GEN_INT (16)));
+ return gen_lowpart (SFmode, ret);
}
- else
- {
- ret = gen_reg_rtx (SImode);
- emit_insn (gen_zero_extendhisi2 (ret, op));
- }
- emit_insn (gen_ashlsi3 (ret, ret, GEN_INT (16)));
- return gen_lowpart (SFmode, ret);
+
+ ret = gen_reg_rtx (SFmode);
+ emit_insn (gen_extendbfsf2_1 (ret, force_reg (BFmode, val)));
+ return ret;
}
#include "gt-i386-expand.h"
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 9451883..58853a7 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -1667,7 +1667,7 @@
(const_int 0)])
(label_ref (match_operand 3))
(pc)))]
- ""
+ "TARGET_80387 || (SSE_FLOAT_MODE_P (SFmode) && TARGET_SSE_MATH)"
{
rtx op1 = ix86_expand_fast_convert_bf_to_sf (operands[1]);
rtx op2 = ix86_expand_fast_convert_bf_to_sf (operands[2]);
@@ -1702,7 +1702,7 @@
(match_operator 1 "comparison_operator"
[(reg:CC FLAGS_REG)
(const_int 0)]))]
- ""
+ "TARGET_80387 || (SSE_FLOAT_MODE_P (SFmode) && TARGET_SSE_MATH)"
{
rtx op1 = ix86_expand_fast_convert_bf_to_sf (operands[2]);
rtx op2 = ix86_expand_fast_convert_bf_to_sf (operands[3]);
@@ -4981,7 +4981,7 @@
pslld\t{$16, %0|%0, 16}
vpslld\t{$16, %1, %0|%0, %1, 16}"
[(set_attr "isa" "noavx,avx")
- (set_attr "type" "sseishft")
+ (set_attr "type" "sseishft1")
(set_attr "length_immediate" "1")
(set_attr "prefix_data16" "1,*")
(set_attr "prefix" "orig,vex")
@@ -11396,11 +11396,12 @@
;; Split DST = (HI<<32)|LO early to minimize register usage.
(define_code_iterator any_or_plus [plus ior xor])
(define_insn_and_split "*concat<mode><dwi>3_1"
- [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro")
+ [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro,r")
(any_or_plus:<DWI>
- (ashift:<DWI> (match_operand:<DWI> 1 "register_operand" "r")
+ (ashift:<DWI> (match_operand:<DWI> 1 "register_operand" "r,r")
(match_operand:<DWI> 2 "const_int_operand"))
- (zero_extend:<DWI> (match_operand:DWIH 3 "register_operand" "r"))))]
+ (zero_extend:<DWI>
+ (match_operand:DWIH 3 "nonimmediate_operand" "r,m"))))]
"INTVAL (operands[2]) == <MODE_SIZE> * BITS_PER_UNIT"
"#"
"&& reload_completed"
@@ -11412,10 +11413,11 @@
})
(define_insn_and_split "*concat<mode><dwi>3_2"
- [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro")
+ [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro,r")
(any_or_plus:<DWI>
- (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "r"))
- (ashift:<DWI> (match_operand:<DWI> 2 "register_operand" "r")
+ (zero_extend:<DWI>
+ (match_operand:DWIH 1 "nonimmediate_operand" "r,m"))
+ (ashift:<DWI> (match_operand:<DWI> 2 "register_operand" "r,r")
(match_operand:<DWI> 3 "const_int_operand"))))]
"INTVAL (operands[3]) == <MODE_SIZE> * BITS_PER_UNIT"
"#"
@@ -11428,12 +11430,14 @@
})
(define_insn_and_split "*concat<mode><dwi>3_3"
- [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro")
+ [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro,r,r,&r")
(any_or_plus:<DWI>
(ashift:<DWI>
- (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "r"))
+ (zero_extend:<DWI>
+ (match_operand:DWIH 1 "nonimmediate_operand" "r,m,r,m"))
(match_operand:<DWI> 2 "const_int_operand"))
- (zero_extend:<DWI> (match_operand:DWIH 3 "register_operand" "r"))))]
+ (zero_extend:<DWI>
+ (match_operand:DWIH 3 "nonimmediate_operand" "r,r,m,m"))))]
"INTVAL (operands[2]) == <MODE_SIZE> * BITS_PER_UNIT"
"#"
"&& reload_completed"
@@ -11444,11 +11448,13 @@
})
(define_insn_and_split "*concat<mode><dwi>3_4"
- [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro")
+ [(set (match_operand:<DWI> 0 "nonimmediate_operand" "=ro,r,r,&r")
(any_or_plus:<DWI>
- (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "r"))
+ (zero_extend:<DWI>
+ (match_operand:DWIH 1 "nonimmediate_operand" "r,m,r,m"))
(ashift:<DWI>
- (zero_extend:<DWI> (match_operand:DWIH 2 "register_operand" "r"))
+ (zero_extend:<DWI>
+ (match_operand:DWIH 2 "nonimmediate_operand" "r,r,m,m"))
(match_operand:<DWI> 3 "const_int_operand"))))]
"INTVAL (operands[3]) == <MODE_SIZE> * BITS_PER_UNIT"
"#"
diff --git a/gcc/config/i386/mmx.md b/gcc/config/i386/mmx.md
index 63aff287..c3afc6b 100644
--- a/gcc/config/i386/mmx.md
+++ b/gcc/config/i386/mmx.md
@@ -1709,7 +1709,8 @@
[(match_operand:V2SF 1 "register_operand")
(match_dup 2)]
UNSPEC_ROUND))]
- "TARGET_SSE4_1 && !flag_trapping_math"
+ "TARGET_SSE4_1 && !flag_trapping_math
+ && TARGET_MMX_WITH_SSE"
"operands[2] = GEN_INT (ROUND_TRUNC | ROUND_NO_EXC);")
(define_insn "*mmx_roundv2sf2"
diff --git a/gcc/config/i386/x86-tune.def b/gcc/config/i386/x86-tune.def
index cd66f33..db85de2 100644
--- a/gcc/config/i386/x86-tune.def
+++ b/gcc/config/i386/x86-tune.def
@@ -499,7 +499,8 @@ DEF_TUNE (X86_TUNE_AVOID_128FMA_CHAINS, "avoid_fma_chains", m_ZNVER)
/* X86_TUNE_AVOID_256FMA_CHAINS: Avoid creating loops with tight 256bit or
smaller FMA chain. */
-DEF_TUNE (X86_TUNE_AVOID_256FMA_CHAINS, "avoid_fma256_chains", m_ZNVER2 | m_ZNVER3)
+DEF_TUNE (X86_TUNE_AVOID_256FMA_CHAINS, "avoid_fma256_chains", m_ZNVER2 | m_ZNVER3
+ | m_ALDERLAKE | m_SAPPHIRERAPIDS | m_CORE_ATOM)
/* X86_TUNE_V2DF_REDUCTION_PREFER_PHADDPD: Prefer haddpd
for v2df vector reduction. */
diff --git a/gcc/config/riscv/constraints.md b/gcc/config/riscv/constraints.md
index 4088c48..51cffb2 100644
--- a/gcc/config/riscv/constraints.md
+++ b/gcc/config/riscv/constraints.md
@@ -151,3 +151,8 @@
A constraint that matches a vector of immediate all ones."
(and (match_code "const_vector")
(match_test "op == CONSTM1_RTX (GET_MODE (op))")))
+
+(define_constraint "Wdm"
+ "Vector duplicate memory operand"
+ (and (match_operand 0 "memory_operand")
+ (match_code "reg" "0")))
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index dfd9876..5a5a49b 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -286,6 +286,11 @@
(match_test "GET_CODE (op) == UNSPEC
&& (XINT (op, 1) == UNSPEC_VUNDEF)"))))
+;; The scalar operand can be directly broadcast by RVV instructions.
+(define_predicate "direct_broadcast_operand"
+ (ior (match_operand 0 "register_operand")
+ (match_test "satisfies_constraint_Wdm (op)")))
+
;; A CONST_INT operand that has exactly two bits cleared.
(define_predicate "const_nottwobits_operand"
(and (match_code "const_int")
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 2ec3af0..e17e003 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -119,6 +119,18 @@ extern void riscv_run_selftests (void);
#endif
namespace riscv_vector {
+#define RVV_VLMAX gen_rtx_REG (Pmode, X0_REGNUM)
+enum vlmul_type
+{
+ LMUL_1 = 0,
+ LMUL_2 = 1,
+ LMUL_4 = 2,
+ LMUL_8 = 3,
+ LMUL_RESERVED = 4,
+ LMUL_F8 = 5,
+ LMUL_F4 = 6,
+ LMUL_F2 = 7,
+};
/* Routines implemented in riscv-vector-builtins.cc. */
extern void init_builtins (void);
extern const char *mangle_builtin_type (const_tree);
@@ -130,6 +142,9 @@ extern tree builtin_decl (unsigned, bool);
extern rtx expand_builtin (unsigned int, tree, rtx);
extern bool const_vec_all_same_in_range_p (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
extern bool legitimize_move (rtx, rtx, machine_mode);
+extern void emit_pred_op (unsigned, rtx, rtx, machine_mode);
+extern enum vlmul_type get_vlmul (machine_mode);
+extern unsigned int get_ratio (machine_mode);
enum tail_policy
{
TAIL_UNDISTURBED = 0,
diff --git a/gcc/config/riscv/riscv-selftests.cc b/gcc/config/riscv/riscv-selftests.cc
index 636874e..1bf1a64 100644
--- a/gcc/config/riscv/riscv-selftests.cc
+++ b/gcc/config/riscv/riscv-selftests.cc
@@ -33,6 +33,9 @@ along with GCC; see the file COPYING3. If not see
#include "expr.h"
#include "selftest.h"
#include "selftest-rtl.h"
+#include "insn-attr.h"
+#include "target.h"
+#include "optabs.h"
#if CHECKING_P
using namespace selftest;
@@ -230,12 +233,136 @@ run_poly_int_selftests (void)
run_poly_int_selftest ("rv32imafd_zve32x1p0", ABI_ILP32D, POLY_TEST_DIMODE,
worklist);
}
+
+static void
+run_const_vector_selftests (void)
+{
+ /* We dont't need to do the redundant tests in different march && mabi.
+ Just pick up the march && mabi which fully support all RVV modes. */
+ riscv_selftest_arch_abi_setter rv ("rv64imafdcv", ABI_LP64D);
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl"));
+ set_new_first_and_last_insn (NULL, NULL);
+
+ machine_mode mode;
+ std::vector<HOST_WIDE_INT> worklist = {-111, -17, -16, 7, 15, 16, 111};
+
+ FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT)
+ {
+ if (riscv_v_ext_vector_mode_p (mode))
+ {
+ for (const HOST_WIDE_INT &val : worklist)
+ {
+ start_sequence ();
+ rtx dest = gen_reg_rtx (mode);
+ rtx dup = gen_const_vec_duplicate (mode, GEN_INT (val));
+ emit_move_insn (dest, dup);
+ rtx_insn *insn = get_last_insn ();
+ rtx src = XEXP (SET_SRC (PATTERN (insn)), 1);
+ /* 1. Should be vmv.v.i for in rang of -16 ~ 15.
+ 2. Should be vmv.v.x for exceed -16 ~ 15. */
+ if (IN_RANGE (val, -16, 15))
+ ASSERT_TRUE (rtx_equal_p (src, dup));
+ else
+ ASSERT_TRUE (
+ rtx_equal_p (src,
+ gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0))));
+ end_sequence ();
+ }
+ }
+ }
+
+ FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_FLOAT)
+ {
+ if (riscv_v_ext_vector_mode_p (mode))
+ {
+ scalar_mode inner_mode = GET_MODE_INNER (mode);
+ REAL_VALUE_TYPE f = REAL_VALUE_ATOF ("0.2928932", inner_mode);
+ rtx ele = const_double_from_real_value (f, inner_mode);
+
+ start_sequence ();
+ rtx dest = gen_reg_rtx (mode);
+ rtx dup = gen_const_vec_duplicate (mode, ele);
+ emit_move_insn (dest, dup);
+ rtx_insn *insn = get_last_insn ();
+ rtx src = XEXP (SET_SRC (PATTERN (insn)), 1);
+ /* Should always be vfmv.v.f. */
+ ASSERT_TRUE (
+ rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0))));
+ end_sequence ();
+ }
+ }
+
+ FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_BOOL)
+ {
+ /* Test vmset.m. */
+ if (riscv_v_ext_vector_mode_p (mode))
+ {
+ start_sequence ();
+ rtx dest = gen_reg_rtx (mode);
+ emit_move_insn (dest, CONSTM1_RTX (mode));
+ rtx_insn *insn = get_last_insn ();
+ rtx src = XEXP (SET_SRC (PATTERN (insn)), 1);
+ ASSERT_TRUE (rtx_equal_p (src, CONSTM1_RTX (mode)));
+ end_sequence ();
+ }
+ }
+}
+
+static void
+run_broadcast_selftests (void)
+{
+ /* We dont't need to do the redundant tests in different march && mabi.
+ Just pick up the march && mabi which fully support all RVV modes. */
+ riscv_selftest_arch_abi_setter rv ("rv64imafdcv", ABI_LP64D);
+ rtl_dump_test t (SELFTEST_LOCATION, locate_file ("riscv/empty-func.rtl"));
+ set_new_first_and_last_insn (NULL, NULL);
+
+ machine_mode mode;
+
+#define BROADCAST_TEST(MODE_CLASS) \
+ FOR_EACH_MODE_IN_CLASS (mode, MODE_VECTOR_INT) \
+ { \
+ if (riscv_v_ext_vector_mode_p (mode)) \
+ { \
+ rtx_insn *insn; \
+ rtx src; \
+ scalar_mode inner_mode = GET_MODE_INNER (mode); \
+ /* Test vlse.v with zero stride. */ \
+ start_sequence (); \
+ rtx addr = gen_reg_rtx (Pmode); \
+ rtx mem = gen_rtx_MEM (inner_mode, addr); \
+ expand_vector_broadcast (mode, mem); \
+ insn = get_last_insn (); \
+ src = XEXP (SET_SRC (PATTERN (insn)), 1); \
+ ASSERT_TRUE (MEM_P (XEXP (src, 0))); \
+ ASSERT_TRUE ( \
+ rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0)))); \
+ end_sequence (); \
+ /* Test vmv.v.x or vfmv.v.f. */ \
+ start_sequence (); \
+ rtx reg = gen_reg_rtx (inner_mode); \
+ expand_vector_broadcast (mode, reg); \
+ insn = get_last_insn (); \
+ src = XEXP (SET_SRC (PATTERN (insn)), 1); \
+ ASSERT_TRUE (REG_P (XEXP (src, 0))); \
+ ASSERT_TRUE ( \
+ rtx_equal_p (src, gen_rtx_VEC_DUPLICATE (mode, XEXP (src, 0)))); \
+ end_sequence (); \
+ } \
+ }
+
+ BROADCAST_TEST (MODE_VECTOR_INT)
+ BROADCAST_TEST (MODE_VECTOR_FLOAT)
+}
+
namespace selftest {
/* Run all target-specific selftests. */
void
riscv_run_selftests (void)
{
run_poly_int_selftests ();
+ run_const_vector_selftests ();
+ run_broadcast_selftests ();
}
} // namespace selftest
#endif /* #if CHECKING_P */
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index e0459e3..4992ff2 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -40,6 +40,7 @@
#include "target.h"
#include "expr.h"
#include "optabs.h"
+#include "tm-constrs.h"
using namespace riscv_vector;
@@ -104,34 +105,81 @@ const_vec_all_same_in_range_p (rtx x, HOST_WIDE_INT minval,
&& IN_RANGE (INTVAL (elt), minval, maxval));
}
-/* Emit an RVV unmask && vl mov from SRC to DEST. */
-static void
-emit_pred_move (rtx dest, rtx src, machine_mode mask_mode)
+static rtx
+emit_vlmax_vsetvl (machine_mode vmode)
{
- insn_expander<7> e;
- machine_mode mode = GET_MODE (dest);
rtx vl = gen_reg_rtx (Pmode);
- unsigned int sew = GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL
+ unsigned int sew = GET_MODE_CLASS (vmode) == MODE_VECTOR_BOOL
? 8
- : GET_MODE_BITSIZE (GET_MODE_INNER (mode));
+ : GET_MODE_BITSIZE (GET_MODE_INNER (vmode));
+
+ emit_insn (
+ gen_vsetvl_no_side_effects (Pmode, vl, RVV_VLMAX, gen_int_mode (sew, Pmode),
+ gen_int_mode ((unsigned int) vmode, Pmode),
+ const1_rtx, const1_rtx));
+ return vl;
+}
- emit_insn (gen_vsetvl_no_side_effects (
- Pmode, vl, gen_rtx_REG (Pmode, 0), gen_int_mode (sew, Pmode),
- gen_int_mode ((unsigned int) mode, Pmode), const1_rtx, const1_rtx));
+/* Emit an RVV unmask && vl mov from SRC to DEST. */
+void
+emit_pred_op (unsigned icode, rtx dest, rtx src, machine_mode mask_mode)
+{
+ insn_expander<7> e;
+ machine_mode mode = GET_MODE (dest);
e.add_output_operand (dest, mode);
e.add_all_one_mask_operand (mask_mode);
e.add_vundef_operand (mode);
- e.add_input_operand (src, mode);
+ e.add_input_operand (src, GET_MODE (src));
+
+ rtx vlmax = emit_vlmax_vsetvl (mode);
+ e.add_input_operand (vlmax, Pmode);
+
+ if (GET_MODE_CLASS (mode) != MODE_VECTOR_BOOL)
+ e.add_policy_operand (TAIL_AGNOSTIC, MASK_AGNOSTIC);
+
+ e.expand ((enum insn_code) icode, MEM_P (dest) || MEM_P (src));
+}
+
+static void
+expand_const_vector (rtx target, rtx src, machine_mode mask_mode)
+{
+ machine_mode mode = GET_MODE (target);
+ scalar_mode elt_mode = GET_MODE_INNER (mode);
+ if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL)
+ {
+ rtx elt;
+ gcc_assert (
+ const_vec_duplicate_p (src, &elt)
+ && (rtx_equal_p (elt, const0_rtx) || rtx_equal_p (elt, const1_rtx)));
+ emit_pred_op (code_for_pred_mov (mode), target, src, mode);
+ return;
+ }
+
+ rtx elt;
+ if (const_vec_duplicate_p (src, &elt))
+ {
+ rtx tmp = register_operand (target, mode) ? target : gen_reg_rtx (mode);
+ /* Element in range -16 ~ 15 integer or 0.0 floating-point,
+ we use vmv.v.i instruction. */
+ if (satisfies_constraint_vi (src) || satisfies_constraint_Wc0 (src))
+ emit_pred_op (code_for_pred_mov (mode), tmp, src, mask_mode);
+ else
+ emit_pred_op (code_for_pred_broadcast (mode), tmp,
+ force_reg (elt_mode, elt), mask_mode);
- e.add_input_operand (vl, Pmode);
+ if (tmp != target)
+ emit_move_insn (target, tmp);
+ return;
+ }
- e.add_policy_operand (TAIL_AGNOSTIC, MASK_AGNOSTIC);
+ /* TODO: We only support const duplicate vector for now. More cases
+ will be supported when we support auto-vectorization:
- enum insn_code icode;
- icode = code_for_pred_mov (mode);
- e.expand (icode, true);
+ 1. series vector.
+ 2. multiple elts duplicate vector.
+ 3. multiple patterns with multiple elts. */
}
/* Expand a pre-RA RVV data move from SRC to DEST.
@@ -140,6 +188,11 @@ bool
legitimize_move (rtx dest, rtx src, machine_mode mask_mode)
{
machine_mode mode = GET_MODE (dest);
+ if (CONST_VECTOR_P (src))
+ {
+ expand_const_vector (dest, src, mask_mode);
+ return true;
+ }
if (known_ge (GET_MODE_SIZE (mode), BYTES_PER_RISCV_VECTOR)
&& GET_MODE_CLASS (mode) != MODE_VECTOR_BOOL)
{
@@ -153,13 +206,54 @@ legitimize_move (rtx dest, rtx src, machine_mode mask_mode)
{
rtx tmp = gen_reg_rtx (mode);
if (MEM_P (src))
- emit_pred_move (tmp, src, mask_mode);
+ emit_pred_op (code_for_pred_mov (mode), tmp, src, mask_mode);
else
emit_move_insn (tmp, src);
src = tmp;
}
- emit_pred_move (dest, src, mask_mode);
+ emit_pred_op (code_for_pred_mov (mode), dest, src, mask_mode);
return true;
}
+/* VTYPE information for machine_mode. */
+struct mode_vtype_group
+{
+ enum vlmul_type vlmul_for_min_vlen32[NUM_MACHINE_MODES];
+ uint8_t ratio_for_min_vlen32[NUM_MACHINE_MODES];
+ enum vlmul_type vlmul_for_min_vlen64[NUM_MACHINE_MODES];
+ uint8_t ratio_for_min_vlen64[NUM_MACHINE_MODES];
+ mode_vtype_group ()
+ {
+#define ENTRY(MODE, REQUIREMENT, VLMUL_FOR_MIN_VLEN32, RATIO_FOR_MIN_VLEN32, \
+ VLMUL_FOR_MIN_VLEN64, RATIO_FOR_MIN_VLEN64) \
+ vlmul_for_min_vlen32[MODE##mode] = VLMUL_FOR_MIN_VLEN32; \
+ ratio_for_min_vlen32[MODE##mode] = RATIO_FOR_MIN_VLEN32; \
+ vlmul_for_min_vlen64[MODE##mode] = VLMUL_FOR_MIN_VLEN64; \
+ ratio_for_min_vlen64[MODE##mode] = RATIO_FOR_MIN_VLEN64;
+#include "riscv-vector-switch.def"
+ }
+};
+
+static mode_vtype_group mode_vtype_infos;
+
+/* Get vlmul field value by comparing LMUL with BYTES_PER_RISCV_VECTOR. */
+enum vlmul_type
+get_vlmul (machine_mode mode)
+{
+ if (TARGET_MIN_VLEN == 32)
+ return mode_vtype_infos.vlmul_for_min_vlen32[mode];
+ else
+ return mode_vtype_infos.vlmul_for_min_vlen64[mode];
+}
+
+/* Get ratio according to machine mode. */
+unsigned int
+get_ratio (machine_mode mode)
+{
+ if (TARGET_MIN_VLEN == 32)
+ return mode_vtype_infos.ratio_for_min_vlen32[mode];
+ else
+ return mode_vtype_infos.ratio_for_min_vlen64[mode];
+}
+
} // namespace riscv_vector
diff --git a/gcc/config/riscv/riscv-vector-switch.def b/gcc/config/riscv/riscv-vector-switch.def
index ee8ebd5..a51f45b 100644
--- a/gcc/config/riscv/riscv-vector-switch.def
+++ b/gcc/config/riscv/riscv-vector-switch.def
@@ -80,7 +80,8 @@ TODO: FP16 vector needs support of 'zvfh', we don't support it yet. */
/* Return 'REQUIREMENT' for machine_mode 'MODE'.
For example: 'MODE' = VNx64BImode needs TARGET_MIN_VLEN > 32. */
#ifndef ENTRY
-#define ENTRY(MODE, REQUIREMENT)
+#define ENTRY(MODE, REQUIREMENT, VLMUL_FOR_MIN_VLEN32, RATIO_FOR_MIN_VLEN32, \
+ VLMUL_FOR_MIN_VLEN64, RATIO_FOR_MIN_VLEN64)
#endif
/* Flag of FP32 vector. */
#ifndef TARGET_VECTOR_FP32
@@ -94,66 +95,68 @@ TODO: FP16 vector needs support of 'zvfh', we don't support it yet. */
#endif
/* Mask modes. Disable VNx64BImode when TARGET_MIN_VLEN == 32. */
-ENTRY (VNx64BI, TARGET_MIN_VLEN > 32)
-ENTRY (VNx32BI, true)
-ENTRY (VNx16BI, true)
-ENTRY (VNx8BI, true)
-ENTRY (VNx4BI, true)
-ENTRY (VNx2BI, true)
-ENTRY (VNx1BI, true)
+ENTRY (VNx64BI, TARGET_MIN_VLEN > 32, LMUL_F8, 64, LMUL_RESERVED, 0)
+ENTRY (VNx32BI, true, LMUL_F4, 32, LMUL_RESERVED, 0)
+ENTRY (VNx16BI, true, LMUL_F2, 16, LMUL_RESERVED, 0)
+ENTRY (VNx8BI, true, LMUL_1, 8, LMUL_RESERVED, 0)
+ENTRY (VNx4BI, true, LMUL_2, 4, LMUL_RESERVED, 0)
+ENTRY (VNx2BI, true, LMUL_4, 2, LMUL_RESERVED, 0)
+ENTRY (VNx1BI, true, LMUL_8, 1, LMUL_RESERVED, 0)
/* SEW = 8. Disable VNx64QImode when TARGET_MIN_VLEN == 32. */
-ENTRY (VNx64QI, TARGET_MIN_VLEN > 32)
-ENTRY (VNx32QI, true)
-ENTRY (VNx16QI, true)
-ENTRY (VNx8QI, true)
-ENTRY (VNx4QI, true)
-ENTRY (VNx2QI, true)
-ENTRY (VNx1QI, true)
+ENTRY (VNx64QI, TARGET_MIN_VLEN > 32, LMUL_8, 1, LMUL_RESERVED, 0)
+ENTRY (VNx32QI, true, LMUL_8, 1, LMUL_4, 2)
+ENTRY (VNx16QI, true, LMUL_4, 2, LMUL_2, 4)
+ENTRY (VNx8QI, true, LMUL_2, 4, LMUL_1, 8)
+ENTRY (VNx4QI, true, LMUL_1, 8, LMUL_F2, 16)
+ENTRY (VNx2QI, true, LMUL_F2, 16, LMUL_F4, 32)
+ENTRY (VNx1QI, true, LMUL_F4, 32, LMUL_F8, 64)
/* SEW = 16. Disable VNx32HImode when TARGET_MIN_VLEN == 32. */
-ENTRY (VNx32HI, TARGET_MIN_VLEN > 32)
-ENTRY (VNx16HI, true)
-ENTRY (VNx8HI, true)
-ENTRY (VNx4HI, true)
-ENTRY (VNx2HI, true)
-ENTRY (VNx1HI, true)
+ENTRY (VNx32HI, TARGET_MIN_VLEN > 32, LMUL_8, 2, LMUL_RESERVED, 0)
+ENTRY (VNx16HI, true, LMUL_8, 2, LMUL_4, 4)
+ENTRY (VNx8HI, true, LMUL_4, 4, LMUL_2, 8)
+ENTRY (VNx4HI, true, LMUL_2, 8, LMUL_1, 16)
+ENTRY (VNx2HI, true, LMUL_1, 16, LMUL_F2, 32)
+ENTRY (VNx1HI, true, LMUL_F2, 32, LMUL_F4, 64)
/* TODO:Disable all FP16 vector, enable them when 'zvfh' is supported. */
-ENTRY (VNx32HF, false)
-ENTRY (VNx16HF, false)
-ENTRY (VNx8HF, false)
-ENTRY (VNx4HF, false)
-ENTRY (VNx2HF, false)
-ENTRY (VNx1HF, false)
+ENTRY (VNx32HF, false, LMUL_8, 2, LMUL_RESERVED, 0)
+ENTRY (VNx16HF, false, LMUL_8, 2, LMUL_4, 4)
+ENTRY (VNx8HF, false, LMUL_4, 4, LMUL_2, 8)
+ENTRY (VNx4HF, false, LMUL_2, 8, LMUL_1, 16)
+ENTRY (VNx2HF, false, LMUL_1, 16, LMUL_F2, 32)
+ENTRY (VNx1HF, false, LMUL_F2, 32, LMUL_F4, 64)
/* SEW = 32. Disable VNx16SImode when TARGET_MIN_VLEN == 32.
For single-precision floating-point, we need TARGET_VECTOR_FP32 ==
RVV_ENABLE. */
-ENTRY (VNx16SI, TARGET_MIN_VLEN > 32)
-ENTRY (VNx8SI, true)
-ENTRY (VNx4SI, true)
-ENTRY (VNx2SI, true)
-ENTRY (VNx1SI, true)
-
-ENTRY (VNx16SF, TARGET_VECTOR_FP32 && (TARGET_MIN_VLEN > 32))
-ENTRY (VNx8SF, TARGET_VECTOR_FP32)
-ENTRY (VNx4SF, TARGET_VECTOR_FP32)
-ENTRY (VNx2SF, TARGET_VECTOR_FP32)
-ENTRY (VNx1SF, TARGET_VECTOR_FP32)
+ENTRY (VNx16SI, TARGET_MIN_VLEN > 32, LMUL_8, 4, LMUL_RESERVED, 0)
+ENTRY (VNx8SI, true, LMUL_8, 4, LMUL_4, 8)
+ENTRY (VNx4SI, true, LMUL_4, 8, LMUL_2, 4)
+ENTRY (VNx2SI, true, LMUL_2, 16, LMUL_1, 2)
+ENTRY (VNx1SI, true, LMUL_1, 32, LMUL_F2, 1)
+
+ENTRY (VNx16SF, TARGET_VECTOR_FP32 && (TARGET_MIN_VLEN > 32), LMUL_8, 4,
+ LMUL_RESERVED, 0)
+ENTRY (VNx8SF, TARGET_VECTOR_FP32, LMUL_8, 4, LMUL_4, 8)
+ENTRY (VNx4SF, TARGET_VECTOR_FP32, LMUL_4, 8, LMUL_2, 4)
+ENTRY (VNx2SF, TARGET_VECTOR_FP32, LMUL_2, 16, LMUL_1, 2)
+ENTRY (VNx1SF, TARGET_VECTOR_FP32, LMUL_1, 32, LMUL_F2, 1)
/* SEW = 64. Enable when TARGET_MIN_VLEN > 32.
For double-precision floating-point, we need TARGET_VECTOR_FP64 ==
RVV_ENABLE. */
-ENTRY (VNx8DI, TARGET_MIN_VLEN > 32)
-ENTRY (VNx4DI, TARGET_MIN_VLEN > 32)
-ENTRY (VNx2DI, TARGET_MIN_VLEN > 32)
-ENTRY (VNx1DI, TARGET_MIN_VLEN > 32)
-
-ENTRY (VNx8DF, TARGET_VECTOR_FP64 && (TARGET_MIN_VLEN > 32))
-ENTRY (VNx4DF, TARGET_VECTOR_FP64)
-ENTRY (VNx2DF, TARGET_VECTOR_FP64)
-ENTRY (VNx1DF, TARGET_VECTOR_FP64)
+ENTRY (VNx8DI, TARGET_MIN_VLEN > 32, LMUL_RESERVED, 0, LMUL_8, 8)
+ENTRY (VNx4DI, TARGET_MIN_VLEN > 32, LMUL_RESERVED, 0, LMUL_4, 16)
+ENTRY (VNx2DI, TARGET_MIN_VLEN > 32, LMUL_RESERVED, 0, LMUL_2, 32)
+ENTRY (VNx1DI, TARGET_MIN_VLEN > 32, LMUL_RESERVED, 0, LMUL_1, 64)
+
+ENTRY (VNx8DF, TARGET_VECTOR_FP64 && (TARGET_MIN_VLEN > 32), LMUL_RESERVED, 0,
+ LMUL_8, 8)
+ENTRY (VNx4DF, TARGET_VECTOR_FP64, LMUL_RESERVED, 0, LMUL_4, 16)
+ENTRY (VNx2DF, TARGET_VECTOR_FP64, LMUL_RESERVED, 0, LMUL_2, 32)
+ENTRY (VNx1DF, TARGET_VECTOR_FP64, LMUL_RESERVED, 0, LMUL_1, 64)
#undef TARGET_VECTOR_FP32
#undef TARGET_VECTOR_FP64
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 05bdba5..1f85391 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -979,7 +979,7 @@ riscv_valid_lo_sum_p (enum riscv_symbol_type sym_type, machine_mode mode,
bool
riscv_v_ext_vector_mode_p (machine_mode mode)
{
-#define ENTRY(MODE, REQUIREMENT) \
+#define ENTRY(MODE, REQUIREMENT, ...) \
case MODE##mode: \
return REQUIREMENT;
switch (mode)
@@ -4229,6 +4229,19 @@ riscv_print_operand (FILE *file, rtx op, int letter)
switch (letter)
{
+ case 'v': {
+ rtx elt;
+
+ if (!const_vec_duplicate_p (op, &elt))
+ output_operand_lossage ("invalid vector constant");
+ else if (satisfies_constraint_Wc0 (op))
+ asm_fprintf (file, "0");
+ else if (satisfies_constraint_vi (op))
+ asm_fprintf (file, "%wd", INTVAL (elt));
+ else
+ output_operand_lossage ("invalid vector constant");
+ break;
+ }
case 'm': {
if (riscv_v_ext_vector_mode_p (mode))
{
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index b05c3c1..defb475 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -651,6 +651,9 @@ enum reg_class
#define FP_ARG_FIRST (FP_REG_FIRST + 10)
#define FP_ARG_LAST (FP_ARG_FIRST + MAX_ARGS_IN_REGISTERS - 1)
+/* Helper macro for RVV vsetvl instruction generation. */
+#define X0_REGNUM GP_REG_FIRST
+
#define CALLEE_SAVED_REG_NUMBER(REGNO) \
((REGNO) >= 8 && (REGNO) <= 9 ? (REGNO) - 8 : \
(REGNO) >= 18 && (REGNO) <= 27 ? (REGNO) - 16 : -1)
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 9d4a9dc..92c4bd0 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -71,6 +71,15 @@
(VNx1DF "VNx1BI") (VNx2DF "VNx2BI") (VNx4DF "VNx4BI") (VNx8DF "VNx8BI")
])
+(define_mode_attr VEL [
+ (VNx1QI "QI") (VNx2QI "QI") (VNx4QI "QI") (VNx8QI "QI") (VNx16QI "QI") (VNx32QI "QI") (VNx64QI "QI")
+ (VNx1HI "HI") (VNx2HI "HI") (VNx4HI "HI") (VNx8HI "HI") (VNx16HI "HI") (VNx32HI "HI")
+ (VNx1SI "SI") (VNx2SI "SI") (VNx4SI "SI") (VNx8SI "SI") (VNx16SI "SI")
+ (VNx1DI "DI") (VNx2DI "DI") (VNx4DI "DI") (VNx8DI "DI")
+ (VNx1SF "SF") (VNx2SF "SF") (VNx4SF "SF") (VNx8SF "SF") (VNx16SF "SF")
+ (VNx1DF "DF") (VNx2DF "DF") (VNx4DF "DF") (VNx8DF "DF")
+])
+
(define_mode_attr sew [
(VNx1QI "8") (VNx2QI "8") (VNx4QI "8") (VNx8QI "8") (VNx16QI "8") (VNx32QI "8") (VNx64QI "8")
(VNx1HI "16") (VNx2HI "16") (VNx4HI "16") (VNx8HI "16") (VNx16HI "16") (VNx32HI "16")
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index 01418ac..1b82218 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -34,6 +34,191 @@
UNSPEC_VPREDICATE
])
+(define_constants [
+ (INVALID_ATTRIBUTE 255)
+])
+
+;; True if the type is RVV instructions that include VTYPE
+;; global status register in the use op list.
+;; We known VTYPE has 4 fields: SEW, LMUL, TA, MA.
+;; The instruction need any of VTYPE field is set as true
+;; in this attribute.
+(define_attr "has_vtype_op" "false,true"
+ (cond [(eq_attr "type" "vlde,vste,vldm,vstm,vlds,vsts,\
+ vldux,vldox,vstux,vstox,vldff,\
+ vialu,viwalu,vext,vicalu,vshift,vnshift,vicmp,\
+ vimul,vidiv,viwmul,vimuladd,viwmuladd,vimerge,vimov,\
+ vsalu,vaalu,vsmul,vsshift,vnclip,\
+ vfalu,vfwalu,vfmul,vfdiv,vfwmul,vfmuladd,vfwmuladd,vfsqrt,vfrecp,\
+ vfcmp,vfsgnj,vfclass,vfmerge,vfmov,\
+ vfcvtitof,vfcvtftoi,vfwcvtitof,vfwcvtftoi,\
+ vfwcvtftof,vfncvtitof,vfncvtftoi,vfncvtftof,\
+ vired,viwred,vfred,vfredo,vfwred,vfwredo,\
+ vmalu,vmpop,vmffs,vmsfs,vmiota,vmidx,vimovvx,vimovxv,vfmovvf,vfmovfv,\
+ vislide,vislide1,vfslide1,vgather,vcompress")
+ (const_string "true")]
+ (const_string "false")))
+
+;; True if the type is RVV instructions that include VL
+;; global status register in the use op list.
+;; The instruction need vector length to be specified is set
+;; in this attribute.
+(define_attr "has_vl_op" "false,true"
+ (cond [(eq_attr "type" "vlde,vste,vldm,vstm,vlds,vsts,\
+ vldux,vldox,vstux,vstox,vldff,\
+ vialu,viwalu,vext,vicalu,vshift,vnshift,vicmp,\
+ vimul,vidiv,viwmul,vimuladd,viwmuladd,vimerge,vimov,\
+ vsalu,vaalu,vsmul,vsshift,vnclip,\
+ vfalu,vfwalu,vfmul,vfdiv,vfwmul,vfmuladd,vfwmuladd,vfsqrt,vfrecp,\
+ vfcmp,vfsgnj,vfclass,vfmerge,vfmov,\
+ vfcvtitof,vfcvtftoi,vfwcvtitof,vfwcvtftoi,\
+ vfwcvtftof,vfncvtitof,vfncvtftoi,vfncvtftof,\
+ vired,viwred,vfred,vfredo,vfwred,vfwredo,\
+ vmalu,vmpop,vmffs,vmsfs,vmiota,vmidx,vimovxv,vfmovfv,\
+ vislide,vislide1,vfslide1,vgather,vcompress")
+ (const_string "true")]
+ (const_string "false")))
+
+;; The default SEW of RVV instruction. This attribute doesn't mean the instruction
+;; is necessary to require SEW check for example vlm.v which require ratio to
+;; check. However, we need default value of SEW for vsetvl instruction since there
+;; is no field for ratio in the vsetvl instruction encoding.
+(define_attr "sew" ""
+ (cond [(eq_attr "mode" "VNx1QI,VNx2QI,VNx4QI,VNx8QI,VNx16QI,VNx32QI,VNx64QI,\
+ VNx1BI,VNx2BI,VNx4BI,VNx8BI,VNx16BI,VNx32BI,VNx64BI")
+ (const_int 8)
+ (eq_attr "mode" "VNx1HI,VNx2HI,VNx4HI,VNx8HI,VNx16HI,VNx32HI")
+ (const_int 16)
+ (eq_attr "mode" "VNx1SI,VNx2SI,VNx4SI,VNx8SI,VNx16SI,\
+ VNx1SF,VNx2SF,VNx4SF,VNx8SF,VNx16SF")
+ (const_int 32)
+ (eq_attr "mode" "VNx1DI,VNx2DI,VNx4DI,VNx8DI,\
+ VNx1DF,VNx2DF,VNx4DF,VNx8DF")
+ (const_int 64)]
+ (const_int INVALID_ATTRIBUTE)))
+
+;; Ditto to LMUL.
+(define_attr "vlmul" ""
+ (cond [(eq_attr "mode" "VNx1QI,VNx1BI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx1QImode)")
+ (eq_attr "mode" "VNx2QI,VNx2BI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx2QImode)")
+ (eq_attr "mode" "VNx4QI,VNx4BI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx4QImode)")
+ (eq_attr "mode" "VNx8QI,VNx8BI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx8QImode)")
+ (eq_attr "mode" "VNx16QI,VNx16BI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx16QImode)")
+ (eq_attr "mode" "VNx32QI,VNx32BI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx32QImode)")
+ (eq_attr "mode" "VNx64QI,VNx64BI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx64QImode)")
+ (eq_attr "mode" "VNx1HI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx1HImode)")
+ (eq_attr "mode" "VNx2HI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx2HImode)")
+ (eq_attr "mode" "VNx4HI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx4HImode)")
+ (eq_attr "mode" "VNx8HI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx8HImode)")
+ (eq_attr "mode" "VNx16HI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx16HImode)")
+ (eq_attr "mode" "VNx32HI")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx32HImode)")
+ (eq_attr "mode" "VNx1SI,VNx1SF")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx1SImode)")
+ (eq_attr "mode" "VNx2SI,VNx2SF")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx2SImode)")
+ (eq_attr "mode" "VNx4SI,VNx4SF")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx4SImode)")
+ (eq_attr "mode" "VNx8SI,VNx8SF")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx8SImode)")
+ (eq_attr "mode" "VNx16SI,VNx16SF")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx16SImode)")
+ (eq_attr "mode" "VNx1DI,VNx1DF")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx1DImode)")
+ (eq_attr "mode" "VNx2DI,VNx2DF")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx2DImode)")
+ (eq_attr "mode" "VNx4DI,VNx4DF")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx4DImode)")
+ (eq_attr "mode" "VNx8DI,VNx8DF")
+ (symbol_ref "riscv_vector::get_vlmul(E_VNx8DImode)")]
+ (const_int INVALID_ATTRIBUTE)))
+
+;; It is valid for instruction that require sew/lmul ratio.
+(define_attr "ratio" ""
+ (cond [(eq_attr "type" "vimov,vfmov")
+ (const_int INVALID_ATTRIBUTE)
+ (eq_attr "mode" "VNx1QI,VNx1BI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx1QImode)")
+ (eq_attr "mode" "VNx2QI,VNx2BI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx2QImode)")
+ (eq_attr "mode" "VNx4QI,VNx4BI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx4QImode)")
+ (eq_attr "mode" "VNx8QI,VNx8BI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx8QImode)")
+ (eq_attr "mode" "VNx16QI,VNx16BI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx16QImode)")
+ (eq_attr "mode" "VNx32QI,VNx32BI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx32QImode)")
+ (eq_attr "mode" "VNx64QI,VNx64BI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx64QImode)")
+ (eq_attr "mode" "VNx1HI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx1HImode)")
+ (eq_attr "mode" "VNx2HI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx2HImode)")
+ (eq_attr "mode" "VNx4HI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx4HImode)")
+ (eq_attr "mode" "VNx8HI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx8HImode)")
+ (eq_attr "mode" "VNx16HI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx16HImode)")
+ (eq_attr "mode" "VNx32HI")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx32HImode)")
+ (eq_attr "mode" "VNx1SI,VNx1SF")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx1SImode)")
+ (eq_attr "mode" "VNx2SI,VNx2SF")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx2SImode)")
+ (eq_attr "mode" "VNx4SI,VNx4SF")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx4SImode)")
+ (eq_attr "mode" "VNx8SI,VNx8SF")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx8SImode)")
+ (eq_attr "mode" "VNx16SI,VNx16SF")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx16SImode)")
+ (eq_attr "mode" "VNx1DI,VNx1DF")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx1DImode)")
+ (eq_attr "mode" "VNx2DI,VNx2DF")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx2DImode)")
+ (eq_attr "mode" "VNx4DI,VNx4DF")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx4DImode)")
+ (eq_attr "mode" "VNx8DI,VNx8DF")
+ (symbol_ref "riscv_vector::get_ratio(E_VNx8DImode)")]
+ (const_int INVALID_ATTRIBUTE)))
+
+;; The index of operand[] to get the merge op.
+(define_attr "merge_op_idx" ""
+ (cond [(eq_attr "type" "vlde,vste,vimov,vfmov,vldm,vstm,vlds,vmalu")
+ (const_int 2)]
+ (const_int INVALID_ATTRIBUTE)))
+
+;; The index of operand[] to get the avl op.
+(define_attr "vl_op_idx" ""
+ (cond [(eq_attr "type" "vlde,vste,vimov,vfmov,vldm,vstm,vlds,vmalu")
+ (const_int 4)]
+ (const_int INVALID_ATTRIBUTE)))
+
+;; The index of operand[] to get the tail policy op.
+(define_attr "tail_policy_op_idx" ""
+ (cond [(eq_attr "type" "vlde,vste,vimov,vfmov,vlds")
+ (const_int 5)]
+ (const_int INVALID_ATTRIBUTE)))
+
+;; The index of operand[] to get the mask policy op.
+(define_attr "mask_policy_op_idx" ""
+ (cond [(eq_attr "type" "vlde,vste,vlds")
+ (const_int 6)]
+ (const_int INVALID_ATTRIBUTE)))
+
;; -----------------------------------------------------------------
;; ---- Miscellaneous Operations
;; -----------------------------------------------------------------
@@ -152,6 +337,26 @@
(set_attr "mode" "<MODE>")])
;; -----------------------------------------------------------------
+;; ---- Duplicate Operations
+;; -----------------------------------------------------------------
+
+;; According to GCC internal:
+;; This pattern only handles duplicates of non-constant inputs.
+;; Constant vectors go through the movm pattern instead.
+;; So "direct_broadcast_operand" can only be mem or reg, no CONSTANT.
+(define_expand "vec_duplicate<mode>"
+ [(set (match_operand:V 0 "register_operand")
+ (vec_duplicate:V
+ (match_operand:<VEL> 1 "direct_broadcast_operand")))]
+ "TARGET_VECTOR"
+ {
+ riscv_vector::emit_pred_op (
+ code_for_pred_broadcast (<MODE>mode), operands[0], operands[1], <VM>mode);
+ DONE;
+ }
+)
+
+;; -----------------------------------------------------------------
;; ---- 6. Configuration-Setting Instructions
;; -----------------------------------------------------------------
;; Includes:
@@ -368,7 +573,7 @@
vle<sew>.v\t%0,%3%p1
vse<sew>.v\t%3,%0%p1
vmv.v.v\t%0,%3
- vmv.v.i\t%0,v%3"
+ vmv.v.i\t%0,%v3"
"&& register_operand (operands[0], <MODE>mode)
&& register_operand (operands[3], <MODE>mode)
&& satisfies_constraint_vu (operands[2])"
@@ -388,8 +593,6 @@
(unspec:VB
[(match_operand:VB 1 "vector_mask_operand" "Wc1, Wc1, Wc1, Wc1, Wc1")
(match_operand 4 "vector_length_operand" " rK, rK, rK, rK, rK")
- (match_operand 5 "const_int_operand" " i, i, i, i, i")
- (match_operand 6 "const_int_operand" " i, i, i, i, i")
(reg:SI VL_REGNUM)
(reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
(match_operand:VB 3 "vector_move_operand" " m, vr, vr, Wc0, Wc1")
@@ -407,3 +610,34 @@
""
[(set_attr "type" "vldm,vstm,vimov,vmalu,vmalu")
(set_attr "mode" "<MODE>")])
+
+;; -------------------------------------------------------------------------------
+;; ---- Predicated Broadcast
+;; -------------------------------------------------------------------------------
+;; Includes:
+;; - 7.5. Vector Strided Instructions (zero stride)
+;; - 11.16 Vector Integer Move Instructions (vmv.v.x)
+;; - 13.16 Vector Floating-Point Move Instruction (vfmv.v.f)
+;; -------------------------------------------------------------------------------
+
+(define_insn "@pred_broadcast<mode>"
+ [(set (match_operand:V 0 "register_operand" "=vr, vr, vr, vr")
+ (if_then_else:V
+ (unspec:<VM>
+ [(match_operand:<VM> 1 "vector_mask_operand" " Wc1, Wc1, vm, Wc1")
+ (match_operand 4 "vector_length_operand" " rK, rK, rK, rK")
+ (match_operand 5 "const_int_operand" " i, i, i, i")
+ (match_operand 6 "const_int_operand" " i, i, i, i")
+ (reg:SI VL_REGNUM)
+ (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
+ (vec_duplicate:V
+ (match_operand:<VEL> 3 "direct_broadcast_operand" " r, f, Wdm, Wdm"))
+ (match_operand:V 2 "vector_merge_operand" "vu0, vu0, vu0, vu0")))]
+ "TARGET_VECTOR"
+ "@
+ vmv.v.x\t%0,%3
+ vfmv.v.f\t%0,%3
+ vlse<sew>.v\t%0,%3,zero,%1.t
+ vlse<sew>.v\t%0,%3,zero"
+ [(set_attr "type" "vimov,vfmov,vlds,vlds")
+ (set_attr "mode" "<MODE>")])
diff --git a/gcc/config/rs6000/rs6000-call.cc b/gcc/config/rs6000/rs6000-call.cc
index 6da4de6..59c51fa 100644
--- a/gcc/config/rs6000/rs6000-call.cc
+++ b/gcc/config/rs6000/rs6000-call.cc
@@ -2802,6 +2802,10 @@ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
return build_va_arg_indirect_ref (addr);
}
+/* Return the permutation index for the swapping on the given vector mode.
+ Note that the permutation index is correspondingly generated by endianness,
+ it should be used by direct vector permutation. */
+
rtx
swap_endian_selector_for_mode (machine_mode mode)
{
@@ -2834,7 +2838,11 @@ swap_endian_selector_for_mode (machine_mode mode)
}
for (i = 0; i < 16; ++i)
- perm[i] = GEN_INT (swaparray[i]);
+ if (BYTES_BIG_ENDIAN)
+ perm[i] = GEN_INT (swaparray[i]);
+ else
+ /* Generates the reversed perm for little endian. */
+ perm[i] = GEN_INT (~swaparray[i] & 0x0000001f);
return force_reg (V16QImode, gen_rtx_CONST_VECTOR (V16QImode,
gen_rtvec_v (16, perm)));
diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md
index fb5cf04..992fbc9 100644
--- a/gcc/config/rs6000/vsx.md
+++ b/gcc/config/rs6000/vsx.md
@@ -6099,8 +6099,8 @@
to the endian mode in use, i.e. in LE mode, put elements
in BE order. */
rtx sel = swap_endian_selector_for_mode (<MODE>mode);
- emit_insn (gen_altivec_vperm_<mode> (operands[0], operands[1],
- operands[1], sel));
+ emit_insn (gen_altivec_vperm_<mode>_direct (operands[0], operands[1],
+ operands[1], sel));
}
}
diff --git a/gcc/configure b/gcc/configure
index fc0bf70..6af7dbd 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -805,17 +805,6 @@ am__leading_dot
doc_build_sys
AR
NM
-HAVE_PYTHON_FALSE
-HAVE_PYTHON_TRUE
-pkgpyexecdir
-pyexecdir
-pkgpythondir
-pythondir
-PYTHON_PLATFORM
-PYTHON_EXEC_PREFIX
-PYTHON_PREFIX
-PYTHON_VERSION
-PYTHON
BISON
FLEX
GENERATED_MANPAGES
@@ -925,7 +914,6 @@ infodir
docdir
oldincludedir
includedir
-runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -1058,7 +1046,6 @@ CXXFLAGS
CCC
CXXCPP
CPP
-PYTHON
GMPLIBS
GMPINC
ISLLIBS
@@ -1101,7 +1088,6 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
-runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}'
@@ -1354,15 +1340,6 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
- -runstatedir | --runstatedir | --runstatedi | --runstated \
- | --runstate | --runstat | --runsta | --runst | --runs \
- | --run | --ru | --r)
- ac_prev=runstatedir ;;
- -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
- | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
- | --run=* | --ru=* | --r=*)
- runstatedir=$ac_optarg ;;
-
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1500,7 +1477,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir runstatedir
+ libdir localedir mandir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1653,7 +1630,6 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
- --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -1847,7 +1823,8 @@ Optional Packages:
--with-stack-clash-protection-guard-size=size
Set the default stack clash protection guard size
for specific targets as a power of two in bytes.
- --with-dwarf2 force the default debug format to be DWARF 2
+ --with-dwarf2 force the default debug format to be DWARF 2 (or
+ later)
--with-specs=SPECS add SPECS to driver command-line processing
--with-pkgversion=PKG Use PKG in the version string in place of "GCC"
--with-bugurl=URL Direct users to URL to report a bug
@@ -1910,7 +1887,6 @@ Some influential environment variables:
CXXFLAGS C++ compiler flags
CXXCPP C++ preprocessor
CPP C preprocessor
- PYTHON the Python interpreter
GMPLIBS How to link GMP
GMPINC How to find GMP include files
ISLLIBS How to link isl
@@ -6179,7 +6155,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -6225,7 +6201,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -6249,7 +6225,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -6294,7 +6270,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -6318,7 +6294,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1)
? 1 : -1];
@@ -8923,223 +8899,6 @@ done
test -n "$BISON" || BISON="$MISSING bison"
-# Python3?
-
-
-
-
-
-
- # Find any Python interpreter.
- if test -z "$PYTHON"; then
- for ac_prog in python python2 python3 python3.5 python3.4 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PYTHON+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- case $PYTHON in
- [\\/]* | ?:[\\/]*)
- ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path.
- ;;
- *)
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
- ;;
-esac
-fi
-PYTHON=$ac_cv_path_PYTHON
-if test -n "$PYTHON"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5
-$as_echo "$PYTHON" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- test -n "$PYTHON" && break
-done
-test -n "$PYTHON" || PYTHON=":"
-
- fi
- am_display_PYTHON=python
-
-
- if test "$PYTHON" = :; then
- :
- else
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON version" >&5
-$as_echo_n "checking for $am_display_PYTHON version... " >&6; }
-if ${am_cv_python_version+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[:3])"`
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5
-$as_echo "$am_cv_python_version" >&6; }
- PYTHON_VERSION=$am_cv_python_version
-
-
-
- PYTHON_PREFIX='${prefix}'
-
- PYTHON_EXEC_PREFIX='${exec_prefix}'
-
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON platform" >&5
-$as_echo_n "checking for $am_display_PYTHON platform... " >&6; }
-if ${am_cv_python_platform+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5
-$as_echo "$am_cv_python_platform" >&6; }
- PYTHON_PLATFORM=$am_cv_python_platform
-
-
- # Just factor out some code duplication.
- am_python_setup_sysconfig="\
-import sys
-# Prefer sysconfig over distutils.sysconfig, for better compatibility
-# with python 3.x. See automake bug#10227.
-try:
- import sysconfig
-except ImportError:
- can_use_sysconfig = 0
-else:
- can_use_sysconfig = 1
-# Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs:
-# <https://github.com/pypa/virtualenv/issues/118>
-try:
- from platform import python_implementation
- if python_implementation() == 'CPython' and sys.version[:3] == '2.7':
- can_use_sysconfig = 0
-except ImportError:
- pass"
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory" >&5
-$as_echo_n "checking for $am_display_PYTHON script directory... " >&6; }
-if ${am_cv_python_pythondir+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test "x$prefix" = xNONE
- then
- am_py_prefix=$ac_default_prefix
- else
- am_py_prefix=$prefix
- fi
- am_cv_python_pythondir=`$PYTHON -c "
-$am_python_setup_sysconfig
-if can_use_sysconfig:
- sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'})
-else:
- from distutils import sysconfig
- sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix')
-sys.stdout.write(sitedir)"`
- case $am_cv_python_pythondir in
- $am_py_prefix*)
- am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'`
- am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"`
- ;;
- *)
- case $am_py_prefix in
- /usr|/System*) ;;
- *)
- am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages
- ;;
- esac
- ;;
- esac
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5
-$as_echo "$am_cv_python_pythondir" >&6; }
- pythondir=$am_cv_python_pythondir
-
-
-
- pkgpythondir=\${pythondir}/$PACKAGE
-
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory" >&5
-$as_echo_n "checking for $am_display_PYTHON extension module directory... " >&6; }
-if ${am_cv_python_pyexecdir+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test "x$exec_prefix" = xNONE
- then
- am_py_exec_prefix=$am_py_prefix
- else
- am_py_exec_prefix=$exec_prefix
- fi
- am_cv_python_pyexecdir=`$PYTHON -c "
-$am_python_setup_sysconfig
-if can_use_sysconfig:
- sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'})
-else:
- from distutils import sysconfig
- sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix')
-sys.stdout.write(sitedir)"`
- case $am_cv_python_pyexecdir in
- $am_py_exec_prefix*)
- am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'`
- am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"`
- ;;
- *)
- case $am_py_exec_prefix in
- /usr|/System*) ;;
- *)
- am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages
- ;;
- esac
- ;;
- esac
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5
-$as_echo "$am_cv_python_pyexecdir" >&6; }
- pyexecdir=$am_cv_python_pyexecdir
-
-
-
- pkgpyexecdir=\${pyexecdir}/$PACKAGE
-
-
-
- fi
-
-
- if test "$PYTHON" != :; then
- HAVE_PYTHON_TRUE=
- HAVE_PYTHON_FALSE='#'
-else
- HAVE_PYTHON_TRUE='#'
- HAVE_PYTHON_FALSE=
-fi
-
-
# Binutils are not build modules, unlike bison/flex/makeinfo. So we
# check for build == host before using them.
@@ -19953,7 +19712,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 19956 "configure"
+#line 19715 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -20059,7 +19818,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 20062 "configure"
+#line 19821 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -32862,10 +32621,6 @@ LIBOBJS=$ac_libobjs
LTLIBOBJS=$ac_ltlibobjs
-if test -z "${HAVE_PYTHON_TRUE}" && test -z "${HAVE_PYTHON_FALSE}"; then
- as_fn_error $? "conditional \"HAVE_PYTHON\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
: "${CONFIG_STATUS=./config.status}"
@@ -34154,3 +33909,4 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
fi
+
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 073bf31..709bf56 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -1023,7 +1023,7 @@ fi,
objc_boehm_gc='')
AC_ARG_WITH(dwarf2,
-[AS_HELP_STRING([--with-dwarf2], [force the default debug format to be DWARF 2])],
+[AS_HELP_STRING([--with-dwarf2], [force the default debug format to be DWARF 2 (or later)])],
dwarf2="$with_dwarf2",
dwarf2=no)
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 02274f6..55b290e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,87 @@
+2022-12-05 Scott Snyder <sss@li-snyder.org>
+
+ PR plugins/107964
+ * Make-lang.in (CP_PLUGIN_HEADERS): Install contracts.h
+
+2022-12-04 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/107417
+ * pt.cc (for_each_template_parm_r) <case REQUIRES_EXPR>: Move
+ walking of the TREE_TYPE of each parameter to ...
+ * tree.cc (cp_walk_subtrees) <case REQUIRES_EXPR>: ... here.
+
+2022-12-04 Iain Sandoe <iain@sandoe.co.uk>
+ Adrian Perl <adrian.perl@web.de>
+
+ PR c++/100611
+ PR c++/101367
+ PR c++/101976
+ PR c++/99576
+ * coroutines.cc (find_interesting_subtree): Do not promote temporaries
+ that are only used as direct initializers for some other object.
+
+2022-12-03 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/103081
+ * pt.cc (tsubst_copy) <case CONST_DECL>: Generalize
+ early exit test for namespace-scope decls to check dependence of
+ the enclosing scope instead. Remove dead early exit test.
+
+2022-12-02 Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
+ Jason Merrill <jason@redhat.com>
+
+ * decl.cc (grokdeclarator): Build RESULT_DECL.
+ (start_preparsed_function): Copy location from template.
+ * semantics.cc (apply_deduced_return_type): Handle
+ arg != current_function_decl.
+ * method.cc (implicitly_declare_fn): Use it.
+
+2022-12-02 Jason Merrill <jason@redhat.com>
+
+ * g++spec.cc (lang_specific_driver): Set SKIPOPT for nostdlib++.
+
+2022-12-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/84469
+ * parser.cc (cp_convert_omp_range_for): After do_auto_deduction if
+ !processing_template_decl call cp_finish_decomp with
+ processing_template_decl temporarily incremented.
+
+2022-12-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/84469
+ * parser.cc (do_range_for_auto_deduction): Add DECOMP_FIRST_NAME
+ and DECOMP_CNT arguments. Call cp_finish_decomp if DECL
+ is a structured binding.
+ (cp_parser_range_for): Adjust do_range_for_auto_deduction caller.
+ (cp_convert_omp_range_for): Likewise.
+
+2022-12-02 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/107539
+ * constraint.cc (norm_hasher::hash, norm_hasher::equal): Set
+ comparing_specializations.
+ (sat_hasher::hash, sat_hasher::equal): Likewise.
+ * cp-tree.h (atom_hasher::hash, atom_hasher::equal): Likewise.
+ * pt.cc (ctp_hasher::hash, ctp_hasher::equal): Likewise.
+
+2022-12-01 Martin Liska <mliska@suse.cz>
+
+ * Make-lang.in: Remove extra object dependency.
+
+2022-12-01 Jason Merrill <jason@redhat.com>
+
+ * contracts.cc (remove_contract_attributes): Actually prepend
+ to the list.
+ * pt.cc (tsubst_contract): Only look for a postcondition if type is
+ nonnull.
+
+2022-11-30 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/107542
+ * typeck.cc (cp_build_binary_op): In the SPACESHIP_EXPR case,
+ handle an error_mark_node result type.
+
2022-11-29 Patrick Palka <ppalka@redhat.com>
PR c++/107864
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index af25bdc..b313196 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -39,7 +39,7 @@ CXX_INSTALL_NAME := $(shell echo c++|sed '$(program_transform_name)')
GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
CXX_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo c++|sed '$(program_transform_name)')
GXX_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo g++|sed '$(program_transform_name)')
-CP_PLUGIN_HEADERS := cp-tree.h cxx-pretty-print.h name-lookup.h type-utils.h operators.def cp-trait.def
+CP_PLUGIN_HEADERS := cp-tree.h cxx-pretty-print.h name-lookup.h type-utils.h operators.def cp-trait.def contracts.h
#
# Define the names for selecting c++ in LANGUAGES.
@@ -81,7 +81,7 @@ g++-cross$(exeext): xg++$(exeext)
# The compiler itself.
# Shared with C front end:
-CXX_C_OBJS = attribs.o incpath.o \
+CXX_C_OBJS = attribs.o \
$(C_COMMON_OBJS) $(CXX_TARGET_OBJS)
# Language-specific object files for C++ and Objective C++.
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index ab0f66b..37eae03 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -715,14 +715,20 @@ struct norm_hasher : ggc_ptr_hash<norm_entry>
{
static hashval_t hash (norm_entry *e)
{
- hashval_t hash = iterative_hash_template_arg (e->tmpl, 0);
- return iterative_hash_template_arg (e->args, hash);
+ ++comparing_specializations;
+ hashval_t val = iterative_hash_template_arg (e->tmpl, 0);
+ val = iterative_hash_template_arg (e->args, val);
+ --comparing_specializations;
+ return val;
}
static bool equal (norm_entry *e1, norm_entry *e2)
{
- return e1->tmpl == e2->tmpl
+ ++comparing_specializations;
+ bool eq = e1->tmpl == e2->tmpl
&& template_args_equal (e1->args, e2->args);
+ --comparing_specializations;
+ return eq;
}
};
@@ -2530,6 +2536,9 @@ struct sat_hasher : ggc_ptr_hash<sat_entry>
{
static hashval_t hash (sat_entry *e)
{
+ auto cso = make_temp_override (comparing_specializations);
+ ++comparing_specializations;
+
if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (e->atom))
{
/* Atoms with instantiated mappings are built during satisfaction.
@@ -2564,6 +2573,9 @@ struct sat_hasher : ggc_ptr_hash<sat_entry>
static bool equal (sat_entry *e1, sat_entry *e2)
{
+ auto cso = make_temp_override (comparing_specializations);
+ ++comparing_specializations;
+
if (ATOMIC_CONSTR_MAP_INSTANTIATED_P (e1->atom)
!= ATOMIC_CONSTR_MAP_INSTANTIATED_P (e2->atom))
return false;
diff --git a/gcc/cp/contracts.cc b/gcc/cp/contracts.cc
index a909701..45f52b2 100644
--- a/gcc/cp/contracts.cc
+++ b/gcc/cp/contracts.cc
@@ -869,7 +869,7 @@ remove_contract_attributes (tree fndecl)
tree list = NULL_TREE;
for (tree p = DECL_ATTRIBUTES (fndecl); p; p = TREE_CHAIN (p))
if (!cxx_contract_attribute_p (p))
- list = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p), NULL_TREE);
+ list = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p), list);
DECL_ATTRIBUTES (fndecl) = nreverse (list);
}
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 01a3e83..3f23317 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -2685,6 +2685,7 @@ find_interesting_subtree (tree *expr_p, int *dosub, void *d)
}
}
else if (tmp_target_expr_p (expr)
+ && !TARGET_EXPR_ELIDING_P (expr)
&& !p->temps_used->contains (expr))
{
p->entry = expr_p;
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 548b533..addd26e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -8418,12 +8418,18 @@ struct atom_hasher : default_hash_traits<tree>
{
static hashval_t hash (tree t)
{
- return hash_atomic_constraint (t);
+ ++comparing_specializations;
+ hashval_t val = hash_atomic_constraint (t);
+ --comparing_specializations;
+ return val;
}
static bool equal (tree t1, tree t2)
{
- return atomic_constraints_identical_p (t1, t2);
+ ++comparing_specializations;
+ bool eq = atomic_constraints_identical_p (t1, t2);
+ --comparing_specializations;
+ return eq;
}
};
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 238e72f..5081563 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -14772,6 +14772,19 @@ grokdeclarator (const cp_declarator *declarator,
else if (constinit_p)
DECL_DECLARED_CONSTINIT_P (decl) = true;
}
+ else if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ /* If we saw a return type, record its location. */
+ location_t loc = declspecs->locations[ds_type_spec];
+ if (loc != UNKNOWN_LOCATION)
+ {
+ tree restype = TREE_TYPE (TREE_TYPE (decl));
+ tree resdecl = build_decl (loc, RESULT_DECL, 0, restype);
+ DECL_ARTIFICIAL (resdecl) = 1;
+ DECL_IGNORED_P (resdecl) = 1;
+ DECL_RESULT (decl) = resdecl;
+ }
+ }
/* Record constancy and volatility on the DECL itself . There's
no need to do this when processing a template; we'll do this
@@ -17326,9 +17339,17 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
if (DECL_RESULT (decl1) == NULL_TREE)
{
- tree resdecl;
+ /* In a template instantiation, copy the return type location. When
+ parsing, the location will be set in grokdeclarator. */
+ location_t loc = input_location;
+ if (DECL_TEMPLATE_INSTANTIATION (decl1))
+ {
+ tree tmpl = template_for_substitution (decl1);
+ if (tree res = DECL_RESULT (DECL_TEMPLATE_RESULT (tmpl)))
+ loc = DECL_SOURCE_LOCATION (res);
+ }
- resdecl = build_decl (input_location, RESULT_DECL, 0, restype);
+ tree resdecl = build_decl (loc, RESULT_DECL, 0, restype);
DECL_ARTIFICIAL (resdecl) = 1;
DECL_IGNORED_P (resdecl) = 1;
DECL_RESULT (decl1) = resdecl;
diff --git a/gcc/cp/g++spec.cc b/gcc/cp/g++spec.cc
index e599ac9..3d3b042 100644
--- a/gcc/cp/g++spec.cc
+++ b/gcc/cp/g++spec.cc
@@ -167,8 +167,10 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
need_experimental = true;
break;
- case OPT_nostdlib:
case OPT_nostdlib__:
+ args[i] |= SKIPOPT;
+ /* FALLTHRU */
+ case OPT_nostdlib:
case OPT_nodefaultlibs:
library = -1;
break;
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 1e962b6..7b4d5a5 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -3079,7 +3079,7 @@ implicitly_declare_fn (special_function_kind kind, tree type,
{
fn = copy_operator_fn (pattern_fn, EQ_EXPR);
DECL_ARTIFICIAL (fn) = 1;
- TREE_TYPE (fn) = change_return_type (boolean_type_node, TREE_TYPE (fn));
+ apply_deduced_return_type (fn, boolean_type_node);
return fn;
}
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index a13fbe4..e8a5090 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2342,7 +2342,7 @@ static tree cp_parser_c_for
static tree cp_parser_range_for
(cp_parser *, tree, tree, tree, bool, unsigned short, bool);
static void do_range_for_auto_deduction
- (tree, tree);
+ (tree, tree, tree, unsigned int);
static tree cp_parser_perform_range_for_lookup
(tree, tree *, tree *);
static tree cp_parser_range_for_member_function
@@ -13668,7 +13668,8 @@ cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
if (!type_dependent_expression_p (range_expr)
/* do_auto_deduction doesn't mess with template init-lists. */
&& !BRACE_ENCLOSED_INITIALIZER_P (range_expr))
- do_range_for_auto_deduction (range_decl, range_expr);
+ do_range_for_auto_deduction (range_decl, range_expr, decomp_first_name,
+ decomp_cnt);
}
else
{
@@ -13707,7 +13708,8 @@ build_range_temp (tree range_expr)
a shortcut version of cp_convert_range_for. */
static void
-do_range_for_auto_deduction (tree decl, tree range_expr)
+do_range_for_auto_deduction (tree decl, tree range_expr,
+ tree decomp_first_name, unsigned int decomp_cnt)
{
tree auto_node = type_uses_auto (TREE_TYPE (decl));
if (auto_node)
@@ -13727,6 +13729,8 @@ do_range_for_auto_deduction (tree decl, tree range_expr)
iter_decl, auto_node,
tf_warning_or_error,
adc_variable_type);
+ if (VAR_P (decl) && DECL_DECOMPOSITION_P (decl))
+ cp_finish_decomp (decl, decomp_first_name, decomp_cnt);
}
}
}
@@ -42994,15 +42998,21 @@ cp_convert_omp_range_for (tree &this_pre_body, vec<tree, va_gc> *for_block,
&& !BRACE_ENCLOSED_INITIALIZER_P (init))
{
tree d = decl;
+ tree decomp_first_name = NULL_TREE;
+ unsigned decomp_cnt = 0;
if (decl != error_mark_node && DECL_HAS_VALUE_EXPR_P (decl))
{
tree v = DECL_VALUE_EXPR (decl);
if (TREE_CODE (v) == ARRAY_REF
&& VAR_P (TREE_OPERAND (v, 0))
&& DECL_DECOMPOSITION_P (TREE_OPERAND (v, 0)))
- d = TREE_OPERAND (v, 0);
+ {
+ d = TREE_OPERAND (v, 0);
+ decomp_cnt = tree_to_uhwi (TREE_OPERAND (v, 1)) + 1;
+ decomp_first_name = decl;
+ }
}
- do_range_for_auto_deduction (d, init);
+ do_range_for_auto_deduction (d, init, decomp_first_name, decomp_cnt);
}
cond = global_namespace;
incr = NULL_TREE;
@@ -43116,8 +43126,16 @@ cp_convert_omp_range_for (tree &this_pre_body, vec<tree, va_gc> *for_block,
tree t = build_x_indirect_ref (input_location, begin, RO_UNARY_STAR,
NULL_TREE, tf_none);
if (!error_operand_p (t))
- TREE_TYPE (orig_decl) = do_auto_deduction (TREE_TYPE (orig_decl),
- t, auto_node);
+ {
+ TREE_TYPE (orig_decl) = do_auto_deduction (TREE_TYPE (orig_decl),
+ t, auto_node);
+ if (decomp_first_name)
+ {
+ ++processing_template_decl;
+ cp_finish_decomp (orig_decl, decomp_first_name, decomp_cnt);
+ --processing_template_decl;
+ }
+ }
}
tree v = make_tree_vec (decomp_cnt + 3);
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 2d8e4fd..80110da 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -4492,18 +4492,23 @@ struct ctp_hasher : ggc_ptr_hash<tree_node>
{
static hashval_t hash (tree t)
{
+ ++comparing_specializations;
tree_code code = TREE_CODE (t);
hashval_t val = iterative_hash_object (code, 0);
val = iterative_hash_object (TEMPLATE_TYPE_LEVEL (t), val);
val = iterative_hash_object (TEMPLATE_TYPE_IDX (t), val);
if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
val = iterative_hash_template_arg (TYPE_TI_ARGS (t), val);
+ --comparing_specializations;
return val;
}
static bool equal (tree t, tree u)
{
- return comptypes (t, u, COMPARE_STRUCTURAL);
+ ++comparing_specializations;
+ bool eq = comptypes (t, u, COMPARE_STRUCTURAL);
+ --comparing_specializations;
+ return eq;
}
};
@@ -10568,21 +10573,6 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d)
return error_mark_node;
break;
- case REQUIRES_EXPR:
- {
- if (!fn)
- return error_mark_node;
-
- /* Recursively walk the type of each constraint variable. */
- tree p = TREE_OPERAND (t, 0);
- while (p)
- {
- WALK_SUBTREE (TREE_TYPE (p));
- p = TREE_CHAIN (p);
- }
- }
- break;
-
default:
break;
}
@@ -11561,7 +11551,7 @@ tsubst_contract (tree decl, tree t, tree args, tsubst_flags_t complain,
tree r = copy_node (t);
/* Rebuild the result variable. */
- if (POSTCONDITION_P (t) && POSTCONDITION_IDENTIFIER (t))
+ if (type && POSTCONDITION_P (t) && POSTCONDITION_IDENTIFIER (t))
{
tree oldvar = POSTCONDITION_IDENTIFIER (t);
@@ -17061,13 +17051,8 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (DECL_TEMPLATE_PARM_P (t))
return tsubst_copy (DECL_INITIAL (t), args, complain, in_decl);
- /* There is no need to substitute into namespace-scope
- enumerators. */
- if (DECL_NAMESPACE_SCOPE_P (t))
+ if (!uses_template_parms (DECL_CONTEXT (t)))
return t;
- /* If ARGS is NULL, then T is known to be non-dependent. */
- if (args == NULL_TREE)
- return scalar_constant_value (t);
/* Unfortunately, we cannot just call lookup_name here.
Consider:
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 9401b35..ab52e56 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12325,24 +12325,23 @@ apply_deduced_return_type (tree fco, tree return_type)
/* We already have a DECL_RESULT from start_preparsed_function.
Now we need to redo the work it and allocate_struct_function
did to reflect the new type. */
- gcc_assert (current_function_decl == fco);
- result = build_decl (input_location, RESULT_DECL, NULL_TREE,
+ result = build_decl (DECL_SOURCE_LOCATION (result), RESULT_DECL, NULL_TREE,
TYPE_MAIN_VARIANT (return_type));
DECL_ARTIFICIAL (result) = 1;
DECL_IGNORED_P (result) = 1;
cp_apply_type_quals_to_decl (cp_type_quals (return_type),
result);
-
DECL_RESULT (fco) = result;
if (!processing_template_decl)
- {
- bool aggr = aggregate_value_p (result, fco);
+ if (function *fun = DECL_STRUCT_FUNCTION (fco))
+ {
+ bool aggr = aggregate_value_p (result, fco);
#ifdef PCC_STATIC_STRUCT_RETURN
- cfun->returns_pcc_struct = aggr;
+ fun->returns_pcc_struct = aggr;
#endif
- cfun->returns_struct = aggr;
- }
+ fun->returns_struct = aggr;
+ }
}
/* DECL is a local variable or parameter from the surrounding scope of a
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 04a055d..33bde16 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -5603,15 +5603,18 @@ cp_walk_subtrees (tree *tp, int *walk_subtrees_p, walk_tree_fn func,
break;
case REQUIRES_EXPR:
- // Only recurse through the nested expression. Do not
- // walk the parameter list. Doing so causes false
- // positives in the pack expansion checker since the
- // requires parameters are introduced as pack expansions.
- ++cp_unevaluated_operand;
- result = cp_walk_tree (&REQUIRES_EXPR_REQS (*tp), func, data, pset);
- --cp_unevaluated_operand;
- *walk_subtrees_p = 0;
- break;
+ {
+ cp_unevaluated u;
+ for (tree parm = REQUIRES_EXPR_PARMS (*tp); parm; parm = DECL_CHAIN (parm))
+ /* Walk the types of each parameter, but not the parameter itself,
+ since doing so would cause false positives in the unexpanded pack
+ checker if the requires-expr introduces a function parameter pack,
+ e.g. requires (Ts... ts) { }. */
+ WALK_SUBTREE (TREE_TYPE (parm));
+ WALK_SUBTREE (REQUIRES_EXPR_REQS (*tp));
+ *walk_subtrees_p = 0;
+ break;
+ }
case DECL_EXPR:
/* User variables should be mentioned in BIND_EXPR_VARS
diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog
index 6691a43..74346ea 100644
--- a/gcc/d/ChangeLog
+++ b/gcc/d/ChangeLog
@@ -1,3 +1,31 @@
+2022-11-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_TEXI_FILES): Add d/implement-d.texi.
+ * gdc.texi: Adjust introduction, include implement-d.texi.
+ * implement-d.texi: New file.
+
+2022-11-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in: Only include doc/include when building documentation.
+ (d.html): Rename html directory to $(build_htmldir)/gdc.
+
+2022-11-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * gdc.texi: Separate indices into options and keywords.
+
+2022-11-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * gdc.texi: Update gdc option documentation.
+ * lang.opt (frevert=intpromote): Correct documentation.
+
+2022-11-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/107592
+ * toir.cc (IRVisitor::push_unrolled_continue_label): New method.
+ (IRVisitor::pop_unrolled_continue_label): New method.
+ (IRVisitor::visit (UnrolledLoopStatement *)): Use them instead of
+ push_continue_label and pop_continue_label.
+
2022-11-23 Martin Liska <mliska@suse.cz>
* Make-lang.in: Use it as $DO_LINK_MUTEX.
diff --git a/gcc/diagnostic-path.h b/gcc/diagnostic-path.h
index 8ce4ff7..aa5cda8 100644
--- a/gcc/diagnostic-path.h
+++ b/gcc/diagnostic-path.h
@@ -167,6 +167,9 @@ class diagnostic_path
virtual const diagnostic_event & get_event (int idx) const = 0;
bool interprocedural_p () const;
+
+private:
+ bool get_first_event_in_a_function (unsigned *out_idx) const;
};
/* Concrete subclasses. */
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index a9562a8..322515b 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -939,18 +939,49 @@ diagnostic_event::meaning::maybe_get_property_str (enum property p)
/* class diagnostic_path. */
+/* Subroutint of diagnostic_path::interprocedural_p.
+ Look for the first event in this path that is within a function
+ i.e. has a non-NULL fndecl, and a non-zero stack depth.
+ If found, write its index to *OUT_IDX and return true.
+ Otherwise return false. */
+
+bool
+diagnostic_path::get_first_event_in_a_function (unsigned *out_idx) const
+{
+ const unsigned num = num_events ();
+ for (unsigned i = 0; i < num; i++)
+ {
+ if (!(get_event (i).get_fndecl () == NULL
+ && get_event (i).get_stack_depth () == 0))
+ {
+ *out_idx = i;
+ return true;
+ }
+ }
+ return false;
+}
+
/* Return true if the events in this path involve more than one
function, or false if it is purely intraprocedural. */
bool
diagnostic_path::interprocedural_p () const
{
+ /* Ignore leading events that are outside of any function. */
+ unsigned first_fn_event_idx;
+ if (!get_first_event_in_a_function (&first_fn_event_idx))
+ return false;
+
+ const diagnostic_event &first_fn_event = get_event (first_fn_event_idx);
+ tree first_fndecl = first_fn_event.get_fndecl ();
+ int first_fn_stack_depth = first_fn_event.get_stack_depth ();
+
const unsigned num = num_events ();
- for (unsigned i = 0; i < num; i++)
+ for (unsigned i = first_fn_event_idx + 1; i < num; i++)
{
- if (get_event (i).get_fndecl () != get_event (0).get_fndecl ())
+ if (get_event (i).get_fndecl () != first_fndecl)
return true;
- if (get_event (i).get_stack_depth () != get_event (0).get_stack_depth ())
+ if (get_event (i).get_stack_depth () != first_fn_stack_depth)
return true;
}
return false;
diff --git a/gcc/doc/analyzer.texi b/gcc/doc/analyzer.texi
index d61b55c..52f89b9 100644
--- a/gcc/doc/analyzer.texi
+++ b/gcc/doc/analyzer.texi
@@ -432,16 +432,6 @@ For example, SSA names are printed to the user in ``raw'' form, rather
than printing the underlying variable name.
@end itemize
-Some ideas for other checkers
-@itemize @bullet
-@item
-File-descriptor-based APIs
-@item
-Linux kernel internal APIs
-@item
-Signal handling
-@end itemize
-
@node Debugging the Analyzer
@section Debugging the Analyzer
@cindex analyzer, debugging
diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index 589c649..89ff6a6 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -1914,7 +1914,8 @@ should not be built.
@item --with-dwarf2
Specify that the compiler should
-use DWARF 2 debugging information as the default.
+use DWARF debugging information as the default; the exact
+DWARF version that is the default is target-specific.
@item --with-advance-toolchain=@var{at}
On 64-bit PowerPC Linux systems, configure the compiler to use the
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 56e5e87..7263924 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8040,17 +8040,34 @@ is enabled by @option{-Wall}. It is more effective when @option{-ftree-vrp}
is active (the default for @option{-O2} and above) but a subset of instances
are issued even without optimization.
+By default, the trailing array of a structure will be treated as a flexible
+array member by @option{-Warray-bounds} or @option{-Warray-bounds=@var{n}}
+if it is declared as either a flexible array member per C99 standard onwards
+(@samp{[]}), a GCC zero-length array extension (@samp{[0]}), or an one-element
+array (@samp{[1]}). As a result, out of bounds subscripts or offsets into
+zero-length arrays or one-element arrays are not warned by default.
+
+You can add the option @option{-fstrict-flex-arrays} or
+@option{-fstrict-flex-arrays=@var{level}} to control how this
+option treat trailing array of a structure as a flexible array member:
+
+when @var{level}<=1, no change to the default behavior.
+
+when @var{level}=2, additional warnings will be issued for out of bounds
+subscripts or offsets into one-element arrays;
+
+when @var{level}=3, in addition to @var{level}=2, additional warnings will be
+issued for out of bounds subscripts or offsets into zero-length arrays.
+
@table @gcctabopt
@item -Warray-bounds=1
This is the default warning level of @option{-Warray-bounds} and is enabled
by @option{-Wall}; higher levels are not, and must be explicitly requested.
@item -Warray-bounds=2
-This warning level also warns about out of bounds accesses to trailing
-struct members of one-element array types (@pxref{Zero Length}) and about
-the intermediate results of pointer arithmetic that may yield out of bounds
-values. This warning level may give a larger number of false positives and
-is deactivated by default.
+This warning level also warns about the intermediate results of pointer
+arithmetic that may yield out of bounds values. This warning level may
+give a larger number of false positives and is deactivated by default.
@end table
@item -Warray-compare
@@ -14963,6 +14980,9 @@ The maximum depth of a loop nest suitable for complete peeling.
@item max-unswitch-insns
The maximum number of insns of an unswitched loop.
+@item max-unswitch-depth
+The maximum depth of a loop nest to be unswitched.
+
@item lim-expensive
The minimum cost of an expensive expression in the loop invariant motion.
diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 114258f..e80be80 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -9369,8 +9369,8 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0)
&& TREE_CODE (tem) == COND_EXPR
&& TREE_CODE (TREE_OPERAND (tem, 1)) == code
&& TREE_CODE (TREE_OPERAND (tem, 2)) == code
- && ! VOID_TYPE_P (TREE_OPERAND (tem, 1))
- && ! VOID_TYPE_P (TREE_OPERAND (tem, 2))
+ && ! VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (tem, 1)))
+ && ! VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (tem, 2)))
&& (TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 1), 0))
== TREE_TYPE (TREE_OPERAND (TREE_OPERAND (tem, 2), 0)))
&& (! (INTEGRAL_TYPE_P (TREE_TYPE (tem))
@@ -15002,7 +15002,7 @@ tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
/* If the initializer is non-void, then it's a normal expression
that will be assigned to the slot. */
- if (!VOID_TYPE_P (t))
+ if (!VOID_TYPE_P (TREE_TYPE (t)))
return RECURSE (t);
/* Otherwise, the initializer sets the slot in some way. One common
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index e3d6684..68df3a0 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,26 @@
+2022-12-04 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/107922
+ * simplify.cc (gfc_simplify_unpack): Terminate simplification when
+ array-valued argument FIELD does not provide enough elements.
+
+2022-12-04 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/107870
+ * intrinsic.texi: Fix typo in documentation of intrinsic FLOOR.
+ Describe the optional KIND argument to intrinsics as a scalar
+ constant expression, in accordance with the current standard.
+
+2022-12-04 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/107899
+ * resolve.cc (resolve_deallocate_expr): Avoid NULL pointer dereference
+ on invalid CLASS variable.
+
+2022-11-30 Martin Liska <mliska@suse.cz>
+
+ * parse.cc (parse_omp_structured_block): Remove extra semicolon.
+
2022-11-29 Harald Anlauf <anlauf@gmx.de>
Steven G. Kargl <kargl@gcc.gnu.org>
diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi
index 55f53fc..7af1ca3 100644
--- a/gcc/fortran/intrinsic.texi
+++ b/gcc/fortran/intrinsic.texi
@@ -553,7 +553,7 @@ Elemental function
@item @emph{Arguments}:
@multitable @columnfractions .15 .70
@item @var{I} @tab The type shall be @code{INTEGER}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -920,7 +920,7 @@ Elemental function
@item @emph{Arguments}:
@multitable @columnfractions .15 .70
@item @var{A} @tab The type of the argument shall be @code{REAL}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -1202,7 +1202,7 @@ Elemental function
@item @emph{Arguments}:
@multitable @columnfractions .15 .70
@item @var{A} @tab The type of the argument shall be @code{REAL}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -3406,7 +3406,7 @@ Elemental function
@item @emph{Arguments}:
@multitable @columnfractions .15 .70
@item @var{A} @tab The type shall be @code{REAL}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -3452,7 +3452,7 @@ Elemental function
@item @emph{Arguments}:
@multitable @columnfractions .15 .70
@item @var{I} @tab The type shall be @code{INTEGER}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -3636,7 +3636,7 @@ Elemental function
or @code{COMPLEX}.
@item @var{Y} @tab (Optional; only allowed if @var{X} is not
@code{COMPLEX}.) May be @code{INTEGER} or @code{REAL}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -4527,7 +4527,7 @@ Transformational function
@multitable @columnfractions .15 .70
@item @var{MASK} @tab The type shall be @code{LOGICAL}.
@item @var{DIM} @tab (Optional) The type shall be @code{INTEGER}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -6186,7 +6186,7 @@ conformance with @var{ARRAY}.
inclusive. It may not be an optional dummy argument.
@item @var{MASK} @tab (Optional) Shall be of type @code{LOGICAL},
and conformable with @var{ARRAY}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@item @var{BACK} @tab (Optional) A scalar of type @code{LOGICAL}.
@end multitable
@@ -6215,7 +6215,7 @@ is of default kind.
@table @asis
@item @emph{Description}:
-@code{FLOOR(A)} returns the greatest integer less than or equal to @var{X}.
+@code{FLOOR(A)} returns the greatest integer less than or equal to @var{A}.
@item @emph{Standard}:
Fortran 95 and later
@@ -6229,7 +6229,7 @@ Elemental function
@item @emph{Arguments}:
@multitable @columnfractions .15 .70
@item @var{A} @tab The type shall be @code{REAL}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -7550,7 +7550,7 @@ Elemental function
@item @emph{Arguments}:
@multitable @columnfractions .15 .70
@item @var{C} @tab Shall be a scalar @code{CHARACTER}, with @code{INTENT(IN)}
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -8007,7 +8007,7 @@ Elemental function
@item @emph{Arguments}:
@multitable @columnfractions .15 .70
@item @var{C} @tab Shall be a scalar @code{CHARACTER}, with @code{INTENT(IN)}
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -8279,7 +8279,7 @@ Elemental function
@code{INTENT(IN)}
@item @var{BACK} @tab (Optional) Shall be a scalar @code{LOGICAL}, with
@code{INTENT(IN)}
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -8324,7 +8324,7 @@ Elemental function
@multitable @columnfractions .15 .70
@item @var{A} @tab Shall be of type @code{INTEGER},
@code{REAL}, or @code{COMPLEX} or a boz-literal-constant.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -9109,7 +9109,7 @@ Inquiry function
@multitable @columnfractions .15 .70
@item @var{ARRAY} @tab Shall be an array, of any type.
@item @var{DIM} @tab (Optional) Shall be a scalar @code{INTEGER}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -9152,7 +9152,7 @@ Inquiry function
@multitable @columnfractions .15 .70
@item @var{ARRAY} @tab Shall be an coarray, of any type.
@item @var{DIM} @tab (Optional) Shall be a scalar @code{INTEGER}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -9239,7 +9239,7 @@ Inquiry function
@multitable @columnfractions .15 .70
@item @var{STRING} @tab Shall be a scalar or array of type
@code{CHARACTER}, with @code{INTENT(IN)}
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -9285,7 +9285,7 @@ Elemental function
@multitable @columnfractions .15 .70
@item @var{STRING} @tab Shall be a scalar of type @code{CHARACTER},
with @code{INTENT(IN)}
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -9823,7 +9823,7 @@ Elemental function
@item @emph{Arguments}:
@multitable @columnfractions .15 .70
@item @var{L} @tab The type shall be @code{LOGICAL}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -10312,7 +10312,7 @@ Transformational function
inclusive. It may not be an optional dummy argument.
@item @var{MASK} @tab Shall be of type @code{LOGICAL},
and conformable with @var{ARRAY}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@item @var{BACK} @tab (Optional) A scalar of type @code{LOGICAL}.
@end multitable
@@ -10679,7 +10679,7 @@ Transformational function
inclusive. It may not be an optional dummy argument.
@item @var{MASK} @tab Shall be of type @code{LOGICAL},
and conformable with @var{ARRAY}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@item @var{BACK} @tab (Optional) A scalar of type @code{LOGICAL}.
@end multitable
@@ -11111,7 +11111,7 @@ Elemental function
@item @emph{Arguments}:
@multitable @columnfractions .15 .70
@item @var{A} @tab The type of the argument shall be @code{REAL}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -12216,7 +12216,7 @@ Elemental function
@multitable @columnfractions .15 .70
@item @var{A} @tab Shall be @code{INTEGER}, @code{REAL}, or
@code{COMPLEX}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -12594,7 +12594,7 @@ Elemental function
@item @var{STRING} @tab Shall be of type @code{CHARACTER}.
@item @var{SET} @tab Shall be of type @code{CHARACTER}.
@item @var{BACK} @tab (Optional) shall be of type @code{LOGICAL}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -12956,7 +12956,7 @@ Inquiry function
@item @var{SOURCE} @tab Shall be an array or scalar of any type.
If @var{SOURCE} is a pointer it must be associated and allocatable
arrays must be allocated.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -13417,7 +13417,7 @@ a pointer it must be associated and allocatable arrays must be allocated.
@item @var{DIM} @tab (Optional) shall be a scalar of type @code{INTEGER}
and its value shall be in the range from 1 to n, where n equals the rank
of @var{ARRAY}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -14680,8 +14680,8 @@ Inquiry function
@item @emph{Arguments}:
@multitable @columnfractions .15 .70
@item @var{ARRAY} @tab Shall be an array, of any type.
-@item @var{DIM} @tab (Optional) Shall be a scalar @code{INTEGER}.
-@item @var{KIND}@tab (Optional) An @code{INTEGER} initialization
+@item @var{DIM} @tab (Optional) Shall be a scalar @code{INTEGER}.
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -14725,7 +14725,7 @@ Inquiry function
@multitable @columnfractions .15 .70
@item @var{ARRAY} @tab Shall be an coarray, of any type.
@item @var{DIM} @tab (Optional) Shall be a scalar @code{INTEGER}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
@@ -14900,7 +14900,7 @@ Elemental function
@item @var{STRING} @tab Shall be of type @code{CHARACTER}.
@item @var{SET} @tab Shall be of type @code{CHARACTER}.
@item @var{BACK} @tab (Optional) shall be of type @code{LOGICAL}.
-@item @var{KIND} @tab (Optional) An @code{INTEGER} initialization
+@item @var{KIND} @tab (Optional) A scalar @code{INTEGER} constant
expression indicating the kind parameter of the result.
@end multitable
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 3396c6c..75dc4b5 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -7570,7 +7570,7 @@ resolve_deallocate_expr (gfc_expr *e)
sym = e->symtree->n.sym;
unlimited = UNLIMITED_POLY(sym);
- if (sym->ts.type == BT_CLASS)
+ if (sym->ts.type == BT_CLASS && sym->attr.class_ok && CLASS_DATA (sym))
{
allocatable = CLASS_DATA (sym)->attr.allocatable;
pointer = CLASS_DATA (sym)->attr.class_pointer;
diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc
index b618418..aff9a1b 100644
--- a/gcc/fortran/simplify.cc
+++ b/gcc/fortran/simplify.cc
@@ -8485,7 +8485,16 @@ gfc_simplify_unpack (gfc_expr *vector, gfc_expr *mask, gfc_expr *field)
}
}
else if (field->expr_type == EXPR_ARRAY)
- e = gfc_copy_expr (field_ctor->expr);
+ {
+ if (field_ctor)
+ e = gfc_copy_expr (field_ctor->expr);
+ else
+ {
+ /* Not enough elements in array FIELD. */
+ gfc_free_expr (result);
+ return &gfc_bad_expr;
+ }
+ }
else
e = gfc_copy_expr (field);
diff --git a/gcc/function.cc b/gcc/function.cc
index 9c8773b..dc333c2 100644
--- a/gcc/function.cc
+++ b/gcc/function.cc
@@ -4997,7 +4997,8 @@ init_function_start (tree subr)
/* Warn if this value is an aggregate type,
regardless of which calling convention we are using for it. */
if (AGGREGATE_TYPE_P (TREE_TYPE (DECL_RESULT (subr))))
- warning (OPT_Waggregate_return, "function returns an aggregate");
+ warning_at (DECL_SOURCE_LOCATION (DECL_RESULT (subr)),
+ OPT_Waggregate_return, "function returns an aggregate");
}
/* Expand code to verify the stack_protect_guard. This is invoked at
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index ca1c9e2..2278e2b 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -9299,12 +9299,15 @@ validate_switches (const char *start, bool user_spec, bool braced)
const char *atom;
size_t len;
int i;
- bool suffix = false;
- bool starred = false;
+ bool suffix;
+ bool starred;
#define SKIP_WHITE() do { while (*p == ' ' || *p == '\t') p++; } while (0)
next_member:
+ suffix = false;
+ starred = false;
+
SKIP_WHITE ();
if (*p == '!')
diff --git a/gcc/gimple-array-bounds.cc b/gcc/gimple-array-bounds.cc
index 972e25f..59bd9eb 100644
--- a/gcc/gimple-array-bounds.cc
+++ b/gcc/gimple-array-bounds.cc
@@ -160,38 +160,17 @@ trailing_array (tree arg, tree *pref)
return array_ref_flexible_size_p (arg);
}
-/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
- arrays and "struct" hacks. If VRP can determine that the array
- subscript is a constant, check if it is outside valid range. If
- the array subscript is a RANGE, warn if it is non-overlapping with
- valid range. IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
- a ADDR_EXPR. Return true if a warning has been issued or if
- no-warning is set. */
+/* Acquire the upper bound and upper bound plus one for the array
+ reference REF and record them into UP_BOUND and UP_BOUND_P1.
+ Set *DECL to the decl or expresssion REF refers to. */
-bool
-array_bounds_checker::check_array_ref (location_t location, tree ref,
- gimple *stmt, bool ignore_off_by_one)
+static void
+get_up_bounds_for_array_ref (tree ref, tree *decl,
+ tree *up_bound, tree *up_bound_p1)
{
- if (warning_suppressed_p (ref, OPT_Warray_bounds_))
- /* Return true to have the caller prevent warnings for enclosing
- refs. */
- return true;
-
- tree low_sub = TREE_OPERAND (ref, 1);
- tree up_sub = low_sub;
- tree up_bound = array_ref_up_bound (ref);
-
- /* Referenced decl if one can be determined. */
- tree decl = NULL_TREE;
-
- /* Set for accesses to interior zero-length arrays. */
- special_array_member sam{ };
-
- tree up_bound_p1;
-
- if (!up_bound
- || TREE_CODE (up_bound) != INTEGER_CST
- || (warn_array_bounds < 2 && trailing_array (ref, &decl)))
+ if (!(*up_bound)
+ || TREE_CODE (*up_bound) != INTEGER_CST
+ || trailing_array (ref, decl))
{
/* Accesses to trailing arrays via pointers may access storage
beyond the types array bounds. For such arrays, or for flexible
@@ -203,8 +182,8 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
if (TREE_CODE (eltsize) != INTEGER_CST
|| integer_zerop (eltsize))
{
- up_bound = NULL_TREE;
- up_bound_p1 = NULL_TREE;
+ *up_bound = NULL_TREE;
+ *up_bound_p1 = NULL_TREE;
}
else
{
@@ -217,7 +196,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
{
/* Try to determine the size of the trailing array from
its initializer (if it has one). */
- if (tree refsize = component_ref_size (arg, &sam))
+ if (tree refsize = component_ref_size (arg))
if (TREE_CODE (refsize) == INTEGER_CST)
maxbound = refsize;
}
@@ -236,7 +215,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
{
/* Try to determine the size from a pointer to
an array if BASE is one. */
- if (tree size = get_ref_size (base, &decl))
+ if (tree size = get_ref_size (base, decl))
maxbound = size;
}
else if (!compref && DECL_P (base))
@@ -244,7 +223,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
if (TREE_CODE (basesize) == INTEGER_CST)
{
maxbound = basesize;
- decl = base;
+ *decl = base;
}
if (known_gt (off, 0))
@@ -256,21 +235,33 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
else
maxbound = fold_convert (sizetype, maxbound);
- up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
+ *up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
- if (up_bound_p1 != NULL_TREE)
- up_bound = int_const_binop (MINUS_EXPR, up_bound_p1,
+ if (*up_bound_p1 != NULL_TREE)
+ *up_bound = int_const_binop (MINUS_EXPR, *up_bound_p1,
build_int_cst (ptrdiff_type_node, 1));
else
- up_bound = NULL_TREE;
+ *up_bound = NULL_TREE;
}
}
else
- up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
- build_int_cst (TREE_TYPE (up_bound), 1));
+ *up_bound_p1 = int_const_binop (PLUS_EXPR, *up_bound,
+ build_int_cst (TREE_TYPE (*up_bound), 1));
+ return;
+}
- tree low_bound = array_ref_low_bound (ref);
+/* Given the LOW_SUB_ORG, LOW_SUB and UP_SUB, and the computed UP_BOUND
+ and UP_BOUND_P1, check whether the array reference REF is out of bound.
+ Issue warnings if out of bound, return TRUE if warnings are issued. */
+static bool
+check_out_of_bounds_and_warn (location_t location, tree ref,
+ tree low_sub_org, tree low_sub, tree up_sub,
+ tree up_bound, tree up_bound_p1,
+ const value_range *vr,
+ bool ignore_off_by_one)
+{
+ tree low_bound = array_ref_low_bound (ref);
tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
bool warned = false;
@@ -279,18 +270,7 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
warned = warning_at (location, OPT_Warray_bounds_,
"array subscript %E is outside array bounds of %qT",
- low_sub, artype);
-
- const value_range *vr = NULL;
- if (TREE_CODE (low_sub) == SSA_NAME)
- {
- vr = get_value_range (low_sub, stmt);
- if (!vr->undefined_p () && !vr->varying_p ())
- {
- low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
- up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
- }
- }
+ low_sub_org, artype);
if (warned)
; /* Do nothing. */
@@ -321,6 +301,68 @@ array_bounds_checker::check_array_ref (location_t location, tree ref,
warned = warning_at (location, OPT_Warray_bounds_,
"array subscript %E is below array bounds of %qT",
low_sub, artype);
+ return warned;
+}
+
+/* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible
+ arrays and "struct" hacks. If VRP can determine that the array
+ subscript is a constant, check if it is outside valid range. If
+ the array subscript is a RANGE, warn if it is non-overlapping with
+ valid range. IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside
+ a ADDR_EXPR. Return true if a warning has been issued or if
+ no-warning is set. */
+
+bool
+array_bounds_checker::check_array_ref (location_t location, tree ref,
+ gimple *stmt, bool ignore_off_by_one)
+{
+ if (warning_suppressed_p (ref, OPT_Warray_bounds_))
+ /* Return true to have the caller prevent warnings for enclosing
+ refs. */
+ return true;
+
+ /* Upper bound and Upper bound plus one for -Warray-bounds. */
+ tree up_bound = array_ref_up_bound (ref);
+ tree up_bound_p1 = NULL_TREE;
+
+ /* Referenced decl if one can be determined. */
+ tree decl = NULL_TREE;
+
+ /* Set to the type of the special array member for a COMPONENT_REF. */
+ special_array_member sam{ };
+
+ tree arg = TREE_OPERAND (ref, 0);
+ const bool compref = TREE_CODE (arg) == COMPONENT_REF;
+
+ if (compref)
+ /* Try to determine special array member type for this COMPONENT_REF. */
+ sam = component_ref_sam_type (arg);
+
+ get_up_bounds_for_array_ref (ref, &decl, &up_bound, &up_bound_p1);
+
+ bool warned = false;
+
+ tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
+ tree low_sub_org = TREE_OPERAND (ref, 1);
+ tree up_sub = low_sub_org;
+ tree low_sub = low_sub_org;
+
+ const value_range *vr = NULL;
+ if (TREE_CODE (low_sub_org) == SSA_NAME)
+ {
+ vr = get_value_range (low_sub_org, stmt);
+ if (!vr->undefined_p () && !vr->varying_p ())
+ {
+ low_sub = vr->kind () == VR_RANGE ? vr->max () : vr->min ();
+ up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
+ }
+ }
+
+ warned = check_out_of_bounds_and_warn (location, ref,
+ low_sub_org, low_sub, up_sub,
+ up_bound, up_bound_p1, vr,
+ ignore_off_by_one);
+
if (!warned && sam == special_array_member::int_0)
warned = warning_at (location, OPT_Wzero_length_bounds,
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index c2d9c80..c87e17f 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -591,7 +591,7 @@ fold_gimple_assign (gimple_stmt_iterator *si)
If the statement has a lhs the last stmt in the sequence is expected
to assign to that lhs. */
-static void
+void
gsi_replace_with_seq_vops (gimple_stmt_iterator *si_p, gimple_seq stmts)
{
gimple *stmt = gsi_stmt (*si_p);
@@ -5387,18 +5387,17 @@ gimple_fold_partial_load_store_mem_ref (gcall *call, tree vectype, bool mask_p)
tree mask = gimple_call_arg (call, 2);
if (!integer_all_onesp (mask))
return NULL_TREE;
- } else {
+ }
+ else
+ {
tree basic_len = gimple_call_arg (call, 2);
- if (!tree_fits_uhwi_p (basic_len))
+ if (!poly_int_tree_p (basic_len))
return NULL_TREE;
unsigned int nargs = gimple_call_num_args (call);
tree bias = gimple_call_arg (call, nargs - 1);
- gcc_assert (tree_fits_shwi_p (bias));
- tree biased_len = int_const_binop (MINUS_EXPR, basic_len, bias);
- unsigned int len = tree_to_uhwi (biased_len);
- unsigned int vect_len
- = GET_MODE_SIZE (TYPE_MODE (vectype)).to_constant ();
- if (vect_len != len)
+ gcc_assert (TREE_CODE (bias) == INTEGER_CST);
+ if (maybe_ne (wi::to_poly_widest (basic_len) - wi::to_widest (bias),
+ GET_MODE_SIZE (TYPE_MODE (vectype))))
return NULL_TREE;
}
diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h
index 7d29ee9..87ed4e5 100644
--- a/gcc/gimple-fold.h
+++ b/gcc/gimple-fold.h
@@ -63,6 +63,7 @@ extern bool arith_code_with_undefined_signed_overflow (tree_code);
extern gimple_seq rewrite_to_defined_overflow (gimple *, bool = false);
extern void replace_call_with_value (gimple_stmt_iterator *, tree);
extern tree tree_vec_extract (gimple_stmt_iterator *, tree, tree, tree, tree);
+extern void gsi_replace_with_seq_vops (gimple_stmt_iterator *, gimple_seq);
/* gimple_build, functionally matching fold_buildN, outputs stmts
int the provided sequence, matching and simplifying them on-the-fly.
diff --git a/gcc/gimple-predicate-analysis.cc b/gcc/gimple-predicate-analysis.cc
index ce2e1d1..afe01e7 100644
--- a/gcc/gimple-predicate-analysis.cc
+++ b/gcc/gimple-predicate-analysis.cc
@@ -1249,7 +1249,7 @@ simplify_1a (pred_chain &chain)
}
/* Implement rule 1b above. PREDS is the AND predicate to simplify
- in place. Returns true if CHAIN simplifies to true. */
+ in place. Returns true if CHAIN simplifies to true or false. */
static bool
simplify_1b (pred_chain &chain)
@@ -1290,6 +1290,8 @@ simplify_1b (pred_chain &chain)
{
chain.ordered_remove (j);
chain.ordered_remove (i);
+ if (chain.is_empty ())
+ return true;
i--;
break;
}
@@ -1503,6 +1505,7 @@ predicate::simplify (gimple *use_or_def, bool is_use)
::simplify_1a (m_preds[i]);
if (::simplify_1b (m_preds[i]))
{
+ m_preds[i].release ();
m_preds.ordered_remove (i);
i--;
}
@@ -1719,10 +1722,11 @@ predicate::normalize (const pred_chain &chain)
while (!work_list.is_empty ())
{
pred_info pi = work_list.pop ();
- predicate pred;
/* The predicate object is not modified here, only NORM_CHAIN and
WORK_LIST are appended to. */
- pred.normalize (&norm_chain, pi, BIT_AND_EXPR, &work_list, &mark_set);
+ unsigned oldlen = m_preds.length ();
+ normalize (&norm_chain, pi, BIT_AND_EXPR, &work_list, &mark_set);
+ gcc_assert (m_preds.length () == oldlen);
}
m_preds.safe_push (norm_chain);
@@ -1740,7 +1744,7 @@ predicate::normalize (gimple *use_or_def, bool is_use)
dump (dump_file, use_or_def, is_use ? "[USE]:\n" : "[DEF]:\n");
}
- predicate norm_preds;
+ predicate norm_preds (empty_val ());
for (unsigned i = 0; i < m_preds.length (); i++)
{
if (m_preds[i].length () != 1)
@@ -2076,6 +2080,8 @@ predicate::operator= (const predicate &rhs)
if (this == &rhs)
return *this;
+ m_cval = rhs.m_cval;
+
unsigned n = m_preds.length ();
for (unsigned i = 0; i != n; ++i)
m_preds[i].release ();
@@ -2204,11 +2210,15 @@ uninit_analysis::is_use_guarded (gimple *use_stmt, basic_block use_bb,
/* Try to build the predicate expression under which the PHI flows
into its use. This will be empty if the PHI is defined and used
in the same bb. */
- predicate use_preds;
+ predicate use_preds (true);
if (!init_use_preds (use_preds, def_bb, use_bb))
return false;
use_preds.simplify (use_stmt, /*is_use=*/true);
+ if (use_preds.is_false ())
+ return true;
+ if (use_preds.is_true ())
+ return false;
use_preds.normalize (use_stmt, /*is_use=*/true);
/* Try to prune the dead incoming phi edges. */
@@ -2227,6 +2237,10 @@ uninit_analysis::is_use_guarded (gimple *use_stmt, basic_block use_bb,
return false;
m_phi_def_preds.simplify (phi);
+ if (m_phi_def_preds.is_false ())
+ return false;
+ if (m_phi_def_preds.is_true ())
+ return true;
m_phi_def_preds.normalize (phi);
}
diff --git a/gcc/gimple-predicate-analysis.h b/gcc/gimple-predicate-analysis.h
index 972af5e..c4a7ed5 100644
--- a/gcc/gimple-predicate-analysis.h
+++ b/gcc/gimple-predicate-analysis.h
@@ -45,7 +45,7 @@ class predicate
{
public:
/* Construct with the specified EVAL object. */
- predicate () : m_preds (vNULL) { }
+ predicate (bool empty_val) : m_preds (vNULL), m_cval (empty_val) { }
/* Copy. */
predicate (const predicate &rhs) : m_preds (vNULL) { *this = rhs; }
@@ -60,6 +60,21 @@ class predicate
return m_preds.is_empty ();
}
+ bool is_true () const
+ {
+ return is_empty () && m_cval;
+ }
+
+ bool is_false () const
+ {
+ return is_empty () && !m_cval;
+ }
+
+ bool empty_val () const
+ {
+ return m_cval;
+ }
+
const pred_chain_union chain () const
{
return m_preds;
@@ -92,8 +107,10 @@ private:
bool simplify_3 ();
bool simplify_4 ();
- /* Representation of the predicate expression(s). */
+ /* Representation of the predicate expression(s). The predicate is
+ m_cval || m_preds[0] || ... */
pred_chain_union m_preds;
+ bool m_cval;
};
/* Represents a complex Boolean predicate expression. */
@@ -119,7 +136,7 @@ class uninit_analysis
/* Construct with the specified EVAL object. */
uninit_analysis (func_t &eval)
- : m_phi_def_preds (), m_eval (eval) { }
+ : m_phi_def_preds (false), m_eval (eval) { }
/* Copy. */
uninit_analysis (const uninit_analysis &rhs) = delete;
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 59a7053..854e47c 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -2127,7 +2127,6 @@ private:
/* Return the argument that a call returns. */
tree gimple_call_return_arg (gcall *);
- tree gimple_call_return_arg_ref (gcall *);
/* Check a call for uses of a dangling pointer arguments. */
void check_call_dangling (gcall *);
@@ -4460,24 +4459,6 @@ pass_waccess::gimple_call_return_arg (gcall *call)
return gimple_call_arg (call, argno);
}
-/* Return the decl referenced by the argument that the call STMT to
- a built-in function returns (including with an offset) or null if
- it doesn't. */
-
-tree
-pass_waccess::gimple_call_return_arg_ref (gcall *call)
-{
- if (tree arg = gimple_call_return_arg (call))
- {
- access_ref aref;
- if (m_ptr_qry.get_ref (arg, call, &aref, 0)
- && DECL_P (aref.ref))
- return aref.ref;
- }
-
- return NULL_TREE;
-}
-
/* Check for and diagnose all uses of the dangling pointer VAR to the auto
object DECL whose lifetime has ended. OBJREF is true when VAR denotes
an access to a DECL that may have been clobbered. */
@@ -4646,11 +4627,10 @@ pass_waccess::check_dangling_uses ()
unsigned i;
FOR_EACH_SSA_NAME (i, var, m_func)
{
- /* For each SSA_NAME pointer VAR find the DECL it points to.
- If the DECL is a clobbered local variable, check to see
+ /* For each SSA_NAME pointer VAR find the object it points to.
+ If the object is a clobbered local variable, check to see
if any of VAR's uses (or those of other pointers derived
from VAR) happens after the clobber. If so, warn. */
- tree decl = NULL_TREE;
gimple *def_stmt = SSA_NAME_DEF_STMT (var);
if (is_gimple_assign (def_stmt))
@@ -4660,23 +4640,30 @@ pass_waccess::check_dangling_uses ()
{
if (!POINTER_TYPE_P (TREE_TYPE (var)))
continue;
- decl = TREE_OPERAND (rhs, 0);
+ check_dangling_uses (var, TREE_OPERAND (rhs, 0));
}
else
{
/* For other expressions, check the base DECL to see
if it's been clobbered, most likely as a result of
inlining a reference to it. */
- decl = get_base_address (rhs);
+ tree decl = get_base_address (rhs);
if (DECL_P (decl))
check_dangling_uses (var, decl, false, true);
- continue;
}
}
else if (POINTER_TYPE_P (TREE_TYPE (var)))
{
if (gcall *call = dyn_cast<gcall *>(def_stmt))
- decl = gimple_call_return_arg_ref (call);
+ {
+ if (tree arg = gimple_call_return_arg (call))
+ {
+ access_ref aref;
+ if (m_ptr_qry.get_ref (arg, call, &aref, 0)
+ && aref.deref < 0)
+ check_dangling_uses (var, aref.ref);
+ }
+ }
else if (gphi *phi = dyn_cast <gphi *>(def_stmt))
{
unsigned nargs = gimple_phi_num_args (phi);
@@ -4684,19 +4671,12 @@ pass_waccess::check_dangling_uses ()
{
access_ref aref;
tree arg = gimple_phi_arg_def (phi, i);
- if (!m_ptr_qry.get_ref (arg, phi, &aref, 0)
- || (aref.deref == 0
- && POINTER_TYPE_P (TREE_TYPE (aref.ref))))
- continue;
- check_dangling_uses (var, aref.ref, true);
+ if (m_ptr_qry.get_ref (arg, phi, &aref, 0)
+ && aref.deref < 0)
+ check_dangling_uses (var, aref.ref, true);
}
- continue;
}
- else
- continue;
}
-
- check_dangling_uses (var, decl);
}
}
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 02415cb..250782b 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -15233,6 +15233,7 @@ computable_teams_clause (tree *tp, int *walk_subtrees, void *)
0 stands for clause not specified at all, use implementation default
-1 stands for value that can't be determined easily before entering
the target construct.
+ -2 means that no explicit teams construct was specified
If teams construct is not present at all, use 1 for num_teams
and 0 for thread_limit (only one team is involved, and the thread
limit is implementation defined. */
@@ -15251,7 +15252,7 @@ optimize_target_teams (tree target, gimple_seq *pre_p)
struct gimplify_omp_ctx *target_ctx = gimplify_omp_ctxp;
if (teams == NULL_TREE)
- num_teams_upper = integer_one_node;
+ num_teams_upper = build_int_cst (integer_type_node, -2);
else
for (c = OMP_TEAMS_CLAUSES (teams); c; c = OMP_CLAUSE_CHAIN (c))
{
diff --git a/gcc/ipa-pure-const.cc b/gcc/ipa-pure-const.cc
index 572a6da..0b748ee 100644
--- a/gcc/ipa-pure-const.cc
+++ b/gcc/ipa-pure-const.cc
@@ -1526,8 +1526,9 @@ ipa_make_function_pure (struct cgraph_node *node, bool looping, bool local)
{
bool cdtor = false;
- if (DECL_PURE_P (node->decl)
- && (looping || !DECL_LOOPING_CONST_OR_PURE_P (node->decl)))
+ if (TREE_READONLY (node->decl)
+ || (DECL_PURE_P (node->decl)
+ && (looping || !DECL_LOOPING_CONST_OR_PURE_P (node->decl))))
return false;
warn_function_pure (node->decl, !looping);
if (local && skip_function_for_local_pure_const (node))
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index 069ed70..96e9227 100644
--- a/gcc/jit/jit-playback.cc
+++ b/gcc/jit/jit-playback.cc
@@ -1213,7 +1213,7 @@ playback::rvalue *
playback::context::
new_comparison (location *loc,
enum gcc_jit_comparison op,
- rvalue *a, rvalue *b)
+ rvalue *a, rvalue *b, type *vec_result_type)
{
// FIXME: type-checking, or coercion?
enum tree_code inner_op;
@@ -1252,10 +1252,27 @@ new_comparison (location *loc,
tree node_b = b->as_tree ();
node_b = fold_const_var (node_b);
- tree inner_expr = build2 (inner_op,
- boolean_type_node,
- node_a,
- node_b);
+ tree inner_expr;
+ tree a_type = TREE_TYPE (node_a);
+ if (VECTOR_TYPE_P (a_type))
+ {
+ /* Build a vector comparison. See build_vec_cmp in c-typeck.cc for
+ reference. */
+ tree t_vec_result_type = vec_result_type->as_tree ();
+ tree zero_vec = build_zero_cst (t_vec_result_type);
+ tree minus_one_vec = build_minus_one_cst (t_vec_result_type);
+ tree cmp_type = truth_type_for (a_type);
+ tree cmp = build2 (inner_op, cmp_type, node_a, node_b);
+ inner_expr = build3 (VEC_COND_EXPR, t_vec_result_type, cmp, minus_one_vec,
+ zero_vec);
+ }
+ else
+ {
+ inner_expr = build2 (inner_op,
+ boolean_type_node,
+ node_a,
+ node_b);
+ }
/* Try to fold. */
inner_expr = fold (inner_expr);
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 1aeee2c..214f399 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -162,7 +162,7 @@ public:
rvalue *
new_comparison (location *loc,
enum gcc_jit_comparison op,
- rvalue *a, rvalue *b);
+ rvalue *a, rvalue *b, type *vec_result_type);
rvalue *
new_call (location *loc,
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
index 6ae5a66..2ce2722 100644
--- a/gcc/jit/jit-recording.cc
+++ b/gcc/jit/jit-recording.cc
@@ -5836,7 +5836,8 @@ recording::comparison::replay_into (replayer *r)
set_playback_obj (r->new_comparison (playback_location (r, m_loc),
m_op,
m_a->playback_rvalue (),
- m_b->playback_rvalue ()));
+ m_b->playback_rvalue (),
+ m_type->playback_type ()));
}
/* Implementation of pure virtual hook recording::rvalue::visit_children
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 8610ea9..5d7c717 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -1683,7 +1683,23 @@ public:
m_op (op),
m_a (a),
m_b (b)
- {}
+ {
+ type *a_type = a->get_type ();
+ vector_type *vec_type = a_type->dyn_cast_vector_type ();
+ if (vec_type != NULL)
+ {
+ type *element_type = vec_type->get_element_type ();
+ type *inner_type;
+ /* Vectors of floating-point values return a vector of integers of the
+ same size. */
+ if (element_type->is_float ())
+ inner_type = ctxt->get_int_type (element_type->get_size (), false);
+ else
+ inner_type = element_type;
+ m_type = new vector_type (inner_type, vec_type->get_num_units ());
+ ctxt->record (m_type);
+ }
+ }
void replay_into (replayer *r) final override;
diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index d92ab76..02b5ab4 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -4582,7 +4582,18 @@ curr_insn_transform (bool check_only_p)
|| (partial_subreg_p (mode, GET_MODE (reg))
&& known_le (GET_MODE_SIZE (GET_MODE (reg)),
UNITS_PER_WORD)
- && WORD_REGISTER_OPERATIONS)))
+ && WORD_REGISTER_OPERATIONS))
+ /* Avoid the situation when there are no available hard regs
+ for the pseudo mode but there are ones for the subreg
+ mode: */
+ && !(goal_alt[i] != NO_REGS
+ && REGNO (reg) >= FIRST_PSEUDO_REGISTER
+ && (prohibited_class_reg_set_mode_p
+ (goal_alt[i], reg_class_contents[goal_alt[i]],
+ GET_MODE (reg)))
+ && !(prohibited_class_reg_set_mode_p
+ (goal_alt[i], reg_class_contents[goal_alt[i]],
+ mode))))
{
/* An OP_INOUT is required when reloading a subreg of a
mode wider than a word to ensure that data beyond the
diff --git a/gcc/match.pd b/gcc/match.pd
index f8610e3..f48cbd9 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3492,6 +3492,30 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(cond (le @0 integer_zerop@1) (negate@2 @0) integer_zerop@1)
(max @2 @1))
+/* ((x & 0x1) == 0) ? y : z <op> y -> (-(typeof(y))(x & 0x1) & z) <op> y */
+(for op (bit_xor bit_ior)
+ (simplify
+ (cond (eq zero_one_valued_p@0
+ integer_zerop)
+ @1
+ (op:c @2 @1))
+ (if (INTEGRAL_TYPE_P (type)
+ && TYPE_PRECISION (type) > 1
+ && (INTEGRAL_TYPE_P (TREE_TYPE (@0))))
+ (op (bit_and (negate (convert:type @0)) @2) @1))))
+
+/* ((x & 0x1) == 0) ? z <op> y : y -> (-(typeof(y))(x & 0x1) & z) <op> y */
+(for op (bit_xor bit_ior)
+ (simplify
+ (cond (ne zero_one_valued_p@0
+ integer_zerop)
+ (op:c @2 @1)
+ @1)
+ (if (INTEGRAL_TYPE_P (type)
+ && TYPE_PRECISION (type) > 1
+ && (INTEGRAL_TYPE_P (TREE_TYPE (@0))))
+ (op (bit_and (negate (convert:type @0)) @2) @1))))
+
/* Simplifications of shift and rotates. */
(for rotate (lrotate rrotate)
@@ -5122,12 +5146,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(cmp { build_real (TREE_TYPE (@0), dconst0); } @1))
/* x != NaN is always true, other ops are always false. */
(if (REAL_VALUE_ISNAN (TREE_REAL_CST (@1))
+ && (cmp == EQ_EXPR || cmp == NE_EXPR || !flag_trapping_math)
&& !tree_expr_signaling_nan_p (@1)
&& !tree_expr_maybe_signaling_nan_p (@0))
{ constant_boolean_node (cmp == NE_EXPR, type); })
/* NaN != y is always true, other ops are always false. */
(if (TREE_CODE (@0) == REAL_CST
&& REAL_VALUE_ISNAN (TREE_REAL_CST (@0))
+ && (cmp == EQ_EXPR || cmp == NE_EXPR || !flag_trapping_math)
&& !tree_expr_signaling_nan_p (@0)
&& !tree_expr_signaling_nan_p (@1))
{ constant_boolean_node (cmp == NE_EXPR, type); })
diff --git a/gcc/params.opt b/gcc/params.opt
index c1dcb7e..397ec0b 100644
--- a/gcc/params.opt
+++ b/gcc/params.opt
@@ -726,6 +726,10 @@ The maximum number of instructions to consider to unroll in a loop.
Common Joined UInteger Var(param_max_unswitch_insns) Init(50) Param Optimization
The maximum number of insns of an unswitched loop.
+-param=max-unswitch-depth=
+Common Joined UInteger Var(param_max_unswitch_depth) Init(50) IntegerRange(1, 50) Param Optimization
+The maximum depth of a loop nest to be unswitched.
+
-param=max-variable-expansions-in-unroller=
Common Joined UInteger Var(param_max_variable_expansions) Init(1) Param Optimization
If -fvariable-expansion-in-unroller is used, the maximum number of times that an individual variable will be expanded during loop unrolling.
diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc
index 95565fd..ea6ca68 100644
--- a/gcc/pointer-query.cc
+++ b/gcc/pointer-query.cc
@@ -600,8 +600,8 @@ gimple_parm_array_size (tree ptr, wide_int rng[2],
/* Initialize the object. */
access_ref::access_ref ()
- : ref (), eval ([](tree x){ return x; }), deref (), trail1special (true),
- base0 (true), parmarray ()
+ : ref (), eval ([](tree x){ return x; }), deref (), ref_nullptr_p (false),
+ trail1special (true), base0 (true), parmarray ()
{
/* Set to valid. */
offrng[0] = offrng[1] = 0;
@@ -1193,7 +1193,16 @@ access_ref::inform_access (access_mode mode, int ostype /* = 1 */) const
loc = EXPR_LOCATION (ref);
else if (TREE_CODE (ref) != IDENTIFIER_NODE
&& TREE_CODE (ref) != SSA_NAME)
- return;
+ {
+ if (TREE_CODE (ref) == INTEGER_CST && ref_nullptr_p)
+ {
+ if (mode == access_read_write || mode == access_write_only)
+ inform (loc, "destination object is likely at address zero");
+ else
+ inform (loc, "source object is likely at address zero");
+ }
+ return;
+ }
if (mode == access_read_write || mode == access_write_only)
{
@@ -2280,7 +2289,10 @@ compute_objsize_r (tree ptr, gimple *stmt, bool addr, int ostype,
if (targetm.addr_space.zero_address_valid (as))
pref->set_max_size_range ();
else
- pref->sizrng[0] = pref->sizrng[1] = 0;
+ {
+ pref->sizrng[0] = pref->sizrng[1] = 0;
+ pref->ref_nullptr_p = true;
+ }
}
else
pref->sizrng[0] = pref->sizrng[1] = 0;
diff --git a/gcc/pointer-query.h b/gcc/pointer-query.h
index 801a240..19a6f15 100644
--- a/gcc/pointer-query.h
+++ b/gcc/pointer-query.h
@@ -88,7 +88,7 @@ struct access_ref
argument to the minimum. */
offset_int size_remaining (offset_int * = nullptr) const;
-/* Return true if the offset and object size are in range for SIZE. */
+ /* Return true if the offset and object size are in range for SIZE. */
bool offset_in_range (const offset_int &) const;
/* Return true if *THIS is an access to a declared object. */
@@ -141,6 +141,9 @@ struct access_ref
/* Positive when REF is dereferenced, negative when its address is
taken. */
int deref;
+ /* The following indicates if heuristics interpreted 'ref' is interpreted
+ as (offsetted) nullptr. */
+ bool ref_nullptr_p;
/* Set if trailing one-element arrays should be treated as flexible
array members. */
bool trail1special;
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index ee88511..c6c1137 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -330,6 +330,18 @@ frange_drop_ninf (frange &r, tree type)
r.intersect (tmp);
}
+// Crop R to [MIN, MAX] where MAX is the maximum representable number
+// for TYPE and MIN the minimum representable number for TYPE.
+
+static inline void
+frange_drop_infs (frange &r, tree type)
+{
+ REAL_VALUE_TYPE max = real_max_representable (type);
+ REAL_VALUE_TYPE min = real_min_representable (type);
+ frange tmp (type, min, max);
+ r.intersect (tmp);
+}
+
// If zero is in R, make sure both -0.0 and +0.0 are in the range.
static inline void
@@ -1883,7 +1895,7 @@ foperator_unordered_equal::op1_range (frange &r, tree type,
static bool
float_binary_op_range_finish (bool ret, frange &r, tree type,
- const frange &lhs)
+ const frange &lhs, bool div_op2 = false)
{
if (!ret)
return false;
@@ -1904,7 +1916,20 @@ float_binary_op_range_finish (bool ret, frange &r, tree type,
// If lhs isn't NAN, then neither operand could be NAN,
// even if the reverse operation does introduce a maybe_nan.
if (!lhs.maybe_isnan ())
- r.clear_nan ();
+ {
+ r.clear_nan ();
+ if (div_op2
+ ? !(real_compare (LE_EXPR, &lhs.lower_bound (), &dconst0)
+ && real_compare (GE_EXPR, &lhs.upper_bound (), &dconst0))
+ : !(real_isinf (&lhs.lower_bound ())
+ || real_isinf (&lhs.upper_bound ())))
+ // For reverse + or - or * or op1 of /, if result is finite, then
+ // r must be finite too, as X + INF or X - INF or X * INF or
+ // INF / X is always +-INF or NAN. For op2 of /, if result is
+ // non-zero and not NAN, r must be finite, as X / INF is always
+ // 0 or NAN.
+ frange_drop_infs (r, type);
+ }
// If lhs is a maybe or known NAN, the operand could be
// NAN.
else
@@ -2143,8 +2168,32 @@ public:
range_op_handler rdiv (RDIV_EXPR, type);
if (!rdiv)
return false;
- return float_binary_op_range_finish (rdiv.fold_range (r, type, lhs, op2),
- r, type, lhs);
+ bool ret = rdiv.fold_range (r, type, lhs, op2);
+ if (ret == false)
+ return false;
+ if (lhs.known_isnan () || op2.known_isnan () || op2.undefined_p ())
+ return float_binary_op_range_finish (ret, r, type, lhs);
+ const REAL_VALUE_TYPE &lhs_lb = lhs.lower_bound ();
+ const REAL_VALUE_TYPE &lhs_ub = lhs.upper_bound ();
+ const REAL_VALUE_TYPE &op2_lb = op2.lower_bound ();
+ const REAL_VALUE_TYPE &op2_ub = op2.upper_bound ();
+ if ((contains_zero_p (lhs_lb, lhs_ub) && contains_zero_p (op2_lb, op2_ub))
+ || ((real_isinf (&lhs_lb) || real_isinf (&lhs_ub))
+ && (real_isinf (&op2_lb) || real_isinf (&op2_ub))))
+ {
+ // If both lhs and op2 could be zeros or both could be infinities,
+ // we don't know anything about op1 except maybe for the sign
+ // and perhaps if it can be NAN or not.
+ REAL_VALUE_TYPE lb, ub;
+ int signbit_known = signbit_known_p (lhs_lb, lhs_ub, op2_lb, op2_ub);
+ zero_to_inf_range (lb, ub, signbit_known);
+ r.set (type, lb, ub);
+ }
+ // Otherwise, if op2 is a singleton INF and lhs doesn't include INF,
+ // or if lhs must be zero and op2 doesn't include zero, it would be
+ // UNDEFINED, while rdiv.fold_range computes a zero or singleton INF
+ // range. Those are supersets of UNDEFINED, so let's keep that way.
+ return float_binary_op_range_finish (ret, r, type, lhs);
}
virtual bool op2_range (frange &r, tree type,
const frange &lhs,
@@ -2271,9 +2320,29 @@ public:
{
if (lhs.undefined_p ())
return false;
- return float_binary_op_range_finish (fop_mult.fold_range (r, type, lhs,
- op2),
- r, type, lhs);
+ bool ret = fop_mult.fold_range (r, type, lhs, op2);
+ if (!ret)
+ return ret;
+ if (lhs.known_isnan () || op2.known_isnan () || op2.undefined_p ())
+ return float_binary_op_range_finish (ret, r, type, lhs);
+ const REAL_VALUE_TYPE &lhs_lb = lhs.lower_bound ();
+ const REAL_VALUE_TYPE &lhs_ub = lhs.upper_bound ();
+ const REAL_VALUE_TYPE &op2_lb = op2.lower_bound ();
+ const REAL_VALUE_TYPE &op2_ub = op2.upper_bound ();
+ if ((contains_zero_p (lhs_lb, lhs_ub)
+ && (real_isinf (&op2_lb) || real_isinf (&op2_ub)))
+ || ((contains_zero_p (op2_lb, op2_ub))
+ && (real_isinf (&lhs_lb) || real_isinf (&lhs_ub))))
+ {
+ // If both lhs could be zero and op2 infinity or vice versa,
+ // we don't know anything about op1 except maybe for the sign
+ // and perhaps if it can be NAN or not.
+ REAL_VALUE_TYPE lb, ub;
+ int signbit_known = signbit_known_p (lhs_lb, lhs_ub, op2_lb, op2_ub);
+ zero_to_inf_range (lb, ub, signbit_known);
+ r.set (type, lb, ub);
+ }
+ return float_binary_op_range_finish (ret, r, type, lhs);
}
virtual bool op2_range (frange &r, tree type,
const frange &lhs,
@@ -2282,8 +2351,28 @@ public:
{
if (lhs.undefined_p ())
return false;
- return float_binary_op_range_finish (fold_range (r, type, op1, lhs),
- r, type, lhs);
+ bool ret = fold_range (r, type, op1, lhs);
+ if (!ret)
+ return ret;
+ if (lhs.known_isnan () || op1.known_isnan () || op1.undefined_p ())
+ return float_binary_op_range_finish (ret, r, type, lhs, true);
+ const REAL_VALUE_TYPE &lhs_lb = lhs.lower_bound ();
+ const REAL_VALUE_TYPE &lhs_ub = lhs.upper_bound ();
+ const REAL_VALUE_TYPE &op1_lb = op1.lower_bound ();
+ const REAL_VALUE_TYPE &op1_ub = op1.upper_bound ();
+ if ((contains_zero_p (lhs_lb, lhs_ub) && contains_zero_p (op1_lb, op1_ub))
+ || ((real_isinf (&lhs_lb) || real_isinf (&lhs_ub))
+ && (real_isinf (&op1_lb) || real_isinf (&op1_ub))))
+ {
+ // If both lhs and op1 could be zeros or both could be infinities,
+ // we don't know anything about op2 except maybe for the sign
+ // and perhaps if it can be NAN or not.
+ REAL_VALUE_TYPE lb, ub;
+ int signbit_known = signbit_known_p (lhs_lb, lhs_ub, op1_lb, op1_ub);
+ zero_to_inf_range (lb, ub, signbit_known);
+ r.set (type, lb, ub);
+ }
+ return float_binary_op_range_finish (ret, r, type, lhs, true);
}
private:
void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub, bool &maybe_nan,
@@ -2296,7 +2385,7 @@ private:
{
// +-0.0 / +-0.0 or +-INF / +-INF is a known NAN.
if ((zero_p (lh_lb, lh_ub) && zero_p (rh_lb, rh_ub))
- || (singleton_inf_p (lh_lb, lh_ub) || singleton_inf_p (rh_lb, rh_ub)))
+ || (singleton_inf_p (lh_lb, lh_ub) && singleton_inf_p (rh_lb, rh_ub)))
{
real_nan (&lb, "", 0, TYPE_MODE (type));
ub = lb;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 0660d56..5058218 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,413 @@
+2022-12-06 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/107882
+ * gcc.dg/analyzer/memcpy-pr107882.c: New test.
+
+2022-12-06 Qing Zhao <qing.zhao@oracle.com>
+
+ * gcc.dg/Warray-bounds-11.c: Update warnings for -Warray-bounds=2.
+ * gcc.dg/Warray-bounds-flex-arrays-1.c: New test.
+ * gcc.dg/Warray-bounds-flex-arrays-2.c: New test.
+ * gcc.dg/Warray-bounds-flex-arrays-3.c: New test.
+ * gcc.dg/Warray-bounds-flex-arrays-4.c: New test.
+ * gcc.dg/Warray-bounds-flex-arrays-5.c: New test.
+ * gcc.dg/Warray-bounds-flex-arrays-6.c: New test.
+
+2022-12-06 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106325
+ * gcc.dg/analyzer/attr-nonnull-pr106325.c: New test.
+ * gcc.dg/analyzer/attribute-nonnull.c (test_6): New.
+ (test_7): New.
+
+2022-12-06 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/analyzer_kernel_plugin.c: Include
+ "analyzer/call-details.h".
+ * gcc.dg/plugin/analyzer_known_fns_plugin.c: Likewise.
+
+2022-12-06 Marcel Vollweiler <marcel@codesourcery.com>
+
+ * c-c++-common/gomp/target-teams-1.c: Adapt expected values for
+ num_teams from "1" to "-2" in cases without num_teams clause.
+ * g++.dg/gomp/target-teams-1.C: Likewise.
+ * gfortran.dg/gomp/defaultmap-4.f90: Likewise.
+ * gfortran.dg/gomp/defaultmap-5.f90: Likewise.
+ * gfortran.dg/gomp/defaultmap-6.f90: Likewise.
+
+2022-12-06 Andre Vieira <andre.simoesdiasvieira@arm.com>
+
+ * gcc.target/arm/mve/pr107987.c: New test.
+
+2022-12-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/107969
+ * gcc.target/i386/pr107969.c: New test.
+
+2022-12-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR testsuite/107046
+ * gcc.c-torture/execute/ieee/ieee.exp: For rx-*-* append
+ -mnofpu.
+
+2022-12-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/107975
+ * gcc.dg/pr107975.c: New test.
+
+2022-12-06 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/104165
+ * g++.dg/warn/Warray-bounds-pr104165-1.C: New testcase.
+
+2022-12-06 Iain Sandoe <iain@sandoe.co.uk>
+
+ * gcc.target/x86_64/abi/bf16/abi-bf16.exp: Use separate asm for Darwin.
+ * gcc.target/x86_64/abi/bf16/m256bf16/abi-bf16-ymm.exp: Likewise.
+ * gcc.target/x86_64/abi/bf16/m512bf16/abi-bf16-zmm.exp: Likewise.
+ * gcc.target/x86_64/abi/bf16/args.h: Make xmm_regs, x87_regs extern.
+ * gcc.target/x86_64/abi/bf16/m256bf16/args.h: Likewise.
+ * gcc.target/x86_64/abi/bf16/m512bf16/args.h: Likewise.
+ * gcc.target/x86_64/abi/bf16/asm-support-darwin.S: New file.
+ * gcc.target/x86_64/abi/bf16/m256bf16/asm-support-darwin.S: New file.
+ * gcc.target/x86_64/abi/bf16/m512bf16/asm-support-darwin.S: New file.
+
+2022-12-06 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+
+ * gcc.target/aarch64/interleave-init-1.c: New test.
+
+2022-12-05 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/40635
+ * gcc.dg/uninit-pr40635.c: New testcase.
+
+2022-12-05 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/106868
+ * gcc.dg/Wdangling-pointer-pr106868.c: New testcase.
+
+2022-12-05 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/106805
+ * c-c++-common/pr57371-4.c: Revert 2021-09-19 changes.
+ * c-c++-common/pr57371-5.c: New test.
+ * gcc.c-torture/execute/ieee/fp-cmp-6.x: Add -fno-trapping-math.
+ * gcc.c-torture/execute/ieee/fp-cmp-9.c: New test.
+ * gcc.c-torture/execute/ieee/fp-cmp-9.x: New file.
+
+2022-12-05 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/107879
+ * gcc.c-torture/execute/pr107879.c: New file.
+
+2022-12-05 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/107833
+ PR tree-optimization/107839
+ * gcc.dg/torture/pr107833.c: New testcase.
+ * gcc.dg/uninit-pr107839.c: Likewise.
+
+2022-12-04 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/107922
+ * gfortran.dg/unpack_field_1.f90: New test.
+
+2022-12-04 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/107899
+ * gfortran.dg/pr107899.f90: New test.
+
+2022-12-04 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/107417
+ * g++.dg/cpp2a/concepts-requires33.C: New test.
+
+2022-12-04 Iain Sandoe <iain@sandoe.co.uk>
+ Adrian Perl <adrian.perl@web.de>
+
+ PR c++/100611
+ PR c++/101367
+ PR c++/101976
+ PR c++/99576
+ * g++.dg/coroutines/pr100611.C: New test.
+ * g++.dg/coroutines/pr101367.C: New test.
+ * g++.dg/coroutines/pr101976.C: New test.
+ * g++.dg/coroutines/pr99576_1.C: New test.
+ * g++.dg/coroutines/pr99576_2.C: New test.
+
+2022-12-03 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/103081
+ * g++.dg/cpp2a/using-enum-10.C: New test.
+ * g++.dg/cpp2a/using-enum-10a.C: New test.
+
+2022-12-03 Alexandre Oliva <oliva@adacore.com>
+
+ * gcc.dg/tree-ssa/ssa-sink-18.c: xfail sink2 on riscv64.
+
+2022-12-03 Alexandre Oliva <oliva@adacore.com>
+
+ * gcc.dg/uninit-pred-9_b.c: Add riscv*-*-* to the xfail list
+ for the bogus warning.
+
+2022-12-02 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/107874
+ * gfortran.dg/merge_1.f90: Avoid recursive I/O.
+
+2022-12-02 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/107851
+ * gcc.dg/analyzer/allocation-size-4.c: Update expected wording.
+ * gcc.dg/analyzer/allocation-size-multiline-1.c: New test.
+ * gcc.dg/analyzer/allocation-size-multiline-2.c: New test.
+ * gcc.dg/analyzer/out-of-bounds-multiline-1.c: Update expected
+ wording.
+ * gcc.dg/analyzer/out-of-bounds-multiline-2.c: New test.
+ * gcc.dg/analyzer/out-of-bounds-read-char-arr.c: Update expected
+ wording.
+ * gcc.dg/analyzer/out-of-bounds-read-int-arr.c: Likewise.
+ * gcc.dg/analyzer/out-of-bounds-write-char-arr.c: Likewise.
+ * gcc.dg/analyzer/out-of-bounds-write-int-arr.c: Likewise.
+
+2022-12-02 Marek Polacek <polacek@redhat.com>
+
+ * g++.dg/cpp0x/constexpr-ex1.C: Adjust dg-error.
+ * g++.dg/cpp23/constexpr-nonlit10.C: Adjust dg-warning.
+ * g++.dg/cpp23/constexpr-nonlit11.C: Likewise.
+ * g++.dg/cpp2a/spaceship-eq3.C: Add dg-error.
+
+2022-12-02 Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
+ Jason Merrill <jason@redhat.com>
+
+ * g++.dg/diagnostic/return-type-loc1.C: New test.
+
+2022-12-02 Vladimir N. Makarov <vmakarov@redhat.com>
+
+ * gcc.target/mips/pr106462.c: New test.
+
+2022-12-02 liuhongt <hongtao.liu@intel.com>
+
+ * gcc.target/i386/cbranchbf4.c: New test.
+
+2022-12-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/106577
+ * gcc.target/i386/pr106577.c: New test.
+
+2022-12-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/84469
+ * g++.dg/gomp/for-21.C (f3, f6, f9): Adjust expected diagnostics.
+ * g++.dg/gomp/for-22.C: New test.
+
+2022-12-02 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/84469
+ * g++.dg/cpp1z/decomp56.C: New test.
+ * g++.dg/gomp/pr84469.C: New test.
+
+2022-12-02 Michael Collison <collison@rivosinc.com>
+
+ * gcc.dg/tree-ssa/branchless-cond.c: New test.
+
+2022-12-02 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/107948
+ * gcc.dg/analyzer/feasibility-pr107948.c: New test.
+
+2022-12-02 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/analyzer/string-ops-concat-pair.c: New test.
+ * gcc.dg/analyzer/string-ops-dup.c: New test.
+
+2022-12-02 liuhongt <hongtao.liu@intel.com>
+
+ * gcc.target/i386/pr107934.c: New test.
+
+2022-12-02 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/107539
+ * g++.dg/template/canon-type-19.C: New test.
+
+2022-12-01 Ju-Zhe Zhong <juzhe.zhong@rivai.ai>
+
+ * gcc.target/riscv/rvv/base/dup-1.c: New test.
+ * gcc.target/riscv/rvv/base/dup-2.c: New test.
+
+2022-12-01 Christophe Lyon <christophe.lyon@arm.com>
+
+ * gcc.target/arm/simd/mve-compare-1.c: Update.
+ * gcc.target/arm/simd/mve-compare-scalar-1.c: Update.
+ * gcc.target/arm/simd/mve-vabs.c: Update.
+ * gcc.target/arm/simd/mve-vadd-1.c: Update.
+ * gcc.target/arm/simd/mve-vadd-scalar-1.c: Update.
+ * gcc.target/arm/simd/mve-vcmp.c: Update.
+ * gcc.target/arm/simd/pr101325.c: Update.
+
+2022-12-01 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/107937
+ * gcc.dg/pr107937.c: New testcase.
+
+2022-12-01 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/107935
+ * gcc.dg/torture/pr107935.c: New testcase.
+
+2022-12-01 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/107627
+ * gcc.target/i386/pr107627-1.c: New test.
+ * gcc.target/i386/pr107627-2.c: New test.
+
+2022-12-01 liuhongt <hongtao.liu@intel.com>
+
+ * gcc.target/i386/pr107863.c: New test.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106626
+ * gcc.dg/analyzer/out-of-bounds-multiline-1.c: New test.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106626
+ * gcc.dg/analyzer/call-summaries-2.c: Update expected results.
+ * gcc.dg/analyzer/out-of-bounds-1.c: Likewise.
+ * gcc.dg/analyzer/out-of-bounds-2.c: Likewise.
+ * gcc.dg/analyzer/out-of-bounds-3.c: Likewise.
+ * gcc.dg/analyzer/out-of-bounds-4.c: Likewise.
+ * gcc.dg/analyzer/out-of-bounds-5.c: Likewise.
+ * gcc.dg/analyzer/out-of-bounds-container_of.c: Likewise.
+ * gcc.dg/analyzer/out-of-bounds-read-char-arr.c: Likewise. Rename
+ functions from "int_arr_" to "char_arr_".
+ * gcc.dg/analyzer/out-of-bounds-read-int-arr.c: Update expected
+ results.
+ * gcc.dg/analyzer/out-of-bounds-read-struct-arr.c: New test.
+ * gcc.dg/analyzer/out-of-bounds-write-char-arr.c: Update expected
+ results. Rename functions from "int_arr_" to "char_arr_".
+ * gcc.dg/analyzer/out-of-bounds-write-int-arr.c: Update expected
+ results.
+ * gcc.dg/analyzer/out-of-bounds-write-struct-arr.c: New test.
+ * gcc.dg/analyzer/pr101962.c: Update expected results.
+ * gcc.dg/analyzer/realloc-5.c: Update expected results.
+ * gcc.dg/analyzer/zlib-3.c: Update expected results.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106626
+ * gcc.dg/analyzer/call-summaries-2.c: Add dg-message for expected
+ note about valid indexes.
+ * gcc.dg/analyzer/out-of-bounds-1.c: Likewise, fixing up existing
+ dg-message directives.
+ * gcc.dg/analyzer/out-of-bounds-write-char-arr.c: Likewise.
+ * gcc.dg/analyzer/out-of-bounds-write-int-arr.c: Likewise.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106626
+ * gcc.dg/analyzer/out-of-bounds-read-char-arr.c: Update for
+ changes to expected wording.
+ * gcc.dg/analyzer/out-of-bounds-read-int-arr.c: Likewise.
+ * gcc.dg/analyzer/out-of-bounds-write-char-arr.c: Likewise.
+ * gcc.dg/analyzer/out-of-bounds-write-int-arr.c: Likewise.
+
+2022-12-01 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/107928
+ * gcc.dg/analyzer/fd-bind-pr107928.c: New test.
+ * gcc.dg/analyzer/fd-connect-pr107928.c: New test.
+ * gcc.dg/analyzer/fd-stream-socket-active-open.c
+ (test_active_open_from_connect_constant): New, adapted from
+ test_active_open_from_connect.
+ * gcc.dg/analyzer/fd-stream-socket-passive-open.c
+ (test_passive_open_from_bind_constant): New, adapted from
+ test_passive_open_from_bind.
+ (test_passive_open_from_listen_constant): New, adapted from
+ test_passive_open_from_listen.
+
+2022-12-01 Haochen Gui <guihaoc@gcc.gnu.org>
+
+ PR target/100866
+ * gcc.target/powerpc/pr100866-1.c: New.
+
+2022-11-30 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+
+ * gcc.target/aarch64/mops_5.c: New test.
+ * gcc.target/aarch64/mops_6.c: Likewise.
+ * gcc.target/aarch64/mops_7.c: Likewise.
+
+2022-11-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR d/107592
+ * gdc.dg/pr107592.d: New test.
+
+2022-11-30 Iskander Shakirzyanov <iskander@ispras.ru>
+ Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
+
+ PR driver/107787
+ * gcc.dg/Warray-bounds-34.c: Correct the regular expression
+ for -Warray-bounds=.
+ * gcc.dg/Warray-bounds-43.c: Likewise.
+ * gcc.dg/pr107787.c: New test.
+
+2022-11-30 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/107919
+ * g++.dg/warn/Wuninitialized-pr107919-1.C: New testcase.
+
+2022-11-30 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/107835
+ * gcc.c-torture/compile/pr107835.c: New test.
+
+2022-11-30 Alexandre Oliva <oliva@adacore.com>
+
+ PR target/107304
+ * gcc.target/i386/pr107304.c: dg-require ifunc support.
+
+2022-11-30 Lulu Cheng <chenglulu@loongson.cn>
+
+ * lib/target-supports.exp:
+ * gcc.target/loongarch/stack-check-alloca-1.c: New test.
+ * gcc.target/loongarch/stack-check-alloca-2.c: New test.
+ * gcc.target/loongarch/stack-check-alloca-3.c: New test.
+ * gcc.target/loongarch/stack-check-alloca-4.c: New test.
+ * gcc.target/loongarch/stack-check-alloca-5.c: New test.
+ * gcc.target/loongarch/stack-check-alloca-6.c: New test.
+ * gcc.target/loongarch/stack-check-alloca.h: New test.
+ * gcc.target/loongarch/stack-check-cfa-1.c: New test.
+ * gcc.target/loongarch/stack-check-cfa-2.c: New test.
+ * gcc.target/loongarch/stack-check-prologue-1.c: New test.
+ * gcc.target/loongarch/stack-check-prologue-2.c: New test.
+ * gcc.target/loongarch/stack-check-prologue-3.c: New test.
+ * gcc.target/loongarch/stack-check-prologue-4.c: New test.
+ * gcc.target/loongarch/stack-check-prologue-5.c: New test.
+ * gcc.target/loongarch/stack-check-prologue-6.c: New test.
+ * gcc.target/loongarch/stack-check-prologue-7.c: New test.
+ * gcc.target/loongarch/stack-check-prologue.h: New test.
+
+2022-11-30 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/103546
+ * gcc.dg/analyzer/ferror-1.c: New test.
+ * gcc.dg/analyzer/fileno-1.c: New test.
+ * gcc.dg/analyzer/flex-with-call-summaries.c: New test.
+ * gcc.dg/analyzer/flex-without-call-summaries.c: New test.
+ * gcc.dg/analyzer/getc-1.c: New test.
+ * gcc.dg/analyzer/isatty-1.c: New test.
+
+2022-11-30 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/105784
+ * gcc.dg/analyzer/torture/fold-ptr-arith-pr105784.c: New test.
+
+2022-11-30 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/107542
+ * g++.dg/cpp2a/spaceship-sfinae2.C: New test.
+
2022-11-29 Harald Anlauf <anlauf@gmx.de>
Steven G. Kargl <kargl@gcc.gnu.org>
diff --git a/gcc/testsuite/c-c++-common/gomp/target-teams-1.c b/gcc/testsuite/c-c++-common/gomp/target-teams-1.c
index 51b8d48..74d60e1 100644
--- a/gcc/testsuite/c-c++-common/gomp/target-teams-1.c
+++ b/gcc/testsuite/c-c++-common/gomp/target-teams-1.c
@@ -81,5 +81,5 @@ foo (int a, int b, long c, long d)
/* { dg-final { scan-tree-dump-times "thread_limit\\(-1\\)" 3 "gimple" } } */
/* { dg-final { scan-tree-dump-times "num_teams\\(0\\)" 4 "gimple" } } */
/* { dg-final { scan-tree-dump-times "thread_limit\\(0\\)" 6 "gimple" } } */
-/* { dg-final { scan-tree-dump-times "num_teams\\(1\\)" 2 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "num_teams\\(-2\\)" 2 "gimple" } } */
/* { dg-final { scan-tree-dump-times "thread_limit\\(1\\)" 0 "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/pr57371-4.c b/gcc/testsuite/c-c++-common/pr57371-4.c
index d938ecd..f43f7c2 100644
--- a/gcc/testsuite/c-c++-common/pr57371-4.c
+++ b/gcc/testsuite/c-c++-common/pr57371-4.c
@@ -13,25 +13,25 @@ void nonfinite(unsigned short x) {
{
volatile int nonfinite_1;
nonfinite_1 = (float) x > QNAN;
- /* { dg-final { scan-tree-dump "nonfinite_1 = 0" "original" } } */
+ /* { dg-final { scan-tree-dump "nonfinite_1 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_2;
nonfinite_2 = (float) x >= QNAN;
- /* { dg-final { scan-tree-dump "nonfinite_2 = 0" "original" } } */
+ /* { dg-final { scan-tree-dump "nonfinite_2 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_3;
nonfinite_3 = (float) x < QNAN;
- /* { dg-final { scan-tree-dump "nonfinite_3 = 0" "original" } } */
+ /* { dg-final { scan-tree-dump "nonfinite_3 = \\(float\\)" "original" } } */
}
{
volatile int nonfinite_4;
nonfinite_4 = (float) x <= QNAN;
- /* { dg-final { scan-tree-dump "nonfinite_4 = 0" "original" } } */
+ /* { dg-final { scan-tree-dump "nonfinite_4 = \\(float\\)" "original" } } */
}
{
diff --git a/gcc/testsuite/c-c++-common/pr57371-5.c b/gcc/testsuite/c-c++-common/pr57371-5.c
new file mode 100644
index 0000000..8e18b0a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr57371-5.c
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fno-signaling-nans -fno-trapping-math -fdump-tree-original" } */
+
+/* We can not get rid of comparison in tests below because of
+ pending NaN exceptions.
+
+ TODO: avoid under -fno-trapping-math. */
+
+#define QNAN __builtin_nanf ("0")
+
+void nonfinite(unsigned short x) {
+ {
+ volatile int nonfinite_1;
+ nonfinite_1 = (float) x > QNAN;
+ /* { dg-final { scan-tree-dump "nonfinite_1 = 0" "original" } } */
+ }
+
+ {
+ volatile int nonfinite_2;
+ nonfinite_2 = (float) x >= QNAN;
+ /* { dg-final { scan-tree-dump "nonfinite_2 = 0" "original" } } */
+ }
+
+ {
+ volatile int nonfinite_3;
+ nonfinite_3 = (float) x < QNAN;
+ /* { dg-final { scan-tree-dump "nonfinite_3 = 0" "original" } } */
+ }
+
+ {
+ volatile int nonfinite_4;
+ nonfinite_4 = (float) x <= QNAN;
+ /* { dg-final { scan-tree-dump "nonfinite_4 = 0" "original" } } */
+ }
+
+ {
+ volatile int nonfinite_11;
+ nonfinite_11 = (float) x == QNAN;
+ /* { dg-final { scan-tree-dump "nonfinite_11 = 0" "original" } } */
+ }
+
+ {
+ volatile int nonfinite_12;
+ nonfinite_12 = (float) x != QNAN;
+ /* { dg-final { scan-tree-dump "nonfinite_12 = 1" "original" } } */
+ }
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr100611.C b/gcc/testsuite/g++.dg/coroutines/pr100611.C
new file mode 100644
index 0000000..14edf48
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr100611.C
@@ -0,0 +1,94 @@
+// { dg-do run }
+/*
+ Test that instances created in capture clauses within co_await statements do not
+ get 'promoted'. This would lead to the members destructor getting called more
+ than once.
+
+ Correct output should look like:
+ Foo(23) 0xf042d8
+ Foo(const& 23) 0xf042ec
+ ~Foo(23) 0xf042ec
+ After co_await
+ ~Foo(23) 0xf042d8
+*/
+#include <coroutine>
+#include <iostream>
+
+static unsigned int struct_Foo_destructor_counter = 0;
+static bool lambda_was_executed = false;
+
+class Task {
+public:
+ struct promise_type {
+ Task get_return_object() {
+ return {std::coroutine_handle<promise_type>::from_promise(*this)};
+ }
+
+ std::suspend_never initial_suspend() { return {}; }
+ std::suspend_always final_suspend() noexcept { return {}; }
+ void unhandled_exception() {}
+ void return_void() {}
+ };
+
+ ~Task() {
+ if (handle_) {
+ handle_.destroy();
+ }
+ }
+
+ bool await_ready() { return false; }
+ bool await_suspend(std::coroutine_handle<>) { return false; }
+ bool await_resume() { return false; }
+
+private:
+ Task(std::coroutine_handle<promise_type> handle) : handle_(handle) {}
+
+ std::coroutine_handle<promise_type> handle_;
+};
+
+class Foo {
+public:
+ Foo(int id) : id_(id) {
+ std::cout << "Foo(" << id_ << ") " << (void*)this << std::endl;
+ }
+
+ Foo(Foo const& other) : id_(other.id_) {
+ std::cout << "Foo(const& " << id_ << ") " << (void*)this << std::endl;
+ }
+
+ Foo(Foo&& other) : id_(other.id_) {
+ std::cout << "Foo(&& " << id_ << ") " << (void*)this << std::endl;
+ }
+
+ ~Foo() {
+ std::cout << "~Foo(" << id_ << ") " << (void*)this << std::endl;
+ struct_Foo_destructor_counter++;
+
+ if (struct_Foo_destructor_counter > 2){
+ std::cout << "Foo was destroyed more than two times!\n";
+ __builtin_abort();
+ }
+ }
+
+private:
+ int id_;
+};
+
+Task test() {
+ Foo foo(23);
+
+ co_await [foo]() -> Task { // A copy of foo is captured. This copy must not get 'promoted'.
+ co_return;
+ }();
+
+ std::cout << "After co_await\n";
+ if (struct_Foo_destructor_counter == 0){
+ std::cout << "The captured copy of foo was not destroyed after the co_await statement!\n";
+ __builtin_abort();
+ }
+}
+
+int main() {
+ test();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr101367.C b/gcc/testsuite/g++.dg/coroutines/pr101367.C
new file mode 100644
index 0000000..0a9e5be
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr101367.C
@@ -0,0 +1,72 @@
+// { dg-do run }
+
+#include <coroutine>
+using namespace std;
+#include <cstdio>
+#include <utility>
+#include <string>
+
+struct resource {
+ template<typename Func>
+ resource(Func fn) { fn(); /*std::printf("resource()\n"); */}
+ ~resource() { /*std::printf("~resource()\n"); */}
+ resource(resource&&) = delete;
+};
+
+template<typename T>
+struct generator {
+ struct promise_type {
+ generator get_return_object() {
+ return generator{coroutine_handle<promise_type>::from_promise(*this)};
+ }
+
+ void return_void() {}
+ void unhandled_exception() {}
+ suspend_always initial_suspend() { return {}; }
+ suspend_always final_suspend() noexcept { return {}; }
+
+ struct awaitable {
+ resource& r;
+
+ awaitable(resource&& r) : r(r) {}
+
+ bool await_ready() noexcept { return false; }
+
+ void await_suspend(coroutine_handle<> h) noexcept {
+ //std::printf("awaitable::await_suspend()\n");
+ }
+
+ void await_resume() noexcept {
+ //std::printf("awaitable::await_resume()\n");
+ }
+ };
+
+ awaitable yield_value(resource&& r) {
+ return awaitable{std::move(r)};
+ }
+ };
+
+ generator(coroutine_handle<promise_type> coro) : coro(coro)
+ {}
+
+ generator(generator&& g) noexcept : coro(std::exchange(g.coro, {}))
+ {}
+
+ ~generator() {
+ if (coro) { coro.destroy(); }
+ }
+
+ coroutine_handle<promise_type> coro;
+};
+
+generator<int> f() {
+ std::string s;
+ // if `s` isn't captured things work ok
+ co_yield resource{[s]{}};
+}
+
+int main() {
+ generator x = f();
+ x.coro.resume();
+ x.coro.resume();
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr101976.C b/gcc/testsuite/g++.dg/coroutines/pr101976.C
new file mode 100644
index 0000000..1854ba0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr101976.C
@@ -0,0 +1,78 @@
+// { dg-do run }
+
+/*
+ Test that members of temporary instances in co_await statements do not get
+ 'promoted'. This would lead to the members destructor getting called more
+ than once.
+
+ Correct output should look like:
+ Before co_await
+ nontrivial_move() 0x6ec2e1
+ nontrivial_move(nontrivial_move&&) 0x6ed320
+ In subtask
+ ~nontrivial_move() 0x6ed320
+ ~nontrivial_move() 0x6ec2e1
+ After co_await
+*/
+#include <coroutine>
+#include <iostream>
+
+static unsigned int struct_nontrivial_move_destructor_counter = 0;
+
+struct task {
+ struct promise_type {
+ task get_return_object() {
+ return {std::coroutine_handle<promise_type>::from_promise(*this)};
+ }
+ std::suspend_never initial_suspend() { return {}; }
+ std::suspend_never final_suspend() noexcept { return {}; }
+ void unhandled_exception() {}
+ void return_void() {}
+ };
+
+ bool await_ready() { return true; }
+ void await_suspend(std::coroutine_handle<>) {}
+ void await_resume() {}
+
+ std::coroutine_handle<promise_type> m_handle;
+};
+
+struct nontrivial_move {
+ nontrivial_move() {
+ std::cout << "nontrivial_move() " << (void *)this << std::endl;
+ }
+ nontrivial_move(nontrivial_move&&) {
+ std::cout << "nontrivial_move(nontrivial_move&&) " << (void *)this
+ << std::endl;
+ }
+ ~nontrivial_move() {
+ std::cout << "~nontrivial_move() " << (void *)this << std::endl;
+ struct_nontrivial_move_destructor_counter++;
+ if (struct_nontrivial_move_destructor_counter > 2){
+ std::cerr << "The destructor of nontrivial_move was called more than two times!\n";
+ __builtin_abort();
+ }
+ }
+
+ char buf[128]{}; // Example why the move could be non trivial
+};
+
+struct wrapper {
+ nontrivial_move member;
+};
+
+task subtask(wrapper /* unused */) {
+ std::cout << "In subtask\n";
+ co_return;
+}
+
+task main_task() {
+ std::cout << "Before co_await\n";
+ co_await subtask({}); // wrapper must get 'promoted', but not its member
+ std::cout << "After co_await\n";
+}
+
+int main() {
+ main_task();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr99576_1.C b/gcc/testsuite/g++.dg/coroutines/pr99576_1.C
new file mode 100644
index 0000000..612f0cd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr99576_1.C
@@ -0,0 +1,124 @@
+// { dg-do run }
+/*
+ Test that instances created in capture clauses within co_await statements do not get
+ 'promoted'. This would lead to their members destructors getting called more
+ than once.
+
+ Correct output should look like:
+ START TASK
+ Foo() 0x4f9320
+ IN LAMBDA
+ ~Foo() 0x4f9320
+ TASK RETURN
+*/
+#include <coroutine>
+#include <exception>
+#include <iostream>
+#include <utility>
+
+static unsigned int struct_Foo_destructor_counter = 0;
+static bool lambda_was_executed = false;
+
+class Task {
+public:
+ struct promise_type {
+ struct final_awaitable {
+ bool await_ready() noexcept { return false; }
+ auto await_suspend(std::coroutine_handle<promise_type> coro) noexcept {
+ return coro.promise().continuation;
+ }
+ void await_resume() noexcept {}
+ };
+ Task get_return_object() {
+ return Task(std::coroutine_handle<promise_type>::from_promise(*this));
+ }
+ std::suspend_always initial_suspend() { return {}; }
+ final_awaitable final_suspend() noexcept { return {}; }
+ void unhandled_exception() { std::terminate(); }
+ void return_void() {}
+
+ std::coroutine_handle<void> continuation = std::noop_coroutine();
+ };
+
+ Task(Task const&) = delete;
+ Task(Task&& other) noexcept
+ : handle_(std::exchange(other.handle_, nullptr)) {}
+ Task& operator=(Task const&) = delete;
+ Task& operator=(Task&& other) noexcept {
+ handle_ = std::exchange(other.handle_, nullptr);
+ return *this;
+ }
+ ~Task() {
+ if (handle_) {
+ handle_.destroy();
+ }
+ }
+
+ bool await_ready() const { return false; }
+ auto await_suspend(std::coroutine_handle<void> continuation) {
+ handle_.promise().continuation = continuation;
+ return handle_;
+ }
+ void await_resume() {}
+
+private:
+ explicit Task(std::coroutine_handle<promise_type> handle) : handle_(handle) {}
+
+ std::coroutine_handle<promise_type> handle_;
+};
+
+struct RunTask {
+ struct promise_type {
+ RunTask get_return_object() { return {}; }
+ std::suspend_never initial_suspend() { return {}; }
+ std::suspend_never final_suspend() noexcept { return {}; }
+ void return_void() {}
+ void unhandled_exception() { std::terminate(); }
+ };
+};
+
+struct Foo {
+ Foo() {
+ std::cout << "Foo() " << (void *)this << std::endl;
+ }
+
+ ~Foo() {
+ std::cout << "~Foo() " << (void *)this << std::endl;
+ struct_Foo_destructor_counter++;
+
+ if (struct_Foo_destructor_counter > 1 || !lambda_was_executed) {
+ std::cout << "The destructor of Foo was called more than once or too early!\n";
+ __builtin_abort();
+ }
+ }
+
+ Foo(Foo&&) = delete;
+ Foo(Foo const&) = delete;
+ Foo& operator=(Foo&&) = delete;
+ Foo& operator=(Foo const&) = delete;
+};
+
+Task DoAsync() {
+ std::cout << "START TASK\n";
+ co_await [foo = Foo{}]() -> Task { // foo is constructed inplace, no copy/move is performed.
+ // foo itself must not get 'promoted'.
+ std::cout << "IN LAMBDA\n";
+ lambda_was_executed = true;
+ co_return;
+ }();
+ // After the co_await statement the temporary lambda and foo
+ // must now have been destroyed
+ if (struct_Foo_destructor_counter == 0){
+ std::cout << "foo was not destroyed after the co_await statement!\n";
+ __builtin_abort();
+ }
+ std::cout << "TASK RETURN\n";
+ co_return;
+}
+
+RunTask Main() { co_await DoAsync(); }
+
+int main() {
+ Main();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr99576_2.C b/gcc/testsuite/g++.dg/coroutines/pr99576_2.C
new file mode 100644
index 0000000..b7371d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr99576_2.C
@@ -0,0 +1,72 @@
+// { dg-do run }
+/*
+ Test that members of temporary awaitables in co_await statements do not get
+ 'promoted'. This would lead to the members destructor getting called more
+ than once.
+
+ Correct output should look like:
+ A 0x4f82d6
+ ~A 0x4f82d6
+*/
+#include <coroutine>
+#include <iostream>
+
+
+static unsigned int struct_A_destructor_counter = 0;
+
+struct task : std::coroutine_handle<> {
+ struct promise_type;
+};
+
+struct task::promise_type {
+ task get_return_object() {
+ return {std::coroutine_handle<promise_type>::from_promise(*this)};
+ }
+ std::suspend_always initial_suspend() { return {}; }
+ std::suspend_always final_suspend() noexcept { return {}; }
+ void unhandled_exception() { std::terminate(); }
+ void return_void() {}
+};
+
+struct A {
+ void log(const char *str) { std::cout << str << " " << (void *)this << std::endl; }
+
+ A() { log(__func__); }
+
+ ~A() {
+ log(__func__);
+ struct_A_destructor_counter++;
+
+ if (struct_A_destructor_counter > 1) {
+ std::cout << "The destructor of A was called more than once!\n";
+ __builtin_abort();
+ }
+ }
+
+ A(A&&) = delete;
+ A(A const&) = delete;
+ A& operator=(A&&) = delete;
+ A& operator=(A const&) = delete;
+};
+
+struct Awaitable {
+ A a{}; // <- This member must NOT get 'promoted'
+ bool await_ready() { return false; }
+ void await_suspend(std::coroutine_handle<> handle) {}
+ void await_resume() {}
+};
+
+task coroutine() {
+ co_await Awaitable{}; // <- This temporary must get 'promoted'
+}
+
+int main() {
+
+ auto task = coroutine();
+ while (!task.done()) {
+ task();
+ }
+ task.destroy();
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C
index 48281a4..383d38a 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ex1.C
@@ -87,8 +87,8 @@ struct resource {
}
};
constexpr resource f(resource d)
-{ return d; } // { dg-error "non-.constexpr." "" { target { { ! implicit_constexpr } && c++20_down } } }
-// { dg-error "non-.constexpr." "" { target c++23 } .-2 }
-constexpr resource d = f(9); // { dg-message ".constexpr." "" { target { ! implicit_constexpr } } }
+{ return d; } // { dg-error "non-.constexpr." "" { target { { { ! implicit_constexpr } && c++20_down } || c++11_only } } }
+// { dg-error "non-.constexpr." "" { target { c++23 && { ! implicit_constexpr } } } .-2 }
+constexpr resource d = f(9); // { dg-message ".constexpr." "" { target { { ! implicit_constexpr } || c++11_only } } }
// 4.4 floating-point constant expressions
diff --git a/gcc/testsuite/g++.dg/cpp1z/decomp56.C b/gcc/testsuite/g++.dg/cpp1z/decomp56.C
new file mode 100644
index 0000000..25a4c3d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/decomp56.C
@@ -0,0 +1,29 @@
+// PR c++/84469
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A {
+ template <typename T>
+ void bar () const {}
+ template <typename T>
+ void baz () const {}
+};
+struct B { A a; };
+
+template <typename>
+void
+foo ()
+{
+ A a[1][1];
+ for (auto const& [b]: a) // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ b.bar<int> ();
+ B c;
+ auto const& [d] = c; // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ d.baz<double> ();
+}
+
+int
+main ()
+{
+ foo<int> ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit10.C b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit10.C
index 48706f7..31d4b87 100644
--- a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit10.C
+++ b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit10.C
@@ -11,13 +11,13 @@ struct NonLiteral {
// C++23: It is possible to write a constexpr function for which no
// invocation satisfies the requirements of a core constant expression.
constexpr NonLiteral
-fn0 (int) // { dg-warning "invalid return type" }
+fn0 (int) // { dg-warning "invalid return type" "" { target { ! implicit_constexpr } } }
{
return NonLiteral{};
}
constexpr int
-fn1 (NonLiteral) // { dg-warning "invalid type" }
+fn1 (NonLiteral) // { dg-warning "invalid type" "" { target { ! implicit_constexpr } } }
{
return 42;
}
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit11.C b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit11.C
index a7114bc..e08809f 100644
--- a/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit11.C
+++ b/gcc/testsuite/g++.dg/cpp23/constexpr-nonlit11.C
@@ -25,10 +25,10 @@ struct X {
struct S {
X x;
// Calls a non-constexpr constructor X::X(int).
- constexpr S(int i) : x(i) { } // { dg-warning "call to" }
+ constexpr S(int i) : x(i) { } // { dg-warning "call to" "" { target { ! implicit_constexpr } } }
S(int, int) { }
// Target constructor isn't constexpr.
- constexpr S() : S(42, 42) { } // { dg-warning "call to" }
+ constexpr S() : S(42, 42) { } // { dg-warning "call to" "" { target { ! implicit_constexpr } } }
};
namespace N1 {
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires33.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires33.C
new file mode 100644
index 0000000..1ff237a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires33.C
@@ -0,0 +1,10 @@
+// PR c++/107417
+// { dg-do compile { target c++20 } }
+
+template<class... T>
+void f() requires (requires (T x) { true; } && ...);
+
+int main() {
+ f<int>();
+ f<int, void>(); // { dg-error "no match" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/spaceship-eq3.C b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq3.C
index 69eaa7b..246839f 100644
--- a/gcc/testsuite/g++.dg/cpp2a/spaceship-eq3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/spaceship-eq3.C
@@ -9,6 +9,7 @@ struct D
A i;
bool operator==(const D& x) const = default; // { dg-error "A::operator==" "" { target c++20_down } }
bool operator!=(const D& z) const = default; // { dg-error "D::operator==" "" { target c++20_down } }
+// { dg-error "called" "" { target { c++23 && implicit_constexpr } } .-1 }
};
constexpr D d{A()};
diff --git a/gcc/testsuite/g++.dg/cpp2a/using-enum-10.C b/gcc/testsuite/g++.dg/cpp2a/using-enum-10.C
new file mode 100644
index 0000000..98fe064
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/using-enum-10.C
@@ -0,0 +1,16 @@
+// PR c++/103081
+// { dg-do compile { target c++20 } }
+
+enum class Pig { OINK };
+
+struct Hog {
+ using enum Pig;
+ Hog(Pig) { }
+};
+
+template<int>
+void pen() {
+ Hog(Hog::OINK);
+}
+
+template void pen<0>();
diff --git a/gcc/testsuite/g++.dg/cpp2a/using-enum-10a.C b/gcc/testsuite/g++.dg/cpp2a/using-enum-10a.C
new file mode 100644
index 0000000..daa3221
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/using-enum-10a.C
@@ -0,0 +1,19 @@
+// A version of using-enum-10.C where Hog is a template.
+// PR c++/103081
+// { dg-do compile { target c++20 } }
+
+enum class Pig { OINK };
+
+template<int>
+struct Hog {
+ using enum Pig;
+ Hog(Pig) { OINK; }
+};
+
+template<int N>
+void pen() {
+ Hog<1>(Hog<1>::OINK);
+ Hog<N>(Hog<N>::OINK);
+}
+
+template void pen<0>();
diff --git a/gcc/testsuite/g++.dg/diagnostic/return-type-loc1.C b/gcc/testsuite/g++.dg/diagnostic/return-type-loc1.C
new file mode 100644
index 0000000..f96179e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/return-type-loc1.C
@@ -0,0 +1,20 @@
+// { dg-do compile { target c++11 } }
+// { dg-additional-options -Waggregate-return }
+
+struct B { int i,j; };
+
+template <class T>
+struct A
+{
+ template <class U>
+ U // { dg-warning "aggregate" }
+ f() { return {}; }
+};
+
+int main()
+{
+ A<int>().f<B>(); // { dg-warning "aggregate" }
+}
+
+B // { dg-warning "aggregate" }
+g() { return {}; }
diff --git a/gcc/testsuite/g++.dg/gomp/for-21.C b/gcc/testsuite/g++.dg/gomp/for-21.C
index fbdaa71..f5a7bf7 100644
--- a/gcc/testsuite/g++.dg/gomp/for-21.C
+++ b/gcc/testsuite/g++.dg/gomp/for-21.C
@@ -24,9 +24,9 @@ void
f3 (S (&a)[10])
{
#pragma omp for collapse (2)
- for (auto [i, j, k] : a) // { dg-error "use of 'i' before deduction of 'auto'" "" { target *-*-* } .+1 }
- for (int l = i; l < j; l += k) // { dg-error "use of 'j' before deduction of 'auto'" }
- ; // { dg-error "use of 'k' before deduction of 'auto'" "" { target *-*-* } .-1 }
+ for (auto [i, j, k] : a) // { dg-error "initializer expression refers to iteration variable 'i'" }
+ for (int l = i; l < j; l += k) // { dg-error "condition expression refers to iteration variable 'j'" }
+ ; // { dg-error "increment expression refers to iteration variable 'k'" "" { target *-*-* } .-2 }
}
template <int N>
@@ -54,9 +54,9 @@ void
f6 (S (&a)[10])
{
#pragma omp for collapse (2)
- for (auto [i, j, k] : a) // { dg-error "use of 'i' before deduction of 'auto'" "" { target *-*-* } .-1 }
- for (int l = i; l < j; l += k) // { dg-error "use of 'j' before deduction of 'auto'" }
- ; // { dg-error "use of 'k' before deduction of 'auto'" "" { target *-*-* } .-3 }
+ for (auto [i, j, k] : a) // { dg-error "initializer expression refers to iteration variable 'i'" "" { target *-*-* } .-1 }
+ for (int l = i; l < j; l += k) // { dg-error "condition expression refers to iteration variable 'j'" }
+ ; // { dg-error "increment expression refers to iteration variable 'k'" "" { target *-*-* } .-3 }
}
template <typename T>
@@ -84,9 +84,9 @@ void
f9 (U (&a)[10])
{
#pragma omp for collapse (2)
- for (auto [i, j, k] : a) // { dg-error "use of 'i' before deduction of 'auto'" "" { target *-*-* } .-1 }
- for (T l = i; l < j; l += k) // { dg-error "use of 'j' before deduction of 'auto'" }
- ; // { dg-error "use of 'k' before deduction of 'auto'" "" { target *-*-* } .-3 }
+ for (auto [i, j, k] : a) // { dg-error "initializer expression refers to iteration variable 'i'" "" { target *-*-* } .-1 }
+ for (T l = i; l < j; l += k) // { dg-error "condition expression refers to iteration variable 'j'" }
+ ; // { dg-error "increment expression refers to iteration variable 'k'" "" { target *-*-* } .-3 }
}
void
diff --git a/gcc/testsuite/g++.dg/gomp/for-22.C b/gcc/testsuite/g++.dg/gomp/for-22.C
new file mode 100644
index 0000000..40802a0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/for-22.C
@@ -0,0 +1,57 @@
+// { dg-do compile { target c++17 } }
+
+namespace std {
+ template<typename T> struct tuple_size;
+ template<int, typename> struct tuple_element;
+}
+
+struct A {
+ int i;
+ template <int I> int& get() { return i; }
+};
+
+template<> struct std::tuple_size<A> { static const int value = 3; };
+template<int I> struct std::tuple_element<I,A> { using type = int; };
+
+struct B {
+ A *begin();
+ A *end();
+};
+
+void
+f1 (B a)
+{
+ #pragma omp for collapse (2)
+ for (auto [i, j, k] : a) // { dg-error "initializer expression refers to iteration variable 'i'" "" { target *-*-* } .+1 }
+ for (int l = i; l < j; l += k) // { dg-error "condition expression refers to iteration variable 'j'" }
+ ; // { dg-error "increment expression refers to iteration variable 'k'" "" { target *-*-* } .-1 }
+}
+
+template <int N>
+void
+f2 (B a)
+{
+ #pragma omp for collapse (2)
+ for (auto [i, j, k] : a) // { dg-error "initializer expression refers to iteration variable 'i'" "" { target *-*-* } .-1 }
+ for (int l = i; l < j; l += k) // { dg-error "condition expression refers to iteration variable 'j'" }
+ ; // { dg-error "increment expression refers to iteration variable 'k'" "" { target *-*-* } .-3 }
+}
+
+template <typename T>
+void
+f3 (T a)
+{
+ #pragma omp for collapse (2)
+ for (auto [i, j, k] : a) // { dg-error "initializer expression refers to iteration variable 'i'" "" { target *-*-* } .-1 }
+ for (int l = i; l < j; l += k) // { dg-error "condition expression refers to iteration variable 'j'" }
+ ; // { dg-error "increment expression refers to iteration variable 'k'" "" { target *-*-* } .-3 }
+}
+
+void
+test ()
+{
+ B b;
+ f1 (b);
+ f2 <0> (b);
+ f3 <B> (b);
+}
diff --git a/gcc/testsuite/g++.dg/gomp/pr84469.C b/gcc/testsuite/g++.dg/gomp/pr84469.C
new file mode 100644
index 0000000..973debf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/pr84469.C
@@ -0,0 +1,24 @@
+// PR c++/84469
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct A {
+ template <typename T>
+ void bar () const {}
+};
+
+template <typename>
+void
+foo ()
+{
+ A a[1][1];
+ #pragma omp for
+ for (auto const& [b]: a) // { dg-warning "structured bindings only available with" "" { target c++14_down } }
+ b.bar<int> ();
+}
+
+int
+main ()
+{
+ foo<int> ();
+}
diff --git a/gcc/testsuite/g++.dg/gomp/target-teams-1.C b/gcc/testsuite/g++.dg/gomp/target-teams-1.C
index f78a608..29e5597 100644
--- a/gcc/testsuite/g++.dg/gomp/target-teams-1.C
+++ b/gcc/testsuite/g++.dg/gomp/target-teams-1.C
@@ -88,5 +88,5 @@ foo (int a, int b, long c, long d)
/* { dg-final { scan-tree-dump-times "thread_limit\\(-1\\)" 3 "gimple" } } */
/* { dg-final { scan-tree-dump-times "num_teams\\(0\\)" 4 "gimple" } } */
/* { dg-final { scan-tree-dump-times "thread_limit\\(0\\)" 6 "gimple" } } */
-/* { dg-final { scan-tree-dump-times "num_teams\\(1\\)" 2 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "num_teams\\(-2\\)" 2 "gimple" } } */
/* { dg-final { scan-tree-dump-times "thread_limit\\(1\\)" 0 "gimple" } } */
diff --git a/gcc/testsuite/g++.dg/template/canon-type-19.C b/gcc/testsuite/g++.dg/template/canon-type-19.C
new file mode 100644
index 0000000..27ef3f1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/canon-type-19.C
@@ -0,0 +1,18 @@
+// PR c++/107539
+// { dg-do compile { target c++11 } }
+
+template<class T>
+struct A { };
+
+template<template<class> class C>
+struct B {
+ template<class T>
+ void f(T t) {
+ A<C<decltype(t)>> a1;
+ }
+
+ template<class T>
+ void g(T t) {
+ A<C<decltype(t)>> a2;
+ }
+};
diff --git a/gcc/testsuite/g++.dg/warn/Warray-bounds-pr104165-1.C b/gcc/testsuite/g++.dg/warn/Warray-bounds-pr104165-1.C
new file mode 100644
index 0000000..bc46285
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Warray-bounds-pr104165-1.C
@@ -0,0 +1,27 @@
+// { dg-do compile }
+// { dg-require-effective-target c++11 }
+// { dg-options "-O2 -Warray-bounds" }
+
+#include <algorithm>
+
+static int bar(int n, int l)
+{
+ int f[l];
+ int x = 0;
+ int r = n;
+
+ for (; x < l;)
+ if (r)
+ x = l;
+ else
+ r = 1;
+
+ if (r == 1)
+ std::sort(f, f + x, [](int a, int b) { return a > b; });
+ return 1;
+}
+
+int foo(int n)
+{
+ return bar(n, 4);
+}
diff --git a/gcc/testsuite/g++.target/aarch64/sve/pr107920.C b/gcc/testsuite/g++.target/aarch64/sve/pr107920.C
new file mode 100644
index 0000000..179b2b6
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve/pr107920.C
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fnon-call-exceptions" } */
+
+#include "arm_sve.h"
+
+svint8_t
+test_s8(int8_t *x)
+{
+ try
+ {
+ return svld1rq_s8 (svptrue_b8 (), &x[0]);
+ }
+ catch (...)
+ {
+ return svdup_s8 (1);
+ }
+}
+
+/* { dg-final { scan-assembler "__cxa_begin_catch" } } */
diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-6.x b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-6.x
index e7c051d..6655a07 100644
--- a/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-6.x
+++ b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-6.x
@@ -1,3 +1,4 @@
+lappend additional_flags "-fno-trapping-math"
# The ARM VxWorks kernel uses an external floating-point library in
# which routines like __ledf2 are just aliases for __cmpdf2. These
# routines therefore don't handle NaNs correctly.
diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-9.c b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-9.c
new file mode 100644
index 0000000..7172634
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-9.c
@@ -0,0 +1,31 @@
+
+const double dnan = 1.0/0.0 - 1.0/0.0;
+double x = 1.0;
+
+extern void link_error (void);
+extern void abort (void);
+
+main ()
+{
+#if ! defined (__vax__) && ! defined (_CRAY)
+ /* NaN is an IEEE unordered operand. All these test should be false. */
+ if (dnan == dnan)
+ link_error ();
+ if (dnan != x)
+ x = 1.0;
+ else
+ link_error ();
+
+ if (dnan == x)
+ link_error ();
+#endif
+ exit (0);
+}
+
+#ifndef __OPTIMIZE__
+void link_error (void)
+{
+ abort ();
+}
+#endif
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-9.x b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-9.x
new file mode 100644
index 0000000..e7c051d
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/ieee/fp-cmp-9.x
@@ -0,0 +1,16 @@
+# The ARM VxWorks kernel uses an external floating-point library in
+# which routines like __ledf2 are just aliases for __cmpdf2. These
+# routines therefore don't handle NaNs correctly.
+if [istarget "arm*-*-vxworks*"] {
+ set torture_eval_before_execute {
+ global compiler_conditional_xfail_data
+ set compiler_conditional_xfail_data {
+ "The ARM kernel uses a flawed floating-point library."
+ { "*-*-*" }
+ { "-O0" }
+ { "-mrtp" }
+ }
+ }
+}
+
+return 0
diff --git a/gcc/testsuite/gcc.c-torture/execute/ieee/ieee.exp b/gcc/testsuite/gcc.c-torture/execute/ieee/ieee.exp
index 6d3c371..fda34a7 100644
--- a/gcc/testsuite/gcc.c-torture/execute/ieee/ieee.exp
+++ b/gcc/testsuite/gcc.c-torture/execute/ieee/ieee.exp
@@ -52,6 +52,9 @@ if { [istarget "alpha*-*-*"]
|| [istarget "sh*-*-*"] } then {
lappend additional_flags "-mieee"
}
+if [istarget rx-*-*] then {
+ lappend additional_flags "-mnofpu"
+}
if { ![check_effective_target_signal] } {
lappend additional_flags "-DSIGNAL_SUPPRESS"
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr107879.c b/gcc/testsuite/gcc.c-torture/execute/pr107879.c
new file mode 100644
index 0000000..2aabe8e
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr107879.c
@@ -0,0 +1,25 @@
+/* PR tree-optimization/107879 */
+
+__attribute__((noipa)) static double
+foo (double *y)
+{
+ volatile int ph = 0;
+ volatile double vf = 1.0;
+ double factor = vf;
+ double x = - (double) ph * factor;
+ if (x == 0)
+ *y = 1.0;
+ else
+ *y = 1.0 / x;
+ double w = 2.0 * x / factor;
+ double omww = 1 - w;
+ return omww > 0.0 ? omww : 0.0;
+}
+
+int
+main ()
+{
+ double y = 42.0;
+ if (foo (&y) != 1.0)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-11.c b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
index c9fc461..3ba2bb6 100644
--- a/gcc/testsuite/gcc.dg/Warray-bounds-11.c
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
@@ -78,7 +78,7 @@ void foo(int (*a)[3])
h->j[4] = 1; // flexible array member
h0->j[4] = 1; // zero-sized array extension
- h1->j[4] = 1; /* { dg-warning "subscript 4 is above array bound" } */
+ h1->j[4] = 1; /* { dg-bogus "subscript 4 is above array bound" } */
h3->j[4] = 1; /* { dg-warning "subscript 4 is above array bound" } */
struct h0b* h0b = malloc(sizeof(struct h) + 3 * sizeof(int));
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-1.c b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-1.c
new file mode 100644
index 0000000..d36ba4d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-1.c
@@ -0,0 +1,39 @@
+/* Test -fstrict-flex-arrays + -Warray-bounds. */
+/* { dg-do compile} */
+/* { dg-options "-O2 -fstrict-flex-arrays=1 -Warray-bounds" } */
+
+struct trailing_array_1 {
+ int a;
+ int b;
+ int c[4];
+};
+
+struct trailing_array_2 {
+ int a;
+ int b;
+ int c[1];
+};
+
+struct trailing_array_3 {
+ int a;
+ int b;
+ int c[0];
+};
+struct trailing_array_4 {
+ int a;
+ int b;
+ int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+ struct trailing_array_1 *normal,
+ struct trailing_array_2 *trailing_1,
+ struct trailing_array_3 *trailing_0,
+ struct trailing_array_4 *trailing_flex)
+{
+ normal->c[5] = 5; /*{ dg-warning "array subscript 5 is above array bounds of" } */
+ trailing_1->c[2] = 2; /* { dg-bogus "array subscript " } */
+ trailing_0->c[1] = 1; /* { dg-bogus "array subscript " } */
+ trailing_flex->c[10] = 10; /* { dg-bogus "array subscript " } */
+
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-2.c b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-2.c
new file mode 100644
index 0000000..f63206e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-2.c
@@ -0,0 +1,39 @@
+/* Test -fstrict-flex-arrays + -Warray-bounds. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2 -Warray-bounds" } */
+
+struct trailing_array_1 {
+ int a;
+ int b;
+ int c[4];
+};
+
+struct trailing_array_2 {
+ int a;
+ int b;
+ int c[1];
+};
+
+struct trailing_array_3 {
+ int a;
+ int b;
+ int c[0];
+};
+struct trailing_array_4 {
+ int a;
+ int b;
+ int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+ struct trailing_array_1 *normal,
+ struct trailing_array_2 *trailing_1,
+ struct trailing_array_3 *trailing_0,
+ struct trailing_array_4 *trailing_flex)
+{
+ normal->c[5] = 5; /*{ dg-warning "array subscript 5 is above array bounds of" } */
+ trailing_1->c[2] = 2; /* { dg-warning "array subscript 2 is above array bounds of" } */
+ trailing_0->c[1] = 1; /* { dg-bogus "array subscript " } */
+ trailing_flex->c[10] = 10; /* { dg-bogus "array subscript " } */
+
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-3.c b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-3.c
new file mode 100644
index 0000000..e327371
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-3.c
@@ -0,0 +1,39 @@
+/* Test -fstrict-flex-arrays + -Warray-bounds. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=3 -Warray-bounds" } */
+
+struct trailing_array_1 {
+ int a;
+ int b;
+ int c[4];
+};
+
+struct trailing_array_2 {
+ int a;
+ int b;
+ int c[1];
+};
+
+struct trailing_array_3 {
+ int a;
+ int b;
+ int c[0];
+};
+struct trailing_array_4 {
+ int a;
+ int b;
+ int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+ struct trailing_array_1 *normal,
+ struct trailing_array_2 *trailing_1,
+ struct trailing_array_3 *trailing_0,
+ struct trailing_array_4 *trailing_flex)
+{
+ normal->c[5] = 5; /*{ dg-warning "array subscript 5 is above array bounds of" } */
+ trailing_1->c[2] = 2; /*{ dg-warning "array subscript 2 is above array bounds of" } */
+ trailing_0->c[1] = 1; /*{ dg-warning "array subscript 1 is outside array bounds of" } */
+ trailing_flex->c[10] = 10; /* { dg-bogus "array subscript" } */
+
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-4.c b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-4.c
new file mode 100644
index 0000000..cabaea7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-4.c
@@ -0,0 +1,39 @@
+/* Test -fstrict-flex-arrays + -Warray-bounds=2. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=1 -Warray-bounds=2" } */
+
+struct trailing_array_1 {
+ int a;
+ int b;
+ int c[4];
+};
+
+struct trailing_array_2 {
+ int a;
+ int b;
+ int c[1];
+};
+
+struct trailing_array_3 {
+ int a;
+ int b;
+ int c[0];
+};
+struct trailing_array_4 {
+ int a;
+ int b;
+ int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+ struct trailing_array_1 *normal,
+ struct trailing_array_2 *trailing_1,
+ struct trailing_array_3 *trailing_0,
+ struct trailing_array_4 *trailing_flex)
+{
+ normal->c[5] = 5; /*{ dg-warning "array subscript 5 is above array bounds of" } */
+ trailing_1->c[2] = 2; /* { dg-bogus "array subscript " } */
+ trailing_0->c[1] = 1; /* { dg-bogus "array subscript " } */
+ trailing_flex->c[10] = 10; /* { dg-bogus "array subscript " } */
+
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-5.c b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-5.c
new file mode 100644
index 0000000..8b7db6e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-5.c
@@ -0,0 +1,39 @@
+/* Test -fstrict-flex-arrays + -Warray-bounds=2. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=2 -Warray-bounds=2" } */
+
+struct trailing_array_1 {
+ int a;
+ int b;
+ int c[4];
+};
+
+struct trailing_array_2 {
+ int a;
+ int b;
+ int c[1];
+};
+
+struct trailing_array_3 {
+ int a;
+ int b;
+ int c[0];
+};
+struct trailing_array_4 {
+ int a;
+ int b;
+ int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+ struct trailing_array_1 *normal,
+ struct trailing_array_2 *trailing_1,
+ struct trailing_array_3 *trailing_0,
+ struct trailing_array_4 *trailing_flex)
+{
+ normal->c[5] = 5; /*{ dg-warning "array subscript 5 is above array bounds of" } */
+ trailing_1->c[2] = 2; /*{ dg-warning "array subscript 2 is above array bounds of" } */
+ trailing_0->c[1] = 1; /* { dg-bogus "array subscript " } */
+ trailing_flex->c[10] = 10; /* { dg-bogus "array subscript " } */
+
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-6.c b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-6.c
new file mode 100644
index 0000000..035bf48
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-flex-arrays-6.c
@@ -0,0 +1,39 @@
+/* Test -fstrict-flex-arrays + -Warray-bounds=2. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstrict-flex-arrays=3 -Warray-bounds=2" } */
+
+struct trailing_array_1 {
+ int a;
+ int b;
+ int c[4];
+};
+
+struct trailing_array_2 {
+ int a;
+ int b;
+ int c[1];
+};
+
+struct trailing_array_3 {
+ int a;
+ int b;
+ int c[0];
+};
+struct trailing_array_4 {
+ int a;
+ int b;
+ int c[];
+};
+
+void __attribute__((__noinline__)) stuff(
+ struct trailing_array_1 *normal,
+ struct trailing_array_2 *trailing_1,
+ struct trailing_array_3 *trailing_0,
+ struct trailing_array_4 *trailing_flex)
+{
+ normal->c[5] = 5; /*{ dg-warning "array subscript 5 is above array bounds of" } */
+ trailing_1->c[2] = 2; /*{ dg-warning "array subscript 2 is above array bounds of" } */
+ trailing_0->c[1] = 1; /*{ dg-warning "array subscript 1 is outside array bounds of" } */
+ trailing_flex->c[10] = 10; /* { dg-bogus "array subscript " } */
+
+}
diff --git a/gcc/testsuite/gcc.dg/Wdangling-pointer-pr106868.c b/gcc/testsuite/gcc.dg/Wdangling-pointer-pr106868.c
new file mode 100644
index 0000000..f782a5e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wdangling-pointer-pr106868.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wdangling-pointer" } */
+
+void alloc(void **p);
+void false_dangling(char **p)
+{
+ {
+ void *q;
+ alloc(&q);
+ *p = q;
+ }
+ char *a = __builtin_memcpy(*p, "", 1);
+ *a = 0; /* { dg-bogus "dangling" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c
index 235c156..a56b25b 100644
--- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c
+++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-4.c
@@ -56,6 +56,6 @@ void test_5 (void)
free (ptr);
/* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc5 } */
- /* { dg-message "1 bytes" "note" { target *-*-* } malloc5 } */
+ /* { dg-message "allocated 1 byte here" "note" { target *-*-* } malloc5 } */
/* { dg-message "'struct base \\*' here; 'sizeof \\(struct base\\)' is '\\d+'" "note" { target *-*-* } malloc5 } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-1.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-1.c
new file mode 100644
index 0000000..7251665
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-1.c
@@ -0,0 +1,59 @@
+/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+
+#include <stdint.h>
+
+void test_constant_1 (void)
+{
+ int32_t *ptr = __builtin_malloc (1); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+ __builtin_free (ptr);
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_malloc (1);
+ ^~~~~~~~~~~~~~~~~~~~
+ 'test_constant_1': events 1-2
+ |
+ | int32_t *ptr = __builtin_malloc (1);
+ | ^~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 1 byte here
+ | (2) assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
+
+void test_constant_2 (void)
+{
+ int32_t *ptr = __builtin_malloc (2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+ __builtin_free (ptr);
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_malloc (2);
+ ^~~~~~~~~~~~~~~~~~~~
+ 'test_constant_2': events 1-2
+ |
+ | int32_t *ptr = __builtin_malloc (2);
+ | ^~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 2 bytes here
+ | (2) assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
+
+void test_symbolic (int n)
+{
+ int32_t *ptr = __builtin_malloc (n * 2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+ __builtin_free (ptr);
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_malloc (n * 2);
+ ^~~~~~~~~~~~~~~~~~~~~~~~
+ 'test_symbolic': event 1
+ |
+ | int32_t *ptr = __builtin_malloc (n * 2);
+ | ^~~~~~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 'n * 2' bytes and assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-2.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-2.c
new file mode 100644
index 0000000..7cadbb7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-multiline-2.c
@@ -0,0 +1,62 @@
+/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fanalyzer-fine-grained" } */
+/* { dg-require-effective-target alloca } */
+
+#include <stdint.h>
+
+void test_constant_1 (void)
+{
+ int32_t *ptr = __builtin_alloca (1); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_alloca (1);
+ ^~~~~~~~~~~~~~~~~~~~
+ 'test_constant_1': events 1-2
+ |
+ | int32_t *ptr = __builtin_alloca (1);
+ | ^~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 1 byte here
+ | (2) assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
+
+void test_constant_2 (void)
+{
+ int32_t *ptr = __builtin_alloca (2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_alloca (2);
+ ^~~~~~~~~~~~~~~~~~~~
+ 'test_constant_2': events 1-2
+ |
+ | int32_t *ptr = __builtin_alloca (2);
+ | ^~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 2 bytes here
+ | (2) assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
+
+void test_symbolic (int n)
+{
+ int32_t *ptr = __builtin_alloca (n * 2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_alloca (n * 2);
+ ^~~~~~~~~~~~~~~~~~~~~~~~
+ 'test_symbolic': events 1-2
+ |
+ | int32_t *ptr = __builtin_alloca (n * 2);
+ | ^~~~~~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 'n * 2' bytes here
+ | (2) assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
+
+/* FIXME: am getting a duplicate warning here for some reason
+ without -fanalyzer-fine-grained (PR PR analyzer/107851). */
+
diff --git a/gcc/testsuite/gcc.dg/analyzer/attr-nonnull-pr106325.c b/gcc/testsuite/gcc.dg/analyzer/attr-nonnull-pr106325.c
new file mode 100644
index 0000000..3b26471
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/attr-nonnull-pr106325.c
@@ -0,0 +1,250 @@
+typedef long int signed_frame_t;
+
+typedef struct Track Track;
+typedef struct ZRegion ZRegion;
+typedef struct AutomationTrack AutomationTrack;
+typedef struct MidiNote MidiNote;
+typedef struct ArrangerObject ArrangerObject;
+typedef struct Project Project;
+typedef struct ZRegion ZRegion;
+typedef struct Position Position;
+typedef struct Track Track;
+typedef struct ClipEditor ClipEditor;
+
+typedef enum ArrangerObjectType
+{
+ /* .... */
+ ARRANGER_OBJECT_TYPE_REGION,
+ ARRANGER_OBJECT_TYPE_MIDI_NOTE,
+ /* .... */
+} ArrangerObjectType;
+
+typedef enum ArrangerObjectPositionType
+{
+ ARRANGER_OBJECT_POSITION_TYPE_START,
+ ARRANGER_OBJECT_POSITION_TYPE_END,
+ ARRANGER_OBJECT_POSITION_TYPE_CLIP_START,
+ ARRANGER_OBJECT_POSITION_TYPE_LOOP_START,
+ ARRANGER_OBJECT_POSITION_TYPE_LOOP_END,
+ ARRANGER_OBJECT_POSITION_TYPE_FADE_IN,
+ ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT,
+} ArrangerObjectPositionType;
+
+typedef struct Position
+{
+ /* .... */
+ double ticks;
+ /* .... */
+} Position;
+
+typedef enum RegionType
+{
+ /* .... */
+ REGION_TYPE_AUTOMATION = 1 << 2,
+ /* .... */
+} RegionType;
+
+typedef struct RegionIdentifier
+{
+ /* .... */
+ RegionType type;
+ /* .... */
+ int lane_pos;
+ /* .... */
+} RegionIdentifier;
+
+typedef struct ArrangerObject
+{
+ /* .... */
+
+ ArrangerObjectType type;
+ /* .... */
+ Position pos;
+ Position end_pos;
+ Position clip_start_pos;
+
+ Position loop_start_pos;
+ Position loop_end_pos;
+
+ Position fade_in_pos;
+ Position fade_out_pos;
+
+ /* .... */
+} ArrangerObject;
+
+typedef struct ZRegion
+{
+ /* .... */
+ RegionIdentifier id;
+ /* .... */
+ int num_midi_notes;
+ /* .... */
+} ZRegion;
+
+typedef struct Zrythm
+{
+ /* ... */
+ Project *project;
+ /* ... */
+} Zrythm;
+
+typedef struct Project
+{
+ /* ... */
+
+ ClipEditor *clip_editor;
+
+ /* ... */
+} Project;
+
+extern Zrythm *zrythm;
+
+extern void g_return_if_fail_warning (const char *log_domain,
+ const char *pretty_function,
+ const char *expression);
+extern void position_add_ticks (Position *self, double ticks);
+extern _Bool
+arranger_object_is_position_valid (const ArrangerObject *const self,
+ const Position *pos,
+ ArrangerObjectPositionType pos_type);
+extern Track *arranger_object_get_track (const ArrangerObject *const self);
+extern void midi_region_insert_midi_note (ZRegion *region, MidiNote *midi_note,
+ int idx, int pub_events);
+extern ZRegion *midi_note_get_region (MidiNote *self);
+extern AutomationTrack *
+region_get_automation_track (const ZRegion *const region);
+extern void track_add_region (Track *track, ZRegion *region,
+ AutomationTrack *at, int lane_pos, int gen_name,
+ int fire_events);
+extern void clip_editor_set_region (ClipEditor *self, ZRegion *region,
+ _Bool fire_events);
+extern ZRegion *clip_editor_get_region (ClipEditor *self);
+
+static Position *
+get_position_ptr (ArrangerObject *self, ArrangerObjectPositionType pos_type)
+{
+ switch (pos_type)
+ {
+ case ARRANGER_OBJECT_POSITION_TYPE_START:
+ return &self->pos;
+ case ARRANGER_OBJECT_POSITION_TYPE_END:
+ return &self->end_pos;
+ case ARRANGER_OBJECT_POSITION_TYPE_CLIP_START:
+ return &self->clip_start_pos;
+ case ARRANGER_OBJECT_POSITION_TYPE_LOOP_START:
+ return &self->loop_start_pos;
+ case ARRANGER_OBJECT_POSITION_TYPE_LOOP_END:
+ return &self->loop_end_pos;
+ case ARRANGER_OBJECT_POSITION_TYPE_FADE_IN:
+ return &self->fade_in_pos;
+ case ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT:
+ return &self->fade_out_pos;
+ }
+ return (((void *)0));
+}
+
+void
+arranger_object_set_position (ArrangerObject *self, const Position *pos,
+ ArrangerObjectPositionType pos_type,
+ const int validate)
+{
+ if (!(self && pos))
+ {
+ g_return_if_fail_warning ("zrythm", ((const char *)(__func__)),
+ "self && pos");
+ return;
+ }
+
+ if (validate && !arranger_object_is_position_valid (self, pos, pos_type))
+ return;
+
+ Position *pos_ptr;
+ pos_ptr = get_position_ptr (self, pos_type);
+ if (!pos_ptr)
+ {
+ g_return_if_fail_warning ("zrythm", ((const char *)(__func__)),
+ "pos_ptr");
+ return;
+ }
+ *(pos_ptr) = *(pos);
+}
+
+void
+arranger_object_end_pos_setter (ArrangerObject *self, const Position *pos)
+{
+ arranger_object_set_position (self, pos, ARRANGER_OBJECT_POSITION_TYPE_END,
+ 1);
+}
+
+ArrangerObject *
+arranger_object_clone (const ArrangerObject *self)
+{
+ if (!self)
+ {
+ g_return_if_fail_warning ("zrythm", ((const char *)(__func__)), "self");
+ return (((void *)0));
+ }
+ /* .... */
+ return (((void *)0));
+}
+
+__attribute__((nonnull(1, 2)))
+void
+arranger_object_unsplit (ArrangerObject *r1, ArrangerObject *r2,
+ ArrangerObject **obj, _Bool fire_events)
+{
+ ZRegion *clip_editor_region
+ = clip_editor_get_region (((zrythm)->project->clip_editor));
+
+ _Bool set_clip_editor_region = 0;
+ if (clip_editor_region == (ZRegion *)r1
+ || clip_editor_region == (ZRegion *)r2)
+ {
+ set_clip_editor_region = 1;
+ clip_editor_set_region (((zrythm)->project->clip_editor), ((void *)0),
+ 1);
+ }
+
+ *obj = arranger_object_clone (r1);
+
+ arranger_object_end_pos_setter (*obj, &r2->end_pos);
+ Position fade_out_pos;
+ *(&fade_out_pos) = *(&r2->end_pos);
+ position_add_ticks (&fade_out_pos, -r2->pos.ticks);
+ arranger_object_set_position (*obj, &fade_out_pos,
+ ARRANGER_OBJECT_POSITION_TYPE_FADE_OUT, 0);
+
+ switch (r1->type) /* { dg-bogus "dereference of NULL 'r1'" } */
+ {
+ case ARRANGER_OBJECT_TYPE_REGION:
+ {
+ ZRegion *r1_region = (ZRegion *)r1;
+ AutomationTrack *at = ((void *)0);
+ if (r1_region->id.type == REGION_TYPE_AUTOMATION)
+ {
+ at = region_get_automation_track (r1_region);
+ }
+ track_add_region (arranger_object_get_track (r1), (ZRegion *)*obj, at,
+ ((ZRegion *)r1)->id.lane_pos, 1, fire_events);
+ }
+ break;
+ case ARRANGER_OBJECT_TYPE_MIDI_NOTE:
+ {
+ ZRegion *parent_region = midi_note_get_region (((MidiNote *)r1));
+ midi_region_insert_midi_note (
+ parent_region, (MidiNote *)*obj,
+ ((ZRegion *)(parent_region))->num_midi_notes, 1);
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch (r1->type) /* { dg-bogus "dereference of NULL 'r1'" } */
+ {
+ /* .... */
+ default:
+ break;
+ }
+ /* .... */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/attribute-nonnull.c b/gcc/testsuite/gcc.dg/analyzer/attribute-nonnull.c
index 70bb921..7c71a71 100644
--- a/gcc/testsuite/gcc.dg/analyzer/attribute-nonnull.c
+++ b/gcc/testsuite/gcc.dg/analyzer/attribute-nonnull.c
@@ -1,3 +1,5 @@
+#include "analyzer-decls.h"
+
#include <stdlib.h>
extern void foo(void *ptrA, void *ptrB, void *ptrC) /* { dg-message "argument 1 of 'foo' must be non-null" } */
@@ -81,3 +83,19 @@ void test_5 (void *q, void *r)
free(p);
}
+
+__attribute__((nonnull(1, 3)))
+void test_6 (void *p, void *q, void *r)
+{
+ __analyzer_eval (p != NULL); /* { dg-warning "TRUE" } */
+ __analyzer_eval (q != NULL); /* { dg-warning "UNKNOWN" } */
+ __analyzer_eval (r != NULL); /* { dg-warning "TRUE" } */
+}
+
+__attribute__((nonnull))
+void test_7 (void *p, void *q, void *r)
+{
+ __analyzer_eval (p != NULL); /* { dg-warning "TRUE" } */
+ __analyzer_eval (q != NULL); /* { dg-warning "TRUE" } */
+ __analyzer_eval (r != NULL); /* { dg-warning "TRUE" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c
index 953cbd3..22ca475 100644
--- a/gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c
@@ -329,7 +329,8 @@ int test_returns_element_ptr (int j)
__analyzer_eval (*returns_element_ptr (0) == 7); /* { dg-warning "TRUE" } */
__analyzer_eval (*returns_element_ptr (1) == 8); /* { dg-warning "TRUE" } */
__analyzer_eval (*returns_element_ptr (2) == 9); /* { dg-warning "TRUE" } */
- return *returns_element_ptr (3); /* { dg-warning "buffer overread" } */
+ return *returns_element_ptr (3); /* { dg-warning "buffer over-read" } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[2\\\]'" "valid subscript note" { target *-*-* } .-1 } */
}
int returns_offset (int arr[3], int i)
diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-bind-pr107928.c b/gcc/testsuite/gcc.dg/analyzer/fd-bind-pr107928.c
new file mode 100644
index 0000000..acc1a1d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/fd-bind-pr107928.c
@@ -0,0 +1,10 @@
+struct sa {};
+
+int
+bind (int, struct sa *, int);
+
+int
+foo (struct sa sa)
+{
+ return bind (1, &sa, sizeof sa);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-connect-pr107928.c b/gcc/testsuite/gcc.dg/analyzer/fd-connect-pr107928.c
new file mode 100644
index 0000000..f3bdc87
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/fd-connect-pr107928.c
@@ -0,0 +1,10 @@
+struct sa {};
+
+int
+connect (int, struct sa *, int);
+
+int
+foo (struct sa sa)
+{
+ return connect (1, &sa, sizeof sa);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c
index 841894c..89ea82e 100644
--- a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c
+++ b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-active-open.c
@@ -74,3 +74,34 @@ void test_active_open_from_connect (int fd, const char *sockname, void *buf)
close (fd);
__analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-stop'" } */
}
+
+void test_active_open_from_connect_constant (const char *sockname, void *buf)
+{
+ const int fd = 42;
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+
+ struct sockaddr_un addr;
+ memset (&addr, 0, sizeof (addr));
+ addr.sun_family = AF_UNIX;
+ strncpy (addr.sun_path, sockname, sizeof(addr.sun_path) - 1);
+
+ errno = 0;
+ if (connect (fd, (struct sockaddr *)&addr, sizeof (addr)) == -1)
+ {
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+ __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+ close (fd);
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+ return;
+ }
+
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-stop'" } */
+ __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+
+ write (fd, "hello", 6);
+ read (fd, buf, 100);
+
+ close (fd);
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-stop'" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c
index a610911..8af5290 100644
--- a/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c
+++ b/gcc/testsuite/gcc.dg/analyzer/fd-stream-socket-passive-open.c
@@ -129,6 +129,62 @@ void test_passive_open_from_bind (int fd, const char *sockname, void *buf)
__analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
}
+void test_passive_open_from_bind_constant (const char *sockname, void *buf)
+{
+ const int fd = 42;
+ struct sockaddr_un addr;
+ int afd;
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+ memset (&addr, 0, sizeof (addr));
+ addr.sun_family = AF_UNIX;
+ strncpy (addr.sun_path, sockname, sizeof(addr.sun_path) - 1);
+ errno = 0;
+ if (bind (fd, (struct sockaddr *)&addr, sizeof (addr)) == -1)
+ {
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+ __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+ close (fd);
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+ return;
+ }
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-bound-unknown-socket'" } */
+ __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+ if (listen (fd, 5) == -1)
+ {
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-bound-unknown-socket'" } */
+ __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+ close (fd);
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+ return;
+ }
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+ __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+ afd = accept (fd, NULL, NULL);
+ if (afd == -1)
+ {
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+ __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+ close (fd);
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+ return;
+ }
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+ __analyzer_dump_state ("file-descriptor", afd); /* { dg-warning "state: 'fd-connected-stream-socket'" } */
+ __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval (afd >= 0); /* { dg-warning "TRUE" } */
+
+ write (afd, "hello", 6);
+ read (afd, buf, 100);
+
+ close (afd);
+ close (fd);
+ __analyzer_dump_state ("file-descriptor", afd); /* { dg-warning "state: 'fd-closed'" } */
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+}
+
void test_passive_open_from_listen (int fd, void *buf)
{
int afd;
@@ -169,6 +225,48 @@ void test_passive_open_from_listen (int fd, void *buf)
__analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
}
+
+void test_passive_open_from_listen_constant (void *buf)
+{
+ const int fd = 42;
+ int afd;
+ errno = 0;
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+ if (listen (fd, 5) == -1)
+ {
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-constant'" } */
+ __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+ close (fd);
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+ return;
+ }
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+ __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+ afd = accept (fd, NULL, NULL);
+ if (afd == -1)
+ {
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+ __analyzer_eval (errno > 0); /* { dg-warning "TRUE" } */
+ close (fd);
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+ return;
+ }
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-listening-stream-socket'" } */
+ __analyzer_dump_state ("file-descriptor", afd); /* { dg-warning "state: 'fd-connected-stream-socket'" } */
+ __analyzer_eval (errno == 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval (fd >= 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval (afd >= 0); /* { dg-warning "TRUE" } */
+
+ write (afd, "hello", 6);
+ read (afd, buf, 100);
+
+ close (afd);
+ close (fd);
+ __analyzer_dump_state ("file-descriptor", afd); /* { dg-warning "state: 'fd-closed'" } */
+ __analyzer_dump_state ("file-descriptor", fd); /* { dg-warning "state: 'fd-closed'" } */
+}
+
void test_passive_open_from_accept (int fd, void *buf)
{
int afd;
diff --git a/gcc/testsuite/gcc.dg/analyzer/feasibility-pr107948.c b/gcc/testsuite/gcc.dg/analyzer/feasibility-pr107948.c
new file mode 100644
index 0000000..5eb8b0a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/feasibility-pr107948.c
@@ -0,0 +1,49 @@
+#include "analyzer-decls.h"
+
+void foo(int width) {
+ int i = 0;
+ int base;
+ if (width > 0){
+ __analyzer_eval(i == 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval(width > 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval(width - i > 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval(i - width <= 0); /* { dg-warning "TRUE" } */
+ if (i - width <= 0) {
+ base = 512;
+ }
+ else {
+ __analyzer_dump_path (); /* { dg-bogus "path" } */
+ }
+ base+=1; /* { dg-bogus "uninit" } */
+ }
+}
+
+void test_ge_zero (int x)
+{
+ if (x >= 0)
+ {
+ __analyzer_eval(x >= 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval(x > 0); /* { dg-warning "UNKNOWN" } */
+ __analyzer_eval(x <= 0); /* { dg-warning "UNKNOWN" } */
+ __analyzer_eval(x < 0); /* { dg-warning "FALSE" } */
+ __analyzer_eval(-x <= 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval(-x < 0); /* { dg-warning "UNKNOWN" } */
+ __analyzer_eval(-x >= 0); /* { dg-warning "UNKNOWN" } */
+ __analyzer_eval(-x > 0); /* { dg-warning "FALSE" } */
+ }
+}
+
+void test_gt_zero (int x)
+{
+ if (x > 0)
+ {
+ __analyzer_eval(x >= 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval(x > 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval(x <= 0); /* { dg-warning "FALSE" } */
+ __analyzer_eval(x < 0); /* { dg-warning "FALSE" } */
+ __analyzer_eval(-x <= 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval(-x < 0); /* { dg-warning "TRUE" } */
+ __analyzer_eval(-x >= 0); /* { dg-warning "FALSE" } */
+ __analyzer_eval(-x > 0); /* { dg-warning "FALSE" } */
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/memcpy-pr107882.c b/gcc/testsuite/gcc.dg/analyzer/memcpy-pr107882.c
new file mode 100644
index 0000000..4ecb0fd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/memcpy-pr107882.c
@@ -0,0 +1,8 @@
+void
+foo (int *x, int y)
+{
+ int *a = x, *b = (int *) &a;
+
+ __builtin_memcpy (b + 1, x, y);
+ foo (a, 0);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-1.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-1.c
index 9f3cda6..977476e 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-1.c
@@ -25,8 +25,9 @@ void test1 (void)
id_sequence[2] = 345;
id_sequence[3] = 456; /* { dg-line test1 } */
- /* { dg-warning "overflow" "warning" { target *-*-* } test1 } */
- /* { dg-message "" "note" { target *-*-* } test1 } */
+ /* { dg-warning "stack-based buffer overflow" "warning" { target *-*-* } test1 } */
+ /* { dg-message "write of 4 bytes to beyond the end of 'id_sequence'" "num bad bytes note" { target *-*-* } test1 } */
+ /* { dg-message "valid subscripts for 'id_sequence' are '\\\[0\\\]' to '\\\[2\\\]'" "valid subscript note" { target *-*-* } test1 } */
}
void test2 (void)
@@ -46,8 +47,9 @@ void test3 (void)
for (int i = n; i >= 0; i--)
arr[i] = i; /* { dg-line test3 } */
- /* { dg-warning "overflow" "warning" { target *-*-* } test3 } */
- /* { dg-message "" "note" { target *-*-* } test3 } */
+ /* { dg-warning "stack-based buffer overflow" "warning" { target *-*-* } test3 } */
+ /* { dg-message "write of 4 bytes to beyond the end of 'arr'" "num bad bytes note" { target *-*-* } test3 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[3\\\]'" "valid subscript note" { target *-*-* } test3 } */
}
void test4 (void)
@@ -72,7 +74,7 @@ void test5 (void)
*last_el = 4; /* { dg-line test5 } */
free (arr);
- /* { dg-warning "overflow" "warning" { target *-*-* } test5 } */
+ /* { dg-warning "heap-based buffer overflow" "warning" { target *-*-* } test5 } */
/* { dg-message "" "note" { target *-*-* } test5 } */
}
@@ -89,9 +91,9 @@ void test6 (void)
printf ("x=%d y=%d *p=%d *q=%d\n" , x, y, *p, *q); /* { dg-line test6c } */
}
- /* { dg-warning "overflow" "warning" { target *-*-* } test6b } */
+ /* { dg-warning "buffer overflow" "warning" { target *-*-* } test6b } */
/* { dg-message "" "note" { target *-*-* } test6b } */
- /* { dg-warning "overread" "warning" { target *-*-* } test6c } */
+ /* { dg-warning "buffer over-read" "warning" { target *-*-* } test6c } */
/* { dg-message "" "note" { target *-*-* } test6c } */
}
@@ -114,7 +116,7 @@ void test7 (void)
fn (destBuf, srcBuf, returnChunkSize (destBuf)); /* { dg-line test7 } */
// TODO: Should we handle widening_svalues as a follow-up?
- /* { dg-warning "overread" "warning" { xfail *-*-* } test7 } */
+ /* { dg-warning "over-read" "warning" { xfail *-*-* } test7 } */
/* { dg-warning "overflow" "warning" { xfail *-*-* } test7 } */
/* { dg-message "" "note" { xfail *-*-* } test7 } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-2.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-2.c
index 0df9364..1330090 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-2.c
@@ -3,7 +3,7 @@
#include <stdio.h>
#include <stdint.h>
-/* Wanalyzer-out-of-bounds tests for buffer overreads. */
+/* Wanalyzer-out-of-bounds tests for buffer over-reads. */
/* Avoid folding of memcpy. */
typedef void * (*memcpy_t) (void *dst, const void *src, size_t n);
@@ -21,8 +21,9 @@ void test1 (void)
memset (id_sequence, 0, 3 * sizeof(int));
printf ("%i", id_sequence[3]); /* { dg-line test1 } */
- /* { dg-warning "overread" "warning" { target *-*-* } test1 } */
- /* { dg-message "" "note" { target *-*-* } test1 } */
+ /* { dg-warning "stack-based buffer over-read" "warning" { target *-*-* } test1 } */
+ /* { dg-message "read of 4 bytes from after the end of 'id_sequence'" "num bad bytes note" { target *-*-* } test1 } */
+ /* { dg-message "valid subscripts for 'id_sequence' are '\\\[0\\\]' to '\\\[2\\\]'" "valid subscript note" { target *-*-* } test1 } */
}
void test2 (void)
@@ -46,7 +47,7 @@ void test3 (void)
for (int i = n; i > 0; i--)
sum += arr[i]; /* { dg-line test3 } */
- /* { dg-warning "overread" "warning" { target *-*-* } test3 } */
+ /* { dg-warning "stack-based buffer over-read" "warning" { target *-*-* } test3 } */
/* { dg-message "" "note" { target *-*-* } test3 } */
}
@@ -78,6 +79,8 @@ void test5 (void)
sum += *(arr + i); /* { dg-line test5 } */
free (arr);
- /* { dg-warning "overread" "warning" { target *-*-* } test5 } */
- /* { dg-message "" "note" { target *-*-* } test5 } */
+ /* { dg-warning "heap-based buffer over-read" "bounds warning" { target *-*-* } test5 } */
+ /* { dg-message "read of 4 bytes from after the end of the region" "num bad bytes note" { target *-*-* } test5 } */
+
+ /* { dg-warning "use of uninitialized value" "uninit warning" { target *-*-* } test5 } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-3.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-3.c
index 7446b18..5fd9cc3 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-3.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-3.c
@@ -2,7 +2,7 @@
#include <string.h>
#include <stdint.h>
-/* Wanalyzer-out-of-bounds tests for buffer underreads and writes. */
+/* Wanalyzer-out-of-bounds tests for buffer under-reads and underwrites. */
/* Avoid folding of memcpy. */
typedef void * (*memcpy_t) (void *dst, const void *src, size_t n);
@@ -19,8 +19,9 @@ void test1 (void)
int *e = buf - 1;
*e = 42; /* { dg-line test1 } */
- /* { dg-warning "underflow" "warning" { target *-*-* } test1 } */
- /* { dg-message "" "note" { target *-*-* } test1 } */
+ /* { dg-warning "stack-based buffer underwrite" "warning" { target *-*-* } test1 } */
+ /* { dg-message "out-of-bounds write from byte -4 till byte -1 but 'buf' starts at byte 0" "final event" { target *-*-* } test1 } */
+ /* { dg-message "valid subscripts for 'buf' are '\\\[0\\\]' to '\\\[3\\\]'" "valid subscript note" { target *-*-* } test1 } */
}
void test2 (void)
@@ -38,8 +39,9 @@ void test3 (void)
*e = 123;
*(e - 2) = 321; /* { dg-line test3 } */
- /* { dg-warning "underflow" "warning" { target *-*-* } test3 } */
- /* { dg-message "" "note" { target *-*-* } test3 } */
+ /* { dg-warning "stack-based buffer underwrite" "warning" { target *-*-* } test3 } */
+ /* { dg-message "out-of-bounds write from byte -4 till byte -1 but 'buf' starts at byte 0" "final event" { target *-*-* } test3 } */
+ /* { dg-message "valid subscripts for 'buf' are '\\\[0\\\]' to '\\\[3\\\]'" "valid subscript note" { target *-*-* } test3 } */
}
void test4 (void)
@@ -50,8 +52,9 @@ void test4 (void)
int n = -4;
fn (&(buf[n]), buf, sizeof (int)); /* { dg-line test4 } */
- /* { dg-warning "underflow" "warning" { target *-*-* } test4 } */
- /* { dg-message "" "note" { target *-*-* } test4 } */
+ /* { dg-warning "stack-based buffer underwrite" "warning" { target *-*-* } test4 } */
+ /* { dg-message "out-of-bounds write from byte -16 till byte -13 but 'buf' starts at byte 0" "final event" { target *-*-* } test4 } */
+ /* { dg-message "valid subscripts for 'buf' are '\\\[0\\\]' to '\\\[3\\\]'" "valid subscript note" { target *-*-* } test4 } */
}
void test5 (void)
@@ -63,8 +66,9 @@ void test5 (void)
for (int i = 4; i >= 0; i++)
sum += *(buf - i); /* { dg-line test5 } */
- /* { dg-warning "underread" "warning" { target *-*-* } test5 } */
- /* { dg-message "" "note" { target *-*-* } test5 } */
+ /* { dg-warning "stack-based buffer under-read" "warning" { target *-*-* } test5 } */
+ /* { dg-message "out-of-bounds read from byte -16 till byte -13 but 'buf' starts at byte 0" "final event" { target *-*-* } test5 } */
+ /* { dg-message "valid subscripts for 'buf' are '\\\[0\\\]' to '\\\[3\\\]'" "valid subscript note" { target *-*-* } test5 } */
}
void test6 (void)
@@ -86,6 +90,7 @@ void test8 (void)
int n = -4;
fn (buf, &(buf[n]), sizeof (int)); /* { dg-line test8 } */
- /* { dg-warning "underread" "warning" { target *-*-* } test8 } */
- /* { dg-message "" "note" { target *-*-* } test8 } */
+ /* { dg-warning "stack-based buffer under-read" "warning" { target *-*-* } test8 } */
+ /* { dg-message "out-of-bounds read from byte -16 till byte -13 but 'buf' starts at byte 0" "note" { target *-*-* } test8 } */
+ /* { dg-message "valid subscripts for 'buf' are '\\\[0\\\]' to '\\\[3\\\]'" "valid subscript note" { target *-*-* } test8 } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-4.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-4.c
index 46f600d..9cd8bda 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-4.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-4.c
@@ -11,8 +11,9 @@ void test1 (void)
char dst[5];
strcpy (dst, "Hello"); /* { dg-line test1 } */
- /* { dg-warning "overflow" "warning" { target *-*-* } test1 } */
- /* { dg-message "dst" "note" { target *-*-* } test1 } */
+ /* { dg-warning "stack-based buffer overflow" "warning" { target *-*-* } test1 } */
+ /* { dg-message "write of 1 byte to beyond the end of 'dst'" "num bad bytes note" { target *-*-* } test1 } */
+ /* { dg-message "valid subscripts for 'dst' are '\\\[0\\\]' to '\\\[4\\\]'" "valid subscript note" { target *-*-* } test1 } */
}
void test2 (void)
@@ -27,8 +28,9 @@ void test3 (void)
char dst[5];
strcpy (dst, src); /* { dg-line test3 } */
- /* { dg-warning "overflow" "warning" { target *-*-* } test3 } */
- /* { dg-message "dst" "note" { target *-*-* } test3 } */
+ /* { dg-warning "stack-based buffer overflow" "warning" { target *-*-* } test3 } */
+ /* { dg-message "write of 1 byte to beyond the end of 'dst'" "num bad bytes note" { target *-*-* } test3 } */
+ /* { dg-message "valid subscripts for 'dst' are '\\\[0\\\]' to '\\\[4\\\]'" "valid subscript note" { target *-*-* } test3 } */
}
void test4 (void)
@@ -51,8 +53,9 @@ void test5 (void)
char dst[5];
strcpy (dst, str); /* { dg-line test5 } */
- /* { dg-warning "overflow" "warning" { target *-*-* } test5 } */
- /* { dg-message "dst" "note" { target *-*-* } test5 } */
+ /* { dg-warning "stack-based buffer overflow" "warning" { target *-*-* } test5 } */
+ /* { dg-message "write of 1 byte to beyond the end of 'dst'" "num bad bytes note" { target *-*-* } test5 } */
+ /* { dg-message "valid subscripts for 'dst' are '\\\[0\\\]' to '\\\[4\\\]'" "valid subscript note" { target *-*-* } test5 } */
}
void test6 (void)
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-5.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-5.c
index 7dc0bc5..52fea79 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-5.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-5.c
@@ -13,7 +13,7 @@ void test1 (size_t size)
char *buf = __builtin_malloc (size);
if (!buf) return;
- buf[size] = '\0'; /* { dg-warning "overflow" } */
+ buf[size] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
free (buf);
}
@@ -22,7 +22,7 @@ void test2 (size_t size)
char *buf = __builtin_malloc (size);
if (!buf) return;
- buf[size + 1] = '\0'; /* { dg-warning "overflow" } */
+ buf[size + 1] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
free (buf);
}
@@ -31,33 +31,33 @@ void test3 (size_t size, size_t op)
char *buf = __builtin_malloc (size);
if (!buf) return;
- buf[size + op] = '\0'; /* { dg-warning "overflow" } */
+ buf[size + op] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
free (buf);
}
void test4 (size_t size, unsigned short s)
{
char *buf = __builtin_alloca (size);
- buf[size + s] = '\0'; /* { dg-warning "overflow" } */
+ buf[size + s] = '\0'; /* { dg-warning "stack-based buffer overflow" } */
}
void test5 (size_t size)
{
int32_t *buf = __builtin_alloca (4 * size);
- buf[size] = 42; /* { dg-warning "overflow" } */
+ buf[size] = 42; /* { dg-warning "stack-based buffer overflow" } */
}
void test6 (size_t size)
{
int32_t *buf = __builtin_alloca (4 * size);
memset (buf, 0, 4 * size);
- int32_t last = *(buf + 4 * size); /* { dg-warning "overread" } */
+ int32_t last = *(buf + 4 * size); /* { dg-warning "stack-based buffer over-read" } */
}
void test7 (size_t size)
{
int32_t *buf = __builtin_alloca (4 * size + 3); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
- buf[size] = 42; /* { dg-warning "overflow" } */
+ buf[size] = 42; /* { dg-warning "stack-based buffer overflow" } */
}
/* Test where the offset itself is not out-of-bounds
@@ -68,7 +68,7 @@ void test8 (size_t size, size_t offset)
char src[size];
char dst[size];
memcpy (dst, src, size + offset); /* { dg-line test8 } */
- /* { dg-warning "overread" "warning" { target *-*-* } test8 } */
+ /* { dg-warning "over-read" "warning" { target *-*-* } test8 } */
/* { dg-warning "overflow" "warning" { target *-*-* } test8 } */
}
@@ -77,7 +77,7 @@ void test9 (size_t size, size_t offset)
int32_t src[size];
int32_t dst[size];
memcpy (dst, src, 4 * size + 1); /* { dg-line test9 } */
- /* { dg-warning "overread" "warning" { target *-*-* } test9 } */
+ /* { dg-warning "over-read" "warning" { target *-*-* } test9 } */
/* { dg-warning "overflow" "warning" { target *-*-* } test9 } */
}
@@ -151,6 +151,6 @@ char *test99 (const char *x, const char *y)
__builtin_memcpy (result, x, len_x);
__builtin_memcpy (result + len_x, y, len_y);
/* BUG (symptom): off-by-one out-of-bounds write to heap. */
- result[len_x + len_y] = '\0'; /* { dg-warning "overflow" } */
+ result[len_x + len_y] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
return result;
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-container_of.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-container_of.c
index 172ec47..ef460f4 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-container_of.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-container_of.c
@@ -44,8 +44,8 @@ int test (struct outer *outer_p, struct inner *inner_p)
sum += o->i; /* { dg-line testB } */
return sum;
- /* { dg-warning "underread" "warning" { target *-*-* } testA } */
+ /* { dg-warning "stack-based buffer under-read" "warning" { target *-*-* } testA } */
/* { dg-message "" "note" { target *-*-* } testA } */
- /* { dg-warning "underread" "warning" { target *-*-* } testB } */
+ /* { dg-warning "stack-based buffer under-read" "warning" { target *-*-* } testB } */
/* { dg-message "" "note" { target *-*-* } testB } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-multiline-1.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-multiline-1.c
new file mode 100644
index 0000000..ca5022d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-multiline-1.c
@@ -0,0 +1,37 @@
+/* Integration test of how the execution path looks for
+ -Wanalyzer-out-of-bounds. */
+
+/* { dg-additional-options "-fdiagnostics-show-path-depths" } */
+/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+
+
+#include <stdint.h>
+
+int32_t arr[10];
+
+void int_arr_write_element_after_end_off_by_one(int32_t x)
+{
+ arr[10] = x; /* { dg-line line } */
+}
+/* { dg-warning "buffer overflow" "warning" { target *-*-* } line } */
+/* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } line } */
+
+
+/* { dg-begin-multiline-output "" }
+ arr[10] = x;
+ ~~~~~~~~^~~
+ event 1 (depth 0)
+ |
+ | int32_t arr[10];
+ | ^~~
+ | |
+ | (1) capacity: 40 bytes
+ |
+ +--> 'int_arr_write_element_after_end_off_by_one': event 2 (depth 1)
+ |
+ | arr[10] = x;
+ | ~~~~~~~~^~~
+ | |
+ | (2) out-of-bounds write from byte 40 till byte 43 but 'arr' ends at byte 40
+ |
+ { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-multiline-2.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-multiline-2.c
new file mode 100644
index 0000000..660901a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-multiline-2.c
@@ -0,0 +1,32 @@
+/* Integration test of how the execution path looks for
+ -Wanalyzer-out-of-bounds with a symbolic size. */
+
+/* { dg-additional-options "-fdiagnostics-show-path-depths" } */
+/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+void int_vla_write_element_after_end_off_by_one(int32_t x, size_t n)
+{
+ int32_t arr[n];
+
+ arr[n] = x; /* { dg-warning "stack-based buffer overflow" } */
+}
+
+/* { dg-begin-multiline-output "" }
+ arr[n] = x;
+ ~~~~~~~^~~
+ 'int_vla_write_element_after_end_off_by_one': events 1-2 (depth 1)
+ |
+ | int32_t arr[n];
+ | ^~~
+ | |
+ | (1) capacity: 'n * 4' bytes
+ |
+ | arr[n] = x;
+ | ~~~~~~~~~~
+ | |
+ | (2) write of 4 bytes at offset 'n * 4' exceeds the buffer
+ |
+ { dg-end-multiline-output "" } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-char-arr.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-char-arr.c
index 61cbfc7..fa4b613 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-char-arr.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-char-arr.c
@@ -1,55 +1,56 @@
-char arr[10]; /* { dg-message "capacity is 10 bytes" } */
+char arr[10]; /* { dg-message "capacity: 10 bytes" } */
-char int_arr_read_element_before_start_far(void)
+char char_arr_read_element_before_start_far(void)
{
- return arr[-100]; /* { dg-warning "buffer underread" "warning" } */
+ return arr[-100]; /* { dg-warning "buffer under-read" "warning" } */
/* { dg-message "out-of-bounds read at byte -100 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
-char int_arr_read_element_before_start_near(void)
+char char_arr_read_element_before_start_near(void)
{
- return arr[-2]; /* { dg-warning "buffer underread" "warning" } */
+ return arr[-2]; /* { dg-warning "buffer under-read" "warning" } */
/* { dg-message "out-of-bounds read at byte -2 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
-char int_arr_read_element_before_start_off_by_one(void)
+char char_arr_read_element_before_start_off_by_one(void)
{
- return arr[-1]; /* { dg-warning "buffer underread" "warning" } */
+ return arr[-1]; /* { dg-warning "buffer under-read" "warning" } */
/* { dg-message "out-of-bounds read at byte -1 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
-char int_arr_read_element_at_start(void)
+char char_arr_read_element_at_start(void)
{
return arr[0];
}
-char int_arr_read_element_at_end(void)
+char char_arr_read_element_at_end(void)
{
return arr[9];
}
-char int_arr_read_element_after_end_off_by_one(void)
+char char_arr_read_element_after_end_off_by_one(void)
{
- return arr[10]; /* { dg-warning "buffer overread" "warning" } */
+ return arr[10]; /* { dg-warning "buffer over-read" "warning" } */
/* { dg-message "out-of-bounds read at byte 10 but 'arr' ends at byte 10" "final event" { target *-*-* } .-1 } */
- /* { dg-message "read is 1 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
- // FIXME(PR 106626): "1 bytes"
+ /* { dg-message "read of 1 byte from after the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
-char int_arr_read_element_after_end_near(void)
+char char_arr_read_element_after_end_near(void)
{
- return arr[11]; /* { dg-warning "buffer overread" "warning" } */
+ return arr[11]; /* { dg-warning "buffer over-read" "warning" } */
/* { dg-message "out-of-bounds read at byte 11 but 'arr' ends at byte 10" "final event" { target *-*-* } .-1 } */
- /* { dg-message "read is 1 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
- // FIXME(PR 106626): is the note correct?
- // FIXME(PR 106626): "1 bytes"
+ /* { dg-message "read of 1 byte from after the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
-char int_arr_read_element_after_end_far(void)
+char char_arr_read_element_after_end_far(void)
{
- return arr[100]; /* { dg-warning "buffer overread" "warning" } */
+ return arr[100]; /* { dg-warning "buffer over-read" "warning" } */
/* { dg-message "out-of-bounds read at byte 100 but 'arr' ends at byte 10" "final event" { target *-*-* } .-1 } */
- /* { dg-message "read is 1 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
- // FIXME(PR 106626): the note seems incorrect (size of access is 1 byte, but magnitude beyond boundary is 90)
- // FIXME(PR 106626): "1 bytes"
+ /* { dg-message "read of 1 byte from after the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-int-arr.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-int-arr.c
index 0bb30d2..c04cc19 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-int-arr.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-int-arr.c
@@ -1,23 +1,26 @@
#include <stdint.h>
-int32_t arr[10]; /* { dg-message "capacity is 40 bytes" } */
+int32_t arr[10]; /* { dg-message "capacity: 40 bytes" } */
int32_t int_arr_read_element_before_start_far(void)
{
- return arr[-100]; /* { dg-warning "buffer underread" "warning" } */
+ return arr[-100]; /* { dg-warning "buffer under-read" "warning" } */
/* { dg-message "out-of-bounds read from byte -400 till byte -397 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
int32_t int_arr_read_element_before_start_near(void)
{
- return arr[-2]; /* { dg-warning "buffer underread" "warning" } */
+ return arr[-2]; /* { dg-warning "buffer under-read" "warning" } */
/* { dg-message "out-of-bounds read from byte -8 till byte -5 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
int32_t int_arr_read_element_before_start_off_by_one(void)
{
- return arr[-1]; /* { dg-warning "buffer underread" "warning" } */
+ return arr[-1]; /* { dg-warning "buffer under-read" "warning" } */
/* { dg-message "out-of-bounds read from byte -4 till byte -1 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
int32_t int_arr_read_element_at_start(void)
@@ -32,23 +35,24 @@ int32_t int_arr_read_element_at_end(void)
int32_t int_arr_read_element_after_end_off_by_one(void)
{
- return arr[10]; /* { dg-warning "buffer overread" "warning" } */
+ return arr[10]; /* { dg-warning "buffer over-read" "warning" } */
/* { dg-message "out-of-bounds read from byte 40 till byte 43 but 'arr' ends at byte 40" "final event" { target *-*-* } .-1 } */
- /* { dg-message "read is 4 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
+ /* { dg-message "read of 4 bytes from after the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
int32_t int_arr_read_element_after_end_near(void)
{
- return arr[11]; /* { dg-warning "buffer overread" "warning" } */
+ return arr[11]; /* { dg-warning "buffer over-read" "warning" } */
/* { dg-message "out-of-bounds read from byte 44 till byte 47 but 'arr' ends at byte 40" "final event" { target *-*-* } .-1 } */
- /* { dg-message "read is 4 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
- // FIXME(PR 106626): is the note correct?
+ /* { dg-message "read of 4 bytes from after the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
int32_t int_arr_read_element_after_end_far(void)
{
- return arr[100]; /* { dg-warning "buffer overread" "warning" } */
+ return arr[100]; /* { dg-warning "buffer over-read" "warning" } */
/* { dg-message "out-of-bounds read from byte 400 till byte 403 but 'arr' ends at byte 40" "final event" { target *-*-* } .-1 } */
- /* { dg-message "read is 4 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
- // FIXME(PR 106626): the note seems incorrect (size of access is 4 bytes, but magnitude beyond boundary is 390-393)
+ /* { dg-message "read of 4 bytes from after the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-struct-arr.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-struct-arr.c
new file mode 100644
index 0000000..0f50bb9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-read-struct-arr.c
@@ -0,0 +1,65 @@
+#include <stdint.h>
+
+struct st
+{
+ char buf[16];
+ int32_t x;
+ int32_t y;
+};
+
+struct st arr[10];
+
+int32_t struct_arr_read_x_element_before_start_far(void)
+{
+ return arr[-100].x; /* { dg-warning "buffer under-read" "warning" } */
+ /* { dg-message "out-of-bounds read from byte -2384 till byte -2381 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
+}
+
+int32_t struct_arr_read_x_element_before_start_near(void)
+{
+ return arr[-2].x; /* { dg-warning "buffer under-read" "warning" } */
+ /* { dg-message "out-of-bounds read from byte -32 till byte -29 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
+}
+
+int32_t struct_arr_read_x_element_before_start_off_by_one(void)
+{
+ return arr[-1].x; /* { dg-warning "buffer under-read" "warning" } */
+ /* { dg-message "out-of-bounds read from byte -8 till byte -5 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
+}
+
+int32_t struct_arr_read_x_element_at_start(void)
+{
+ return arr[0].x;
+}
+
+int32_t struct_arr_read_x_element_at_end(void)
+{
+ return arr[9].x;
+}
+
+int32_t struct_arr_read_x_element_after_end_off_by_one(void)
+{
+ return arr[10].x; /* { dg-warning "buffer over-read" "warning" } */
+ /* { dg-message "out-of-bounds read from byte 256 till byte 259 but 'arr' ends at byte 240" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "read of 4 bytes from after the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
+}
+
+int32_t struct_arr_read_x_element_after_end_near(void)
+{
+ return arr[11].x; /* { dg-warning "buffer over-read" "warning" } */
+ /* { dg-message "out-of-bounds read from byte 280 till byte 283 but 'arr' ends at byte 240" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "read of 4 bytes from after the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
+}
+
+int32_t struct_arr_read_x_element_after_end_far(void)
+{
+ return arr[100].x; /* { dg-warning "buffer over-read" "warning" } */
+ /* { dg-message "out-of-bounds read from byte 2416 till byte 2419 but 'arr' ends at byte 240" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "read of 4 bytes from after the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-char-arr.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-char-arr.c
index 47fbc52..2bc707c 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-char-arr.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-char-arr.c
@@ -1,55 +1,56 @@
-char arr[10]; /* { dg-message "capacity is 10 bytes" } */
+char arr[10]; /* { dg-message "capacity: 10 bytes" } */
-void int_arr_write_element_before_start_far(char x)
+void char_arr_write_element_before_start_far(char x)
{
- arr[-100] = x; /* { dg-warning "buffer underflow" "warning" } */
+ arr[-100] = x; /* { dg-warning "buffer underwrite" "warning" } */
/* { dg-message "out-of-bounds write at byte -100 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
-void int_arr_write_element_before_start_near(char x)
+void char_arr_write_element_before_start_near(char x)
{
- arr[-2] = x; /* { dg-warning "buffer underflow" "warning" } */
+ arr[-2] = x; /* { dg-warning "buffer underwrite" "warning" } */
/* { dg-message "out-of-bounds write at byte -2 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
-void int_arr_write_element_before_start_off_by_one(char x)
+void char_arr_write_element_before_start_off_by_one(char x)
{
- arr[-1] = x; /* { dg-warning "buffer underflow" "warning" } */
+ arr[-1] = x; /* { dg-warning "buffer underwrite" "warning" } */
/* { dg-message "out-of-bounds write at byte -1 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
-void int_arr_write_element_at_start(char x)
+void char_arr_write_element_at_start(char x)
{
arr[0] = x;
}
-void int_arr_write_element_at_end(char x)
+void char_arr_write_element_at_end(char x)
{
arr[9] = x;
}
-void int_arr_write_element_after_end_off_by_one(char x)
+void char_arr_write_element_after_end_off_by_one(char x)
{
arr[10] = x; /* { dg-warning "buffer overflow" "warning" } */
/* { dg-message "out-of-bounds write at byte 10 but 'arr' ends at byte 10" "final event" { target *-*-* } .-1 } */
- /* { dg-message "write is 1 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
- // FIXME(PR 106626): "1 bytes"
+ /* { dg-message "write of 1 byte to beyond the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
-void int_arr_write_element_after_end_near(char x)
+void char_arr_write_element_after_end_near(char x)
{
arr[11] = x; /* { dg-warning "buffer overflow" "warning" } */
/* { dg-message "out-of-bounds write at byte 11 but 'arr' ends at byte 10" "final event" { target *-*-* } .-1 } */
- /* { dg-message "write is 1 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
- // FIXME(PR 106626): is the note correct?
- // FIXME(PR 106626): "1 bytes"
+ /* { dg-message "write of 1 byte to beyond the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
-void int_arr_write_element_after_end_far(char x)
+void char_arr_write_element_after_end_far(char x)
{
arr[100] = x; /* { dg-warning "buffer overflow" "warning" } */
/* { dg-message "out-of-bounds write at byte 100 but 'arr' ends at byte 10" "final event" { target *-*-* } .-1 } */
- /* { dg-message "write is 1 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
- // FIXME(PR 106626): the note seems incorrect (size of access is 1 byte, but magnitude beyond boundary is 90)
- // FIXME(PR 106626): "1 bytes"
+ /* { dg-message "write of 1 byte to beyond the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-int-arr.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-int-arr.c
index bf9760e..c6c0435 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-int-arr.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-int-arr.c
@@ -1,23 +1,26 @@
#include <stdint.h>
-int32_t arr[10]; /* { dg-message "capacity is 40 bytes" } */
+int32_t arr[10]; /* { dg-message "capacity: 40 bytes" } */
void int_arr_write_element_before_start_far(int32_t x)
{
- arr[-100] = x; /* { dg-warning "buffer underflow" "warning" } */
+ arr[-100] = x; /* { dg-warning "buffer underwrite" "warning" } */
/* { dg-message "out-of-bounds write from byte -400 till byte -397 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
void int_arr_write_element_before_start_near(int32_t x)
{
- arr[-2] = x; /* { dg-warning "buffer underflow" "warning" } */
+ arr[-2] = x; /* { dg-warning "buffer underwrite" "warning" } */
/* { dg-message "out-of-bounds write from byte -8 till byte -5 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
void int_arr_write_element_before_start_off_by_one(int32_t x)
{
- arr[-1] = x; /* { dg-warning "buffer underflow" "warning" } */
+ arr[-1] = x; /* { dg-warning "buffer underwrite" "warning" } */
/* { dg-message "out-of-bounds write from byte -4 till byte -1 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
}
void int_arr_write_element_at_start(int32_t x)
@@ -34,21 +37,22 @@ void int_arr_write_element_after_end_off_by_one(int32_t x)
{
arr[10] = x; /* { dg-warning "buffer overflow" "warning" } */
/* { dg-message "out-of-bounds write from byte 40 till byte 43 but 'arr' ends at byte 40" "final event" { target *-*-* } .-1 } */
- /* { dg-message "write is 4 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
+ /* { dg-message "write of 4 bytes to beyond the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
void int_arr_write_element_after_end_near(int32_t x)
{
arr[11] = x; /* { dg-warning "buffer overflow" "warning" } */
/* { dg-message "out-of-bounds write from byte 44 till byte 47 but 'arr' ends at byte 40" "final event" { target *-*-* } .-1 } */
- /* { dg-message "write is 4 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
- // FIXME(PR 106626): is the note correct?
+ /* { dg-message "write of 4 bytes to beyond the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
void int_arr_write_element_after_end_far(int32_t x)
{
arr[100] = x; /* { dg-warning "buffer overflow" "warning" } */
/* { dg-message "out-of-bounds write from byte 400 till byte 403 but 'arr' ends at byte 40" "final event" { target *-*-* } .-1 } */
- /* { dg-message "write is 4 bytes past the end of 'arr'" "note" { target *-*-* } .-2 } */
- // FIXME(PR 106626): the note seems incorrect (size of access is 4 bytes, but magnitude beyond boundary is 390-393)
+ /* { dg-message "write of 4 bytes to beyond the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-struct-arr.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-struct-arr.c
new file mode 100644
index 0000000..cf6b458
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-write-struct-arr.c
@@ -0,0 +1,65 @@
+#include <stdint.h>
+
+struct st
+{
+ char buf[16];
+ int32_t x;
+ int32_t y;
+};
+
+struct st arr[10];
+
+void struct_arr_write_x_element_before_start_far(int32_t x)
+{
+ arr[-100].x = x; /* { dg-warning "buffer underwrite" "warning" } */
+ /* { dg-message "out-of-bounds write from byte -2384 till byte -2381 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
+}
+
+void struct_arr_write_x_element_before_start_near(int32_t x)
+{
+ arr[-2].x = x; /* { dg-warning "buffer underwrite" "warning" } */
+ /* { dg-message "out-of-bounds write from byte -32 till byte -29 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
+}
+
+void struct_arr_write_x_element_before_start_off_by_one(int32_t x)
+{
+ arr[-1].x = x; /* { dg-warning "buffer underwrite" "warning" } */
+ /* { dg-message "out-of-bounds write from byte -8 till byte -5 but 'arr' starts at byte 0" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-2 } */
+}
+
+void struct_arr_write_x_element_at_start(int32_t x)
+{
+ arr[0].x = x;
+}
+
+void struct_arr_write_x_element_at_end(int32_t x)
+{
+ arr[9].x = x;
+}
+
+void struct_arr_write_x_element_after_end_off_by_one(int32_t x)
+{
+ arr[10].x = x; /* { dg-warning "buffer overflow" "warning" } */
+ /* { dg-message "out-of-bounds write from byte 256 till byte 259 but 'arr' ends at byte 240" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "write of 4 bytes to beyond the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
+}
+
+void struct_arr_write_x_element_after_end_near(int32_t x)
+{
+ arr[11].x = x; /* { dg-warning "buffer overflow" "warning" } */
+ /* { dg-message "out-of-bounds write from byte 280 till byte 283 but 'arr' ends at byte 240" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "write of 4 bytes to beyond the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
+}
+
+void struct_arr_write_x_element_after_end_far(int32_t x)
+{
+ arr[100].x = x; /* { dg-warning "buffer overflow" "warning" } */
+ /* { dg-message "out-of-bounds write from byte 2416 till byte 2419 but 'arr' ends at byte 240" "final event" { target *-*-* } .-1 } */
+ /* { dg-message "write of 4 bytes to beyond the end of 'arr'" "num bad bytes note" { target *-*-* } .-2 } */
+ /* { dg-message "valid subscripts for 'arr' are '\\\[0\\\]' to '\\\[9\\\]'" "valid subscript note" { target *-*-* } .-3 } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr101962.c b/gcc/testsuite/gcc.dg/analyzer/pr101962.c
index cf0041b..08c0aba 100644
--- a/gcc/testsuite/gcc.dg/analyzer/pr101962.c
+++ b/gcc/testsuite/gcc.dg/analyzer/pr101962.c
@@ -25,7 +25,7 @@ test_1 (void)
return *a; /* { dg-line test_1 } */
/* { dg-warning "use of uninitialized value '\\*a'" "warning" { target *-*-* } test_1 } */
- /* { dg-warning "overread" "warning" { target *-*-* } test_1 } */
+ /* { dg-warning "stack-based buffer over-read" "warning" { target *-*-* } test_1 } */
}
static const char * __attribute__((noinline))
diff --git a/gcc/testsuite/gcc.dg/analyzer/realloc-5.c b/gcc/testsuite/gcc.dg/analyzer/realloc-5.c
index 2efe337..75f0b70 100644
--- a/gcc/testsuite/gcc.dg/analyzer/realloc-5.c
+++ b/gcc/testsuite/gcc.dg/analyzer/realloc-5.c
@@ -37,7 +37,7 @@ void test_1 ()
__analyzer_eval (q[8] == 1); /* { dg-line eval } */
/* { dg-warning "UNKNOWN" "warning" { target *-*-* } eval } */
- /* { dg-warning "overread" "warning" { target *-*-* } eval } */
+ /* { dg-warning "heap-based buffer over-read" "warning" { target *-*-* } eval } */
/* { dg-warning "use of uninitialized value" "warning" { target *-*-* } eval } */
}
diff --git a/gcc/testsuite/gcc.dg/analyzer/string-ops-concat-pair.c b/gcc/testsuite/gcc.dg/analyzer/string-ops-concat-pair.c
new file mode 100644
index 0000000..f5bcd67
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/string-ops-concat-pair.c
@@ -0,0 +1,67 @@
+typedef __SIZE_TYPE__ size_t;
+#define NULL ((void *)0)
+
+/* Concatenating a pair of strings. */
+
+/* Correct but poor implementation with repeated __builtin_strlen calls. */
+
+char *
+alloc_dup_of_concatenated_pair_1_correct (const char *x, const char *y)
+{
+ size_t sz = __builtin_strlen (x) + __builtin_strlen (y) + 1;
+ char *result = __builtin_malloc (sz);
+ if (!result)
+ return NULL;
+ __builtin_memcpy (result, x, __builtin_strlen (x));
+ __builtin_memcpy (result + __builtin_strlen (x), y, __builtin_strlen (y));
+ result[__builtin_strlen(x) + __builtin_strlen (y)] = '\0';
+ return result;
+}
+
+/* Incorrect version: forgetting to add space for terminator. */
+
+char *
+alloc_dup_of_concatenated_pair_1_incorrect (const char *x, const char *y)
+{
+ /* Forgetting to add space for the terminator here. */
+ size_t sz = __builtin_strlen (x) + __builtin_strlen (y);
+ char *result = __builtin_malloc (sz);
+ if (!result)
+ return NULL;
+ __builtin_memcpy (result, x, __builtin_strlen (x));
+ __builtin_memcpy (result + __builtin_strlen (x), y, __builtin_strlen (y));
+ result[__builtin_strlen(x) + __builtin_strlen (y)] = '\0'; /* { dg-warning "heap-based buffer overflow" "PR analyzer/105899" { xfail *-*-* } } */
+ return result;
+}
+
+/* As above, but only calling __builtin_strlen once on each input. */
+
+char *
+alloc_dup_of_concatenated_pair_2_correct (const char *x, const char *y)
+{
+ size_t len_x = __builtin_strlen (x);
+ size_t len_y = __builtin_strlen (y);
+ size_t sz = len_x + len_y + 1;
+ char *result = __builtin_malloc (sz);
+ if (!result)
+ return NULL;
+ __builtin_memcpy (result, x, len_x);
+ __builtin_memcpy (result + len_x, y, len_y);
+ result[len_x + len_y] = '\0';
+ return result;
+}
+
+char *
+alloc_dup_of_concatenated_pair_2_incorrect (const char *x, const char *y)
+{
+ size_t len_x = __builtin_strlen (x);
+ size_t len_y = __builtin_strlen (y);
+ size_t sz = len_x + len_y; /* Forgetting to add space for the terminator. */
+ char *result = __builtin_malloc (sz); /* { dg-message "capacity: 'len_x \\+ len_y' bytes" } */
+ if (!result)
+ return NULL;
+ __builtin_memcpy (result, x, len_x);
+ __builtin_memcpy (result + len_x, y, len_y);
+ result[len_x + len_y] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
+ return result;
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/string-ops-dup.c b/gcc/testsuite/gcc.dg/analyzer/string-ops-dup.c
new file mode 100644
index 0000000..44c4e9d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/string-ops-dup.c
@@ -0,0 +1,61 @@
+typedef __SIZE_TYPE__ size_t;
+#define NULL ((void *)0)
+
+/* Duplicating a string. */
+
+/* Correct but poor implementation with repeated __builtin_strlen calls. */
+
+char *
+alloc_dup_1_correct (const char *x)
+{
+ size_t sz = __builtin_strlen (x) + 1;
+ char *result = __builtin_malloc (sz);
+ if (!result)
+ return NULL;
+ __builtin_memcpy (result, x, __builtin_strlen (x));
+ result[__builtin_strlen(x)] = '\0';
+ return result;
+}
+
+/* Incorrect version: forgetting to add space for terminator. */
+
+char *
+alloc_dup_1_incorrect (const char *x, const char *y)
+{
+ /* Forgetting to add space for the terminator here. */
+ size_t sz = __builtin_strlen (x) + 1;
+ char *result = __builtin_malloc (sz);
+ if (!result)
+ return NULL;
+ __builtin_memcpy (result, x, __builtin_strlen (x));
+ result[__builtin_strlen(x)] = '\0'; /* { dg-warning "heap-based buffer overflow" "PR analyzer/105899" { xfail *-*-* } } */
+ return result;
+}
+
+/* As above, but only calling __builtin_strlen once. */
+
+char *
+alloc_dup_2_correct (const char *x)
+{
+ size_t len_x = __builtin_strlen (x);
+ size_t sz = len_x + 1;
+ char *result = __builtin_malloc (sz);
+ if (!result)
+ return NULL;
+ __builtin_memcpy (result, x, len_x);
+ result[len_x] = '\0';
+ return result;
+}
+
+char *
+alloc_dup_of_concatenated_pair_2_incorrect (const char *x, const char *y)
+{
+ size_t len_x = __builtin_strlen (x);
+ size_t sz = len_x; /* Forgetting to add space for the terminator. */
+ char *result = __builtin_malloc (sz); /* { dg-message "capacity: 'len_x' bytes" } */
+ if (!result)
+ return NULL;
+ __builtin_memcpy (result, x, len_x);
+ result[len_x] = '\0'; /* { dg-warning "heap-based buffer overflow" } */
+ return result;
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/zlib-3.c b/gcc/testsuite/gcc.dg/analyzer/zlib-3.c
index b05b862..def8300 100644
--- a/gcc/testsuite/gcc.dg/analyzer/zlib-3.c
+++ b/gcc/testsuite/gcc.dg/analyzer/zlib-3.c
@@ -184,7 +184,7 @@ static int huft_build(uInt *b, uInt n, uInt s, const uInt *d, const uInt *e,
mask = (1 << w) - 1;
/* The analyzer thinks that h can be -1 here.
This is probably a false positive. */
- while ((i & mask) != x[h]) { /* { dg-bogus "underread" "" { xfail *-*-* } } */
+ while ((i & mask) != x[h]) { /* { dg-bogus "under-read" "" { xfail *-*-* } } */
h--;
w -= l;
mask = (1 << w) - 1;
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c
index b424337..57bccf4 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.c
@@ -41,6 +41,7 @@
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
#include "make-unique.h"
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c
index 1435b38..de887db 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.c
@@ -41,6 +41,7 @@
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
#include "make-unique.h"
diff --git a/gcc/testsuite/gcc.dg/pr105676.c b/gcc/testsuite/gcc.dg/pr105676.c
new file mode 100644
index 0000000..077fc18
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr105676.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wsuggest-attribute=pure" } */
+
+__attribute__((const))
+extern int do_expensive_calculation(void);
+
+__attribute__((const))
+int getval(void) /* { dg-bogus "candidate for attribute" } */
+{
+ static int cache = -1;
+ if (cache == -1)
+ cache = do_expensive_calculation();
+ return cache;
+}
diff --git a/gcc/testsuite/gcc.dg/pr107937.c b/gcc/testsuite/gcc.dg/pr107937.c
new file mode 100644
index 0000000..524850b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr107937.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized" } */
+
+int _setjmp(int);
+int regs, vm_debug_engine_vp_0, vm_debug_engine_vp_2;
+
+void
+vm_dispatch_hook();
+
+
+void
+vm_debug_engine() {
+ int fp;
+ void *jump_table = &&l_nop;
+l_nop:
+ if (__builtin_expect(vm_debug_engine_vp_2, 0))
+ vm_dispatch_hook();
+ if (_setjmp(regs)) {
+ fp = fp;
+ vm_dispatch_hook();
+ goto *jump_table;
+ }
+ vm_debug_engine_vp_0 = fp;
+}
diff --git a/gcc/testsuite/gcc.dg/pr107975.c b/gcc/testsuite/gcc.dg/pr107975.c
new file mode 100644
index 0000000..7710f6f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr107975.c
@@ -0,0 +1,15 @@
+/* PR tree-optimization/107975 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-add-options ieee } */
+
+double
+foo (double x, double y)
+{
+ if (x == 42.0)
+ return 1.0;
+ double r = x * y;
+ if (!__builtin_isnan (r))
+ __builtin_unreachable ();
+ return r;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr107833.c b/gcc/testsuite/gcc.dg/torture/pr107833.c
new file mode 100644
index 0000000..0edf7c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr107833.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+
+int a, b[1] = { 0 }, c, *d = b, e, *f, g;
+
+__attribute__((noipa)) int
+foo (const char *x)
+{
+ (void) x;
+ return 0;
+}
+
+int
+main ()
+{
+ for (int h = 0; a < 2; a++)
+ {
+ int i;
+ for (g = 0; g < 2; g++)
+ if (a < h)
+ {
+ e = i % 2;
+ c = *f;
+ }
+ for (h = 0; h < 3; h++)
+ {
+ if (d)
+ break;
+ i--;
+ foo ("0");
+ }
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr107935.c b/gcc/testsuite/gcc.dg/torture/pr107935.c
new file mode 100644
index 0000000..7817510
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr107935.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+
+int *a, **b;
+int main() {
+ int d = 0, *e = &d;
+ L:
+ *e = d;
+ if (a) {
+ int *g = e = *b;
+ if (!e)
+ __builtin_abort();
+ if (**b)
+ return 0;
+ *g = 1;
+ goto L;
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/branchless-cond.c b/gcc/testsuite/gcc.dg/tree-ssa/branchless-cond.c
new file mode 100644
index 0000000..68087ae
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/branchless-cond.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+int f1(unsigned int x, unsigned int y, unsigned int z)
+{
+ return ((x & 1) == 0) ? y : z ^ y;
+}
+
+int f2(unsigned int x, unsigned int y, unsigned int z)
+{
+ return ((x & 1) != 0) ? z ^ y : y;
+}
+
+int f3(unsigned int x, unsigned int y, unsigned int z)
+{
+ return ((x & 1) == 0) ? y : z | y;
+}
+
+int f4(unsigned int x, unsigned int y, unsigned int z)
+{
+ return ((x & 1) != 0) ? z | y : y;
+}
+
+/* { dg-final { scan-tree-dump-times " -" 4 "optimized" } } */
+/* { dg-final { scan-tree-dump-times " & " 8 "optimized" } } */
+/* { dg-final { scan-tree-dump-not "if" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-18.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-18.c
index 421c78e..9ac0fc6e 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-18.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-18.c
@@ -207,6 +207,9 @@ compute_on_bytes (uint8_t *in_data, int in_len, uint8_t *out_data, int out_len)
from bb 31 to bb 33"
When -m32, Power and X86 will sink 3 instructions, but arm ilp32 couldn't
sink due to ivopts chooses two IV candidates instead of one, which is
- expected, so this case is restricted to lp64 only so far. */
+ expected, so this case is restricted to lp64 only so far. This different
+ ivopts choice affects riscv64 as well, probably because it also lacks
+ base+index addressing modes, so the ip[len] address computation can't be
+ made from the IV computation above. */
- /* { dg-final { scan-tree-dump-times "Sunk statements: 4" 1 "sink2" { target lp64 } } } */
+ /* { dg-final { scan-tree-dump-times "Sunk statements: 4" 1 "sink2" { target lp64 xfail { riscv64-*-* } } } } */
diff --git a/gcc/testsuite/gcc.dg/uninit-pr107839.c b/gcc/testsuite/gcc.dg/uninit-pr107839.c
new file mode 100644
index 0000000..c2edcfa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-pr107839.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wuninitialized" } */
+
+int f (int);
+void g (int c)
+{
+ int v;
+ if (c)
+ v = f(0);
+ while (1)
+ if (c)
+ f(v + v); /* { dg-bogus "uninitialized" } */
+}
diff --git a/gcc/testsuite/gcc.dg/uninit-pr40635.c b/gcc/testsuite/gcc.dg/uninit-pr40635.c
new file mode 100644
index 0000000..fab7c3d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-pr40635.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized" } */
+
+struct hostent {
+ char **h_addr_list;
+};
+struct hostent *gethostbyname(const char*);
+int socket(void);
+int close(int);
+int connect(int, const char*);
+
+int get_tcp_socket(const char *machine)
+{
+ struct hostent *hp;
+ int s42, x;
+ char **addr;
+
+ hp = gethostbyname(machine);
+ x = 0;
+ for (addr = hp->h_addr_list; *addr; addr++)
+ {
+ s42 = socket();
+ if (s42 < 0)
+ return -1;
+ x = connect(s42, *addr);
+ if (x == 0)
+ break;
+ close(s42);
+ }
+ if (x < 0)
+ return -1;
+ return s42; /* { dg-warning "uninitialized" } */
+}
diff --git a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
index 53c4a53..c8f427b 100644
--- a/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
+++ b/gcc/testsuite/gcc.dg/uninit-pred-9_b.c
@@ -17,7 +17,7 @@ int foo (int n, int l, int m, int r)
if (l > 100)
if ( (n <= 9) && (m < 100) && (r < 19) )
- blah(v); /* { dg-bogus "uninitialized" "bogus warning" { xfail powerpc64*-*-* cris-*-* } } */
+ blah(v); /* { dg-bogus "uninitialized" "bogus warning" { xfail powerpc64*-*-* cris-*-* riscv*-*-* } } */
if ( (n <= 8) && (m < 99) && (r < 19) )
blah(v); /* { dg-bogus "uninitialized" "pr101674" { xfail mmix-*-* } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/interleave-init-1.c b/gcc/testsuite/gcc.target/aarch64/interleave-init-1.c
new file mode 100644
index 0000000..ee77504
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/interleave-init-1.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+#include <arm_neon.h>
+
+/*
+** foo:
+** ...
+** dup v[0-9]+\.8h, w[0-9]+
+** dup v[0-9]+\.8h, w[0-9]+
+** zip1 v[0-9]+\.8h, v[0-9]+\.8h, v[0-9]+\.8h
+** ...
+** ret
+*/
+
+int16x8_t foo(int16_t x, int y)
+{
+ int16x8_t v = (int16x8_t) {x, y, x, y, x, y, x, y};
+ return v;
+}
+
+/*
+** foo2:
+** ...
+** dup v[0-9]+\.8h, w[0-9]+
+** movi v[0-9]+\.8h, 0x1
+** zip1 v[0-9]+\.8h, v[0-9]+\.8h, v[0-9]+\.8h
+** ...
+** ret
+*/
+
+int16x8_t foo2(int16_t x)
+{
+ int16x8_t v = (int16x8_t) {x, 1, x, 1, x, 1, x, 1};
+ return v;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr107920.c b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr107920.c
new file mode 100644
index 0000000..11448ed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/general/pr107920.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fno-tree-ccp -fno-tree-forwprop" } */
+
+#include "arm_sve.h"
+
+svint8_t
+test_s8(int8_t *x)
+{
+ return svld1rq_s8 (svptrue_b8 (), &x[0]);
+}
diff --git a/gcc/testsuite/gcc.target/arm/mve/pr107987.c b/gcc/testsuite/gcc.target/arm/mve/pr107987.c
new file mode 100644
index 0000000..e19a3f2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/mve/pr107987.c
@@ -0,0 +1,11 @@
+/* { dg-options "-O2" } */
+/* { dg-require-effective-target arm_v8_1m_mve_ok } */
+/* { dg-add-options arm_v8_1m_mve } */
+
+#include <arm_mve.h>
+
+uint32x4_t foo (uint32x4_t a, uint32x4_t b)
+{
+ mve_pred16_t p = vcmpneq_n_u32 (vandq_u32 (a, b), 0);
+ return vaddq_x_u32 (a, b, p);
+}
diff --git a/gcc/testsuite/gcc.target/arm/simd/mve-compare-1.c b/gcc/testsuite/gcc.target/arm/simd/mve-compare-1.c
index 029c931..887f8db 100644
--- a/gcc/testsuite/gcc.target/arm/simd/mve-compare-1.c
+++ b/gcc/testsuite/gcc.target/arm/simd/mve-compare-1.c
@@ -50,31 +50,31 @@ TEST_TYPE (vs32, __INT32_TYPE__, COMPARE_REG_AND_ZERO, 16)
TEST_TYPE (vu32, __UINT32_TYPE__, COMPARE_REG, 16)
/* { 8 bits } x { eq, ne, lt, le, gt, ge, hi, cs }.
-/* { dg-final { scan-assembler-times {\tvcmp.i8 eq, q[0-9]+, q[0-9]+\n} 4 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.i8 ne, q[0-9]+, q[0-9]+\n} 4 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s8 lt, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s8 le, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s8 gt, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s8 ge, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u8 hi, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u8 cs, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i8\teq, q[0-9]+, q[0-9]+\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i8\tne, q[0-9]+, q[0-9]+\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s8\tlt, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s8\tle, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s8\tgt, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s8\tge, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u8\thi, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u8\tcs, q[0-9]+, q[0-9]+\n} 2 } } */
/* { 16 bits } x { eq, ne, lt, le, gt, ge, hi, cs }.
-/* { dg-final { scan-assembler-times {\tvcmp.i16 eq, q[0-9]+, q[0-9]+\n} 4 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.i16 ne, q[0-9]+, q[0-9]+\n} 4 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s16 lt, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s16 le, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s16 gt, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s16 ge, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u16 hi, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u16 cs, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i16\teq, q[0-9]+, q[0-9]+\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i16\tne, q[0-9]+, q[0-9]+\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s16\tlt, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s16\tle, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s16\tgt, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s16\tge, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u16\thi, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u16\tcs, q[0-9]+, q[0-9]+\n} 2 } } */
/* { 32 bits } x { eq, ne, lt, le, gt, ge, hi, cs }.
-/* { dg-final { scan-assembler-times {\tvcmp.i32 eq, q[0-9]+, q[0-9]+\n} 4 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.i32 ne, q[0-9]+, q[0-9]+\n} 4 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s32 lt, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s32 le, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s32 gt, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s32 ge, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u32 hi, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u32 cs, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i32\teq, q[0-9]+, q[0-9]+\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i32\tne, q[0-9]+, q[0-9]+\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s32\tlt, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s32\tle, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s32\tgt, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s32\tge, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u32\thi, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u32\tcs, q[0-9]+, q[0-9]+\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/arm/simd/mve-compare-scalar-1.c b/gcc/testsuite/gcc.target/arm/simd/mve-compare-scalar-1.c
index 7774972..20ab0a2 100644
--- a/gcc/testsuite/gcc.target/arm/simd/mve-compare-scalar-1.c
+++ b/gcc/testsuite/gcc.target/arm/simd/mve-compare-scalar-1.c
@@ -39,31 +39,31 @@ TEST_TYPE (vs32, __INT32_TYPE__, 16)
TEST_TYPE (vu32, __UINT32_TYPE__, 16)
/* { 8 bits } x { eq, ne, lt, le, gt, ge, hi, cs }.
-/* { dg-final { scan-assembler-times {\tvcmp.i8 eq, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.i8 ne, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s8 lt, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s8 le, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s8 gt, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s8 ge, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u8 hi, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u8 cs, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i8\teq, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i8\tne, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s8\tlt, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s8\tle, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s8\tgt, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s8\tge, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u8\thi, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u8\tcs, q[0-9]+, q[0-9]+\n} 2 } } */
/* { 16 bits } x { eq, ne, lt, le, gt, ge, hi, cs }.
-/* { dg-final { scan-assembler-times {\tvcmp.i16 eq, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.i16 ne, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s16 lt, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s16 le, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s16 gt, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s16 ge, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u16 hi, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u16 cs, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i16\teq, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i16\tne, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s16\tlt, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s16\tle, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s16\tgt, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s16\tge, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u16\thi, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u16\tcs, q[0-9]+, q[0-9]+\n} 2 } } */
/* { 32 bits } x { eq, ne, lt, le, gt, ge, hi, cs }.
-/* { dg-final { scan-assembler-times {\tvcmp.i32 eq, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.i32 ne, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s32 lt, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s32 le, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s32 gt, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s32 ge, q[0-9]+, q[0-9]+\n} 1 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u32 hi, q[0-9]+, q[0-9]+\n} 2 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u32 cs, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i32\teq, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i32\tne, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s32\tlt, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s32\tle, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s32\tgt, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s32\tge, q[0-9]+, q[0-9]+\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u32\thi, q[0-9]+, q[0-9]+\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u32\tcs, q[0-9]+, q[0-9]+\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/arm/simd/mve-vabs.c b/gcc/testsuite/gcc.target/arm/simd/mve-vabs.c
index 64cd1c2..f2f9ee3 100644
--- a/gcc/testsuite/gcc.target/arm/simd/mve-vabs.c
+++ b/gcc/testsuite/gcc.target/arm/simd/mve-vabs.c
@@ -38,7 +38,7 @@ FUNC(f, float, 16, 8, vabs)
integer optimizations actually generate a call to memmove, the other ones a
'vabs'. */
/* { dg-final { scan-assembler-times {vabs.s[0-9]+\tq[0-9]+, q[0-9]+} 3 } } */
-/* { dg-final { scan-assembler-times {vabs.f[0-9]+ q[0-9]+, q[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {vabs.f[0-9]+\tq[0-9]+, q[0-9]+} 2 } } */
/* { dg-final { scan-assembler-times {vldr[bhw].[0-9]+\tq[0-9]+} 5 } } */
/* { dg-final { scan-assembler-times {vstr[bhw].[0-9]+\tq[0-9]+} 5 } } */
/* { dg-final { scan-assembler-times {memmove} 3 } } */
diff --git a/gcc/testsuite/gcc.target/arm/simd/mve-vadd-1.c b/gcc/testsuite/gcc.target/arm/simd/mve-vadd-1.c
index 15a9daa..f31d1cc 100644
--- a/gcc/testsuite/gcc.target/arm/simd/mve-vadd-1.c
+++ b/gcc/testsuite/gcc.target/arm/simd/mve-vadd-1.c
@@ -22,9 +22,9 @@ FUNC(u, uint, 16, 8, +, vadd)
FUNC(s, int, 8, 16, +, vadd)
FUNC(u, uint, 8, 16, +, vadd)
-/* { dg-final { scan-assembler-times {vadd\.i32 q[0-9]+, q[0-9]+, q[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {vadd\.i16 q[0-9]+, q[0-9]+, q[0-9]+} 2 } } */
-/* { dg-final { scan-assembler-times {vadd\.i8 q[0-9]+, q[0-9]+, q[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {vadd\.i32\tq[0-9]+, q[0-9]+, q[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {vadd\.i16\tq[0-9]+, q[0-9]+, q[0-9]+} 2 } } */
+/* { dg-final { scan-assembler-times {vadd\.i8\tq[0-9]+, q[0-9]+, q[0-9]+} 2 } } */
void test_vadd_f32 (float * dest, float * a, float * b) {
int i;
@@ -32,7 +32,7 @@ void test_vadd_f32 (float * dest, float * a, float * b) {
dest[i] = a[i] + b[i];
}
}
-/* { dg-final { scan-assembler-times {vadd\.f32 q[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {vadd\.f32\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
void test_vadd_f16 (__fp16 * dest, __fp16 * a, __fp16 * b) {
int i;
@@ -40,4 +40,4 @@ void test_vadd_f16 (__fp16 * dest, __fp16 * a, __fp16 * b) {
dest[i] = a[i] + b[i];
}
}
-/* { dg-final { scan-assembler-times {vadd\.f16 q[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
+/* { dg-final { scan-assembler-times {vadd\.f16\tq[0-9]+, q[0-9]+, q[0-9]+} 1 } } */
diff --git a/gcc/testsuite/gcc.target/arm/simd/mve-vadd-scalar-1.c b/gcc/testsuite/gcc.target/arm/simd/mve-vadd-scalar-1.c
index bbf70e1..7eec234 100644
--- a/gcc/testsuite/gcc.target/arm/simd/mve-vadd-scalar-1.c
+++ b/gcc/testsuite/gcc.target/arm/simd/mve-vadd-scalar-1.c
@@ -24,9 +24,9 @@ FUNC_IMM(u, uint, 8, 16, +, vaddimm)
/* For the moment we do not select the T2 vadd variant operating on a scalar
final argument. */
-/* { dg-final { scan-assembler-times {vadd\.i32 q[0-9]+, q[0-9]+, r[0-9]+} 2 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {vadd\.i16 q[0-9]+, q[0-9]+, r[0-9]+} 2 { xfail *-*-* } } } */
-/* { dg-final { scan-assembler-times {vadd\.i8 q[0-9]+, q[0-9]+, r[0-9]+} 2 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {vadd\.i32\tq[0-9]+, q[0-9]+, r[0-9]+} 2 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {vadd\.i16\tq[0-9]+, q[0-9]+, r[0-9]+} 2 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {vadd\.i8\tq[0-9]+, q[0-9]+, r[0-9]+} 2 { xfail *-*-* } } } */
void test_vaddimm_f32 (float * dest, float * a) {
int i;
@@ -34,7 +34,7 @@ void test_vaddimm_f32 (float * dest, float * a) {
dest[i] = a[i] + 5.0;
}
}
-/* { dg-final { scan-assembler-times {vadd\.f32 q[0-9]+, q[0-9]+, r[0-9]+} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {vadd\.f32\tq[0-9]+, q[0-9]+, r[0-9]+} 1 { xfail *-*-* } } } */
/* Note that dest[i] = a[i] + 5.0f16 is not vectorized. */
void test_vaddimm_f16 (__fp16 * dest, __fp16 * a) {
@@ -44,4 +44,4 @@ void test_vaddimm_f16 (__fp16 * dest, __fp16 * a) {
dest[i] = a[i] + b;
}
}
-/* { dg-final { scan-assembler-times {vadd\.f16 q[0-9]+, q[0-9]+, r[0-9]+} 1 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times {vadd\.f16\tq[0-9]+, q[0-9]+, r[0-9]+} 1 { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.target/arm/simd/mve-vcmp.c b/gcc/testsuite/gcc.target/arm/simd/mve-vcmp.c
index 8da15e7..806b145 100644
--- a/gcc/testsuite/gcc.target/arm/simd/mve-vcmp.c
+++ b/gcc/testsuite/gcc.target/arm/simd/mve-vcmp.c
@@ -36,15 +36,15 @@ ALL_FUNCS(>=, vcmpge)
/* MVE has only 128-bit vectors, so we can vectorize only half of the
functions above. */
-/* { dg-final { scan-assembler-times {\tvcmp.i[0-9]+ eq, q[0-9]+, q[0-9]+\n} 6 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.i[0-9]+ ne, q[0-9]+, q[0-9]+\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i[0-9]+\teq, q[0-9]+, q[0-9]+\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.i[0-9]+\tne, q[0-9]+, q[0-9]+\n} 6 } } */
/* lt, le, gt, ge apply to signed types, cs and hi to unsigned types. */
/* lt and le with unsigned types are replaced with the opposite condition, hence
the double number of matches for cs and hi. */
-/* { dg-final { scan-assembler-times {\tvcmp.s[0-9]+ lt, q[0-9]+, q[0-9]+\n} 3 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s[0-9]+ le, q[0-9]+, q[0-9]+\n} 3 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s[0-9]+ gt, q[0-9]+, q[0-9]+\n} 3 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.s[0-9]+ ge, q[0-9]+, q[0-9]+\n} 3 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u[0-9]+ cs, q[0-9]+, q[0-9]+\n} 6 } } */
-/* { dg-final { scan-assembler-times {\tvcmp.u[0-9]+ hi, q[0-9]+, q[0-9]+\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s[0-9]+\tlt, q[0-9]+, q[0-9]+\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s[0-9]+\tle, q[0-9]+, q[0-9]+\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s[0-9]+\tgt, q[0-9]+, q[0-9]+\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.s[0-9]+\tge, q[0-9]+, q[0-9]+\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u[0-9]+\tcs, q[0-9]+, q[0-9]+\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tvcmp.u[0-9]+\thi, q[0-9]+, q[0-9]+\n} 6 } } */
diff --git a/gcc/testsuite/gcc.target/arm/simd/pr101325.c b/gcc/testsuite/gcc.target/arm/simd/pr101325.c
index 4cb2513..ce9ce3a 100644
--- a/gcc/testsuite/gcc.target/arm/simd/pr101325.c
+++ b/gcc/testsuite/gcc.target/arm/simd/pr101325.c
@@ -9,6 +9,6 @@ unsigned foo(int8x16_t v, int8x16_t w)
{
return vcmpeqq (v, w);
}
-/* { dg-final { scan-assembler {\tvcmp.i8 eq} } } */
-/* { dg-final { scan-assembler {\tvmrs\tr[0-9]+, P0} } } */
+/* { dg-final { scan-assembler {\tvcmp.i8\teq} } } */
+/* { dg-final { scan-assembler {\tvmrs\tr[0-9]+, p0} } } */
/* { dg-final { scan-assembler {\tuxth} } } */
diff --git a/gcc/testsuite/gcc.target/i386/cbranchbf4.c b/gcc/testsuite/gcc.target/i386/cbranchbf4.c
new file mode 100644
index 0000000..8241a0c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cbranchbf4.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-fexcess-precision=16 -O -msse2 -mfpmath=sse" } */
+/* { dg-final { scan-assembler-times "pslld" 4 } } */
+
+char
+foo (__bf16 a, __bf16 b)
+{
+ return a > b;
+}
+
+float
+foo1 (__bf16 a, __bf16 b, float c, float d)
+{
+ return a > b ? c : d;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr106577.c b/gcc/testsuite/gcc.target/i386/pr106577.c
new file mode 100644
index 0000000..1182d4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr106577.c
@@ -0,0 +1,10 @@
+/* PR target/106577 */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O2 -mavx" } */
+
+int i;
+void
+foo (void)
+{
+ i ^= !(((unsigned __int128)0xf0f0f0f0f0f0f0f0 << 64 | 0xf0f0f0f0f0f0f0f0) & i);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr107627-1.c b/gcc/testsuite/gcc.target/i386/pr107627-1.c
new file mode 100644
index 0000000..60ec87b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr107627-1.c
@@ -0,0 +1,22 @@
+/* PR target/107627 */
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-final { scan-assembler-not "\torq\t" } } */
+
+static inline unsigned __int128
+foo (unsigned long long x, unsigned long long y)
+{
+ return ((unsigned __int128) x << 64) | y;
+}
+
+static inline unsigned long long
+bar (unsigned long long x, unsigned long long y, unsigned z)
+{
+ return foo (x, y) >> (z % 64);
+}
+
+void
+baz (unsigned long long *x, const unsigned long long *y, unsigned z)
+{
+ x[0] = bar (y[0], y[1], z);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr107627-2.c b/gcc/testsuite/gcc.target/i386/pr107627-2.c
new file mode 100644
index 0000000..7f96613
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr107627-2.c
@@ -0,0 +1,22 @@
+/* PR target/107627 */
+/* { dg-do compile { target ia32 } } */
+/* { dg-options "-O2 -masm=att" } */
+/* { dg-final { scan-assembler-not "\torl\t" } } */
+
+static inline unsigned long long
+qux (unsigned int x, unsigned int y)
+{
+ return ((unsigned long long) x << 32) | y;
+}
+
+static inline unsigned int
+corge (unsigned int x, unsigned int y, unsigned z)
+{
+ return qux (x, y) >> (z % 32);
+}
+
+void
+garply (unsigned int *x, const unsigned int *y, unsigned z)
+{
+ x[0] = corge (y[0], y[1], z);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr107863.c b/gcc/testsuite/gcc.target/i386/pr107863.c
new file mode 100644
index 0000000..99fd85d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr107863.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-mavx2 -O" } */
+
+typedef char v16qi __attribute__((vector_size(16)));
+
+v16qi foo(v16qi a){
+ return __builtin_ia32_vec_set_v16qi (a, -1, 2);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr107934.c b/gcc/testsuite/gcc.target/i386/pr107934.c
new file mode 100644
index 0000000..59106b29
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr107934.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=knl -ffinite-math-only -msse2" } */
+
+int
+foo (__bf16 bf)
+{
+ return bf;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr107969.c b/gcc/testsuite/gcc.target/i386/pr107969.c
new file mode 100644
index 0000000..f73a862
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr107969.c
@@ -0,0 +1,12 @@
+/* PR target/107969 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fexcess-precision=16 -msoft-float -msse2" } */
+
+int i;
+__bf16 f;
+
+void
+bar (void)
+{
+ i *= 0 <= f;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr107970.c b/gcc/testsuite/gcc.target/i386/pr107970.c
new file mode 100644
index 0000000..1fbbb14
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr107970.c
@@ -0,0 +1,10 @@
+/* { dg-do compile { target ia32 } } */
+/* { dg-options "-Ofast -m3dnow -msse4.1" } */
+
+float *foo_p;
+
+void
+foo(float *__restrict q) {
+ foo_p[0] = __builtin_truncf(q[0]);
+ foo_p[1] = __builtin_truncf(q[1]);
+}
diff --git a/gcc/testsuite/gcc.target/mips/pr106462.c b/gcc/testsuite/gcc.target/mips/pr106462.c
new file mode 100644
index 0000000..c910540
--- /dev/null
+++ b/gcc/testsuite/gcc.target/mips/pr106462.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=64 -msingle-float" } */
+
+extern void bar (float x, short y);
+
+void foo (int argc)
+{
+ short c = argc * 2;
+ float a = (float)(short)c, b = 9.5;
+
+ bar (b/a, c);
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/pr100866-1.c b/gcc/testsuite/gcc.target/powerpc/pr100866-1.c
new file mode 100644
index 0000000..63872f2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr100866-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-O2 -mdejagnu-cpu=power8" } */
+/* { dg-final { scan-assembler-not {\mxxlnor\M} } } */
+
+#include <altivec.h>
+
+vector unsigned int revb (vector unsigned int a)
+{
+ return vec_revb(a);
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/dup-1.c b/gcc/testsuite/gcc.target/riscv/rvv/base/dup-1.c
new file mode 100644
index 0000000..2a83afa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/dup-1.c
@@ -0,0 +1,521 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -O3 -fgimple" } */
+
+#include "riscv_vector.h"
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f1 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint8mf8_t> ((vint8mf8_t *)out_2(D)) = _Literal (vint8mf8_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f2 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint8mf4_t> ((vint8mf4_t *)out_2(D)) = _Literal (vint8mf4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f3 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint8mf2_t> ((vint8mf2_t *)out_2(D)) = _Literal (vint8mf2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f4 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint8m1_t> ((vint8m1_t *)out_2(D)) = _Literal (vint8m1_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f5 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint8m2_t> ((vint8m2_t *)out_2(D)) = _Literal (vint8m2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f6 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint8m4_t> ((vint8m4_t *)out_2(D)) = _Literal (vint8m4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f7 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint8m8_t> ((vint8m8_t *)out_2(D)) = _Literal (vint8m8_t) 0;
+ return;
+
+}
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f8 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint8mf8_t> ((vuint8mf8_t *)out_2(D)) = _Literal (vuint8mf8_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f9 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint8mf4_t> ((vuint8mf4_t *)out_2(D)) = _Literal (vuint8mf4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f10 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint8mf2_t> ((vuint8mf2_t *)out_2(D)) = _Literal (vuint8mf2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f11 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint8m1_t> ((vuint8m1_t *)out_2(D)) = _Literal (vuint8m1_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f12 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint8m2_t> ((vuint8m2_t *)out_2(D)) = _Literal (vuint8m2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f13 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint8m4_t> ((vuint8m4_t *)out_2(D)) = _Literal (vuint8m4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f14 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint8m8_t> ((vuint8m8_t *)out_2(D)) = _Literal (vuint8m8_t) 0;
+ return;
+
+}
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f15 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint16mf4_t> ((vint16mf4_t *)out_2(D)) = _Literal (vint16mf4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f16 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint16mf2_t> ((vint16mf2_t *)out_2(D)) = _Literal (vint16mf2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f17 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint16m1_t> ((vint16m1_t *)out_2(D)) = _Literal (vint16m1_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f18 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint16m2_t> ((vint16m2_t *)out_2(D)) = _Literal (vint16m2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f19 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint16m4_t> ((vint16m4_t *)out_2(D)) = _Literal (vint16m4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f20 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint16m8_t> ((vint16m8_t *)out_2(D)) = _Literal (vint16m8_t) 0;
+ return;
+
+}
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f21 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint16mf4_t> ((vuint16mf4_t *)out_2(D)) = _Literal (vuint16mf4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f22 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint16mf2_t> ((vuint16mf2_t *)out_2(D)) = _Literal (vuint16mf2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f23 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint16m1_t> ((vuint16m1_t *)out_2(D)) = _Literal (vuint16m1_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f24 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint16m2_t> ((vuint16m2_t *)out_2(D)) = _Literal (vuint16m2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f25 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint16m4_t> ((vuint16m4_t *)out_2(D)) = _Literal (vuint16m4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f26 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint16m8_t> ((vuint16m8_t *)out_2(D)) = _Literal (vuint16m8_t) 0;
+ return;
+
+}
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f27 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint32mf2_t> ((vint32mf2_t *)out_2(D)) = _Literal (vint32mf2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f28 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint32m1_t> ((vint32m1_t *)out_2(D)) = _Literal (vint32m1_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f29 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint32m2_t> ((vint32m2_t *)out_2(D)) = _Literal (vint32m2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f30 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint32m4_t> ((vint32m4_t *)out_2(D)) = _Literal (vint32m4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f31 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint32m8_t> ((vint32m8_t *)out_2(D)) = _Literal (vint32m8_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f32 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint32mf2_t> ((vuint32mf2_t *)out_2(D)) = _Literal (vuint32mf2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f33 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint32m1_t> ((vuint32m1_t *)out_2(D)) = _Literal (vuint32m1_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f34 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint32m2_t> ((vuint32m2_t *)out_2(D)) = _Literal (vuint32m2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f35 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint32m4_t> ((vuint32m4_t *)out_2(D)) = _Literal (vuint32m4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f36 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint32m8_t> ((vuint32m8_t *)out_2(D)) = _Literal (vuint32m8_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f37 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint64m1_t> ((vint64m1_t *)out_2(D)) = _Literal (vint64m1_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f38 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint64m2_t> ((vint64m2_t *)out_2(D)) = _Literal (vint64m2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f39 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint64m4_t> ((vint64m4_t *)out_2(D)) = _Literal (vint64m4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f40 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vint64m8_t> ((vint64m8_t *)out_2(D)) = _Literal (vint64m8_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f41 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint64m1_t> ((vuint64m1_t *)out_2(D)) = _Literal (vuint64m1_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f42 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint64m2_t> ((vuint64m2_t *)out_2(D)) = _Literal (vuint64m2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f43 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint64m4_t> ((vuint64m4_t *)out_2(D)) = _Literal (vuint64m4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f44 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vuint64m8_t> ((vuint64m8_t *)out_2(D)) = _Literal (vuint64m8_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f45 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vfloat32m1_t> ((vfloat32m1_t *)out_2(D)) = _Literal (vfloat32m1_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f46 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vfloat32m2_t> ((vfloat32m2_t *)out_2(D)) = _Literal (vfloat32m2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f47 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vfloat32m4_t> ((vfloat32m4_t *)out_2(D)) = _Literal (vfloat32m4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f48 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vfloat32m8_t> ((vfloat32m8_t *)out_2(D)) = _Literal (vfloat32m8_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f49 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vfloat64m1_t> ((vfloat64m1_t *)out_2(D)) = _Literal (vfloat64m1_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f50 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vfloat64m2_t> ((vfloat64m2_t *)out_2(D)) = _Literal (vfloat64m2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f51 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vfloat64m4_t> ((vfloat64m4_t *)out_2(D)) = _Literal (vfloat64m4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f52 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vfloat64m8_t> ((vfloat64m8_t *)out_2(D)) = _Literal (vfloat64m8_t) 0;
+ return;
+
+}
+
+/* { dg-final { scan-assembler-times {vmv\.v\.i\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1]),\s*0} 52 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/dup-2.c b/gcc/testsuite/gcc.target/riscv/rvv/base/dup-2.c
new file mode 100644
index 0000000..c690303
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/dup-2.c
@@ -0,0 +1,75 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gcv -mabi=ilp32 -O3 -fgimple" } */
+
+#include "riscv_vector.h"
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f1 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vbool1_t> ((vbool1_t *)out_2(D)) = _Literal (vbool1_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f2 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vbool2_t> ((vbool2_t *)out_2(D)) = _Literal (vbool2_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f3 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vbool4_t> ((vbool4_t *)out_2(D)) = _Literal (vbool4_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f4 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vbool8_t> ((vbool8_t *)out_2(D)) = _Literal (vbool8_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f5 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vbool16_t> ((vbool16_t *)out_2(D)) = _Literal (vbool16_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f6 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vbool32_t> ((vbool32_t *)out_2(D)) = _Literal (vbool32_t) 0;
+ return;
+
+}
+
+
+void __GIMPLE (ssa,guessed_local(1073741824))
+f7 (void * out)
+{
+ __BB(2,guessed_local(1073741824)):
+ __MEM <vbool64_t> ((vbool64_t *)out_2(D)) = _Literal (vbool64_t) 0;
+ return;
+
+}
+
+/* { dg-final { scan-assembler-times {vmclr\.m\s+(?:v[0-9]|v[1-2][0-9]|v3[0-1])} 7 } } */
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/bf16/abi-bf16.exp b/gcc/testsuite/gcc.target/x86_64/abi/bf16/abi-bf16.exp
index bd386f2..8edab85 100644
--- a/gcc/testsuite/gcc.target/x86_64/abi/bf16/abi-bf16.exp
+++ b/gcc/testsuite/gcc.target/x86_64/abi/bf16/abi-bf16.exp
@@ -36,9 +36,15 @@ set additional_flags "-W -Wall -msse2"
foreach src [lsort [glob -nocomplain $srcdir/$subdir/test_*.c]] {
if {[runtest_file_p $runtests $src]} {
- c-torture-execute [list $src \
- $srcdir/$subdir/asm-support.S] \
- $additional_flags
+ if { ([istarget *-*-darwin*]) } then {
+ c-torture-execute [list $src \
+ $srcdir/$subdir/asm-support-darwin.S] \
+ $additional_flags
+ } else {
+ c-torture-execute [list $src \
+ $srcdir/$subdir/asm-support.S] \
+ $additional_flags
+ }
}
}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/bf16/args.h b/gcc/testsuite/gcc.target/x86_64/abi/bf16/args.h
index 11d7e2b..95f9a39 100644
--- a/gcc/testsuite/gcc.target/x86_64/abi/bf16/args.h
+++ b/gcc/testsuite/gcc.target/x86_64/abi/bf16/args.h
@@ -42,8 +42,8 @@ typedef union {
} X87_T;
extern void (*callthis)(void);
extern unsigned long long rax,rbx,rcx,rdx,rsi,rdi,rsp,rbp,r8,r9,r10,r11,r12,r13,r14,r15;
-XMM_T xmm_regs[16];
-X87_T x87_regs[8];
+extern XMM_T xmm_regs[16];
+extern X87_T x87_regs[8];
extern volatile unsigned long long volatile_var;
extern void snapshot (void);
extern void snapshot_ret (void);
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/bf16/asm-support-darwin.S b/gcc/testsuite/gcc.target/x86_64/abi/bf16/asm-support-darwin.S
new file mode 100644
index 0000000..bdaa02f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/bf16/asm-support-darwin.S
@@ -0,0 +1,97 @@
+ .text
+ .p2align 4,,15
+ .globl _snapshot
+_snapshot:
+LFB3:
+ movq %rax, _rax(%rip)
+ movq %rbx, _rbx(%rip)
+ movq %rcx, _rcx(%rip)
+ movq %rdx, _rdx(%rip)
+ movq %rdi, _rdi(%rip)
+ movq %rsi, _rsi(%rip)
+ movq %rbp, _rbp(%rip)
+ movq %rsp, _rsp(%rip)
+ movq %r8, _r8(%rip)
+ movq %r9, _r9(%rip)
+ movq %r10, _r10(%rip)
+ movq %r11, _r11(%rip)
+ movq %r12, _r12(%rip)
+ movq %r13, _r13(%rip)
+ movq %r14, _r14(%rip)
+ movq %r15, _r15(%rip)
+ movdqu %xmm0, _xmm_regs+0(%rip)
+ movdqu %xmm1, _xmm_regs+16(%rip)
+ movdqu %xmm2, _xmm_regs+32(%rip)
+ movdqu %xmm3, _xmm_regs+48(%rip)
+ movdqu %xmm4, _xmm_regs+64(%rip)
+ movdqu %xmm5, _xmm_regs+80(%rip)
+ movdqu %xmm6, _xmm_regs+96(%rip)
+ movdqu %xmm7, _xmm_regs+112(%rip)
+ movdqu %xmm8, _xmm_regs+128(%rip)
+ movdqu %xmm9, _xmm_regs+144(%rip)
+ movdqu %xmm10, _xmm_regs+160(%rip)
+ movdqu %xmm11, _xmm_regs+176(%rip)
+ movdqu %xmm12, _xmm_regs+192(%rip)
+ movdqu %xmm13, _xmm_regs+208(%rip)
+ movdqu %xmm14, _xmm_regs+224(%rip)
+ movdqu %xmm15, _xmm_regs+240(%rip)
+ jmp *_callthis(%rip)
+LFE3:
+
+ .p2align 4,,15
+ .globl _snapshot_ret
+_snapshot_ret:
+ movq %rdi, _rdi(%rip)
+ subq $8, %rsp
+ call *_callthis(%rip)
+ addq $8, %rsp
+ movq %rax, _rax(%rip)
+ movq %rdx, _rdx(%rip)
+ movdqu %xmm0, _xmm_regs+0(%rip)
+ movdqu %xmm1, _xmm_regs+16(%rip)
+ fstpt _x87_regs(%rip)
+ fstpt _x87_regs+16(%rip)
+ fldt _x87_regs+16(%rip)
+ fldt _x87_regs(%rip)
+ ret
+
+ .globl _callthis
+ .zerofill __DATA,__bss,_callthis,8,3
+ .globl _rax
+ .zerofill __DATA,__bss,_rax,8,3
+ .globl _rbx
+ .zerofill __DATA,__bss,_rbx,8,3
+ .globl _rcx
+ .zerofill __DATA,__bss,_rcx,8,3
+ .globl _rdx
+ .zerofill __DATA,__bss,_rdx,8,3
+ .globl _rsi
+ .zerofill __DATA,__bss,_rsi,8,3
+ .globl _rdi
+ .zerofill __DATA,__bss,_rdi,8,3
+ .globl _rsp
+ .zerofill __DATA,__bss,_rsp,8,3
+ .globl _rbp
+ .zerofill __DATA,__bss,_rbp,8,3
+ .globl _r8
+ .zerofill __DATA,__bss,_r8,8,3
+ .globl _r9
+ .zerofill __DATA,__bss,_r9,8,3
+ .globl _r10
+ .zerofill __DATA,__bss,_r10,8,3
+ .globl _r11
+ .zerofill __DATA,__bss,_r11,8,3
+ .globl _r12
+ .zerofill __DATA,__bss,_r12,8,3
+ .globl _r13
+ .zerofill __DATA,__bss,_r13,8,3
+ .globl _r14
+ .zerofill __DATA,__bss,_r14,8,3
+ .globl _r15
+ .zerofill __DATA,__bss,_r15,8,3
+ .globl _xmm_regs
+ .zerofill __DATA,__bss,_xmm_regs,256,5
+ .globl _x87_regs
+ .zerofill __DATA,__bss,_x87_regs,128,5
+ .globl _volatile_var
+ .zerofill __DATA,__bss,_volatile_var,8,3
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/abi-bf16-ymm.exp b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/abi-bf16-ymm.exp
index 309db8f..02b4505 100644
--- a/gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/abi-bf16-ymm.exp
+++ b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/abi-bf16-ymm.exp
@@ -36,9 +36,15 @@ set additional_flags "-W -Wall -mavx2"
foreach src [lsort [glob -nocomplain $srcdir/$subdir/test_*.c]] {
if {[runtest_file_p $runtests $src]} {
- c-torture-execute [list $src \
- $srcdir/$subdir/asm-support.S] \
- $additional_flags
+ if { ([istarget *-*-darwin*]) } then {
+ c-torture-execute [list $src \
+ $srcdir/$subdir/asm-support-darwin.S] \
+ $additional_flags
+ } else {
+ c-torture-execute [list $src \
+ $srcdir/$subdir/asm-support.S] \
+ $additional_flags
+ }
}
}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/args.h b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/args.h
index 94627ff..1027742 100644
--- a/gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/args.h
+++ b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/args.h
@@ -50,8 +50,8 @@ typedef union {
} X87_T;
extern void (*callthis)(void);
extern unsigned long long rax,rbx,rcx,rdx,rsi,rdi,rsp,rbp,r8,r9,r10,r11,r12,r13,r14,r15;
-YMM_T ymm_regs[16];
-X87_T x87_regs[8];
+extern YMM_T ymm_regs[16];
+extern X87_T x87_regs[8];
extern volatile unsigned long long volatile_var;
extern void snapshot (void);
extern void snapshot_ret (void);
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/asm-support-darwin.S b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/asm-support-darwin.S
new file mode 100644
index 0000000..e136b57
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m256bf16/asm-support-darwin.S
@@ -0,0 +1,97 @@
+ .text
+ .p2align 4,,15
+ .globl _snapshot
+_snapshot:
+.LFB3:
+ movq %rax, _rax(%rip)
+ movq %rbx, _rbx(%rip)
+ movq %rcx, _rcx(%rip)
+ movq %rdx, _rdx(%rip)
+ movq %rdi, _rdi(%rip)
+ movq %rsi, _rsi(%rip)
+ movq %rbp, _rbp(%rip)
+ movq %rsp, _rsp(%rip)
+ movq %r8, _r8(%rip)
+ movq %r9, _r9(%rip)
+ movq %r10, _r10(%rip)
+ movq %r11, _r11(%rip)
+ movq %r12, _r12(%rip)
+ movq %r13, _r13(%rip)
+ movq %r14, _r14(%rip)
+ movq %r15, _r15(%rip)
+ vmovdqu %ymm0, _ymm_regs+0(%rip)
+ vmovdqu %ymm1, _ymm_regs+32(%rip)
+ vmovdqu %ymm2, _ymm_regs+64(%rip)
+ vmovdqu %ymm3, _ymm_regs+96(%rip)
+ vmovdqu %ymm4, _ymm_regs+128(%rip)
+ vmovdqu %ymm5, _ymm_regs+160(%rip)
+ vmovdqu %ymm6, _ymm_regs+192(%rip)
+ vmovdqu %ymm7, _ymm_regs+224(%rip)
+ vmovdqu %ymm8, _ymm_regs+256(%rip)
+ vmovdqu %ymm9, _ymm_regs+288(%rip)
+ vmovdqu %ymm10, _ymm_regs+320(%rip)
+ vmovdqu %ymm11, _ymm_regs+352(%rip)
+ vmovdqu %ymm12, _ymm_regs+384(%rip)
+ vmovdqu %ymm13, _ymm_regs+416(%rip)
+ vmovdqu %ymm14, _ymm_regs+448(%rip)
+ vmovdqu %ymm15, _ymm_regs+480(%rip)
+ jmp *_callthis(%rip)
+.LFE3:
+
+ .p2align 4,,15
+ .globl _snapshot_ret
+_snapshot_ret:
+ movq %rdi, _rdi(%rip)
+ subq $8, %rsp
+ call *_callthis(%rip)
+ addq $8, %rsp
+ movq %rax, _rax(%rip)
+ movq %rdx, _rdx(%rip)
+ vmovdqu %ymm0, _ymm_regs+0(%rip)
+ vmovdqu %ymm1, _ymm_regs+32(%rip)
+ fstpt _x87_regs(%rip)
+ fstpt _x87_regs+16(%rip)
+ fldt _x87_regs+16(%rip)
+ fldt _x87_regs(%rip)
+ ret
+
+ .globl _callthis
+ .zerofill __DATA,__bss,_callthis,8,3
+ .globl _rax
+ .zerofill __DATA,__bss,_rax,8,3
+ .globl _rbx
+ .zerofill __DATA,__bss,_rbx,8,3
+ .globl _rcx
+ .zerofill __DATA,__bss,_rcx,8,3
+ .globl _rdx
+ .zerofill __DATA,__bss,_rdx,8,3
+ .globl _rsi
+ .zerofill __DATA,__bss,_rsi,8,3
+ .globl _rdi
+ .zerofill __DATA,__bss,_rdi,8,3
+ .globl _rsp
+ .zerofill __DATA,__bss,_rsp,8,3
+ .globl _rbp
+ .zerofill __DATA,__bss,_rbp,8,3
+ .globl _r8
+ .zerofill __DATA,__bss,_r8,8,3
+ .globl _r9
+ .zerofill __DATA,__bss,_r9,8,3
+ .globl _r10
+ .zerofill __DATA,__bss,_r10,8,3
+ .globl _r11
+ .zerofill __DATA,__bss,_r11,8,3
+ .globl _r12
+ .zerofill __DATA,__bss,_r12,8,3
+ .globl _r13
+ .zerofill __DATA,__bss,_r13,8,3
+ .globl _r14
+ .zerofill __DATA,__bss,_r14,8,3
+ .globl _r15
+ .zerofill __DATA,__bss,_r15,8,3
+ .globl _ymm_regs
+ .zerofill __DATA,__bss,_ymm_regs,512,5
+ .globl _x87_regs
+ .zerofill __DATA,__bss,_x87_regs,128,5
+ .globl _volatile_var
+ .zerofill __DATA,__bss,_volatile_var,8,3
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/abi-bf16-zmm.exp b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/abi-bf16-zmm.exp
index b6e0fed..28abb4e 100644
--- a/gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/abi-bf16-zmm.exp
+++ b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/abi-bf16-zmm.exp
@@ -36,9 +36,15 @@ set additional_flags "-W -Wall -mavx512f"
foreach src [lsort [glob -nocomplain $srcdir/$subdir/test_*.c]] {
if {[runtest_file_p $runtests $src]} {
- c-torture-execute [list $src \
- $srcdir/$subdir/asm-support.S] \
- $additional_flags
+ if { ([istarget *-*-darwin*]) } then {
+ c-torture-execute [list $src \
+ $srcdir/$subdir/asm-support-darwin.S] \
+ $additional_flags
+ } else {
+ c-torture-execute [list $src \
+ $srcdir/$subdir/asm-support.S] \
+ $additional_flags
+ }
}
}
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/args.h b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/args.h
index 64b2478..f9710ba 100644
--- a/gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/args.h
+++ b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/args.h
@@ -51,8 +51,8 @@ typedef union {
} X87_T;
extern void (*callthis)(void);
extern unsigned long long rax,rbx,rcx,rdx,rsi,rdi,rsp,rbp,r8,r9,r10,r11,r12,r13,r14,r15;
-ZMM_T zmm_regs[32];
-X87_T x87_regs[8];
+extern ZMM_T zmm_regs[32];
+extern X87_T x87_regs[8];
extern volatile unsigned long long volatile_var;
extern void snapshot (void);
extern void snapshot_ret (void);
diff --git a/gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/asm-support-darwin.S b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/asm-support-darwin.S
new file mode 100644
index 0000000..71b61b3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/x86_64/abi/bf16/m512bf16/asm-support-darwin.S
@@ -0,0 +1,113 @@
+ .text
+ .p2align 4,,15
+ .globl _snapshot
+_snapshot:
+.LFB3:
+ movq %rax, _rax(%rip)
+ movq %rbx, _rbx(%rip)
+ movq %rcx, _rcx(%rip)
+ movq %rdx, _rdx(%rip)
+ movq %rdi, _rdi(%rip)
+ movq %rsi, _rsi(%rip)
+ movq %rbp, _rbp(%rip)
+ movq %rsp, _rsp(%rip)
+ movq %r8, _r8(%rip)
+ movq %r9, _r9(%rip)
+ movq %r10, _r10(%rip)
+ movq %r11, _r11(%rip)
+ movq %r12, _r12(%rip)
+ movq %r13, _r13(%rip)
+ movq %r14, _r14(%rip)
+ movq %r15, _r15(%rip)
+ vmovdqu32 %zmm0, _zmm_regs+0(%rip)
+ vmovdqu32 %zmm1, _zmm_regs+64(%rip)
+ vmovdqu32 %zmm2, _zmm_regs+128(%rip)
+ vmovdqu32 %zmm3, _zmm_regs+192(%rip)
+ vmovdqu32 %zmm4, _zmm_regs+256(%rip)
+ vmovdqu32 %zmm5, _zmm_regs+320(%rip)
+ vmovdqu32 %zmm6, _zmm_regs+384(%rip)
+ vmovdqu32 %zmm7, _zmm_regs+448(%rip)
+ vmovdqu32 %zmm8, _zmm_regs+512(%rip)
+ vmovdqu32 %zmm9, _zmm_regs+576(%rip)
+ vmovdqu32 %zmm10, _zmm_regs+640(%rip)
+ vmovdqu32 %zmm11, _zmm_regs+704(%rip)
+ vmovdqu32 %zmm12, _zmm_regs+768(%rip)
+ vmovdqu32 %zmm13, _zmm_regs+832(%rip)
+ vmovdqu32 %zmm14, _zmm_regs+896(%rip)
+ vmovdqu32 %zmm15, _zmm_regs+960(%rip)
+ vmovdqu32 %zmm16, _zmm_regs+1024(%rip)
+ vmovdqu32 %zmm17, _zmm_regs+1088(%rip)
+ vmovdqu32 %zmm18, _zmm_regs+1152(%rip)
+ vmovdqu32 %zmm19, _zmm_regs+1216(%rip)
+ vmovdqu32 %zmm20, _zmm_regs+1280(%rip)
+ vmovdqu32 %zmm21, _zmm_regs+1344(%rip)
+ vmovdqu32 %zmm22, _zmm_regs+1408(%rip)
+ vmovdqu32 %zmm23, _zmm_regs+1472(%rip)
+ vmovdqu32 %zmm24, _zmm_regs+1536(%rip)
+ vmovdqu32 %zmm25, _zmm_regs+1600(%rip)
+ vmovdqu32 %zmm26, _zmm_regs+1664(%rip)
+ vmovdqu32 %zmm27, _zmm_regs+1728(%rip)
+ vmovdqu32 %zmm28, _zmm_regs+1792(%rip)
+ vmovdqu32 %zmm29, _zmm_regs+1856(%rip)
+ vmovdqu32 %zmm30, _zmm_regs+1920(%rip)
+ vmovdqu32 %zmm31, _zmm_regs+1984(%rip)
+ jmp *_callthis(%rip)
+.LFE3:
+
+ .p2align 4,,15
+ .globl _snapshot_ret
+_snapshot_ret:
+ movq %rdi, _rdi(%rip)
+ subq $8, %rsp
+ call *_callthis(%rip)
+ addq $8, %rsp
+ movq %rax, _rax(%rip)
+ movq %rdx, _rdx(%rip)
+ vmovdqu32 %zmm0, _zmm_regs+0(%rip)
+ vmovdqu32 %zmm1, _zmm_regs+64(%rip)
+ fstpt _x87_regs(%rip)
+ fstpt _x87_regs+16(%rip)
+ fldt _x87_regs+16(%rip)
+ fldt _x87_regs(%rip)
+ ret
+
+ .globl _callthis
+ .zerofill __DATA,__bss,_callthis,8,3
+ .globl _rax
+ .zerofill __DATA,__bss,_rax,8,3
+ .globl _rbx
+ .zerofill __DATA,__bss,_rbx,8,3
+ .globl _rcx
+ .zerofill __DATA,__bss,_rcx,8,3
+ .globl _rdx
+ .zerofill __DATA,__bss,_rdx,8,3
+ .globl _rsi
+ .zerofill __DATA,__bss,_rsi,8,3
+ .globl _rdi
+ .zerofill __DATA,__bss,_rdi,8,3
+ .globl _rsp
+ .zerofill __DATA,__bss,_rsp,8,3
+ .globl _rbp
+ .zerofill __DATA,__bss,_rbp,8,3
+ .globl _r8
+ .zerofill __DATA,__bss,_r8,8,3
+ .globl _r9
+ .zerofill __DATA,__bss,_r9,8,3
+ .globl _r10
+ .zerofill __DATA,__bss,_r10,8,3
+ .globl _r11
+ .zerofill __DATA,__bss,_r11,8,3
+ .globl _r12
+ .zerofill __DATA,__bss,_r12,8,3
+ .globl _r13
+ .zerofill __DATA,__bss,_r13,8,3
+ .globl _r14
+ .zerofill __DATA,__bss,_r14,8,3
+ .globl _r15
+ .zerofill __DATA,__bss,_r15,8,3
+ .globl _zmm_regs
+ .zerofill __DATA,__bss,_zmm_regs,2048,6
+ .globl _x87_regs
+ .zerofill __DATA,__bss,_x87_regs,128,5
+ .globl _volatile_var
+ .zerofill __DATA,__bss,_volatile_var,8,3
diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-4.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-4.f90
index 7b182b5..9081159 100644
--- a/gcc/testsuite/gfortran.dg/gomp/defaultmap-4.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-4.f90
@@ -141,5 +141,5 @@ end
! { dg-final { scan-tree-dump-times "map\\(to:\\.strxparr \\\[len:" 2 "gimple" } }
! { dg-final { scan-tree-dump-times "map\\(to:strxparr \\\[pointer set, len:" 2 "gimple" } }
! { dg-final { scan-tree-dump-times "map\\(to:\\.strxp \\\[len:" 2 "gimple" } }
-! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(1\\) thread_limit\\(0\\) defaultmap\\(alloc\\)" 1 "gimple" } }
-! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(1\\) thread_limit\\(0\\) defaultmap\\(alloc:scalar\\) defaultmap\\(to:aggregate\\) defaultmap\\(tofrom:allocatable\\) defaultmap\\(firstprivate:pointer\\)" 1 "gimple" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\) defaultmap\\(alloc\\)" 1 "gimple" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\) defaultmap\\(alloc:scalar\\) defaultmap\\(to:aggregate\\) defaultmap\\(tofrom:allocatable\\) defaultmap\\(firstprivate:pointer\\)" 1 "gimple" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-5.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-5.f90
index 1391274..91566ed 100644
--- a/gcc/testsuite/gfortran.dg/gomp/defaultmap-5.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-5.f90
@@ -141,5 +141,5 @@ end
! { dg-final { scan-tree-dump-times "map\\(to:strxparr \\\[pointer set, len:" 2 "gimple" } }
! { dg-final { scan-tree-dump-times "map\\(to:\\*strxp \\\[len:" 1 "gimple" } }
! { dg-final { scan-tree-dump-times "map\\(to:\\.strxp \\\[len:" 1 "gimple" } }
-! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(1\\) thread_limit\\(0\\) defaultmap\\(to\\)" 1 "gimple" } }
-! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(1\\) thread_limit\\(0\\) defaultmap\\(to:scalar\\) defaultmap\\(tofrom:aggregate\\) defaultmap\\(firstprivate:allocatable\\) defaultmap\\(default:pointer\\)" 1 "gimple" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\) defaultmap\\(to\\)" 1 "gimple" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\) defaultmap\\(to:scalar\\) defaultmap\\(tofrom:aggregate\\) defaultmap\\(firstprivate:allocatable\\) defaultmap\\(default:pointer\\)" 1 "gimple" } }
diff --git a/gcc/testsuite/gfortran.dg/gomp/defaultmap-6.f90 b/gcc/testsuite/gfortran.dg/gomp/defaultmap-6.f90
index 9a81d0f..867e41a 100644
--- a/gcc/testsuite/gfortran.dg/gomp/defaultmap-6.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/defaultmap-6.f90
@@ -101,4 +101,4 @@ end
! { dg-final { scan-tree-dump-times "map\\(to:\\.strxparr \\\[len:" 1 "gimple" } }
! { dg-final { scan-tree-dump-times "map\\(to:strxparr \\\[pointer set, len:" 1 "gimple" } }
! { dg-final { scan-tree-dump-times "map\\(to:\\.strxp \\\[len:" 1 "gimple" } }
-! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(1\\) thread_limit\\(0\\) defaultmap\\(default\\)" 1 "gimple" } }
+! { dg-final { scan-tree-dump-times "#pragma omp target num_teams\\(-2\\) thread_limit\\(0\\) defaultmap\\(default\\)" 1 "gimple" } }
diff --git a/gcc/testsuite/gfortran.dg/merge_1.f90 b/gcc/testsuite/gfortran.dg/merge_1.f90
index abbc227..437b13a 100644
--- a/gcc/testsuite/gfortran.dg/merge_1.f90
+++ b/gcc/testsuite/gfortran.dg/merge_1.f90
@@ -7,32 +7,40 @@ program testmerge9
integer :: i
logical :: x(2) = (/.true., .false./)
logical :: called(2)
+ logical :: y
! At run-time all arguments shall be evaluated
do i = 1,2
called = .false.
- print *, merge (tstuff(), fstuff(), x(i))
+ y = merge (tstuff(), fstuff(), x(i))
+ print *, y
if (any (.not. called)) stop 1
end do
! Compile-time simplification shall not drop non-constant args
called = .false.
- print *, merge (tstuff(),fstuff(),.true.)
+ y = merge (tstuff(),fstuff(),.true.)
+ print *, y
if (any (.not. called)) stop 2
called = .false.
- print *, merge (tstuff(),fstuff(),.false.)
+ y = merge (tstuff(),fstuff(),.false.)
+ print *, y
if (any (.not. called)) stop 3
called = .false.
- print *, merge (tstuff(),.false.,.true.)
+ y = merge (tstuff(),.false.,.true.)
+ print *, y
if (any (called .neqv. [.true.,.false.])) stop 4
called = .false.
- print *, merge (tstuff(),.false.,.false.)
+ y = merge (tstuff(),.false.,.false.)
+ print *, y
if (any (called .neqv. [.true.,.false.])) stop 5
called = .false.
- print *, merge (.true.,fstuff(),.true.)
+ y = merge (.true.,fstuff(),.true.)
+ print *, y
if (any (called .neqv. [.false.,.true.])) stop 6
called = .false.
- print *, merge (.true.,fstuff(),.false.)
+ y = merge (.true.,fstuff(),.false.)
+ print *, y
if (any (called .neqv. [.false.,.true.])) stop 7
contains
logical function tstuff()
diff --git a/gcc/testsuite/gfortran.dg/pr107899.f90 b/gcc/testsuite/gfortran.dg/pr107899.f90
new file mode 100644
index 0000000..e47b57b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr107899.f90
@@ -0,0 +1,13 @@
+! { dg-do compile }
+! { dg-options "-fcoarray=single" }
+! PR fortran/107899 - ICE in resolve_deallocate_expr
+! Contributed by G.Steinmetz
+
+program p
+ type t
+ end type
+ class(t), target :: x[:] ! { dg-error "deferred shape" }
+ if (allocated (x)) then ! { dg-error "must be ALLOCATABLE" }
+ deallocate (x) ! { dg-error "must be ALLOCATABLE or a POINTER" }
+ end if
+end
diff --git a/gcc/testsuite/gfortran.dg/unpack_field_1.f90 b/gcc/testsuite/gfortran.dg/unpack_field_1.f90
new file mode 100644
index 0000000..ca3cfbd
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/unpack_field_1.f90
@@ -0,0 +1,15 @@
+! { dg-do compile }
+! PR fortran/107922 - ICE in gfc_simplify_unpack
+! Test error recovery when shapes of FIELD and MASK do not match
+! Contributed by G.Steinmetz
+
+program p
+ integer, parameter :: a(2) = 1
+ integer, parameter :: d(3) = 1
+ logical, parameter :: mask(3) = [.false.,.true.,.false.]
+ integer, parameter :: b(2) = unpack(a,mask,a) ! { dg-error "must have identical shape" }
+ integer :: c(3) = unpack(a,[.false.,.true.,.false.],a) ! { dg-error "must have identical shape" }
+ print *, unpack(a,mask,a) ! { dg-error "must have identical shape" }
+ print *, unpack(a,mask,d) ! OK
+ print *, unpack(a,mask,3) ! OK
+end
diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h
index 7b70ce7..e423abe 100644
--- a/gcc/testsuite/jit.dg/harness.h
+++ b/gcc/testsuite/jit.dg/harness.h
@@ -68,6 +68,21 @@ static char test[1024];
} \
} while (0)
+#define CHECK_VECTOR_VALUE(LEN, ACTUAL, EXPECTED) \
+ do { \
+ for (int __check_vector_it = 0; __check_vector_it < LEN; ++__check_vector_it) { \
+ if ((ACTUAL)[__check_vector_it] != (EXPECTED)[__check_vector_it]) { \
+ fail ("%s: %s: actual: %s != expected: %s (position %d)", \
+ test, __func__, #ACTUAL, #EXPECTED, __check_vector_it); \
+ fprintf (stderr, "incorrect value\n"); \
+ abort (); \
+ } \
+ } \
+ pass ("%s: %s: actual: %s == expected: %s", \
+ test, __func__, #ACTUAL, #EXPECTED); \
+ } while (0)
+
+
#define CHECK_DOUBLE_VALUE(ACTUAL, EXPECTED) \
do { \
double expected = (EXPECTED); \
diff --git a/gcc/testsuite/jit.dg/test-expressions.c b/gcc/testsuite/jit.dg/test-expressions.c
index f9cc64f..13b3baf 100644
--- a/gcc/testsuite/jit.dg/test-expressions.c
+++ b/gcc/testsuite/jit.dg/test-expressions.c
@@ -383,15 +383,7 @@ make_test_of_comparison (gcc_jit_context *ctxt,
gcc_jit_param *param_b =
gcc_jit_context_new_param (ctxt, NULL, type, "b");
gcc_jit_param *params[] = {param_a, param_b};
- gcc_jit_type *bool_type =
- gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL);
- gcc_jit_function *test_fn =
- gcc_jit_context_new_function (ctxt, NULL,
- GCC_JIT_FUNCTION_EXPORTED,
- bool_type,
- funcname,
- 2, params,
- 0);
+
gcc_jit_rvalue *comparison =
gcc_jit_context_new_comparison (
ctxt,
@@ -400,6 +392,16 @@ make_test_of_comparison (gcc_jit_context *ctxt,
gcc_jit_param_as_rvalue (param_a),
gcc_jit_param_as_rvalue (param_b));
+ gcc_jit_type *comparison_type = gcc_jit_rvalue_get_type(comparison);
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ comparison_type,
+ funcname,
+ 2, params,
+ 0);
+
gcc_jit_block *initial = gcc_jit_function_new_block (test_fn, "initial");
gcc_jit_block_end_with_return (initial, NULL, comparison);
@@ -407,48 +409,103 @@ make_test_of_comparison (gcc_jit_context *ctxt,
gcc_jit_rvalue_as_object (comparison));
}
-static void
-make_tests_of_comparisons (gcc_jit_context *ctxt)
+static void run_test_of_comparison(gcc_jit_context *ctxt,
+ gcc_jit_type *type,
+ enum gcc_jit_comparison op,
+ const char *funcname,
+ const char *vec_funcname,
+ const char *expected)
{
- gcc_jit_type *int_type =
- gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *vec_type =
+ gcc_jit_type_get_vector (type, 4);
CHECK_STRING_VALUE (
make_test_of_comparison (ctxt,
- int_type,
- GCC_JIT_COMPARISON_EQ,
- "test_COMPARISON_EQ_on_int"),
- "a == b");
- CHECK_STRING_VALUE (
- make_test_of_comparison (ctxt,
- int_type,
- GCC_JIT_COMPARISON_NE,
- "test_COMPARISON_NE_on_int"),
- "a != b");
- CHECK_STRING_VALUE (
- make_test_of_comparison (ctxt,
- int_type,
- GCC_JIT_COMPARISON_LT,
- "test_COMPARISON_LT_on_int"),
- "a < b");
+ type,
+ op,
+ funcname),
+ expected);
CHECK_STRING_VALUE (
make_test_of_comparison (ctxt,
- int_type,
- GCC_JIT_COMPARISON_LE,
- "test_COMPARISON_LE_on_int"),
- "a <= b");
- CHECK_STRING_VALUE (
- make_test_of_comparison (ctxt,
- int_type,
- GCC_JIT_COMPARISON_GT,
- "test_COMPARISON_GT_on_int"),
- "a > b");
- CHECK_STRING_VALUE (
- make_test_of_comparison (ctxt,
- int_type,
- GCC_JIT_COMPARISON_GE,
- "test_COMPARISON_GE_on_int"),
- "a >= b");
+ vec_type,
+ op,
+ vec_funcname),
+ expected);
+}
+
+static void
+make_tests_of_comparisons (gcc_jit_context *ctxt)
+{
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *float_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+
+ run_test_of_comparison(
+ ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_EQ,
+ "test_COMPARISON_EQ_on_int",
+ "test_COMPARISON_EQ_on_vec_int",
+ "a == b");
+ run_test_of_comparison(
+ ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_NE,
+ "test_COMPARISON_NE_on_int",
+ "test_COMPARISON_NE_on_vec_int",
+ "a != b");
+ run_test_of_comparison(
+ ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_LT,
+ "test_COMPARISON_LT_on_int",
+ "test_COMPARISON_LT_on_vec_int",
+ "a < b");
+ run_test_of_comparison(
+ ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_LE,
+ "test_COMPARISON_LE_on_int",
+ "test_COMPARISON_LE_on_vec_int",
+ "a <= b");
+ run_test_of_comparison(
+ ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_GT,
+ "test_COMPARISON_GT_on_int",
+ "test_COMPARISON_GT_on_vec_int",
+ "a > b");
+ run_test_of_comparison(
+ ctxt,
+ int_type,
+ GCC_JIT_COMPARISON_GE,
+ "test_COMPARISON_GE_on_int",
+ "test_COMPARISON_GE_on_vec_int",
+ "a >= b");
+
+ // Float tests
+ run_test_of_comparison(
+ ctxt,
+ float_type,
+ GCC_JIT_COMPARISON_NE,
+ "test_COMPARISON_NE_on_float",
+ "test_COMPARISON_NE_on_vec_float",
+ "a != b");
+ run_test_of_comparison(
+ ctxt,
+ float_type,
+ GCC_JIT_COMPARISON_LT,
+ "test_COMPARISON_LT_on_float",
+ "test_COMPARISON_LT_on_vec_float",
+ "a < b");
+ run_test_of_comparison(
+ ctxt,
+ float_type,
+ GCC_JIT_COMPARISON_GT,
+ "test_COMPARISON_GT_on_float",
+ "test_COMPARISON_GT_on_vec_float",
+ "a > b");
}
static void
@@ -502,6 +559,93 @@ verify_comparisons (gcc_jit_result *result)
CHECK_VALUE (test_COMPARISON_GE_on_int (0, 0), 1);
CHECK_VALUE (test_COMPARISON_GE_on_int (1, 2), 0);
CHECK_VALUE (test_COMPARISON_GE_on_int (2, 1), 1);
+
+ typedef int __vector __attribute__ ((__vector_size__ (sizeof(int) * 2)));
+ typedef __vector (*test_vec_fn) (__vector, __vector);
+
+ __vector zero_zero = {0, 0};
+ __vector zero_one = {0, 1};
+ __vector one_zero = {1, 0};
+
+ __vector true_true = {-1, -1};
+ __vector false_true = {0, -1};
+ __vector true_false = {-1, 0};
+ __vector false_false = {0, 0};
+
+ test_vec_fn test_COMPARISON_EQ_on_vec_int =
+ (test_vec_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_EQ_on_vec_int");
+ CHECK_NON_NULL (test_COMPARISON_EQ_on_vec_int);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_EQ_on_vec_int (zero_zero, zero_zero), true_true);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_EQ_on_vec_int (zero_one, one_zero), false_false);
+
+ test_vec_fn test_COMPARISON_NE_on_vec_int =
+ (test_vec_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_NE_on_vec_int");
+ CHECK_NON_NULL (test_COMPARISON_NE_on_vec_int);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_NE_on_vec_int (zero_zero, zero_zero), false_false);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_NE_on_vec_int (zero_one, one_zero), true_true);
+
+ test_vec_fn test_COMPARISON_LT_on_vec_int =
+ (test_vec_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_LT_on_vec_int");
+ CHECK_NON_NULL (test_COMPARISON_LT_on_vec_int);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_LT_on_vec_int (zero_zero, zero_zero), false_false);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_LT_on_vec_int (zero_one, one_zero), true_false);
+
+ test_vec_fn test_COMPARISON_LE_on_vec_int =
+ (test_vec_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_LE_on_vec_int");
+ CHECK_NON_NULL (test_COMPARISON_LE_on_vec_int);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_LE_on_vec_int (zero_zero, zero_zero), true_true);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_LE_on_vec_int (zero_one, one_zero), true_false);
+
+ test_vec_fn test_COMPARISON_GT_on_vec_int =
+ (test_vec_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_GT_on_vec_int");
+ CHECK_NON_NULL (test_COMPARISON_GT_on_vec_int);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_GT_on_vec_int (zero_zero, zero_zero), false_false);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_GT_on_vec_int (zero_one, one_zero), false_true);
+
+ test_vec_fn test_COMPARISON_GE_on_vec_int =
+ (test_vec_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_GE_on_vec_int");
+ CHECK_NON_NULL (test_COMPARISON_GE_on_vec_int);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_GE_on_vec_int (zero_zero, zero_zero), true_true);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_GE_on_vec_int (zero_one, one_zero), false_true);
+
+ typedef float __vector_f __attribute__ ((__vector_size__ (sizeof(float) * 2)));
+ typedef __vector (*test_vec_f_fn) (__vector_f, __vector_f);
+
+ __vector_f zero_zero_f = {0, 0};
+ __vector_f zero_one_f = {0, 1};
+ __vector_f one_zero_f = {1, 0};
+
+ __vector_f true_true_f = {-1, -1};
+ __vector_f false_true_f = {0, -1};
+ __vector_f true_false_f = {-1, 0};
+ __vector_f false_false_f = {0, 0};
+
+ test_vec_f_fn test_COMPARISON_NE_on_vec_float =
+ (test_vec_f_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_NE_on_vec_float");
+ CHECK_NON_NULL (test_COMPARISON_NE_on_vec_float);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_NE_on_vec_float (zero_zero_f, zero_zero_f), false_false_f);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_NE_on_vec_float (zero_one_f, one_zero_f), true_true_f);
+
+ test_vec_f_fn test_COMPARISON_LT_on_vec_float =
+ (test_vec_f_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_LT_on_vec_float");
+ CHECK_NON_NULL (test_COMPARISON_LT_on_vec_float);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_LT_on_vec_float (zero_zero_f, zero_zero_f), false_false_f);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_LT_on_vec_float (zero_one_f, one_zero_f), true_false_f);
+
+ test_vec_f_fn test_COMPARISON_GT_on_vec_float =
+ (test_vec_f_fn)gcc_jit_result_get_code (result,
+ "test_COMPARISON_GT_on_vec_float");
+ CHECK_NON_NULL (test_COMPARISON_GT_on_vec_float);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_GT_on_vec_float (zero_zero_f, zero_zero_f), false_false_f);
+ CHECK_VECTOR_VALUE (2, test_COMPARISON_GT_on_vec_float (zero_one_f, one_zero_f), false_true_f);
}
/**********************************************************************
diff --git a/gcc/tree-into-ssa.cc b/gcc/tree-into-ssa.cc
index f21ed2b..9a2417d 100644
--- a/gcc/tree-into-ssa.cc
+++ b/gcc/tree-into-ssa.cc
@@ -2110,7 +2110,6 @@ rewrite_update_phi_arguments (basic_block bb)
symbol we may find NULL arguments. That's why we
take the symbol from the LHS of the PHI node. */
reaching_def = get_reaching_def (lhs_sym);
-
}
else
{
@@ -2122,8 +2121,9 @@ rewrite_update_phi_arguments (basic_block bb)
reaching_def = get_reaching_def (arg);
}
- /* Update the argument if there is a reaching def. */
- if (reaching_def)
+ /* Update the argument if there is a reaching def different
+ from arg. */
+ if (reaching_def && reaching_def != arg)
{
location_t locus;
int arg_i = PHI_ARG_INDEX_FROM_USE (arg_p);
@@ -2133,6 +2133,10 @@ rewrite_update_phi_arguments (basic_block bb)
/* Virtual operands do not need a location. */
if (virtual_operand_p (reaching_def))
locus = UNKNOWN_LOCATION;
+ /* If SSA update didn't insert this PHI the argument
+ might have a location already, keep that. */
+ else if (gimple_phi_arg_has_location (phi, arg_i))
+ locus = gimple_phi_arg_location (phi, arg_i);
else
{
gimple *stmt = SSA_NAME_DEF_STMT (reaching_def);
@@ -2150,7 +2154,6 @@ rewrite_update_phi_arguments (basic_block bb)
gimple_phi_arg_set_location (phi, arg_i, locus);
}
-
if (e->flags & EDGE_ABNORMAL)
SSA_NAME_OCCURS_IN_ABNORMAL_PHI (USE_FROM_PTR (arg_p)) = 1;
}
diff --git a/gcc/tree-ssa-loop-im.cc b/gcc/tree-ssa-loop-im.cc
index 2119d40..20a9ca7 100644
--- a/gcc/tree-ssa-loop-im.cc
+++ b/gcc/tree-ssa-loop-im.cc
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see
#include "alias.h"
#include "builtins.h"
#include "tree-dfa.h"
+#include "tree-ssa.h"
#include "dbgcnt.h"
/* TODO: Support for predicated code motion. I.e.
@@ -331,8 +332,8 @@ enum move_pos
because it may trap), return MOVE_PRESERVE_EXECUTION.
Otherwise return MOVE_IMPOSSIBLE. */
-enum move_pos
-movement_possibility (gimple *stmt)
+static enum move_pos
+movement_possibility_1 (gimple *stmt)
{
tree lhs;
enum move_pos ret = MOVE_POSSIBLE;
@@ -422,6 +423,23 @@ movement_possibility (gimple *stmt)
return ret;
}
+static enum move_pos
+movement_possibility (gimple *stmt)
+{
+ enum move_pos pos = movement_possibility_1 (stmt);
+ if (pos == MOVE_POSSIBLE)
+ {
+ use_operand_p use_p;
+ ssa_op_iter ssa_iter;
+ FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, ssa_iter, SSA_OP_USE)
+ if (TREE_CODE (USE_FROM_PTR (use_p)) == SSA_NAME
+ && ssa_name_maybe_undef_p (USE_FROM_PTR (use_p)))
+ return MOVE_PRESERVE_EXECUTION;
+ }
+ return pos;
+}
+
+
/* Compare the profile count inequality of bb and loop's preheader, it is
three-state as stated in profile-count.h, FALSE is returned if inequality
cannot be decided. */
@@ -3532,6 +3550,8 @@ loop_invariant_motion_in_fun (function *fun, bool store_motion)
tree_ssa_lim_initialize (store_motion);
+ mark_ssa_maybe_undefs ();
+
/* Gathers information about memory accesses in the loops. */
analyze_memory_references (store_motion);
diff --git a/gcc/tree-ssa-loop-ivopts.cc b/gcc/tree-ssa-loop-ivopts.cc
index a6f926a..5b9044f 100644
--- a/gcc/tree-ssa-loop-ivopts.cc
+++ b/gcc/tree-ssa-loop-ivopts.cc
@@ -3071,117 +3071,6 @@ get_loop_invariant_expr (struct ivopts_data *data, tree inv_expr)
return *slot;
}
-/* Return TRUE iff VAR is marked as maybe-undefined. See
- mark_ssa_maybe_undefs. */
-
-static inline bool
-ssa_name_maybe_undef_p (tree var)
-{
- gcc_checking_assert (TREE_CODE (var) == SSA_NAME);
- return TREE_VISITED (var);
-}
-
-/* Set (or clear, depending on VALUE) VAR's maybe-undefined mark. */
-
-static inline void
-ssa_name_set_maybe_undef (tree var, bool value = true)
-{
- gcc_checking_assert (TREE_CODE (var) == SSA_NAME);
- TREE_VISITED (var) = value;
-}
-
-/* Return TRUE iff there are any non-PHI uses of VAR that dominate the
- end of BB. If we return TRUE and BB is a loop header, then VAR we
- be assumed to be defined within the loop, even if it is marked as
- maybe-undefined. */
-
-static inline bool
-ssa_name_any_use_dominates_bb_p (tree var, basic_block bb)
-{
- imm_use_iterator iter;
- use_operand_p use_p;
- FOR_EACH_IMM_USE_FAST (use_p, iter, var)
- {
- if (is_a <gphi *> (USE_STMT (use_p))
- || is_gimple_debug (USE_STMT (use_p)))
- continue;
- basic_block dombb = gimple_bb (USE_STMT (use_p));
- if (dominated_by_p (CDI_DOMINATORS, bb, dombb))
- return true;
- }
-
- return false;
-}
-
-/* Mark as maybe_undef any SSA_NAMEs that are unsuitable as ivopts
- candidates for potentially involving undefined behavior. */
-
-static void
-mark_ssa_maybe_undefs (void)
-{
- auto_vec<tree> queue;
-
- /* Scan all SSA_NAMEs, marking the definitely-undefined ones as
- maybe-undefined and queuing them for propagation, while clearing
- the mark on others. */
- unsigned int i;
- tree var;
- FOR_EACH_SSA_NAME (i, var, cfun)
- {
- if (SSA_NAME_IS_VIRTUAL_OPERAND (var)
- || !ssa_undefined_value_p (var, false))
- ssa_name_set_maybe_undef (var, false);
- else
- {
- ssa_name_set_maybe_undef (var);
- queue.safe_push (var);
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "marking _%i as maybe-undef\n",
- SSA_NAME_VERSION (var));
- }
- }
-
- /* Now propagate maybe-undefined from a DEF to any other PHI that
- uses it, as long as there isn't any intervening use of DEF. */
- while (!queue.is_empty ())
- {
- var = queue.pop ();
- imm_use_iterator iter;
- use_operand_p use_p;
- FOR_EACH_IMM_USE_FAST (use_p, iter, var)
- {
- /* Any uses of VAR that aren't PHI args imply VAR must be
- defined, otherwise undefined behavior would have been
- definitely invoked. Only PHI args may hold
- maybe-undefined values without invoking undefined
- behavior for that reason alone. */
- if (!is_a <gphi *> (USE_STMT (use_p)))
- continue;
- gphi *phi = as_a <gphi *> (USE_STMT (use_p));
-
- tree def = gimple_phi_result (phi);
- if (ssa_name_maybe_undef_p (def))
- continue;
-
- /* Look for any uses of the maybe-unused SSA_NAME that
- dominates the block that reaches the incoming block
- corresponding to the PHI arg in which it is mentioned.
- That means we can assume the SSA_NAME is defined in that
- path, so we only mark a PHI result as maybe-undef if we
- find an unused reaching SSA_NAME. */
- int idx = phi_arg_index_from_use (use_p);
- basic_block bb = gimple_phi_arg_edge (phi, idx)->src;
- if (ssa_name_any_use_dominates_bb_p (var, bb))
- continue;
-
- ssa_name_set_maybe_undef (def);
- queue.safe_push (def);
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "marking _%i as maybe-undef because of _%i\n",
- SSA_NAME_VERSION (def), SSA_NAME_VERSION (var));
- }
- }
-}
/* Return *TP if it is an SSA_NAME marked with TREE_VISITED, i.e., as
unsuitable as ivopts candidates for potentially involving undefined
diff --git a/gcc/tree-ssa-loop-unswitch.cc b/gcc/tree-ssa-loop-unswitch.cc
index e8c9bd6..df7a201 100644
--- a/gcc/tree-ssa-loop-unswitch.cc
+++ b/gcc/tree-ssa-loop-unswitch.cc
@@ -263,8 +263,10 @@ init_loop_unswitch_info (class loop *&loop, unswitch_predicate *&hottest,
/* Unswitch only nests with no sibling loops. */
class loop *outer_loop = loop;
+ unsigned max_depth = param_max_unswitch_depth;
while (loop_outer (outer_loop)->num != 0
- && !loop_outer (outer_loop)->inner->next)
+ && !loop_outer (outer_loop)->inner->next
+ && --max_depth != 0)
outer_loop = loop_outer (outer_loop);
hottest = NULL;
hottest_bb = NULL;
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index 1e7763b..b9f289b 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -5840,7 +5840,12 @@ visit_phi (gimple *phi, bool *inserted, bool backedges_varying_p)
continue;
}
/* There's also the possibility to use equivalences. */
- if (!FLOAT_TYPE_P (TREE_TYPE (def)))
+ if (!FLOAT_TYPE_P (TREE_TYPE (def))
+ /* But only do this if we didn't force any of sameval or
+ val to VARYING because of backedge processing rules. */
+ && (TREE_CODE (sameval) != SSA_NAME
+ || SSA_VAL (sameval) == sameval)
+ && (TREE_CODE (def) != SSA_NAME || SSA_VAL (def) == def))
{
vn_nary_op_t vnresult;
tree ops[2];
diff --git a/gcc/tree-ssa.cc b/gcc/tree-ssa.cc
index 1a93ffd..5dedc09 100644
--- a/gcc/tree-ssa.cc
+++ b/gcc/tree-ssa.cc
@@ -1400,6 +1400,99 @@ gimple_uses_undefined_value_p (gimple *stmt)
}
+/* Return TRUE iff there are any non-PHI uses of VAR that dominate the
+ end of BB. If we return TRUE and BB is a loop header, then VAR we
+ be assumed to be defined within the loop, even if it is marked as
+ maybe-undefined. */
+
+bool
+ssa_name_any_use_dominates_bb_p (tree var, basic_block bb)
+{
+ imm_use_iterator iter;
+ use_operand_p use_p;
+ FOR_EACH_IMM_USE_FAST (use_p, iter, var)
+ {
+ if (is_a <gphi *> (USE_STMT (use_p))
+ || is_gimple_debug (USE_STMT (use_p)))
+ continue;
+ basic_block dombb = gimple_bb (USE_STMT (use_p));
+ if (dominated_by_p (CDI_DOMINATORS, bb, dombb))
+ return true;
+ }
+
+ return false;
+}
+
+/* Mark as maybe_undef any SSA_NAMEs that are unsuitable as ivopts
+ candidates for potentially involving undefined behavior. */
+
+void
+mark_ssa_maybe_undefs (void)
+{
+ auto_vec<tree> queue;
+
+ /* Scan all SSA_NAMEs, marking the definitely-undefined ones as
+ maybe-undefined and queuing them for propagation, while clearing
+ the mark on others. */
+ unsigned int i;
+ tree var;
+ FOR_EACH_SSA_NAME (i, var, cfun)
+ {
+ if (SSA_NAME_IS_VIRTUAL_OPERAND (var)
+ || !ssa_undefined_value_p (var, false))
+ ssa_name_set_maybe_undef (var, false);
+ else
+ {
+ ssa_name_set_maybe_undef (var);
+ queue.safe_push (var);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "marking _%i as maybe-undef\n",
+ SSA_NAME_VERSION (var));
+ }
+ }
+
+ /* Now propagate maybe-undefined from a DEF to any other PHI that
+ uses it, as long as there isn't any intervening use of DEF. */
+ while (!queue.is_empty ())
+ {
+ var = queue.pop ();
+ imm_use_iterator iter;
+ use_operand_p use_p;
+ FOR_EACH_IMM_USE_FAST (use_p, iter, var)
+ {
+ /* Any uses of VAR that aren't PHI args imply VAR must be
+ defined, otherwise undefined behavior would have been
+ definitely invoked. Only PHI args may hold
+ maybe-undefined values without invoking undefined
+ behavior for that reason alone. */
+ if (!is_a <gphi *> (USE_STMT (use_p)))
+ continue;
+ gphi *phi = as_a <gphi *> (USE_STMT (use_p));
+
+ tree def = gimple_phi_result (phi);
+ if (ssa_name_maybe_undef_p (def))
+ continue;
+
+ /* Look for any uses of the maybe-unused SSA_NAME that
+ dominates the block that reaches the incoming block
+ corresponding to the PHI arg in which it is mentioned.
+ That means we can assume the SSA_NAME is defined in that
+ path, so we only mark a PHI result as maybe-undef if we
+ find an unused reaching SSA_NAME. */
+ int idx = phi_arg_index_from_use (use_p);
+ basic_block bb = gimple_phi_arg_edge (phi, idx)->src;
+ if (ssa_name_any_use_dominates_bb_p (var, bb))
+ continue;
+
+ ssa_name_set_maybe_undef (def);
+ queue.safe_push (def);
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "marking _%i as maybe-undef because of _%i\n",
+ SSA_NAME_VERSION (def), SSA_NAME_VERSION (var));
+ }
+ }
+}
+
/* If necessary, rewrite the base of the reference tree *TP from
a MEM_REF to a plain or converted symbol. */
diff --git a/gcc/tree-ssa.h b/gcc/tree-ssa.h
index 0085354..19c1eed 100644
--- a/gcc/tree-ssa.h
+++ b/gcc/tree-ssa.h
@@ -55,6 +55,31 @@ extern tree find_released_ssa_name (tree *, int *, void *);
extern bool ssa_defined_default_def_p (tree t);
extern bool ssa_undefined_value_p (tree, bool = true);
extern bool gimple_uses_undefined_value_p (gimple *);
+
+
+bool ssa_name_any_use_dominates_bb_p (tree var, basic_block bb);
+extern void mark_ssa_maybe_undefs (void);
+
+/* Return TRUE iff VAR is marked as maybe-undefined. See
+ mark_ssa_maybe_undefs. */
+
+static inline bool
+ssa_name_maybe_undef_p (tree var)
+{
+ gcc_checking_assert (TREE_CODE (var) == SSA_NAME);
+ return TREE_VISITED (var);
+}
+
+/* Set (or clear, depending on VALUE) VAR's maybe-undefined mark. */
+
+static inline void
+ssa_name_set_maybe_undef (tree var, bool value = true)
+{
+ gcc_checking_assert (TREE_CODE (var) == SSA_NAME);
+ TREE_VISITED (var) = value;
+}
+
+
extern void execute_update_addresses_taken (void);
/* Given an edge_var_map V, return the PHI arg definition. */
diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
index f6c34bb..d9fdb24 100644
--- a/gcc/tree-vect-patterns.cc
+++ b/gcc/tree-vect-patterns.cc
@@ -4964,6 +4964,8 @@ vect_recog_mask_conversion_pattern (vec_info *vinfo,
else
{
lhs = gimple_call_lhs (last_stmt);
+ if (!lhs)
+ return NULL;
vectype1 = get_vectype_for_scalar_type (vinfo, TREE_TYPE (lhs));
}
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 254b237..b40c95a 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -12719,15 +12719,21 @@ array_ref_up_bound (tree exp)
int test (uint8_t *p, uint32_t t[1][1], int n) {
for (int i = 0; i < 4; i++, p++)
t[i][0] = ...;
+
+ If non-null, set IS_TRAILING_ARRAY to true if the ref is the above case A.
*/
bool
-array_ref_flexible_size_p (tree ref)
+array_ref_flexible_size_p (tree ref, bool *is_trailing_array /* = NULL */)
{
- /* the TYPE for this array referece. */
+ /* The TYPE for this array referece. */
tree atype = NULL_TREE;
- /* the FIELD_DECL for the array field in the containing structure. */
+ /* The FIELD_DECL for the array field in the containing structure. */
tree afield_decl = NULL_TREE;
+ /* Whether this array is the trailing array of a structure. */
+ bool is_trailing_array_tmp = false;
+ if (!is_trailing_array)
+ is_trailing_array = &is_trailing_array_tmp;
if (TREE_CODE (ref) == ARRAY_REF
|| TREE_CODE (ref) == ARRAY_RANGE_REF)
@@ -12815,7 +12821,10 @@ array_ref_flexible_size_p (tree ref)
if (! TYPE_SIZE (atype)
|| ! TYPE_DOMAIN (atype)
|| ! TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
- return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+ {
+ *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
+ return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+ }
/* If the reference is based on a declared entity, the size of the array
is constrained by its given domain. (Do not trust commons PR/69368). */
@@ -12837,9 +12846,17 @@ array_ref_flexible_size_p (tree ref)
if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (atype))) != INTEGER_CST
|| TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST
|| TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (atype))) != INTEGER_CST)
- return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+ {
+ *is_trailing_array
+ = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
+ return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+ }
if (! get_addr_base_and_unit_offset (ref_to_array, &offset))
- return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+ {
+ *is_trailing_array
+ = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
+ return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+ }
/* If at least one extra element fits it is a flexarray. */
if (known_le ((wi::to_offset (TYPE_MAX_VALUE (TYPE_DOMAIN (atype)))
@@ -12847,11 +12864,16 @@ array_ref_flexible_size_p (tree ref)
+ 2)
* wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (atype))),
wi::to_offset (DECL_SIZE_UNIT (ref)) - offset))
- return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+ {
+ *is_trailing_array
+ = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
+ return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
+ }
return false;
}
+ *is_trailing_array = afield_decl && TREE_CODE (afield_decl) == FIELD_DECL;
return afield_decl ? !DECL_NOT_FLEXARRAY (afield_decl) : true;
}
@@ -12913,11 +12935,63 @@ get_initializer_for (tree init, tree decl)
return NULL_TREE;
}
+/* Determines the special array member type for the array reference REF. */
+special_array_member
+component_ref_sam_type (tree ref)
+{
+ special_array_member sam_type = special_array_member::none;
+
+ tree member = TREE_OPERAND (ref, 1);
+ tree memsize = DECL_SIZE_UNIT (member);
+ if (memsize)
+ {
+ tree memtype = TREE_TYPE (member);
+ if (TREE_CODE (memtype) != ARRAY_TYPE)
+ return sam_type;
+
+ bool trailing = false;
+ (void)array_ref_flexible_size_p (ref, &trailing);
+ bool zero_length = integer_zerop (memsize);
+ if (!trailing && !zero_length)
+ /* MEMBER is an interior array with
+ more than one element. */
+ return special_array_member::int_n;
+
+ if (zero_length)
+ {
+ if (trailing)
+ return special_array_member::trail_0;
+ else
+ return special_array_member::int_0;
+ }
+
+ if (!zero_length)
+ if (tree dom = TYPE_DOMAIN (memtype))
+ if (tree min = TYPE_MIN_VALUE (dom))
+ if (tree max = TYPE_MAX_VALUE (dom))
+ if (TREE_CODE (min) == INTEGER_CST
+ && TREE_CODE (max) == INTEGER_CST)
+ {
+ offset_int minidx = wi::to_offset (min);
+ offset_int maxidx = wi::to_offset (max);
+ offset_int neltsm1 = maxidx - minidx;
+ if (neltsm1 > 0)
+ /* MEMBER is a trailing array with more than
+ one elements. */
+ return special_array_member::trail_n;
+
+ if (neltsm1 == 0)
+ return special_array_member::trail_1;
+ }
+ }
+
+ return sam_type;
+}
+
/* Determines the size of the member referenced by the COMPONENT_REF
REF, using its initializer expression if necessary in order to
determine the size of an initialized flexible array member.
- If non-null, set *ARK when REF refers to an interior zero-length
- array or a trailing one-element array.
+ If non-null, set *SAM to the type of special array member.
Returns the size as sizetype (which might be zero for an object
with an uninitialized flexible array member) or null if the size
cannot be determined. */
@@ -12930,7 +13004,7 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
special_array_member sambuf;
if (!sam)
sam = &sambuf;
- *sam = special_array_member::none;
+ *sam = component_ref_sam_type (ref);
/* The object/argument referenced by the COMPONENT_REF and its type. */
tree arg = TREE_OPERAND (ref, 0);
@@ -12951,43 +13025,46 @@ component_ref_size (tree ref, special_array_member *sam /* = NULL */)
return (tree_int_cst_equal (memsize, TYPE_SIZE_UNIT (memtype))
? memsize : NULL_TREE);
- bool trailing = array_ref_flexible_size_p (ref);
- bool zero_length = integer_zerop (memsize);
- if (!trailing && !zero_length)
- /* MEMBER is either an interior array or is an array with
- more than one element. */
+ /* 2-or-more elements arrays are treated as normal arrays by default. */
+ if (*sam == special_array_member::int_n
+ || *sam == special_array_member::trail_n)
return memsize;
- if (zero_length)
+ /* flag_strict_flex_arrays will control how to treat
+ the trailing arrays as flexiable array members. */
+
+ tree afield_decl = TREE_OPERAND (ref, 1);
+ unsigned int strict_flex_array_level
+ = strict_flex_array_level_of (afield_decl);
+
+ switch (strict_flex_array_level)
{
- if (trailing)
- *sam = special_array_member::trail_0;
- else
- {
- *sam = special_array_member::int_0;
- memsize = NULL_TREE;
- }
+ case 3:
+ /* Treaing 0-length trailing arrays as normal array. */
+ if (*sam == special_array_member::trail_0)
+ return size_zero_node;
+ /* FALLTHROUGH. */
+ case 2:
+ /* Treating 1-element trailing arrays as normal array. */
+ if (*sam == special_array_member::trail_1)
+ return memsize;
+ /* FALLTHROUGH. */
+ case 1:
+ /* Treating 2-or-more elements trailing arrays as normal
+ array. */
+ if (*sam == special_array_member::trail_n)
+ return memsize;
+ /* FALLTHROUGH. */
+ case 0:
+ break;
+ default:
+ gcc_unreachable ();
}
- if (!zero_length)
- if (tree dom = TYPE_DOMAIN (memtype))
- if (tree min = TYPE_MIN_VALUE (dom))
- if (tree max = TYPE_MAX_VALUE (dom))
- if (TREE_CODE (min) == INTEGER_CST
- && TREE_CODE (max) == INTEGER_CST)
- {
- offset_int minidx = wi::to_offset (min);
- offset_int maxidx = wi::to_offset (max);
- offset_int neltsm1 = maxidx - minidx;
- if (neltsm1 > 0)
- /* MEMBER is an array with more than one element. */
- return memsize;
-
- if (neltsm1 == 0)
- *sam = special_array_member::trail_1;
- }
+ if (*sam == special_array_member::int_0)
+ memsize = NULL_TREE;
- /* For a reference to a zero- or one-element array member of a union
+ /* For a reference to a flexible array member of a union
use the size of the union instead of the size of the member. */
if (TREE_CODE (argtype) == UNION_TYPE)
memsize = TYPE_SIZE_UNIT (argtype);
diff --git a/gcc/tree.h b/gcc/tree.h
index 4a19de1..23223ca 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5553,22 +5553,26 @@ extern tree array_ref_low_bound (tree);
/* Returns true if REF is an array reference, a component reference,
or a memory reference to an array whose actual size might be larger
than its upper bound implies. */
-extern bool array_ref_flexible_size_p (tree);
+extern bool array_ref_flexible_size_p (tree, bool * = NULL);
/* Return a tree representing the offset, in bytes, of the field referenced
by EXP. This does not include any offset in DECL_FIELD_BIT_OFFSET. */
extern tree component_ref_field_offset (tree);
-/* Describes a "special" array member due to which component_ref_size
- returns null. */
+/* Describes a "special" array member for a COMPONENT_REF. */
enum struct special_array_member
{
none, /* Not a special array member. */
int_0, /* Interior array member with size zero. */
trail_0, /* Trailing array member with size zero. */
- trail_1 /* Trailing array member with one element. */
+ trail_1, /* Trailing array member with one element. */
+ trail_n, /* Trailing array member with two or more elements. */
+ int_n /* Interior array member with one or more elements. */
};
+/* Determines the special array member type for a COMPONENT_REF. */
+extern special_array_member component_ref_sam_type (tree);
+
/* Return the size of the member referenced by the COMPONENT_REF, using
its initializer expression if necessary in order to determine the size
of an initialized flexible array member. The size might be zero for
diff --git a/gcc/varasm.cc b/gcc/varasm.cc
index 9dfbebb..6851201b 100644
--- a/gcc/varasm.cc
+++ b/gcc/varasm.cc
@@ -2400,7 +2400,7 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
else
{
/* Special-case handling of vtv comdat sections. */
- if (sect->named.name
+ if (SECTION_STYLE (sect) == SECTION_NAMED
&& (strcmp (sect->named.name, ".vtable_map_vars") == 0))
handle_vtv_comdat_section (sect, decl);
else
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index f29085a..bfad2c5 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,60 @@
+2022-12-06 Marcel Vollweiler <marcel@codesourcery.com>
+
+ * config/gcn/icv-device.c (omp_get_teams_thread_limit): Added to
+ allow processing of device-specific values.
+ (omp_set_teams_thread_limit): Likewise.
+ (ialias): Likewise.
+ * config/nvptx/icv-device.c (omp_get_teams_thread_limit): Likewise.
+ (omp_set_teams_thread_limit): Likewise.
+ (ialias): Likewise.
+ * icv-device.c (omp_get_teams_thread_limit): Likewise.
+ (ialias): Likewise.
+ (omp_set_teams_thread_limit): Likewise.
+ * icv.c (omp_set_teams_thread_limit): Removed.
+ (omp_get_teams_thread_limit): Likewise.
+ (ialias): Likewise.
+ * libgomp.texi: Updated documentation for nvptx and gcn corresponding
+ to the limitation of the number of teams.
+ * plugin/plugin-gcn.c (limit_teams): New helper function that limits
+ the number of teams by twice the number of compute units.
+ (parse_target_attributes): Limit the number of teams on gcn offload
+ devices.
+ * target.c (get_gomp_offload_icvs): Added teams_thread_limit_var
+ handling.
+ (gomp_load_image_to_device): Added a size check for the ICVs struct
+ variable.
+ (gomp_copy_back_icvs): New function that is used in GOMP_target_ext to
+ copy back the ICV values from device to host.
+ (GOMP_target_ext): Update the number of teams and threads in the kernel
+ args also considering device-specific values.
+ * testsuite/libgomp.c-c++-common/icv-4.c: Fixed an error in the reading
+ of OMP_TEAMS_THREAD_LIMIT from the environment.
+ * testsuite/libgomp.c-c++-common/icv-5.c: Extended.
+ * testsuite/libgomp.c-c++-common/icv-6.c: Extended.
+ * testsuite/libgomp.c-c++-common/icv-7.c: Extended.
+ * testsuite/libgomp.c-c++-common/icv-9.c: New test.
+ * testsuite/libgomp.fortran/icv-5.f90: New test.
+ * testsuite/libgomp.fortran/icv-6.f90: New test.
+
+2022-12-06 Tobias Burnus <tobias@codesourcery.com>
+
+ * libgomp.texi (OpenMP 5.2): Add missing 'the'.
+ (TR11): Add missing '@tab N @tab'.
+
+2022-11-30 Tobias Burnus <tobias@codesourcery.com>
+
+ * libgomp.texi (OpenMP Context Selectors): Add 'gfx803' to gcn's isa.
+
+2022-11-30 Paul-Antoine Arras <pa@codesourcery.com>
+
+ * testsuite/libgomp.c/declare-variant-4-fiji.c: New test.
+ * testsuite/libgomp.c/declare-variant-4-gfx803.c: New test.
+ * testsuite/libgomp.c/declare-variant-4-gfx900.c: New test.
+ * testsuite/libgomp.c/declare-variant-4-gfx906.c: New test.
+ * testsuite/libgomp.c/declare-variant-4-gfx908.c: New test.
+ * testsuite/libgomp.c/declare-variant-4-gfx90a.c: New test.
+ * testsuite/libgomp.c/declare-variant-4.h: New header file.
+
2022-11-28 Tobias Burnus <tobias@codesourcery.com>
* libgomp.texi (OpenMP 5.2): Mark end-directive as Y.
diff --git a/libgomp/config/gcn/icv-device.c b/libgomp/config/gcn/icv-device.c
index bf757ba..eb68881 100644
--- a/libgomp/config/gcn/icv-device.c
+++ b/libgomp/config/gcn/icv-device.c
@@ -81,6 +81,19 @@ omp_set_num_teams (int num_teams)
GOMP_ADDITIONAL_ICVS.nteams = num_teams;
}
+int
+omp_get_teams_thread_limit (void)
+{
+ return GOMP_ADDITIONAL_ICVS.teams_thread_limit;
+}
+
+void
+omp_set_teams_thread_limit (int thread_limit)
+{
+ if (thread_limit >= 0)
+ GOMP_ADDITIONAL_ICVS.teams_thread_limit = thread_limit;
+}
+
ialias (omp_set_default_device)
ialias (omp_get_default_device)
ialias (omp_get_initial_device)
@@ -89,3 +102,5 @@ ialias (omp_is_initial_device)
ialias (omp_get_device_num)
ialias (omp_get_max_teams)
ialias (omp_set_num_teams)
+ialias (omp_get_teams_thread_limit)
+ialias (omp_set_teams_thread_limit)
diff --git a/libgomp/config/nvptx/icv-device.c b/libgomp/config/nvptx/icv-device.c
index eef151c..818e696 100644
--- a/libgomp/config/nvptx/icv-device.c
+++ b/libgomp/config/nvptx/icv-device.c
@@ -81,6 +81,19 @@ omp_set_num_teams (int num_teams)
GOMP_ADDITIONAL_ICVS.nteams = num_teams;
}
+int
+omp_get_teams_thread_limit (void)
+{
+ return GOMP_ADDITIONAL_ICVS.teams_thread_limit;
+}
+
+void
+omp_set_teams_thread_limit (int thread_limit)
+{
+ if (thread_limit >= 0)
+ GOMP_ADDITIONAL_ICVS.teams_thread_limit = thread_limit;
+}
+
ialias (omp_set_default_device)
ialias (omp_get_default_device)
ialias (omp_get_initial_device)
@@ -89,3 +102,5 @@ ialias (omp_is_initial_device)
ialias (omp_get_device_num)
ialias (omp_get_max_teams)
ialias (omp_set_num_teams)
+ialias (omp_get_teams_thread_limit)
+ialias (omp_set_teams_thread_limit)
diff --git a/libgomp/icv-device.c b/libgomp/icv-device.c
index d8acf0e..48607ce 100644
--- a/libgomp/icv-device.c
+++ b/libgomp/icv-device.c
@@ -97,3 +97,20 @@ omp_set_num_teams (int num_teams)
}
ialias (omp_set_num_teams)
+
+int
+omp_get_teams_thread_limit (void)
+{
+ return gomp_teams_thread_limit_var;
+}
+
+ialias (omp_get_teams_thread_limit)
+
+void
+omp_set_teams_thread_limit (int thread_limit)
+{
+ if (thread_limit >= 0)
+ gomp_teams_thread_limit_var = thread_limit;
+}
+
+ialias (omp_set_teams_thread_limit)
diff --git a/libgomp/icv.c b/libgomp/icv.c
index df423c0..9aef91c 100644
--- a/libgomp/icv.c
+++ b/libgomp/icv.c
@@ -148,19 +148,6 @@ omp_get_supported_active_levels (void)
return gomp_supported_active_levels;
}
-void
-omp_set_teams_thread_limit (int thread_limit)
-{
- if (thread_limit >= 0)
- gomp_teams_thread_limit_var = thread_limit;
-}
-
-int
-omp_get_teams_thread_limit (void)
-{
- return gomp_teams_thread_limit_var;
-}
-
int
omp_get_cancellation (void)
{
@@ -261,8 +248,6 @@ ialias (omp_get_thread_limit)
ialias (omp_set_max_active_levels)
ialias (omp_get_max_active_levels)
ialias (omp_get_supported_active_levels)
-ialias (omp_set_teams_thread_limit)
-ialias (omp_get_teams_thread_limit)
ialias (omp_get_cancellation)
ialias (omp_get_proc_bind)
ialias (omp_get_max_task_priority)
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index 4caac49..e8798a0 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -406,7 +406,7 @@ to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
@item @code{allocate} and @code{firstprivate} clauses on @code{scope}
@tab Y @tab
@item @code{ompt_callback_work} @tab N @tab
-@item Default map-type for @code{map} clause in @code{target enter/exit data}
+@item Default map-type for the @code{map} clause in @code{target enter/exit data}
@tab Y @tab
@item New @code{doacross} clause as alias for @code{depend} with
@code{source}/@code{sink} modifier @tab Y @tab
@@ -463,6 +463,7 @@ Technical Report (TR) 11 is the first preview for OpenMP 6.0.
@item @code{access} allocator trait changes @tab N @tab
@item Extension of @code{interop} operation of @code{append_args}, allowing all
modifiers of the @code{init} clause
+ @tab N @tab
@item @code{interop} clause to @code{dispatch} @tab N @tab
@item @code{apply} code to loop-transforming constructs @tab N @tab
@item @code{omp_curr_progress_width} identifier @tab N @tab
@@ -4420,7 +4421,7 @@ On the hardware side, there is the hierarchy (fine to coarse):
@item work item (thread)
@item wavefront
@item work group
-@item compute unite (CU)
+@item compute unit (CU)
@end itemize
All OpenMP and OpenACC levels are used, i.e.
@@ -4435,7 +4436,8 @@ All OpenMP and OpenACC levels are used, i.e.
The used sizes are
@itemize
@item Number of teams is the specified @code{num_teams} (OpenMP) or
- @code{num_gangs} (OpenACC) or otherwise the number of CU
+ @code{num_gangs} (OpenACC) or otherwise the number of CU. It is limited
+ by two times the number of CU.
@item Number of wavefronts is 4 for gfx900 and 16 otherwise;
@code{num_threads} (OpenMP) and @code{num_workers} (OpenACC)
overrides this if smaller.
@@ -4481,6 +4483,8 @@ The used sizes are
@itemize
@item The @code{warp_size} is always 32
@item CUDA kernel launched: @code{dim=@{#teams,1,1@}, blocks=@{#threads,warp_size,1@}}.
+@item The number of teams is limited by the number of blocks the device can
+ host simultaneously.
@end itemize
Additional information can be obtained by setting the environment variable to
diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c
index 99a7002..f9b8dda 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -1150,6 +1150,18 @@ limit_worker_threads (int threads)
return threads;
}
+/* This sets the maximum number of teams to twice the number of GPU Compute
+ Units to avoid memory waste and corresponding memory access faults. */
+
+static int
+limit_teams (int teams, struct agent_info *agent)
+{
+ int max_teams = 2 * get_cu_count (agent);
+ if (teams > max_teams)
+ teams = max_teams;
+ return teams;
+}
+
/* Parse the target attributes INPUT provided by the compiler and return true
if we should run anything all. If INPUT is NULL, fill DEF with default
values, then store INPUT or DEF into *RESULT.
@@ -1194,7 +1206,7 @@ parse_target_attributes (void **input,
switch (id & GOMP_TARGET_ARG_ID_MASK)
{
case GOMP_TARGET_ARG_NUM_TEAMS:
- gcn_teams = val;
+ gcn_teams = limit_teams (val, agent);
break;
case GOMP_TARGET_ARG_THREAD_LIMIT:
gcn_threads = limit_worker_threads (val);
diff --git a/libgomp/target.c b/libgomp/target.c
index 189b201..06809db 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -2155,6 +2155,19 @@ get_gomp_offload_icvs (int dev_num)
new->icvs.nteams = gomp_default_icv_values.nteams_var;
if (dev_x != NULL
+ && gomp_get_icv_flag (dev_x->flags, GOMP_ICV_TEAMS_THREAD_LIMIT))
+ new->icvs.teams_thread_limit = dev_x->icvs.teams_thread_limit_var;
+ else if (dev != NULL
+ && gomp_get_icv_flag (dev->flags, GOMP_ICV_TEAMS_THREAD_LIMIT))
+ new->icvs.teams_thread_limit = dev->icvs.teams_thread_limit_var;
+ else if (all != NULL
+ && gomp_get_icv_flag (all->flags, GOMP_ICV_TEAMS_THREAD_LIMIT))
+ new->icvs.teams_thread_limit = all->icvs.teams_thread_limit_var;
+ else
+ new->icvs.teams_thread_limit
+ = gomp_default_icv_values.teams_thread_limit_var;
+
+ if (dev_x != NULL
&& gomp_get_icv_flag (dev_x->flags, GOMP_ICV_DEFAULT_DEVICE))
new->icvs.default_device = dev_x->icvs.default_device_var;
else if (dev != NULL
@@ -2290,7 +2303,14 @@ gomp_load_image_to_device (struct gomp_device_descr *devicep, unsigned version,
int dev_num = (int) (devicep - &devices[0]);
struct gomp_offload_icvs *icvs = get_gomp_offload_icvs (dev_num);
size_t var_size = var->end - var->start;
-
+ if (var_size != sizeof (struct gomp_offload_icvs))
+ {
+ gomp_mutex_unlock (&devicep->lock);
+ if (is_register_lock)
+ gomp_mutex_unlock (&register_lock);
+ gomp_fatal ("offload plugin managed 'icv struct' not of expected "
+ "format");
+ }
/* Copy the ICVs variable to place on device memory, hereby
actually designating its device number into effect. */
gomp_copy_host2dev (devicep, NULL, (void *) var->start, icvs,
@@ -2769,6 +2789,20 @@ clear_unsupported_flags (struct gomp_device_descr *devicep, unsigned int flags)
return flags;
}
+static void
+gomp_copy_back_icvs (struct gomp_device_descr *devicep, int device)
+{
+ struct gomp_offload_icv_list *item = gomp_get_offload_icv_item (device);
+ if (item == NULL)
+ return;
+
+ void *host_ptr = &item->icvs;
+ void *dev_ptr = omp_get_mapped_ptr (host_ptr, device);
+ if (dev_ptr != NULL)
+ gomp_copy_dev2host (devicep, NULL, host_ptr, dev_ptr,
+ sizeof (struct gomp_offload_icvs));
+}
+
/* Like GOMP_target, but KINDS is 16-bit, UNUSED is no longer present,
and several arguments have been added:
FLAGS is a bitmask, see GOMP_TARGET_FLAG_* in gomp-constants.h.
@@ -2801,6 +2835,146 @@ GOMP_target_ext (int device, void (*fn) (void *), size_t mapnum,
size_t tgt_align = 0, tgt_size = 0;
bool fpc_done = false;
+ /* Obtain the original TEAMS and THREADS values from ARGS. */
+ intptr_t orig_teams = 1, orig_threads = 0;
+ size_t num_args = 0, len = 1, teams_len = 1, threads_len = 1;
+ void **tmpargs = args;
+ while (*tmpargs)
+ {
+ intptr_t id = (intptr_t) *tmpargs++, val;
+ if (id & GOMP_TARGET_ARG_SUBSEQUENT_PARAM)
+ {
+ val = (intptr_t) *tmpargs++;
+ len = 2;
+ }
+ else
+ {
+ val = id >> GOMP_TARGET_ARG_VALUE_SHIFT;
+ len = 1;
+ }
+ num_args += len;
+ if ((id & GOMP_TARGET_ARG_DEVICE_MASK) != GOMP_TARGET_ARG_DEVICE_ALL)
+ continue;
+ val = val > INT_MAX ? INT_MAX : val;
+ if ((id & GOMP_TARGET_ARG_ID_MASK) == GOMP_TARGET_ARG_NUM_TEAMS)
+ {
+ orig_teams = val;
+ teams_len = len;
+ }
+ else if ((id & GOMP_TARGET_ARG_ID_MASK) == GOMP_TARGET_ARG_THREAD_LIMIT)
+ {
+ orig_threads = val;
+ threads_len = len;
+ }
+ }
+
+ intptr_t new_teams = orig_teams, new_threads = orig_threads;
+ /* ORIG_TEAMS == -2: No explicit teams construct specified. Set to 1.
+ ORIG_TEAMS == -1: TEAMS construct with NUM_TEAMS clause specified, but the
+ value could not be determined. No change.
+ ORIG_TEAMS == 0: TEAMS construct without NUM_TEAMS clause.
+ Set device-specific value.
+ ORIG_TEAMS > 0: Value was already set through e.g. NUM_TEAMS clause.
+ No change. */
+ if (orig_teams == -2)
+ new_teams = 1;
+ else if (orig_teams == 0)
+ {
+ struct gomp_offload_icv_list *item = gomp_get_offload_icv_item (device);
+ if (item != NULL)
+ new_teams = item->icvs.nteams;
+ }
+ /* The device-specific teams-thread-limit is only set if (a) an explicit TEAMS
+ region exists, i.e. ORIG_TEAMS > -2, and (b) THREADS was not already set by
+ e.g. a THREAD_LIMIT clause. */
+ if (orig_teams > -2 && orig_threads == 0)
+ {
+ struct gomp_offload_icv_list *item = gomp_get_offload_icv_item (device);
+ if (item != NULL)
+ new_threads = item->icvs.teams_thread_limit;
+ }
+
+ /* Copy and change the arguments list only if TEAMS or THREADS need to be
+ updated. */
+ void **new_args = args;
+ if (orig_teams != new_teams || orig_threads != new_threads)
+ {
+ size_t tms_len = (orig_teams == new_teams
+ ? teams_len
+ : (new_teams > -(1 << 15) && new_teams < (1 << 15)
+ ? 1 : 2));
+ size_t ths_len = (orig_threads == new_threads
+ ? threads_len
+ : (new_threads > -(1 << 15) && new_threads < (1 << 15)
+ ? 1 : 2));
+ /* One additional item after the last arg must be NULL. */
+ size_t new_args_cnt = num_args - teams_len - threads_len + tms_len
+ + ths_len + 1;
+ new_args = (void **) gomp_alloca (new_args_cnt * sizeof (void*));
+
+ tmpargs = args;
+ void **tmp_new_args = new_args;
+ /* Copy all args except TEAMS and THREADS. TEAMS and THREADS are copied
+ too if they have not been changed and skipped otherwise. */
+ while (*tmpargs)
+ {
+ intptr_t id = (intptr_t) *tmpargs;
+ if (((id & GOMP_TARGET_ARG_ID_MASK) == GOMP_TARGET_ARG_NUM_TEAMS
+ && orig_teams != new_teams)
+ || ((id & GOMP_TARGET_ARG_ID_MASK) == GOMP_TARGET_ARG_THREAD_LIMIT
+ && orig_threads != new_threads))
+ {
+ tmpargs++;
+ if (id & GOMP_TARGET_ARG_SUBSEQUENT_PARAM)
+ tmpargs++;
+ }
+ else
+ {
+ *tmp_new_args++ = *tmpargs++;
+ if (id & GOMP_TARGET_ARG_SUBSEQUENT_PARAM)
+ *tmp_new_args++ = *tmpargs++;
+ }
+ }
+
+ /* Add the new TEAMS arg to the new args list if it has been changed. */
+ if (orig_teams != new_teams)
+ {
+ intptr_t new_val = new_teams;
+ if (tms_len == 1)
+ {
+ new_val = (new_val << GOMP_TARGET_ARG_VALUE_SHIFT)
+ | GOMP_TARGET_ARG_NUM_TEAMS;
+ *tmp_new_args++ = (void *) new_val;
+ }
+ else
+ {
+ *tmp_new_args++ = (void *) (GOMP_TARGET_ARG_SUBSEQUENT_PARAM
+ | GOMP_TARGET_ARG_NUM_TEAMS);
+ *tmp_new_args++ = (void *) new_val;
+ }
+ }
+
+ /* Add the new THREADS arg to the new args list if it has been changed. */
+ if (orig_threads != new_threads)
+ {
+ intptr_t new_val = new_threads;
+ if (ths_len == 1)
+ {
+ new_val = (new_val << GOMP_TARGET_ARG_VALUE_SHIFT)
+ | GOMP_TARGET_ARG_THREAD_LIMIT;
+ *tmp_new_args++ = (void *) new_val;
+ }
+ else
+ {
+ *tmp_new_args++ = (void *) (GOMP_TARGET_ARG_SUBSEQUENT_PARAM
+ | GOMP_TARGET_ARG_THREAD_LIMIT);
+ *tmp_new_args++ = (void *) new_val;
+ }
+ }
+
+ *tmp_new_args = NULL;
+ }
+
flags = clear_unsupported_flags (devicep, flags);
if (flags & GOMP_TARGET_FLAG_NOWAIT)
@@ -2848,7 +3022,7 @@ GOMP_target_ext (int device, void (*fn) (void *), size_t mapnum,
&& !thr->task->final_task)
{
gomp_create_target_task (devicep, fn, mapnum, hostaddrs,
- sizes, kinds, flags, depend, args,
+ sizes, kinds, flags, depend, new_args,
GOMP_TARGET_TASK_BEFORE_MAP);
return;
}
@@ -2894,7 +3068,7 @@ GOMP_target_ext (int device, void (*fn) (void *), size_t mapnum,
tgt_align, tgt_size);
}
}
- gomp_target_fallback (fn, hostaddrs, devicep, args);
+ gomp_target_fallback (fn, hostaddrs, devicep, new_args);
return;
}
@@ -2924,7 +3098,7 @@ GOMP_target_ext (int device, void (*fn) (void *), size_t mapnum,
}
devicep->run_func (devicep->target_id, fn_addr,
tgt_vars ? (void *) tgt_vars->tgt_start : hostaddrs,
- args);
+ new_args);
if (tgt_vars)
{
htab_clear (refcount_set);
@@ -2932,6 +3106,12 @@ GOMP_target_ext (int device, void (*fn) (void *), size_t mapnum,
}
if (refcount_set)
htab_free (refcount_set);
+
+ /* Copy back ICVs from device to host.
+ HOST_PTR is expected to exist since it was added in
+ gomp_load_image_to_device if not already available. */
+ gomp_copy_back_icvs (devicep, device);
+
}
/* Handle reverse offload. This is called by the device plugins for a
diff --git a/libgomp/testsuite/libgomp.c-c++-common/icv-4.c b/libgomp/testsuite/libgomp.c-c++-common/icv-4.c
index b987a33..9da0d63 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/icv-4.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/icv-4.c
@@ -16,7 +16,7 @@ main ()
}
else
omp_set_num_teams (6);
- if (getenv ("OMP_TEAMS_THREAD_LIMIT") == NULL
+ if (getenv ("OMP_TEAMS_THREAD_LIMIT") != NULL
&& strcmp (getenv ("OMP_TEAMS_THREAD_LIMIT"), "12") == 0)
{
if (omp_get_teams_thread_limit () != 12)
diff --git a/libgomp/testsuite/libgomp.c-c++-common/icv-5.c b/libgomp/testsuite/libgomp.c-c++-common/icv-5.c
index 431cfc7..72d7af6 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/icv-5.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/icv-5.c
@@ -1,25 +1,203 @@
/* { dg-do run } */
-/* { dg-set-target-env-var OMP_NUM_TEAMS_DEV_0 "42" } */
-/* { dg-set-target-env-var OMP_NUM_TEAMS_DEV_1 "43" } */
-/* { dg-set-target-env-var OMP_NUM_TEAMS_DEV_2 "44" } */
-/* { dg-set-target-env-var OMP_NUM_TEAMS_ALL "45" } */
-/* { dg-set-target-env-var OMP_NUM_TEAMS_DEV "46" } */
-/* { dg-set-target-env-var OMP_NUM_TEAMS "47" } */
+/* { dg-set-target-env-var OMP_NUM_TEAMS_ALL "3" } */
+/* { dg-set-target-env-var OMP_NUM_TEAMS_DEV "4" } */
+/* { dg-set-target-env-var OMP_NUM_TEAMS "5" } */
+/* { dg-set-target-env-var OMP_NUM_TEAMS_DEV_0 "6" } */
+/* { dg-set-target-env-var OMP_NUM_TEAMS_DEV_1 "7" } */
+/* { dg-set-target-env-var OMP_NUM_TEAMS_DEV_2 "8" } */
+/* { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_ALL "2" } */
+/* { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_DEV "3" } */
+/* { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT "4" } */
+/* { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_DEV_0 "5" } */
+/* { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_DEV_1 "6" } */
+/* { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_DEV_2 "7" } */
#include <omp.h>
#include <stdlib.h>
+#include <unistd.h>
int
main ()
{
- if (omp_get_max_teams () != 47)
+ if (omp_get_max_teams () != 5
+ || omp_get_teams_thread_limit () != 4)
abort ();
+ #pragma omp teams
+ {
+ if (omp_get_num_teams () > 5
+ || omp_get_team_num () >= 5)
+ abort ();
+ #pragma omp parallel
+ if (omp_get_thread_limit () > 4
+ || omp_get_thread_num () >= 4)
+ abort ();
+ }
+
+ omp_set_num_teams (4);
+ omp_set_teams_thread_limit (3);
+ if (omp_get_max_teams () != 4
+ || omp_get_teams_thread_limit () != 3)
+ abort ();
+
+ #pragma omp teams
+ {
+ if (omp_get_num_teams () > 4
+ || omp_get_team_num () >= 4)
+ abort ();
+ #pragma omp parallel
+ if (omp_get_thread_limit () > 3
+ || omp_get_thread_num () >= 3)
+ abort ();
+ }
+
+ #pragma omp teams num_teams(3) thread_limit(2)
+ {
+ if (omp_get_num_teams () != 3
+ || omp_get_team_num () >= 3)
+ abort ();
+ #pragma omp parallel
+ if (omp_get_thread_limit () > 2
+ || omp_get_thread_num () >= 2)
+ abort ();
+ }
+
+ #pragma omp teams num_teams(5) thread_limit(4)
+ {
+ if (omp_get_num_teams () != 5
+ || omp_get_team_num () >= 5)
+ abort ();
+ #pragma omp parallel
+ if (omp_get_thread_limit () > 4
+ || omp_get_thread_num () >= 4)
+ abort ();
+ }
+
int num_devices = omp_get_num_devices () > 3 ? 3 : omp_get_num_devices ();
- for (int i=0; i < num_devices; i++)
- #pragma omp target device (i)
- if (omp_get_max_teams () != 42 + i)
+
+ for (int i = 0; i < num_devices; i++)
+ {
+ #pragma omp target device (i)
+ if (omp_get_max_teams () != 6 + i
+ || omp_get_teams_thread_limit () != 5 + i)
+ abort ();
+
+ #pragma omp target device (i)
+ #pragma omp teams
+ #pragma omp parallel
+ if (omp_get_thread_limit () > 5 + i
+ || omp_get_thread_num () >= 5 + i)
+ abort ();
+
+ #pragma omp target device (i)
+ {
+ omp_set_num_teams (5 + i);
+ omp_set_teams_thread_limit (4 + i);
+ if (omp_get_max_teams () != 5 + i
+ || omp_get_teams_thread_limit () != 4 + i)
+ abort ();
+ }
+
+ /* omp_set_num_teams and omp_set_teams_thread_limit above set the value
+ of nteams-var and teams-thread-limit-var ICVs on device 'i', which has
+ scope 'device' and should be avaible in subsequent target regions. */
+ #pragma omp target device (i)
+ if (omp_get_max_teams () != 5 + i
+ || omp_get_teams_thread_limit () != 4 + i)
+ abort ();
+
+ #pragma omp target device (i)
+ #pragma omp teams
+ {
+ if (omp_get_num_teams () > 5 + i
+ || omp_get_team_num () >= 5 + i)
+ abort ();
+ #pragma omp parallel
+ if (omp_get_thread_limit () > 4 + i
+ || omp_get_thread_num () >= 4 + i)
+ abort ();
+ }
+
+ #pragma omp target device (i)
+ #pragma omp teams num_teams(6 + i) thread_limit(5 + i)
+ {
+ if (omp_get_num_teams () > 6 + i
+ || omp_get_team_num () >= 6 + i)
+ abort ();
+ #pragma omp parallel
+ if (omp_get_thread_limit () > 5 + i
+ || omp_get_thread_num () >= 5 + i
+ || omp_get_num_teams () > 6 + i
+ || omp_get_team_num () >= 6 + i)
+ abort ();
+ }
+
+ #pragma omp target device (i)
+ #pragma omp teams num_teams(4 + i) thread_limit(3 + i)
+ {
+ if (omp_get_num_teams () > 4 + i
+ || omp_get_team_num () >= 4 + i)
+ abort ();
+ #pragma omp parallel
+ if (omp_get_thread_limit () > 3 + i
+ || omp_get_thread_num () >= 3 + i
+ || omp_get_num_teams () > 4 + i
+ || omp_get_team_num () >= 4 + i)
+ abort ();
+ }
+
+ #pragma omp target device (i)
+ #pragma omp teams thread_limit(3 + i) num_teams(4 + i)
+ {
+ if (omp_get_num_teams () > 4 + i
+ || omp_get_team_num () >= 4 + i)
+ abort ();
+ #pragma omp parallel
+ if (omp_get_thread_limit () > 3 + i
+ || omp_get_thread_num () >= 3 + i
+ || omp_get_num_teams () > 4 + i
+ || omp_get_team_num () >= 4 + i)
+ abort ();
+ }
+
+ /* The NUM_TEAMS and THREAD_LIMIT clauses should not change the values
+ of the corresponding ICVs. */
+ #pragma omp target device (i)
+ if (omp_get_max_teams () != 5 + i
+ || omp_get_teams_thread_limit () != 4 + i)
+ abort ();
+
+ /* This tests a large number of teams and threads. If it is larger than
+ 2^15+1 then the according argument in the kernels arguments list
+ is encoded with two items instead of one. */
+ intptr_t large_num_teams = 66000;
+ intptr_t large_threads_limit = 67000;
+ #pragma omp target device (i)
+ {
+ omp_set_num_teams (large_num_teams + i);
+ omp_set_teams_thread_limit (large_threads_limit + i);
+ if (omp_get_max_teams () != large_num_teams + i
+ || omp_get_teams_thread_limit () != large_threads_limit + i)
+ abort ();
+ }
+
+ #pragma omp target device (i)
+ if (omp_get_max_teams () != large_num_teams + i
+ || omp_get_teams_thread_limit () != large_threads_limit + i)
abort ();
+ #pragma omp target device (i)
+ #pragma omp teams
+ {
+ if (omp_get_num_teams () > large_num_teams + i
+ || omp_get_team_num () >= large_num_teams + i)
+ abort ();
+ #pragma omp parallel
+ if (omp_get_thread_limit () > large_threads_limit + i
+ || omp_get_thread_num () >= large_threads_limit + i)
+ abort ();
+ }
+ }
+
return 0;
}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/icv-6.c b/libgomp/testsuite/libgomp.c-c++-common/icv-6.c
index e199a18..1b17f2d 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/icv-6.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/icv-6.c
@@ -1,9 +1,10 @@
/* { dg-do run } */
-/* { dg-set-target-env-var OMP_NUM_TEAMS_ALL "42" } */
-/* { dg-set-target-env-var OMP_NUM_TEAMS_DEV "43" } */
+/* { dg-set-target-env-var OMP_NUM_TEAMS_ALL "3" } */
+/* { dg-set-target-env-var OMP_NUM_TEAMS_DEV "4" } */
+/* { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_ALL "2" } */
+/* { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_DEV "3" } */
/* { dg-set-target-env-var OMP_SCHEDULE_ALL "guided,4" } */
/* { dg-set-target-env-var OMP_DYNAMIC_ALL "true" } */
-/* { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_ALL "44" } */
/* { dg-set-target-env-var OMP_THREAD_LIMIT_ALL "45" } */
/* { dg-set-target-env-var OMP_NUM_THREADS_ALL "46,3,2" } */
/* { dg-set-target-env-var OMP_MAX_ACTIVE_LEVELS_ALL "47" } */
@@ -12,8 +13,8 @@
/* This tests the hierarchical usage of ICVs on the device, i.e. if
OMP_NUM_TEAMS_DEV_<device_num> is not configured, then the value of
- OMP_NUM_TEAMS_DEV should be used. And if there is no environment variable
- without suffix, then the corresponding _ALL variant should be used. */
+ OMP_NUM_TEAMS_DEV should be used. And if OMP_NUM_TEAMS (without suffix) is
+ not defined, then OMP_NUM_TEAMS_ALL should be used for the host. */
#include <omp.h>
#include <stdlib.h>
@@ -26,10 +27,10 @@ main ()
int chunk_size;
omp_get_schedule(&kind, &chunk_size);
- if ((!getenv ("OMP_NUM_TEAMS") && omp_get_max_teams () != 42)
+ if ((!getenv ("OMP_NUM_TEAMS") && omp_get_max_teams () != 3)
|| (!getenv ("OMP_DYNAMIC") && !omp_get_dynamic ())
|| (!getenv ("OMP_SCHEDULE") && (kind != 3 || chunk_size != 4))
- || (!getenv ("OMP_TEAMS_THREAD_LIMIT") && omp_get_teams_thread_limit () != 44)
+ || (!getenv ("OMP_TEAMS_THREAD_LIMIT") && omp_get_teams_thread_limit () != 2)
|| (!getenv ("OMP_THREAD_LIMIT") && omp_get_thread_limit () != 45)
|| (!getenv ("OMP_NUM_THREADS") && omp_get_max_threads () != 46)
|| (!getenv ("OMP_PROC_BIND") && omp_get_proc_bind () != omp_proc_bind_spread)
@@ -44,9 +45,51 @@ main ()
name[sizeof ("OMP_NUM_TEAMS_DEV_1") - 2] = '0' + i;
if (getenv (name))
continue;
- #pragma omp target device (i)
- if (omp_get_max_teams () != 43)
+
+ #pragma omp target device (i)
+ if (omp_get_max_teams () != 4
+ || omp_get_teams_thread_limit () != 3)
abort ();
+ #pragma omp target device (i)
+ #pragma omp teams
+ {
+ if (omp_get_num_teams () > 4
+ || omp_get_team_num () >= 4)
+ abort ();
+ #pragma omp parallel
+ if (omp_get_thread_limit () > 3
+ || omp_get_thread_num () >= 3)
+ abort ();
+ }
+
+ #pragma omp target device (i)
+ {
+ omp_set_num_teams (3 + i);
+ omp_set_teams_thread_limit (2 + i);
+ if (omp_get_max_teams () != 3 + i
+ || omp_get_teams_thread_limit () != 2 + i)
+ abort ();
+ }
+
+ /* omp_set_num_teams above set the value of nteams-var ICV on device 'i',
+ which has scope 'device' and should be avaible in subsequent target
+ regions. */
+ #pragma omp target device (i)
+ if (omp_get_max_teams () != 3 + i
+ || omp_get_teams_thread_limit () != 2 + i)
+ abort ();
+
+ #pragma omp target device (i)
+ #pragma omp teams
+ {
+ if (omp_get_num_teams () > 3 + i
+ || omp_get_team_num () >= 3 + i)
+ abort ();
+ #pragma omp parallel
+ if (omp_get_thread_limit () > 2 + i
+ || omp_get_thread_num () >= 2 + i)
+ abort ();
+ }
}
return 0;
diff --git a/libgomp/testsuite/libgomp.c-c++-common/icv-7.c b/libgomp/testsuite/libgomp.c-c++-common/icv-7.c
index 70a716d..bbbd6df 100644
--- a/libgomp/testsuite/libgomp.c-c++-common/icv-7.c
+++ b/libgomp/testsuite/libgomp.c-c++-common/icv-7.c
@@ -1,5 +1,6 @@
/* { dg-do run } */
-/* { dg-set-target-env-var OMP_NUM_TEAMS_ALL "42" } */
+/* { dg-set-target-env-var OMP_NUM_TEAMS_ALL "7" } */
+/* { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_ALL "2" } */
/* This tests the hierarchical usage of ICVs on the host and on devices, i.e. if
OMP_NUM_TEAMS_DEV_<device_num>, OMP_NUM_TEAMS_DEV, and
@@ -9,18 +10,90 @@
#include <omp.h>
#include <stdlib.h>
+#include <string.h>
int
main ()
{
- if (omp_get_max_teams () != 42)
+ if ((!getenv ("OMP_NUM_TEAMS") && omp_get_max_teams () != 7)
+ || (!getenv ("OMP_TEAMS_THREAD_LIMIT") && omp_get_teams_thread_limit () != 2))
abort ();
+ #pragma omp teams
+ if ((!getenv ("OMP_NUM_TEAMS"))
+ && (omp_get_num_teams () > 7 || omp_get_team_num () >= 7))
+ abort ();
+
+ omp_set_num_teams (9);
+ omp_set_teams_thread_limit (3);
+ if (omp_get_max_teams () != 9
+ || omp_get_teams_thread_limit () != 3)
+ abort ();
+
+ #pragma omp teams
+ if (omp_get_num_teams () > 9
+ || omp_get_team_num () >= 9)
+ abort ();
+
+ #pragma omp teams num_teams(5)
+ if (omp_get_num_teams () > 5
+ || omp_get_team_num () >= 5)
+ abort ();
+
+ if (getenv ("OMP_NUM_TEAMS_DEV") || getenv ("OMP_TEAMS_THREAD_LIMIT_DEV"))
+ return 0;
+
int num_devices = omp_get_num_devices () > 3 ? 3 : omp_get_num_devices ();
- for (int i=0; i < num_devices; i++)
- #pragma omp target device (i)
- if (omp_get_max_teams () != 42)
+ for (int i = 0; i < num_devices; i++)
+ {
+ char nteams[sizeof ("OMP_NUM_TEAMS_DEV_1")];
+ strcpy (nteams, "OMP_NUM_TEAMS_DEV_1");
+ nteams[sizeof ("OMP_NUM_TEAMS_DEV_1") - 2] = '0' + i;
+ char teams_thread_limit[sizeof ("OMP_TEAMS_THREAD_LIMIT_DEV_1")];
+ strcpy (teams_thread_limit, "OMP_TEAMS_THREAD_LIMIT_DEV_1");
+ teams_thread_limit[sizeof ("OMP_TEAMS_THREAD_LIMIT_DEV_1") - 2] = '0' + i;
+ if (getenv (nteams) || getenv (teams_thread_limit))
+ continue;
+
+ #pragma omp target device (i)
+ if (omp_get_max_teams () != 7
+ || omp_get_teams_thread_limit () != 2)
+ abort ();
+
+ #pragma omp target device (i)
+ #pragma omp teams
+ if (omp_get_num_teams () > 7
+ || omp_get_team_num () >= 7)
+ abort ();
+
+ #pragma omp target device (i)
+ {
+ omp_set_num_teams (8 + i);
+ omp_set_teams_thread_limit (4 + i);
+ if (omp_get_max_teams () != 8 + i
+ || omp_get_teams_thread_limit () != 4 + i)
+ abort ();
+ }
+
+ /* omp_set_num_teams above set the value of nteams-var ICV on device 'i',
+ which has scope 'device' and should be avaible in subsequent target
+ regions. */
+ #pragma omp target device (i)
+ if (omp_get_max_teams () != 8 + i
+ || omp_get_teams_thread_limit () != 4 + i)
+ abort ();
+
+ #pragma omp target device (i)
+ #pragma omp teams
+ if (omp_get_num_teams () > 8 + i
+ || omp_get_team_num () >= 8 + i)
+ abort ();
+
+ #pragma omp target device (i)
+ #pragma omp teams num_teams(5 + i)
+ if (omp_get_num_teams () != 5 + i)
abort ();
+ }
return 0;
}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/icv-9.c b/libgomp/testsuite/libgomp.c-c++-common/icv-9.c
new file mode 100644
index 0000000..21b874f
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/icv-9.c
@@ -0,0 +1,72 @@
+/* { dg-do run } */
+
+/* This tests usage of ICVs on the host and on devices if no corresponding
+ environment variables are configured. */
+
+#include <omp.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+ if (omp_get_max_teams () != 0
+ || omp_get_teams_thread_limit () != 0)
+ abort ();
+
+ omp_set_num_teams (9);
+ omp_set_teams_thread_limit (2);
+ if (omp_get_max_teams () != 9
+ || omp_get_teams_thread_limit () != 2)
+ abort ();
+
+ #pragma omp teams
+ if (omp_get_num_teams () > 9
+ || omp_get_team_num () >= 9)
+ abort ();
+
+ #pragma omp teams num_teams(5)
+ if (omp_get_num_teams () > 5
+ || omp_get_team_num () >= 5)
+ abort ();
+
+ int num_devices = omp_get_num_devices () > 3 ? 3 : omp_get_num_devices ();
+ for (int i = 0; i < num_devices; i++)
+ {
+ #pragma omp target device (i)
+ if (omp_get_max_teams () != 0
+ || omp_get_teams_thread_limit () != 0)
+ abort ();
+
+ #pragma omp target device (i)
+ {
+ omp_set_num_teams (8 + i);
+ omp_set_teams_thread_limit (3 + i);
+ if (omp_get_max_teams () != 8 + i
+ || omp_get_teams_thread_limit () != 3 + i)
+ abort ();
+ }
+
+ /* omp_set_num_teams above set the value of nteams-var ICV on device 'i',
+ which has scope 'device' and should be avaible in subsequent target
+ regions. */
+ #pragma omp target device (i)
+ if (omp_get_max_teams () != 8 + i
+ || omp_get_teams_thread_limit () != 3 + i)
+ abort ();
+
+ #pragma omp target device (i)
+ #pragma omp teams
+ if (omp_get_num_teams () > 8 + i
+ || omp_get_team_num () >= 8 + i)
+ abort ();
+
+ /* NUM_TEAMS clause has priority over previously set NUM_TEAMS value. */
+ #pragma omp target device (i)
+ #pragma omp teams num_teams(5 + i)
+ if (omp_get_num_teams () > 5 + i
+ || omp_get_team_num () >= 5 + i)
+ abort ();
+ }
+
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.fortran/icv-5.f90 b/libgomp/testsuite/libgomp.fortran/icv-5.f90
new file mode 100644
index 0000000..05a35fa
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/icv-5.f90
@@ -0,0 +1,226 @@
+! { dg-set-target-env-var OMP_NUM_TEAMS_ALL "3" }
+! { dg-set-target-env-var OMP_NUM_TEAMS_DEV "4" }
+! { dg-set-target-env-var OMP_NUM_TEAMS "5" }
+! { dg-set-target-env-var OMP_NUM_TEAMS_DEV_0 "6" }
+! { dg-set-target-env-var OMP_NUM_TEAMS_DEV_1 "7" }
+! { dg-set-target-env-var OMP_NUM_TEAMS_DEV_2 "8" }
+! { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_ALL "2" }
+! { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_DEV "3" }
+! { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT "4" }
+! { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_DEV_0 "5" }
+! { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_DEV_1 "6" }
+! { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_DEV_2 "7" }
+
+use omp_lib
+implicit none (type, external)
+ integer :: num_devices, i, large_num_teams, large_threads_limit
+ logical :: err
+
+ if (omp_get_num_devices () > 3) then
+ num_devices = 3
+ else
+ num_devices = omp_get_num_devices ()
+ end if
+
+ do i=0,num_devices-1
+
+ ! Testing NUM_TEAMS.
+ if (env_is_set_dev ("OMP_NUM_TEAMS_DEV_", i, 6 + i)) then
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ if (omp_get_max_teams () /= 6 + i) err = .true.
+ !$omp end target
+ if (err) stop 1
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams
+ if (omp_get_num_teams () > 6 + i .or. omp_get_team_num () >= 6 + i) &
+ err = .true.
+ !$omp end teams
+ !$omp end target
+ if (err) stop 2
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ call omp_set_num_teams (5 + i)
+ if (omp_get_max_teams () /= 5 + i) err = .true.
+ !$omp end target
+ if (err) stop 3
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ if (omp_get_max_teams () /= 5 + i) err = .true.
+ !$omp end target
+ if (err) stop 4
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams
+ if (omp_get_num_teams () > 5 + i .or. omp_get_team_num () >= 5 + i) &
+ err = .true.
+ !$omp end teams
+ !$omp end target
+ if (err) stop 5
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams num_teams(6 + i)
+ if (omp_get_num_teams () > 6 + i .or. omp_get_team_num () >= 6 + i) &
+ err = .true.
+ !$omp end teams
+ !$omp end target
+ if (err) stop 6
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams num_teams(4 + i)
+ if (omp_get_num_teams () > 4 + i .or. omp_get_team_num () >= 4 + i) &
+ err = .true.
+ !$omp end teams
+ !$omp end target
+ if (err) stop 7
+
+ large_num_teams = 66000
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ call omp_set_num_teams (large_num_teams + i)
+ if (omp_get_max_teams () /= large_num_teams + i) err = .true.
+ !$omp end target
+ if (err) stop 8
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ if (omp_get_max_teams () /= large_num_teams + i) err = .true.
+ !$omp end target
+ if (err) stop 9
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams
+ if (omp_get_num_teams () > large_num_teams + i &
+ .or. omp_get_team_num () >= large_num_teams + i) err = .true.
+ !$omp end teams
+ !$omp end target
+ if (err) stop 10
+ end if
+
+ ! Testing TEAMS-THREAD-LIMIT
+ if (env_is_set_dev ("OMP_TEAMS_THREAD_LIMIT_DEV_", i, 5 + i)) then
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ if (omp_get_teams_thread_limit () /= 5 + i) err = .true.
+ !$omp end target
+ if (err) stop 11
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams
+ !$omp parallel
+ if (omp_get_thread_limit () > 5 + i .or. omp_get_thread_num () >= 5 + i) &
+ err = .true.
+ !$omp end parallel
+ !$omp end teams
+ !$omp end target
+ if (err) stop 12
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ call omp_set_teams_thread_limit (4 + i)
+ if (omp_get_teams_thread_limit () /= 4 + i) err = .true.
+ !$omp end target
+ if (err) stop 13
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ if (omp_get_teams_thread_limit () /= 4 + i) err = .true.
+ !$omp end target
+ if (err) stop 14
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams
+ !$omp parallel
+ if (omp_get_thread_limit () > 4 + i .or. omp_get_thread_num () >= 4 + i) &
+ err = .true.
+ !$omp end parallel
+ !$omp end teams
+ !$omp end target
+ if (err) stop 15
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams thread_limit(5 + i)
+ !$omp parallel
+ if (omp_get_thread_limit () > 5 + i .or. omp_get_thread_num () >= 5 + i) &
+ err = .true.
+ !$omp end parallel
+ !$omp end teams
+ !$omp end target
+ if (err) stop 16
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams thread_limit(3 + i)
+ !$omp parallel
+ if (omp_get_thread_limit () > 3 + i .or. omp_get_thread_num () >= 3 + i) &
+ err = .true.
+ !$omp end parallel
+ !$omp end teams
+ !$omp end target
+ if (err) stop 17
+
+ large_threads_limit = 67000
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ call omp_set_teams_thread_limit (large_threads_limit + i)
+ if (omp_get_teams_thread_limit () /= large_threads_limit + i) err = .true.
+ !$omp end target
+ if (err) stop 18
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ if (omp_get_teams_thread_limit () /= large_threads_limit + i) err = .true.
+ !$omp end target
+ if (err) stop 19
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams
+ !$omp parallel
+ if (omp_get_thread_limit () > large_threads_limit + i &
+ .or. omp_get_thread_num () >= large_threads_limit + i) err = .true.
+ !$omp end parallel
+ !$omp end teams
+ !$omp end target
+ if (err) stop 20
+ end if
+
+ end do
+
+contains
+ logical function env_is_set (name, val)
+ character(len=*) :: name, val
+ character(len=40) :: val2
+ integer :: stat
+ call get_environment_variable (name, val2, status=stat)
+ if (stat == 0) then
+ if (val == val2) then
+ env_is_set = .true.
+ return
+ end if
+ else if (stat /= 1) then
+ error stop 30
+ endif
+ env_is_set = .false.
+ end
+ logical function env_is_set_dev (name, dev_num, val)
+ character(len=*) :: name
+ integer :: dev_num, val
+ character(len=64) :: dev_num_str, env_var, val_str
+ dev_num_str = ADJUSTL(dev_num_str)
+ env_var = name // dev_num_str
+ val_str = ADJUSTL(val_str)
+ env_is_set_dev = env_is_set (TRIM(env_var), TRIM(val_str))
+ end
+end
diff --git a/libgomp/testsuite/libgomp.fortran/icv-6.f90 b/libgomp/testsuite/libgomp.fortran/icv-6.f90
new file mode 100644
index 0000000..c8e6a0d
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/icv-6.f90
@@ -0,0 +1,140 @@
+! { dg-set-target-env-var OMP_NUM_TEAMS_ALL "3" }
+! { dg-set-target-env-var OMP_NUM_TEAMS_DEV "4" }
+! { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_ALL "2" }
+! { dg-set-target-env-var OMP_TEAMS_THREAD_LIMIT_DEV "3" }
+
+! This test considers the hierarchical usage of ICVs on the device, i.e. if
+! e.g. OMP_NUM_TEAMS_DEV_<device_num> is not configured, then the value of
+! OMP_NUM_TEAMS_DEV should be used for the targets.
+
+use omp_lib
+implicit none (type, external)
+ integer :: num_devices, i, stat, tmp
+ logical :: err
+ character(len=40) :: val
+
+ ! The following environment variables should not be set.
+ call get_environment_variable ("OMP_NUM_TEAMS_DEV_0", val, status=stat)
+ if (stat /= 1) return
+ call get_environment_variable ("OMP_NUM_TEAMS_DEV_1", val, status=stat)
+ if (stat /= 1) return
+ call get_environment_variable ("OMP_NUM_TEAMS_DEV_2", val, status=stat)
+ if (stat /= 1) return
+ call get_environment_variable ("OMP_TEAMS_THREAD_LIMIT_DEV_0", val, status=stat)
+ if (stat /= 1) return
+ call get_environment_variable ("OMP_TEAMS_THREAD_LIMIT_DEV_1", val, status=stat)
+ if (stat /= 1) return
+ call get_environment_variable ("OMP_TEAMS_THREAD_LIMIT_DEV_2", val, status=stat)
+ if (stat /= 1) return
+
+ if (omp_get_num_devices () > 3) then
+ num_devices = 3
+ else
+ num_devices = omp_get_num_devices ()
+ end if
+
+ do i=0,num_devices-1
+
+ ! Testing NUM_TEAMS.
+ if (env_is_set ("OMP_NUM_TEAMS_DEV", "4")) then
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ if (omp_get_max_teams () /= 4) err = .true.
+ !$omp end target
+ if (err) stop 1
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams
+ if (omp_get_num_teams () > 4 .or. omp_get_team_num () >= 4) &
+ err = .true.
+ !$omp end teams
+ !$omp end target
+ if (err) stop 2
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ call omp_set_num_teams (3 + i)
+ if (omp_get_max_teams () /= 3 + i) err = .true.
+ !$omp end target
+ if (err) stop 3
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ if (omp_get_max_teams () /= 3 + i) err = .true.
+ !$omp end target
+ if (err) stop 4
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams
+ if (omp_get_num_teams () > 3 + i .or. omp_get_team_num () >= 3 + i) &
+ err = .true.
+ !$omp end teams
+ !$omp end target
+ if (err) stop 5
+ end if
+
+ ! Testing TEAMS-THREAD-LIMIT
+ if (env_is_set ("OMP_TEAMS_THREAD_LIMIT_DEV", "3")) then
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ if (omp_get_teams_thread_limit () /= 3) err = .true.
+ !$omp end target
+ if (err) stop 6
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams
+ !$omp parallel
+ if (omp_get_thread_limit () > 3 .or. omp_get_thread_num () >= 3) &
+ err = .true.
+ !$omp end parallel
+ !$omp end teams
+ !$omp end target
+ if (err) stop 7
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ call omp_set_teams_thread_limit (2 + i)
+ if (omp_get_teams_thread_limit () /= 2 + i) err = .true.
+ !$omp end target
+ if (err) stop 8
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ if (omp_get_teams_thread_limit () /= 2 + i) err = .true.
+ !$omp end target
+ if (err) stop 9
+
+ err = .false.
+ !$omp target device(i) map(tofrom: err)
+ !$omp teams
+ !$omp parallel
+ if (omp_get_thread_limit () > 2 + i .or. omp_get_thread_num () >= 2 + i) &
+ err = .true.
+ !$omp end parallel
+ !$omp end teams
+ !$omp end target
+ if (err) stop 10
+ end if
+
+ end do
+
+contains
+ logical function env_is_set (name, val)
+ character(len=*) :: name, val
+ character(len=40) :: val2
+ integer :: stat
+ call get_environment_variable (name, val2, status=stat)
+ if (stat == 0) then
+ if (val == val2) then
+ env_is_set = .true.
+ return
+ end if
+ else if (stat /= 1) then
+ error stop 10
+ endif
+ env_is_set = .false.
+ end
+end
diff --git a/libsanitizer/ChangeLog b/libsanitizer/ChangeLog
index a0e5003..2a7ce17 100644
--- a/libsanitizer/ChangeLog
+++ b/libsanitizer/ChangeLog
@@ -1,3 +1,7 @@
+2022-12-04 Iain Sandoe <iain@sandoe.co.uk>
+
+ * configure.tgt: Restrict build to Darwin 16 or newer.
+
2022-11-15 Martin Liska <mliska@suse.cz>
* LOCAL_PATCHES: Update local patches.
diff --git a/libsanitizer/configure.tgt b/libsanitizer/configure.tgt
index 87d8a2c..1175cd1 100644
--- a/libsanitizer/configure.tgt
+++ b/libsanitizer/configure.tgt
@@ -64,7 +64,7 @@ case "${target}" in
HWASAN_SUPPORTED=yes
fi
;;
- x86_64-*-darwin2* | x86_64-*-darwin1[2-9]* | i?86-*-darwin1[2-9]*)
+ x86_64-*-darwin2* | x86_64-*-darwin1[6-9]* | i?86-*-darwin1[6-8]*)
TSAN_SUPPORTED=no
EXTRA_CXXFLAGS="${EXTRA_CXXFLAGS} -Wl,-undefined,dynamic_lookup"
;;
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 8c764b6..cfa25d0 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,97 @@
+2022-12-06 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/107979
+ * testsuite/17_intro/names.cc: Do not check __unused on old
+ Glibc versions.
+
+2022-12-06 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/107871
+ * include/std/format (_Iter_sink::_M_overflow): Add cast to
+ size_t.
+ (_Iter_sink<CharT, contiguous_iterator auto>::_M_make_span): Use
+ typedef instead of decltype.
+ * testsuite/std/format/functions/107871.cc: New test.
+
+2022-12-06 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/std/chrono (chrono::hh_mm_ss): Do not use 64-bit
+ representations for all four duration members. Reorder members.
+ (hh_mm_ss::hh_mm_ss()): Define as defaulted.
+ (hh_mm_ss::hh_mm_ss(Duration)): Delegate to a new private
+ constructor, instead of calling chrono::abs repeatedly.
+ * testsuite/std/time/hh_mm_ss/1.cc: Check floating-point
+ representations. Check default constructor. Check sizes.
+
+2022-12-06 Jonathan Wakely <jwakely@redhat.com>
+
+ PR c++/106434
+ * include/bits/vector.tcc (insert(const_iterator, const T&)):
+ Add assertion and optimization hint that the iterator for the
+ insertion point must be non-null.
+
+2022-12-06 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/bits/std_mutex.h (mutex): Add nodiscard attribute to
+ try_lock member function.
+ * include/bits/unique_lock.h (unique_lock): Likewise for
+ try_lock, try_lock_until, try_lock_for member functions, and
+ owns_lock and mutex member functions.
+ * include/std/mutex (recursive_mutex): Likewise for try_lock
+ member function.
+ (timed_mutex, recursive_timed_mutex, try_lock): Likewise for
+ try_lock, try_lock_until, try_lock_for member functions.
+ (try_lock): Likewise for non-member function.
+ * include/std/shared_mutex (shared_mutex): Likewise for try_lock
+ and try_lock_shared member functions.
+ (shared_timed_mutex): Likewise for try_lock, try_lock_for,
+ try_lock_shared, try_lock_shared_for, try_lock_until, and
+ try_lock_shared_until member functions.
+ (shared_lock): Likewise for try_lock, try_lock, try_lock_for,
+ try_lock_until, owns_lock, and mutex member functions.
+ * testsuite/30_threads/recursive_timed_mutex/try_lock_until/clock_neg.cc:
+ Cast discarded value expression to void.
+ * testsuite/30_threads/shared_lock/locking/3.cc: Likewise.
+ * testsuite/30_threads/shared_lock/locking/4.cc: Likewise.
+ * testsuite/30_threads/shared_lock/locking/clock_neg.cc:
+ Likewise.
+ * testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc:
+ Likewise.
+ * testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc:
+ Likewise.
+ * testsuite/30_threads/try_lock/4.cc: Likewise.
+ * testsuite/30_threads/unique_lock/cons/60497.cc: Likewise.
+ * testsuite/30_threads/unique_lock/locking/3.cc: Likewise.
+ * testsuite/30_threads/unique_lock/locking/clock_neg.cc:
+ Likewise.
+
+2022-12-06 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/std/format (basic_format_parse_context::next_arg_id):
+ Only check arg-id is in range during constant evaluation.
+ * testsuite/std/format/functions/format.cc: Check "{:#Lx}".
+ * testsuite/std/format/parse_ctx.cc: Adjust expected results for
+ format-strings using an out-of-range arg-id.
+
+2022-12-04 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/os/bsd/darwin/os_defines.h
+ (_GTHREAD_USE_RECURSIVE_MUTEX_INIT_FUNC): Limit use of this macro
+ to OS versions that need it.
+
+2022-12-04 Iain Sandoe <iain@sandoe.co.uk>
+
+ * config/os/bsd/darwin/os_defines.h (_GLIBCXX_WEAK_DEFINITION): Use the
+ implementation namespace for the weak attribute.
+
+2022-12-02 Björn Schäpers <bjoern@hazardy.de>
+ Jonathan Wakely <jwakely@redhat.com>
+
+ * include/std/stacktrace (stacktrace_entry::_S_err_handler): New
+ static function.
+ (stacktrace_entry, basic_stacktrace): Pass &_S_err_handler to
+ all calls to libbacktrace.
+
2022-11-29 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/107852
diff --git a/libstdc++-v3/config/os/bsd/darwin/os_defines.h b/libstdc++-v3/config/os/bsd/darwin/os_defines.h
index a8b6d4f..5b611d3 100644
--- a/libstdc++-v3/config/os/bsd/darwin/os_defines.h
+++ b/libstdc++-v3/config/os/bsd/darwin/os_defines.h
@@ -33,14 +33,18 @@
links to, so there's no need for weak-ness for that. */
#define _GLIBCXX_GTHREAD_USE_WEAK 0
-// On Darwin, in order to enable overriding of operator new and delete,
-// GCC makes the definition of these functions weak, relies on the
-// loader to implement weak semantics properly, and uses
-// -flat_namespace to work around the way that it doesn't.
-#define _GLIBCXX_WEAK_DEFINITION __attribute__ ((weak))
-
-// Static initializer macro is buggy in darwin, see libstdc++/51906
+// On Darwin, in order to enable overriding of operator new and delete, the
+// ABI library exports a weak definition. The static linker will override this
+// iff a user-provided implementation is given (providing that the user
+// implementation is not itself a weak definition).
+#define _GLIBCXX_WEAK_DEFINITION __attribute__ ((__weak__))
+
+#if defined (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) \
+ && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1080)
+// Static initializer macro is absent for Darwin < 11 and buggy in Darwin 11,
+// see libstdc++/51906. Fixed in Darwin 12 (OS X 10.8).
#define _GTHREAD_USE_RECURSIVE_MUTEX_INIT_FUNC
+#endif
// Configure checks for nanosleep fail on Darwin, but nanosleep and
// sched_yield are always available, so use them.
diff --git a/libstdc++-v3/include/bits/std_mutex.h b/libstdc++-v3/include/bits/std_mutex.h
index b22e0e1..68f5fb9 100644
--- a/libstdc++-v3/include/bits/std_mutex.h
+++ b/libstdc++-v3/include/bits/std_mutex.h
@@ -117,6 +117,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__throw_system_error(__e);
}
+ _GLIBCXX_NODISCARD
bool
try_lock() noexcept
{
diff --git a/libstdc++-v3/include/bits/unique_lock.h b/libstdc++-v3/include/bits/unique_lock.h
index 9ed7ba2..c6402d9 100644
--- a/libstdc++-v3/include/bits/unique_lock.h
+++ b/libstdc++-v3/include/bits/unique_lock.h
@@ -143,6 +143,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
}
+ _GLIBCXX_NODISCARD
bool
try_lock()
{
@@ -158,6 +159,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Clock, typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
{
@@ -173,6 +175,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Rep, typename _Period>
+ _GLIBCXX_NODISCARD
bool
try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
{
@@ -215,6 +218,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __ret;
}
+ _GLIBCXX_NODISCARD
bool
owns_lock() const noexcept
{ return _M_owns; }
@@ -222,6 +226,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
explicit operator bool() const noexcept
{ return owns_lock(); }
+ _GLIBCXX_NODISCARD
mutex_type*
mutex() const noexcept
{ return _M_device; }
diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc
index 27ef1a4..8ae79ff 100644
--- a/libstdc++-v3/include/bits/vector.tcc
+++ b/libstdc++-v3/include/bits/vector.tcc
@@ -139,26 +139,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{
const size_type __n = __position - begin();
if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage)
- if (__position == end())
- {
- _GLIBCXX_ASAN_ANNOTATE_GROW(1);
- _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
- __x);
- ++this->_M_impl._M_finish;
- _GLIBCXX_ASAN_ANNOTATE_GREW(1);
- }
- else
- {
+ {
+ __glibcxx_assert(__position != const_iterator());
+ if (!(__position != const_iterator()))
+ __builtin_unreachable(); // PR 106434
+
+ if (__position == end())
+ {
+ _GLIBCXX_ASAN_ANNOTATE_GROW(1);
+ _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish,
+ __x);
+ ++this->_M_impl._M_finish;
+ _GLIBCXX_ASAN_ANNOTATE_GREW(1);
+ }
+ else
+ {
#if __cplusplus >= 201103L
- const auto __pos = begin() + (__position - cbegin());
- // __x could be an existing element of this vector, so make a
- // copy of it before _M_insert_aux moves elements around.
- _Temporary_value __x_copy(this, __x);
- _M_insert_aux(__pos, std::move(__x_copy._M_val()));
+ const auto __pos = begin() + (__position - cbegin());
+ // __x could be an existing element of this vector, so make a
+ // copy of it before _M_insert_aux moves elements around.
+ _Temporary_value __x_copy(this, __x);
+ _M_insert_aux(__pos, std::move(__x_copy._M_val()));
#else
- _M_insert_aux(__position, __x);
+ _M_insert_aux(__position, __x);
#endif
- }
+ }
+ }
else
#if __cplusplus >= 201103L
_M_realloc_insert(begin() + (__position - cbegin()), __x);
diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono
index 2468023..8d73d98 100644
--- a/libstdc++-v3/include/std/chrono
+++ b/libstdc++-v3/include/std/chrono
@@ -41,6 +41,7 @@
#include <bits/chrono.h>
#if __cplusplus >= 202002L
+# include <bit>
# include <sstream>
# include <string>
# include <vector>
@@ -2262,6 +2263,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// HH_MM_SS
+ /// @cond undocumented
namespace __detail
{
consteval long long
@@ -2273,22 +2275,28 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __r;
}
}
+ /// @endcond
+ /** Utility for splitting a duration into hours, minutes, and seconds
+ *
+ * This is a convenience type that provides accessors for the constituent
+ * parts (hours, minutes, seconds and subseconds) of a duration.
+ *
+ * @since C++20
+ */
template<typename _Duration>
class hh_mm_ss
{
+ static_assert( __is_duration<_Duration>::value );
+
private:
- static constexpr int
+ static consteval int
_S_fractional_width()
{
- int __multiplicity_2 = 0;
- int __multiplicity_5 = 0;
auto __den = _Duration::period::den;
- while ((__den % 2) == 0)
- {
- ++__multiplicity_2;
- __den /= 2;
- }
+ const int __multiplicity_2 = std::__countr_zero((uintmax_t)__den);
+ __den >>= __multiplicity_2;
+ int __multiplicity_5 = 0;
while ((__den % 5) == 0)
{
++__multiplicity_5;
@@ -2304,6 +2312,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __width;
}
+ constexpr
+ hh_mm_ss(_Duration __d, bool __is_neg) noexcept
+ : _M_h (duration_cast<chrono::hours>(__d)),
+ _M_m (duration_cast<chrono::minutes>(__d - hours())),
+ _M_s (duration_cast<chrono::seconds>(__d - hours() - minutes())),
+ _M_is_neg(__is_neg)
+ {
+ auto __ss = __d - hours() - minutes() - seconds();
+ if constexpr (treat_as_floating_point_v<typename precision::rep>)
+ _M_ss._M_r = __ss.count();
+ else if constexpr (precision::period::den != 1)
+ _M_ss._M_r = duration_cast<precision>(__ss).count();
+ }
+
public:
static constexpr unsigned fractional_width = {_S_fractional_width()};
@@ -2312,28 +2334,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
chrono::seconds::rep>,
ratio<1, __detail::__pow10(fractional_width)>>;
- constexpr
- hh_mm_ss() noexcept
- : hh_mm_ss{_Duration::zero()}
- { }
+ constexpr hh_mm_ss() noexcept = default;
constexpr explicit
hh_mm_ss(_Duration __d) noexcept
- : _M_is_neg (__d < _Duration::zero()),
- _M_h (duration_cast<chrono::hours>(abs(__d))),
- _M_m (duration_cast<chrono::minutes>(abs(__d) - hours())),
- _M_s (duration_cast<chrono::seconds>(abs(__d) - hours() - minutes()))
- {
- if constexpr (treat_as_floating_point_v<typename precision::rep>)
- _M_ss = abs(__d) - hours() - minutes() - seconds();
- else
- _M_ss = duration_cast<precision>(abs(__d) - hours()
- - minutes() - seconds());
- }
+ : hh_mm_ss(chrono::abs(__d), __d < _Duration::zero())
+ { }
constexpr bool
is_negative() const noexcept
- { return _M_is_neg; }
+ {
+ if constexpr (!__is_unsigned)
+ return _M_is_neg;
+ else
+ return false;
+ }
constexpr chrono::hours
hours() const noexcept
@@ -2349,7 +2364,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr precision
subseconds() const noexcept
- { return _M_ss; }
+ { return static_cast<precision>(_M_ss); }
constexpr explicit
operator precision() const noexcept
@@ -2358,20 +2373,82 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr precision
to_duration() const noexcept
{
- if (_M_is_neg)
- return -(_M_h + _M_m + _M_s + _M_ss);
- else
- return _M_h + _M_m + _M_s + _M_ss;
+ if constexpr (!__is_unsigned)
+ if (_M_is_neg)
+ return -(_M_h + _M_m + _M_s + subseconds());
+ return _M_h + _M_m + _M_s + subseconds();
}
// TODO: Implement operator<<.
private:
- bool _M_is_neg;
- chrono::hours _M_h;
- chrono::minutes _M_m;
- chrono::seconds _M_s;
- precision _M_ss;
+ static constexpr bool __is_unsigned
+ = __and_v<is_integral<typename _Duration::rep>,
+ is_unsigned<typename _Duration::rep>>;
+
+ template<typename _Ratio>
+ using __byte_duration = duration<unsigned char, _Ratio>;
+
+ // The type of the _M_ss member that holds the subsecond precision.
+ template<typename _Dur>
+ struct __subseconds
+ {
+ typename _Dur::rep _M_r{};
+
+ constexpr explicit
+ operator _Dur() const noexcept
+ { return _Dur(_M_r); }
+ };
+
+ // An empty class if this precision doesn't need subseconds.
+ template<typename _Rep>
+ requires (!treat_as_floating_point_v<_Rep>)
+ struct __subseconds<duration<_Rep, ratio<1>>>
+ {
+ constexpr explicit
+ operator duration<_Rep, ratio<1>>() const noexcept
+ { return {}; }
+ };
+
+ // True if the maximum constructor argument can be represented in _Tp.
+ template<typename _Tp>
+ static constexpr bool __fits
+ = duration_values<typename _Duration::rep>::max()
+ <= duration_values<_Tp>::max();
+
+ template<typename _Rep, typename _Period>
+ requires (!treat_as_floating_point_v<_Rep>)
+ && ratio_less_v<_Period, ratio<1, 1>>
+ && (ratio_greater_equal_v<_Period, ratio<1, 250>>
+ || __fits<unsigned char>)
+ struct __subseconds<duration<_Rep, _Period>>
+ {
+ unsigned char _M_r{};
+
+ constexpr explicit
+ operator duration<_Rep, _Period>() const noexcept
+ { return duration<_Rep, _Period>(_M_r); }
+ };
+
+ template<typename _Rep, typename _Period>
+ requires (!treat_as_floating_point_v<_Rep>)
+ && ratio_less_v<_Period, ratio<1, 250>>
+ && (ratio_greater_equal_v<_Period, ratio<1, 4'000'000'000>>
+ || __fits<uint_least32_t>)
+ struct __subseconds<duration<_Rep, _Period>>
+ {
+ uint_least32_t _M_r{};
+
+ constexpr explicit
+ operator duration<_Rep, _Period>() const noexcept
+ { return duration<_Rep, _Period>(_M_r); }
+ };
+
+ chrono::hours _M_h{};
+ __byte_duration<ratio<60>> _M_m{};
+ __byte_duration<ratio<1>> _M_s{};
+ bool _M_is_neg{};
+ __subseconds<precision> _M_ss{};
};
// 12/24 HOURS FUNCTIONS
diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format
index cb5ce40..1072e2c 100644
--- a/libstdc++-v3/include/std/format
+++ b/libstdc++-v3/include/std/format
@@ -221,7 +221,10 @@ namespace __format
if (_M_indexing == _Manual)
__format::__conflicting_indexing_in_format_string();
_M_indexing = _Auto;
- // if (std::is_constant_evaluated()) // XXX skip runtime check?
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3825. Missing compile-time argument id check in next_arg_id
+ if (std::is_constant_evaluated())
if (_M_next_arg_id == _M_num_args)
__format::__invalid_arg_id_in_format_string();
return _M_next_arg_id++;
@@ -234,7 +237,7 @@ namespace __format
__format::__conflicting_indexing_in_format_string();
_M_indexing = _Manual;
- // if (std::is_constant_evaluated()) // XXX skip runtime check?
+ if (std::is_constant_evaluated())
if (__id >= _M_num_args)
__format::__invalid_arg_id_in_format_string();
}
@@ -1167,15 +1170,18 @@ namespace __format
string __grp = __np.grouping();
if (!__grp.empty())
{
- size_t __n = __str.size();
+ size_t __n = __str.size() - __prefix_len;
auto __p = (_CharT*)__builtin_alloca(2 * __n
- * sizeof(_CharT));
- auto __end = std::__add_grouping(__p,
+ * sizeof(_CharT)
+ + __prefix_len);
+ auto __s = __str.data();
+ char_traits<_CharT>::copy(__p, __s, __prefix_len);
+ __s += __prefix_len;
+ auto __end = std::__add_grouping(__p + __prefix_len,
__np.thousands_sep(),
__grp.data(),
__grp.size(),
- __str.data(),
- __str.data() + __n);
+ __s, __s + __n);
__str = {__p, size_t(__end - __p)};
}
}
@@ -2475,12 +2481,12 @@ namespace __format
auto __s = this->_M_used();
if (_M_max < 0) // No maximum.
_M_out = ranges::copy(__s, std::move(_M_out)).out;
- else if (_M_count < size_t(_M_max))
+ else if (_M_count < static_cast<size_t>(_M_max))
{
auto __max = _M_max - _M_count;
span<_CharT> __first;
if (__max < __s.size())
- __first = __s.first(__max);
+ __first = __s.first(static_cast<size_t>(__max));
else
__first = __s;
_M_out = ranges::copy(__first, std::move(_M_out)).out;
@@ -2558,11 +2564,11 @@ namespace __format
if (__n > 0)
{
- if constexpr (!is_integral_v<decltype(__n)>
+ if constexpr (!is_integral_v<iter_difference_t<_OutIter>>
|| sizeof(__n) > sizeof(size_t))
{
// __int128 or __detail::__max_diff_type
- auto __m = (decltype(__n))(size_t)-1;
+ auto __m = iter_difference_t<_OutIter>((size_t)-1);
if (__n > __m)
__n = __m;
}
@@ -3381,10 +3387,11 @@ namespace __format
__ctx.advance_to(__format::__write(__ctx.out()));
}
- // TODO define __process_format_string which takes an object with callbacks
- // can use that for initial constexpr parse of format string (with callbacks
- // that have no side effects, just non-constant on error).
-
+ // Abstract base class defining an interface for scanning format strings.
+ // Scan the characters in a format string, dividing it up into strings of
+ // ordinary characters, escape sequences, and replacement fields.
+ // Call virtual functions for derived classes to parse format-specifiers
+ // or write formatted output.
template<typename _CharT>
struct _Scanner
{
diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex
index b310c15..aca5f91 100644
--- a/libstdc++-v3/include/std/mutex
+++ b/libstdc++-v3/include/std/mutex
@@ -124,6 +124,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__throw_system_error(__e);
}
+ _GLIBCXX_NODISCARD
bool
try_lock() noexcept
{
@@ -253,6 +254,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__throw_system_error(__e);
}
+ _GLIBCXX_NODISCARD
bool
try_lock() noexcept
{
@@ -261,11 +263,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template <class _Rep, class _Period>
+ _GLIBCXX_NODISCARD
bool
try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
{ return _M_try_lock_for(__rtime); }
template <class _Clock, class _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
{ return _M_try_lock_until(__atime); }
@@ -328,6 +332,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__throw_system_error(__e);
}
+ _GLIBCXX_NODISCARD
bool
try_lock() noexcept
{
@@ -336,11 +341,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template <class _Rep, class _Period>
+ _GLIBCXX_NODISCARD
bool
try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
{ return _M_try_lock_for(__rtime); }
template <class _Clock, class _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
{ return _M_try_lock_until(__atime); }
@@ -395,6 +402,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_locked = true;
}
+ _GLIBCXX_NODISCARD
bool
try_lock()
{
@@ -406,6 +414,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Rep, typename _Period>
+ _GLIBCXX_NODISCARD
bool
try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
{
@@ -417,6 +426,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Clock, typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
{
@@ -478,6 +488,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
++_M_count;
}
+ _GLIBCXX_NODISCARD
bool
try_lock()
{
@@ -494,6 +505,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Rep, typename _Period>
+ _GLIBCXX_NODISCARD
bool
try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
{
@@ -510,6 +522,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Clock, typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
{
@@ -616,6 +629,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
* Sequentially calls try_lock() on each argument.
*/
template<typename _L1, typename _L2, typename... _L3>
+ _GLIBCXX_NODISCARD
inline int
try_lock(_L1& __l1, _L2& __l2, _L3&... __l3)
{
diff --git a/libstdc++-v3/include/std/shared_mutex b/libstdc++-v3/include/std/shared_mutex
index cf74b32..7b70697 100644
--- a/libstdc++-v3/include/std/shared_mutex
+++ b/libstdc++-v3/include/std/shared_mutex
@@ -420,13 +420,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Exclusive ownership
void lock() { _M_impl.lock(); }
- bool try_lock() { return _M_impl.try_lock(); }
+ [[nodiscard]] bool try_lock() { return _M_impl.try_lock(); }
void unlock() { _M_impl.unlock(); }
// Shared ownership
void lock_shared() { _M_impl.lock_shared(); }
- bool try_lock_shared() { return _M_impl.try_lock_shared(); }
+ [[nodiscard]] bool try_lock_shared() { return _M_impl.try_lock_shared(); }
void unlock_shared() { _M_impl.unlock_shared(); }
#if _GLIBCXX_USE_PTHREAD_RWLOCK_T
@@ -473,10 +473,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Exclusive ownership
void lock() { _Base::lock(); }
- bool try_lock() { return _Base::try_lock(); }
+ _GLIBCXX_NODISCARD bool try_lock() { return _Base::try_lock(); }
void unlock() { _Base::unlock(); }
template<typename _Rep, typename _Period>
+ _GLIBCXX_NODISCARD
bool
try_lock_for(const chrono::duration<_Rep, _Period>& __rtime)
{
@@ -489,10 +490,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Shared ownership
void lock_shared() { _Base::lock_shared(); }
+ _GLIBCXX_NODISCARD
bool try_lock_shared() { return _Base::try_lock_shared(); }
void unlock_shared() { _Base::unlock_shared(); }
template<typename _Rep, typename _Period>
+ _GLIBCXX_NODISCARD
bool
try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rtime)
{
@@ -507,6 +510,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Exclusive ownership
template<typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_until(const chrono::time_point<chrono::system_clock,
_Duration>& __atime)
@@ -532,6 +536,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK
template<typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_until(const chrono::time_point<chrono::steady_clock,
_Duration>& __atime)
@@ -558,6 +563,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
template<typename _Clock, typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_until(const chrono::time_point<_Clock, _Duration>& __atime)
{
@@ -580,6 +586,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Shared ownership
template<typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_shared_until(const chrono::time_point<chrono::system_clock,
_Duration>& __atime)
@@ -619,6 +626,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#ifdef _GLIBCXX_USE_PTHREAD_RWLOCK_CLOCKLOCK
template<typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_shared_until(const chrono::time_point<chrono::steady_clock,
_Duration>& __atime)
@@ -645,6 +653,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
template<typename _Clock, typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_shared_until(const chrono::time_point<_Clock,
_Duration>& __atime)
@@ -670,6 +679,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Exclusive ownership
template<typename _Clock, typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
{
@@ -694,6 +704,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Shared ownership
template <typename _Clock, typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_shared_until(const chrono::time_point<_Clock,
_Duration>& __abs_time)
@@ -776,6 +787,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_owns = true;
}
+ _GLIBCXX_NODISCARD
bool
try_lock()
{
@@ -784,6 +796,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Rep, typename _Period>
+ _GLIBCXX_NODISCARD
bool
try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
{
@@ -792,6 +805,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
template<typename _Clock, typename _Duration>
+ _GLIBCXX_NODISCARD
bool
try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
{
@@ -826,10 +840,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Getters
+ _GLIBCXX_NODISCARD
bool owns_lock() const noexcept { return _M_owns; }
explicit operator bool() const noexcept { return _M_owns; }
+ _GLIBCXX_NODISCARD
mutex_type* mutex() const noexcept { return _M_pm; }
private:
diff --git a/libstdc++-v3/include/std/stacktrace b/libstdc++-v3/include/std/stacktrace
index e7cbbee..ec3335e 100644
--- a/libstdc++-v3/include/std/stacktrace
+++ b/libstdc++-v3/include/std/stacktrace
@@ -155,11 +155,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Allocator> friend class basic_stacktrace;
+ static void _S_err_handler(void*, const char*, int) { }
+
static __glibcxx_backtrace_state*
_S_init()
{
static __glibcxx_backtrace_state* __state
- = __glibcxx_backtrace_create_state(nullptr, 1, nullptr, nullptr);
+ = __glibcxx_backtrace_create_state(nullptr, 1, _S_err_handler, nullptr);
return __state;
}
@@ -192,7 +194,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __function != nullptr;
};
const auto __state = _S_init();
- if (::__glibcxx_backtrace_pcinfo(__state, _M_pc, +__cb, nullptr, &__data))
+ if (::__glibcxx_backtrace_pcinfo(__state, _M_pc, +__cb, _S_err_handler,
+ &__data))
return true;
if (__desc && __desc->empty())
{
@@ -201,8 +204,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__symname)
*static_cast<_Data*>(__data)->_M_desc = _S_demangle(__symname);
};
- if (::__glibcxx_backtrace_syminfo(__state, _M_pc, +__cb2, nullptr,
- &__data))
+ if (::__glibcxx_backtrace_syminfo(__state, _M_pc, +__cb2,
+ _S_err_handler, &__data))
return true;
}
return false;
@@ -252,7 +255,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (auto __cb = __ret._M_prepare()) [[likely]]
{
auto __state = stacktrace_entry::_S_init();
- if (__glibcxx_backtrace_simple(__state, 1, __cb, nullptr,
+ if (__glibcxx_backtrace_simple(__state, 1, __cb,
+ stacktrace_entry::_S_err_handler,
std::__addressof(__ret)))
__ret._M_clear();
}
@@ -270,7 +274,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (auto __cb = __ret._M_prepare()) [[likely]]
{
auto __state = stacktrace_entry::_S_init();
- if (__glibcxx_backtrace_simple(__state, __skip + 1, __cb, nullptr,
+ if (__glibcxx_backtrace_simple(__state, __skip + 1, __cb,
+ stacktrace_entry::_S_err_handler,
std::__addressof(__ret)))
__ret._M_clear();
}
@@ -294,7 +299,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
auto __state = stacktrace_entry::_S_init();
int __err = __glibcxx_backtrace_simple(__state, __skip + 1, __cb,
- nullptr,
+ stacktrace_entry::_S_err_handler,
std::__addressof(__ret));
if (__err < 0)
__ret._M_clear();
diff --git a/libstdc++-v3/testsuite/17_intro/names.cc b/libstdc++-v3/testsuite/17_intro/names.cc
index ffbb199..963f74c 100644
--- a/libstdc++-v3/testsuite/17_intro/names.cc
+++ b/libstdc++-v3/testsuite/17_intro/names.cc
@@ -241,6 +241,13 @@
#undef y
#endif
+#ifdef __GLIBC_PREREQ
+#if ! __GLIBC_PREREQ(2, 19)
+// Glibc defines this prior to 2.19
+#undef __unused
+#endif
+#endif
+
#if __has_include(<newlib.h>)
// newlib's <sys/cdefs.h> defines these as macros.
#undef __lockable
diff --git a/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/clock_neg.cc
index 541bd19..91f2c83 100644
--- a/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/clock_neg.cc
+++ b/libstdc++-v3/testsuite/30_threads/recursive_timed_mutex/try_lock_until/clock_neg.cc
@@ -33,7 +33,7 @@ void
test01()
{
std::recursive_timed_mutex m;
- m.try_lock_until(clok::now()); // { dg-error "here" }
+ (void) m.try_lock_until(clok::now()); // { dg-error "here" }
}
struct cloc
@@ -51,7 +51,7 @@ void
test02()
{
std::recursive_timed_mutex m;
- m.try_lock_until(cloc::now()); // { dg-error "here" }
+ (void) m.try_lock_until(cloc::now()); // { dg-error "here" }
}
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/shared_lock/locking/3.cc b/libstdc++-v3/testsuite/30_threads/shared_lock/locking/3.cc
index c7637d2..8ad962b 100644
--- a/libstdc++-v3/testsuite/30_threads/shared_lock/locking/3.cc
+++ b/libstdc++-v3/testsuite/30_threads/shared_lock/locking/3.cc
@@ -38,7 +38,7 @@ int main()
try
{
- l.try_lock_for(std::chrono::milliseconds(100));
+ (void) l.try_lock_for(std::chrono::milliseconds(100));
}
catch(const std::system_error&)
{
diff --git a/libstdc++-v3/testsuite/30_threads/shared_lock/locking/4.cc b/libstdc++-v3/testsuite/30_threads/shared_lock/locking/4.cc
index 126098d..96388a1 100644
--- a/libstdc++-v3/testsuite/30_threads/shared_lock/locking/4.cc
+++ b/libstdc++-v3/testsuite/30_threads/shared_lock/locking/4.cc
@@ -40,7 +40,7 @@ int main()
try
{
- l.try_lock_until(t);
+ (void) l.try_lock_until(t);
}
catch(const std::system_error&)
{
diff --git a/libstdc++-v3/testsuite/30_threads/shared_lock/locking/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/shared_lock/locking/clock_neg.cc
index 3a6373b..d6df66e 100644
--- a/libstdc++-v3/testsuite/30_threads/shared_lock/locking/clock_neg.cc
+++ b/libstdc++-v3/testsuite/30_threads/shared_lock/locking/clock_neg.cc
@@ -34,7 +34,7 @@ test01()
{
std::shared_timed_mutex m;
std::shared_lock<std::shared_timed_mutex> l(m, std::defer_lock);
- l.try_lock_until(clok::now()); // { dg-error "here" }
+ (void) l.try_lock_until(clok::now()); // { dg-error "here" }
}
struct cloc
@@ -53,7 +53,7 @@ test02()
{
std::shared_timed_mutex m;
std::shared_lock<std::shared_timed_mutex> l(m, std::defer_lock);
- l.try_lock_until(cloc::now()); // { dg-error "here" }
+ (void) l.try_lock_until(cloc::now()); // { dg-error "here" }
}
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc
index ac40123..f948101 100644
--- a/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc
+++ b/libstdc++-v3/testsuite/30_threads/shared_timed_mutex/try_lock_until/clock_neg.cc
@@ -33,7 +33,7 @@ void
test01()
{
std::shared_timed_mutex m;
- m.try_lock_until(clok::now()); // { dg-error "here" }
+ (void) m.try_lock_until(clok::now()); // { dg-error "here" }
}
struct cloc
@@ -51,7 +51,7 @@ void
test02()
{
std::shared_timed_mutex m;
- m.try_lock_shared_until(cloc::now()); // { dg-error "here" }
+ (void) m.try_lock_shared_until(cloc::now()); // { dg-error "here" }
}
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc
index 3642474..71c83c5 100644
--- a/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc
+++ b/libstdc++-v3/testsuite/30_threads/timed_mutex/try_lock_until/clock_neg.cc
@@ -33,7 +33,7 @@ void
test01()
{
std::timed_mutex m;
- m.try_lock_until(clok::now()); // { dg-error "here" }
+ (void) m.try_lock_until(clok::now()); // { dg-error "here" }
}
struct cloc
@@ -51,7 +51,7 @@ void
test02()
{
std::timed_mutex m;
- m.try_lock_until(cloc::now()); // { dg-error "here" }
+ (void) m.try_lock_until(cloc::now()); // { dg-error "here" }
}
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/try_lock/4.cc b/libstdc++-v3/testsuite/30_threads/try_lock/4.cc
index cfb5a74..96afa55 100644
--- a/libstdc++-v3/testsuite/30_threads/try_lock/4.cc
+++ b/libstdc++-v3/testsuite/30_threads/try_lock/4.cc
@@ -125,7 +125,7 @@ void test03()
unreliable_lock::count = 0;
try
{
- std::try_lock(l1, l2, l3);
+ (void) std::try_lock(l1, l2, l3);
VERIFY( false );
}
catch (int e)
diff --git a/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc b/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc
index c3cb621..a8a8db4 100644
--- a/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc
+++ b/libstdc++-v3/testsuite/30_threads/unique_lock/cons/60497.cc
@@ -50,5 +50,5 @@ void test02()
void test03()
{
test_type l1, l2, l3;
- std::try_lock(l1, l2, l3);
+ (void) std::try_lock(l1, l2, l3);
}
diff --git a/libstdc++-v3/testsuite/30_threads/unique_lock/locking/3.cc b/libstdc++-v3/testsuite/30_threads/unique_lock/locking/3.cc
index 3cb787b..ecc5b82 100644
--- a/libstdc++-v3/testsuite/30_threads/unique_lock/locking/3.cc
+++ b/libstdc++-v3/testsuite/30_threads/unique_lock/locking/3.cc
@@ -38,7 +38,7 @@ int main()
try
{
- l.try_lock_for(std::chrono::milliseconds(100));
+ (void) l.try_lock_for(std::chrono::milliseconds(100));
}
catch(const std::system_error&)
{
diff --git a/libstdc++-v3/testsuite/30_threads/unique_lock/locking/clock_neg.cc b/libstdc++-v3/testsuite/30_threads/unique_lock/locking/clock_neg.cc
index 68157f6..b633e5f 100644
--- a/libstdc++-v3/testsuite/30_threads/unique_lock/locking/clock_neg.cc
+++ b/libstdc++-v3/testsuite/30_threads/unique_lock/locking/clock_neg.cc
@@ -34,7 +34,7 @@ test01()
{
std::timed_mutex m;
std::unique_lock<std::timed_mutex> l(m, std::defer_lock);
- l.try_lock_until(clok::now()); // { dg-error "here" }
+ (void) l.try_lock_until(clok::now()); // { dg-error "here" }
}
struct cloc
@@ -53,7 +53,7 @@ test02()
{
std::recursive_timed_mutex m;
std::unique_lock<std::recursive_timed_mutex> l(m, std::defer_lock);
- l.try_lock_until(cloc::now()); // { dg-error "here" }
+ (void) l.try_lock_until(cloc::now()); // { dg-error "here" }
}
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/std/format/functions/107871.cc b/libstdc++-v3/testsuite/std/format/functions/107871.cc
new file mode 100644
index 0000000..1fb558e
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/functions/107871.cc
@@ -0,0 +1,14 @@
+// { dg-options "-std=gnu++20" }
+// { dg-do compile { target c++20 } }
+
+#include <format>
+
+struct O {
+ using difference_type = std::ranges::__detail::__max_diff_type;
+ O& operator=(const char&);
+ O& operator*();
+ O& operator++();
+ O& operator++(int);
+};
+
+auto str = std::format_to_n(O{}, 4, "{}", " "); // PR libstdc++/107871
diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc b/libstdc++-v3/testsuite/std/format/functions/format.cc
index 8019fbd..7a15520 100644
--- a/libstdc++-v3/testsuite/std/format/functions/format.cc
+++ b/libstdc++-v3/testsuite/std/format/functions/format.cc
@@ -111,6 +111,10 @@ test_std_examples()
string s3 = format("{:L}", 1234);
VERIFY(s3 == "1,234");
+ // Test locale's "byte-and-a-half" grouping (Imperial word? tribble?).
+ string s4 = format("{:#Lx}", 0xfffff);
+ VERIFY(s4 == "0xff,fff");
+
// Restore
std::locale::global(std::locale::classic());
}
diff --git a/libstdc++-v3/testsuite/std/format/parse_ctx.cc b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
index dd6ca68..069dfce 100644
--- a/libstdc++-v3/testsuite/std/format/parse_ctx.cc
+++ b/libstdc++-v3/testsuite/std/format/parse_ctx.cc
@@ -4,11 +4,11 @@
#include <format>
#include <testsuite_hooks.h>
-template<typename T, size_t N = 1, bool auto_indexing = true>
+template<typename T, bool auto_indexing = true>
bool
is_std_format_spec_for(std::string_view spec)
{
- std::format_parse_context pc(spec, N);
+ std::format_parse_context pc(spec);
if (auto_indexing)
(void) pc.next_arg_id();
else
@@ -49,11 +49,9 @@ test_char()
VERIFY( ! is_std_format_spec_for<char>("0") );
VERIFY( ! is_std_format_spec_for<char>("00d") );
VERIFY( is_std_format_spec_for<char>("01d") );
- VERIFY( ! is_std_format_spec_for<char>("0{}d") );
+ VERIFY( is_std_format_spec_for<char>("0{}d") );
VERIFY( ! is_std_format_spec_for<char>("0{1}d") );
- VERIFY(( is_std_format_spec_for<char, 2>("0{}d") ));
- VERIFY(( ! is_std_format_spec_for<char, 2>("0{1}d") ));
- VERIFY(( is_std_format_spec_for<char, 2, false>("0{1}d") ));
+ VERIFY(( is_std_format_spec_for<char, false>("0{1}d") ));
VERIFY( is_std_format_spec_for<char>("1") );
VERIFY( ! is_std_format_spec_for<char>("-1") );
VERIFY( is_std_format_spec_for<char>("-1d") ); // sign and width
@@ -98,11 +96,10 @@ test_int()
VERIFY( is_std_format_spec_for<int>("0") );
VERIFY( ! is_std_format_spec_for<int>("00d") );
VERIFY( is_std_format_spec_for<int>("01d") );
- VERIFY( ! is_std_format_spec_for<int>("0{}d") );
VERIFY( ! is_std_format_spec_for<int>("0{1}d") );
- VERIFY(( is_std_format_spec_for<int, 2>("0{}d") ));
- VERIFY(( ! is_std_format_spec_for<int, 2>("0{1}d") ));
- VERIFY(( is_std_format_spec_for<int, 2, false>("0{1}d") ));
+ VERIFY(( is_std_format_spec_for<int>("0{}d") ));
+ VERIFY(( ! is_std_format_spec_for<int>("0{1}d") ));
+ VERIFY(( is_std_format_spec_for<int, false>("0{1}d") ));
VERIFY( is_std_format_spec_for<int>("1") );
VERIFY( is_std_format_spec_for<int>("-1") ); // sign and width
VERIFY( ! is_std_format_spec_for<int>(".") );
@@ -193,24 +190,20 @@ test_float()
VERIFY( is_std_format_spec_for<float>("0") );
VERIFY( ! is_std_format_spec_for<float>("00f") );
VERIFY( is_std_format_spec_for<float>("01f") );
- VERIFY( ! is_std_format_spec_for<float>("0{}f") );
+ VERIFY( is_std_format_spec_for<float>("0{}f") );
VERIFY( ! is_std_format_spec_for<float>("0{1}f") );
- VERIFY(( is_std_format_spec_for<float, 2>("0{}f") ));
- VERIFY(( ! is_std_format_spec_for<float, 2>("0{1}f") ));
- VERIFY(( is_std_format_spec_for<float, 2, false>("0{1}f") ));
+ VERIFY( ! is_std_format_spec_for<float>("0{1}f") );
+ VERIFY(( is_std_format_spec_for<float, false>("0{1}f") ));
VERIFY( is_std_format_spec_for<float>("1") );
VERIFY( is_std_format_spec_for<float>("-1") ); // sign and width
VERIFY( ! is_std_format_spec_for<float>(".") );
VERIFY( is_std_format_spec_for<float>(".1") );
- VERIFY( ! is_std_format_spec_for<float>(".{}") );
+ VERIFY( is_std_format_spec_for<float>(".{}") );
VERIFY( ! is_std_format_spec_for<float>(".{1}") );
- VERIFY(( is_std_format_spec_for<float, 2>(".{}") ));
- VERIFY(( ! is_std_format_spec_for<float, 2>(".{1}") ));
- VERIFY(( is_std_format_spec_for<float, 2, false>(".{1}") ));
- VERIFY(( ! is_std_format_spec_for<float, 2>("{}.{}") ));
- VERIFY(( is_std_format_spec_for<float, 3>("{}.{}") ));
- VERIFY(( is_std_format_spec_for<float, 2, false>("{1}.{1}") ));
- VERIFY(( is_std_format_spec_for<float, 3, false>("{2}.{1}") ));
+ VERIFY(( is_std_format_spec_for<float, false>(".{1}") ));
+ VERIFY( is_std_format_spec_for<float>("{}.{}") );
+ VERIFY(( is_std_format_spec_for<float, false>("{1}.{1}") ));
+ VERIFY(( is_std_format_spec_for<float, false>("{2}.{1}") ));
VERIFY( ! is_std_format_spec_for<float>("c") );
VERIFY( ! is_std_format_spec_for<float>("b") );
VERIFY( ! is_std_format_spec_for<float>("B") );
@@ -302,11 +295,9 @@ test_string()
VERIFY( ! is_std_format_spec_for<const char*>("-1s") );
VERIFY( ! is_std_format_spec_for<const char*>(".") );
VERIFY( is_std_format_spec_for<const char*>(".1") );
- VERIFY( ! is_std_format_spec_for<const char*>(".{}") );
- VERIFY(( ! is_std_format_spec_for<const char*, 1, false>(".{1}") ));
- VERIFY(( is_std_format_spec_for<const char*, 1, false>(".{0}") ));
- VERIFY(( is_std_format_spec_for<const char*, 2>(".{}") ));
- VERIFY(( is_std_format_spec_for<const char*, 2, false>(".{1}") ));
+ VERIFY( is_std_format_spec_for<const char*>(".{}") );
+ VERIFY(( is_std_format_spec_for<const char*, false>(".{0}") ));
+ VERIFY(( is_std_format_spec_for<const char*, false>(".{1}") ));
VERIFY( ! is_std_format_spec_for<const char*>("c") );
VERIFY( ! is_std_format_spec_for<const char*>("b") );
VERIFY( ! is_std_format_spec_for<const char*>("B") );
diff --git a/libstdc++-v3/testsuite/std/time/hh_mm_ss/1.cc b/libstdc++-v3/testsuite/std/time/hh_mm_ss/1.cc
index 31dd1b2..3f8a838 100644
--- a/libstdc++-v3/testsuite/std/time/hh_mm_ss/1.cc
+++ b/libstdc++-v3/testsuite/std/time/hh_mm_ss/1.cc
@@ -59,5 +59,59 @@ constexpr_hh_mm_ss()
static_assert(seconds{hh_mm_ss{100min}} == 100min);
- // TODO: treat_as_floating_point_v
+ // treat_as_floating_point_v
+ using fseconds = duration<double, ratio<1>>;
+ constexpr hh_mm_ss<fseconds> fsec{0x123.0004p5s};
+ static_assert(std::is_same_v<hh_mm_ss<fseconds>::precision, fseconds>);
+ static_assert(fsec.hours() == 2h);
+ static_assert(fsec.minutes() == 35min);
+ static_assert(fsec.seconds() == 12s);
+ static_assert(fsec.subseconds() == 0x.0004p5s);
+ static_assert(!fsec.is_negative());
+ static_assert(fsec.to_duration() == 0x123.0004p5s);
+
+ using fminutes = duration<double, ratio<60>>;
+ constexpr hh_mm_ss<fminutes> fmin{-0x1.23p4min};
+ static_assert(std::is_same_v<hh_mm_ss<fminutes>::precision, fseconds>);
+ static_assert(fmin.hours() == 0h);
+ static_assert(fmin.minutes() == 18min);
+ static_assert(fmin.seconds() == 11s);
+ static_assert(fmin.subseconds() == 0.25s);
+ static_assert(fmin.is_negative());
+ static_assert(fmin.to_duration() == -0x1.23p4min);
+}
+
+constexpr void
+default_construction()
+{
+ using namespace std::chrono;
+
+ constexpr hh_mm_ss<seconds> s1;
+ static_assert(s1.to_duration() == s1.to_duration().zero());
+ constexpr hh_mm_ss<duration<char>> s2;
+ static_assert(s2.to_duration() == s2.to_duration().zero());
+ constexpr hh_mm_ss<duration<int, std::centi>> s3;
+ static_assert(s3.to_duration() == s3.to_duration().zero());
+ constexpr hh_mm_ss<duration<long long, std::femto>> s4;
+ static_assert(s4.to_duration() == s4.to_duration().zero());
+ constexpr hh_mm_ss<duration<double>> s5;
+ static_assert(s5.to_duration() == s5.to_duration().zero());
+}
+
+constexpr void
+size()
+{
+ using namespace std::chrono;
+
+ struct S0 { long long h; char m; char s; bool neg; };
+ static_assert(sizeof(hh_mm_ss<seconds>) == sizeof(S0));
+ struct S1 { long long h; char m; char s; bool neg; char ss; };
+ static_assert(sizeof(hh_mm_ss<duration<int, std::centi>>) == sizeof(S1));
+ struct S2 { long long h; char m, s; bool neg; int ss; };
+ static_assert(sizeof(hh_mm_ss<duration<int, std::milli>>) == sizeof(S2));
+ static_assert(sizeof(hh_mm_ss<duration<int, std::pico>>) == sizeof(S2));
+ struct S3 { long long h; char m, s; bool neg; long long ss; };
+ static_assert(sizeof(hh_mm_ss<duration<long long, std::pico>>) == sizeof(S3));
+ struct S4 { long long h; char m, s; bool neg; double ss; };
+ static_assert(sizeof(hh_mm_ss<duration<double, std::micro>>) == sizeof(S4));
}
diff --git a/maintainer-scripts/ChangeLog b/maintainer-scripts/ChangeLog
index 125dd99..6dbe4ba 100644
--- a/maintainer-scripts/ChangeLog
+++ b/maintainer-scripts/ChangeLog
@@ -1,3 +1,8 @@
+2022-11-30 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ PR web/107749
+ * update_web_docs_git: Add gdc to MANUALS.
+
2022-11-23 Sam James <sam@gentoo.org>
* gcc_release (XZ): Add -T0.