aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry DeLisle <jvdelisle@gcc.gnu.org>2025-07-29 10:56:10 -0700
committerJerry DeLisle <jvdelisle@gcc.gnu.org>2025-07-29 10:56:10 -0700
commitdb57737117c3765e379750c977a7d404f2e2d50e (patch)
tree8ac49c9638d27138c1cc5793c0b71d64700d03a1
parent75164bb769816261706d317e08a5fee6d8ba49b6 (diff)
parent0f61284eae6365e77b28af8fa4bc3dc7e5e0fac9 (diff)
downloadgcc-db57737117c3765e379750c977a7d404f2e2d50e.zip
gcc-db57737117c3765e379750c977a7d404f2e2d50e.tar.gz
gcc-db57737117c3765e379750c977a7d404f2e2d50e.tar.bz2
Merge branch 'master' into devel/gfortran-test
-rw-r--r--ChangeLog4
-rw-r--r--MAINTAINERS1
-rw-r--r--contrib/ChangeLog14
-rwxr-xr-xcontrib/filter-clang-warnings.py2
-rwxr-xr-xcontrib/gcc-changelog/git_commit.py1
-rw-r--r--contrib/gcc.doxy2
-rw-r--r--gcc/ChangeLog1916
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/Makefile.in53
-rw-r--r--gcc/ada/ChangeLog425
-rw-r--r--gcc/ada/accessibility.adb27
-rw-r--r--gcc/ada/aspects.ads7
-rw-r--r--gcc/ada/doc/gnat_rm/gnat_language_extensions.rst68
-rw-r--r--gcc/ada/doc/gnat_rm/standard_and_implementation_defined_restrictions.rst6
-rw-r--r--gcc/ada/einfo.ads76
-rw-r--r--gcc/ada/exp_aggr.adb178
-rw-r--r--gcc/ada/exp_attr.adb404
-rw-r--r--gcc/ada/exp_ch3.adb67
-rw-r--r--gcc/ada/exp_ch4.adb10
-rw-r--r--gcc/ada/exp_ch6.adb1321
-rw-r--r--gcc/ada/exp_ch6.ads13
-rw-r--r--gcc/ada/exp_ch7.adb168
-rw-r--r--gcc/ada/exp_ch9.adb44
-rw-r--r--gcc/ada/exp_ch9.ads9
-rw-r--r--gcc/ada/exp_disp.adb87
-rw-r--r--gcc/ada/exp_disp.ads3
-rw-r--r--gcc/ada/exp_put_image.adb343
-rw-r--r--gcc/ada/exp_spark.adb24
-rw-r--r--gcc/ada/exp_strm.adb35
-rw-r--r--gcc/ada/exp_util.adb66
-rw-r--r--gcc/ada/exp_util.ads10
-rw-r--r--gcc/ada/freeze.adb48
-rw-r--r--gcc/ada/gcc-interface/misc.cc4
-rw-r--r--gcc/ada/gcc-interface/trans.cc21
-rw-r--r--gcc/ada/gcc-interface/utils.cc31
-rw-r--r--gcc/ada/gen_il-fields.ads7
-rw-r--r--gcc/ada/gen_il-gen-gen_entities.adb9
-rw-r--r--gcc/ada/gen_il-gen-gen_nodes.adb9
-rw-r--r--gcc/ada/gen_il-internals.adb2
-rw-r--r--gcc/ada/gnat_rm.texi144
-rw-r--r--gcc/ada/gsocket.h6
-rw-r--r--gcc/ada/inline.adb11
-rw-r--r--gcc/ada/libgnat/a-calend.adb29
-rw-r--r--gcc/ada/libgnat/a-cbhama.adb2
-rw-r--r--gcc/ada/libgnat/a-cbhama.ads2
-rw-r--r--gcc/ada/libgnat/g-calend.adb21
-rw-r--r--gcc/ada/libgnat/g-socket.adb9
-rw-r--r--gcc/ada/s-oscons-tmplt.c6
-rw-r--r--gcc/ada/sem_attr.adb42
-rw-r--r--gcc/ada/sem_aux.adb88
-rw-r--r--gcc/ada/sem_aux.ads14
-rw-r--r--gcc/ada/sem_ch12.adb23
-rw-r--r--gcc/ada/sem_ch13.adb162
-rw-r--r--gcc/ada/sem_ch3.adb52
-rw-r--r--gcc/ada/sem_ch4.adb38
-rw-r--r--gcc/ada/sem_ch5.adb9
-rw-r--r--gcc/ada/sem_ch6.adb877
-rw-r--r--gcc/ada/sem_ch6.ads160
-rw-r--r--gcc/ada/sem_ch8.adb10
-rw-r--r--gcc/ada/sem_ch9.adb6
-rw-r--r--gcc/ada/sem_disp.adb49
-rw-r--r--gcc/ada/sem_res.adb4
-rw-r--r--gcc/ada/sem_util.adb101
-rw-r--r--gcc/ada/sem_util.ads20
-rw-r--r--gcc/ada/sinfo.ads36
-rw-r--r--gcc/ada/snames.ads-tmpl1
-rw-r--r--gcc/ada/styleg.adb6
-rw-r--r--gcc/ada/sysdep.c6
-rw-r--r--gcc/ada/tbuild.adb6
-rw-r--r--gcc/analyzer/ChangeLog107
-rw-r--r--gcc/analyzer/access-diagram.cc10
-rw-r--r--gcc/analyzer/access-diagram.h2
-rw-r--r--gcc/analyzer/ana-state-to-diagnostic-state.cc4
-rw-r--r--gcc/analyzer/ana-state-to-diagnostic-state.h2
-rw-r--r--gcc/analyzer/analyzer.cc4
-rw-r--r--gcc/analyzer/bounds-checking.cc28
-rw-r--r--gcc/analyzer/call-details.cc6
-rw-r--r--gcc/analyzer/call-info.cc2
-rw-r--r--gcc/analyzer/checker-event.cc95
-rw-r--r--gcc/analyzer/checker-event.h43
-rw-r--r--gcc/analyzer/checker-path.cc2
-rw-r--r--gcc/analyzer/checker-path.h30
-rw-r--r--gcc/analyzer/common.h4
-rw-r--r--gcc/analyzer/diagnostic-manager.cc20
-rw-r--r--gcc/analyzer/diagnostic-manager.h5
-rw-r--r--gcc/analyzer/infinite-loop.cc7
-rw-r--r--gcc/analyzer/infinite-recursion.cc7
-rw-r--r--gcc/analyzer/kf.cc2
-rw-r--r--gcc/analyzer/pending-diagnostic.cc6
-rw-r--r--gcc/analyzer/pending-diagnostic.h34
-rw-r--r--gcc/analyzer/program-point.cc15
-rw-r--r--gcc/analyzer/program-state.cc4
-rw-r--r--gcc/analyzer/region-model-asm.cc7
-rw-r--r--gcc/analyzer/region-model.cc19
-rw-r--r--gcc/analyzer/sm-fd.cc23
-rw-r--r--gcc/analyzer/sm-file.cc20
-rw-r--r--gcc/analyzer/sm-malloc.cc26
-rw-r--r--gcc/analyzer/sm-pattern-test.cc2
-rw-r--r--gcc/analyzer/sm-sensitive.cc13
-rw-r--r--gcc/analyzer/sm-signal.cc2
-rw-r--r--gcc/analyzer/sm-taint.cc26
-rw-r--r--gcc/analyzer/varargs.cc16
-rw-r--r--gcc/c-family/ChangeLog83
-rw-r--r--gcc/c-family/c-common.cc28
-rw-r--r--gcc/c-family/c-common.h5
-rw-r--r--gcc/c-family/c-cppbuiltin.cc2
-rw-r--r--gcc/c-family/c-format.cc16
-rw-r--r--gcc/c-family/c-indentation.cc19
-rw-r--r--gcc/c-family/c-lex.cc2
-rw-r--r--gcc/c-family/c-opts.cc20
-rw-r--r--gcc/c-family/c-pragma.cc15
-rw-r--r--gcc/c-family/c-warn.cc4
-rw-r--r--gcc/c-family/known-headers.cc7
-rw-r--r--gcc/c-family/known-headers.h4
-rw-r--r--gcc/c/ChangeLog35
-rw-r--r--gcc/c/c-decl.cc2
-rw-r--r--gcc/c/c-errors.cc63
-rw-r--r--gcc/c/c-objc-common.cc2
-rw-r--r--gcc/c/c-parser.cc7
-rw-r--r--gcc/c/c-tree.h10
-rw-r--r--gcc/c/c-typeck.cc31
-rw-r--r--gcc/cfgexpand.cc53
-rw-r--r--gcc/cgraphunit.cc7
-rw-r--r--gcc/cobol/ChangeLog165
-rw-r--r--gcc/cobol/Make-lang.in9
-rw-r--r--gcc/cobol/cbldiag.h20
-rw-r--r--gcc/cobol/cdf.y2
-rw-r--r--gcc/cobol/gcobolspec.cc13
-rw-r--r--gcc/cobol/genapi.cc341
-rw-r--r--gcc/cobol/genapi.h43
-rw-r--r--gcc/cobol/gengen.cc101
-rw-r--r--gcc/cobol/gengen.h10
-rw-r--r--gcc/cobol/genmath.cc2
-rw-r--r--gcc/cobol/genutil.cc20
-rw-r--r--gcc/cobol/genutil.h8
-rw-r--r--gcc/cobol/parse.y24
-rw-r--r--gcc/cobol/parse_ante.h10
-rw-r--r--gcc/cobol/scan.l19
-rw-r--r--gcc/cobol/scan_ante.h381
-rw-r--r--gcc/cobol/symbols.cc5
-rw-r--r--gcc/cobol/symbols.h2
-rw-r--r--gcc/cobol/util.cc89
-rw-r--r--gcc/cobol/util.h2
-rw-r--r--gcc/common.opt4
-rw-r--r--gcc/config.gcc5
-rw-r--r--gcc/config/aarch64/aarch64-cost-tables.h54
-rw-r--r--gcc/config/aarch64/aarch64-simd.md5
-rw-r--r--gcc/config/aarch64/aarch64-sve.md395
-rw-r--r--gcc/config/aarch64/aarch64-sve2.md10
-rw-r--r--gcc/config/aarch64/aarch64.cc51
-rw-r--r--gcc/config/aarch64/cortex-a57-fma-steering.cc5
-rw-r--r--gcc/config/aarch64/iterators.md23
-rw-r--r--gcc/config/arm/aarch-cost-tables.h36
-rw-r--r--gcc/config/arm/arm.cc12
-rw-r--r--gcc/config/avr/avr-passes.cc6
-rw-r--r--gcc/config/cris/cris.cc6
-rw-r--r--gcc/config/epiphany/epiphany.cc8
-rw-r--r--gcc/config/gcn/gcn-opts.h5
-rw-r--r--gcc/config/gcn/gcn-valu.md289
-rw-r--r--gcc/config/gcn/gcn.cc280
-rw-r--r--gcc/config/gcn/gcn.md249
-rw-r--r--gcc/config/i386/i386-options.cc4
-rw-r--r--gcc/config/i386/i386.cc6
-rw-r--r--gcc/config/loongarch/loongarch.cc8
-rw-r--r--gcc/config/pru/pru-pragma.cc13
-rw-r--r--gcc/config/pru/pru-protos.h8
-rw-r--r--gcc/config/pru/pru.cc8
-rw-r--r--gcc/config/riscv/autovec-opt.md122
-rw-r--r--gcc/config/riscv/autovec.md26
-rw-r--r--gcc/config/riscv/generic-vector-ooo.md85
-rw-r--r--gcc/config/riscv/mips-p8700.md2
-rw-r--r--gcc/config/riscv/predicates.md13
-rw-r--r--gcc/config/riscv/riscv-ext.def30
-rw-r--r--gcc/config/riscv/riscv-protos.h16
-rw-r--r--gcc/config/riscv/riscv-string.cc6
-rw-r--r--gcc/config/riscv/riscv-v.cc302
-rw-r--r--gcc/config/riscv/riscv-vector-builtins-bases.cc3
-rw-r--r--gcc/config/riscv/riscv-vector-builtins.cc41
-rw-r--r--gcc/config/riscv/riscv-vector-builtins.h1
-rw-r--r--gcc/config/riscv/riscv-vector-costs.cc71
-rw-r--r--gcc/config/riscv/riscv-vector-costs.h16
-rw-r--r--gcc/config/riscv/riscv.cc100
-rw-r--r--gcc/config/riscv/riscv.md10
-rw-r--r--gcc/config/riscv/vector-iterators.md16
-rw-r--r--gcc/config/riscv/vector.md410
-rw-r--r--gcc/config/riscv/xiangshan.md3
-rw-r--r--gcc/config/rs6000/rs6000.cc11
-rw-r--r--gcc/config/s390/s390.cc27
-rw-r--r--gcc/config/xtensa/xtensa.cc44
-rw-r--r--gcc/config/xtensa/xtensa.md16
-rwxr-xr-xgcc/configure2
-rw-r--r--gcc/configure.ac2
-rw-r--r--gcc/coretypes.h6
-rw-r--r--gcc/cp/ChangeLog170
-rw-r--r--gcc/cp/call.cc58
-rw-r--r--gcc/cp/constexpr.cc29
-rw-r--r--gcc/cp/constraint.cc270
-rw-r--r--gcc/cp/coroutines.cc39
-rw-r--r--gcc/cp/cp-tree.h34
-rw-r--r--gcc/cp/decl.cc46
-rw-r--r--gcc/cp/error.cc112
-rw-r--r--gcc/cp/except.cc12
-rw-r--r--gcc/cp/init.cc6
-rw-r--r--gcc/cp/lambda.cc4
-rw-r--r--gcc/cp/method.cc243
-rw-r--r--gcc/cp/module.cc82
-rw-r--r--gcc/cp/name-lookup.cc2
-rw-r--r--gcc/cp/parser.cc38
-rw-r--r--gcc/cp/pt.cc24
-rw-r--r--gcc/cp/semantics.cc9
-rw-r--r--gcc/cp/tree.cc86
-rw-r--r--gcc/cp/typeck.cc29
-rw-r--r--gcc/cp/typeck2.cc20
-rw-r--r--gcc/d/ChangeLog19
-rw-r--r--gcc/d/d-diagnostic.cc23
-rw-r--r--gcc/d/toir.cc6
-rw-r--r--gcc/diagnostic-core.h84
-rw-r--r--gcc/diagnostic-global-context.cc121
-rw-r--r--gcc/diagnostic.h1268
-rw-r--r--gcc/diagnostics/buffering.cc199
-rw-r--r--gcc/diagnostics/buffering.h (renamed from gcc/diagnostic-buffer.h)64
-rw-r--r--gcc/diagnostics/changes.cc (renamed from gcc/edit-context.cc)303
-rw-r--r--gcc/diagnostics/changes.h (renamed from gcc/edit-context.h)29
-rw-r--r--gcc/diagnostics/client-data-hooks.h (renamed from gcc/diagnostic-client-data-hooks.h)55
-rw-r--r--gcc/diagnostics/color.cc (renamed from gcc/diagnostic-color.cc)8
-rw-r--r--gcc/diagnostics/color.h (renamed from gcc/diagnostic-color.h)6
-rw-r--r--gcc/diagnostics/context-options.h116
-rw-r--r--gcc/diagnostics/context.cc (renamed from gcc/diagnostic.cc)1069
-rw-r--r--gcc/diagnostics/context.h959
-rw-r--r--gcc/diagnostics/diagnostic-info.h75
-rw-r--r--gcc/diagnostics/diagnostics-selftests.cc59
-rw-r--r--gcc/diagnostics/diagnostics-selftests.h55
-rw-r--r--gcc/diagnostics/diagram.h (renamed from gcc/diagnostic-diagram.h)16
-rw-r--r--gcc/diagnostics/digraphs.cc (renamed from gcc/diagnostic-digraphs.cc)32
-rw-r--r--gcc/diagnostics/digraphs.h (renamed from gcc/diagnostic-digraphs.h)56
-rw-r--r--gcc/diagnostics/event-id.h (renamed from gcc/diagnostic-event-id.h)35
-rw-r--r--gcc/diagnostics/file-cache.cc1083
-rw-r--r--gcc/diagnostics/file-cache.h125
-rw-r--r--gcc/diagnostics/html-sink.cc (renamed from gcc/diagnostic-format-html.cc)420
-rw-r--r--gcc/diagnostics/html-sink.h (renamed from gcc/diagnostic-format-html.h)34
-rw-r--r--gcc/diagnostics/kinds.def (renamed from gcc/diagnostic.def)40
-rw-r--r--gcc/diagnostics/kinds.h45
-rw-r--r--gcc/diagnostics/lazy-paths.cc (renamed from gcc/lazy-diagnostic-path.cc)103
-rw-r--r--gcc/diagnostics/lazy-paths.h (renamed from gcc/lazy-diagnostic-path.h)36
-rw-r--r--gcc/diagnostics/logical-locations.h (renamed from gcc/logical-location.h)127
-rw-r--r--gcc/diagnostics/macro-unwinding.cc (renamed from gcc/diagnostic-macro-unwinding.cc)17
-rw-r--r--gcc/diagnostics/macro-unwinding.h (renamed from gcc/diagnostic-macro-unwinding.h)16
-rw-r--r--gcc/diagnostics/metadata.h (renamed from gcc/diagnostic-metadata.h)34
-rw-r--r--gcc/diagnostics/option-classifier.cc222
-rw-r--r--gcc/diagnostics/option-classifier.h110
-rw-r--r--gcc/diagnostics/option-id.h49
-rw-r--r--gcc/diagnostics/output-file.h (renamed from gcc/diagnostic-output-file.h)34
-rw-r--r--gcc/diagnostics/output-spec.cc (renamed from gcc/diagnostic-output-spec.cc)136
-rw-r--r--gcc/diagnostics/output-spec.h (renamed from gcc/diagnostic-output-spec.h)40
-rw-r--r--gcc/diagnostics/paths-output.cc (renamed from gcc/diagnostic-path-output.cc)449
-rw-r--r--gcc/diagnostics/paths.cc (renamed from gcc/diagnostic-path.cc)45
-rw-r--r--gcc/diagnostics/paths.h (renamed from gcc/diagnostic-path.h)74
-rw-r--r--gcc/diagnostics/sarif-sink.cc (renamed from gcc/diagnostic-format-sarif.cc)734
-rw-r--r--gcc/diagnostics/sarif-sink.h (renamed from gcc/diagnostic-format-sarif.h)85
-rw-r--r--gcc/diagnostics/selftest-context.cc (renamed from gcc/selftest-diagnostic.cc)55
-rw-r--r--gcc/diagnostics/selftest-context.h (renamed from gcc/selftest-diagnostic.h)54
-rw-r--r--gcc/diagnostics/selftest-logical-locations.cc (renamed from gcc/selftest-logical-location.cc)44
-rw-r--r--gcc/diagnostics/selftest-logical-locations.h (renamed from gcc/selftest-logical-location.h)35
-rw-r--r--gcc/diagnostics/selftest-paths.cc (renamed from gcc/selftest-diagnostic-path.cc)143
-rw-r--r--gcc/diagnostics/selftest-paths.h (renamed from gcc/selftest-diagnostic-path.h)84
-rw-r--r--gcc/diagnostics/selftest-source-printing.h (renamed from gcc/selftest-diagnostic-show-locus.h)27
-rw-r--r--gcc/diagnostics/sink.h (renamed from gcc/diagnostic-format.h)58
-rw-r--r--gcc/diagnostics/source-printing-effects.h (renamed from gcc/diagnostic-label-effects.h)14
-rw-r--r--gcc/diagnostics/source-printing.cc (renamed from gcc/diagnostic-show-locus.cc)1022
-rw-r--r--gcc/diagnostics/state-graphs-to-dot.cc (renamed from gcc/diagnostic-state-to-dot.cc)27
-rw-r--r--gcc/diagnostics/state-graphs.cc (renamed from gcc/diagnostic-state-graphs.cc)16
-rw-r--r--gcc/diagnostics/state-graphs.h (renamed from gcc/diagnostic-state-graphs.h)14
-rw-r--r--gcc/diagnostics/text-sink.cc (renamed from gcc/diagnostic-format-text.cc)215
-rw-r--r--gcc/diagnostics/text-sink.h (renamed from gcc/diagnostic-format-text.h)65
-rw-r--r--gcc/diagnostics/url.h (renamed from gcc/diagnostic-url.h)6
-rw-r--r--gcc/doc/analyzer.texi4
-rw-r--r--gcc/doc/cpp.texi2
-rw-r--r--gcc/doc/extend.texi170
-rw-r--r--gcc/doc/md.texi6
-rw-r--r--gcc/doc/tm.texi8
-rw-r--r--gcc/errors.cc5
-rw-r--r--gcc/expr.cc2
-rw-r--r--gcc/final.cc3
-rw-r--r--gcc/fortran/ChangeLog78
-rw-r--r--gcc/fortran/cpp.cc18
-rw-r--r--gcc/fortran/error.cc132
-rw-r--r--gcc/fortran/expr.cc5
-rw-r--r--gcc/fortran/gfortran.h4
-rw-r--r--gcc/fortran/options.cc3
-rw-r--r--gcc/fortran/trans-array.cc162
-rw-r--r--gcc/fortran/trans-decl.cc16
-rw-r--r--gcc/fortran/trans-expr.cc64
-rw-r--r--gcc/function.cc116
-rw-r--r--gcc/gcc-diagnostic-spec.cc (renamed from gcc/diagnostic-spec.cc)2
-rw-r--r--gcc/gcc-diagnostic-spec.h (renamed from gcc/diagnostic-spec.h)6
-rw-r--r--gcc/gcc-rich-location.cc7
-rw-r--r--gcc/gcc-rich-location.h8
-rw-r--r--gcc/gcc.cc15
-rw-r--r--gcc/gdbinit.in6
-rw-r--r--gcc/gengtype.cc2
-rw-r--r--gcc/genoutput.cc60
-rw-r--r--gcc/genpreds.cc269
-rw-r--r--gcc/gimple-fold.cc13
-rw-r--r--gcc/gimple-walk.cc11
-rw-r--r--gcc/gimplify-me.cc5
-rw-r--r--gcc/gimplify.cc142
-rw-r--r--gcc/gimplify_reg_info.h182
-rw-r--r--gcc/input.cc1073
-rw-r--r--gcc/input.h104
-rw-r--r--gcc/internal-fn.cc96
-rw-r--r--gcc/internal-fn.h3
-rw-r--r--gcc/ipa-pure-const.cc2
-rw-r--r--gcc/ira.cc84
-rw-r--r--gcc/jit/ChangeLog27
-rw-r--r--gcc/jit/dummy-frontend.cc32
-rw-r--r--gcc/jit/jit-playback.cc2
-rw-r--r--gcc/jit/jit-playback.h9
-rw-r--r--gcc/langhooks-def.h8
-rw-r--r--gcc/langhooks.cc10
-rw-r--r--gcc/langhooks.h8
-rw-r--r--gcc/lazily-created.h51
-rw-r--r--gcc/libgdiagnostics.cc277
-rw-r--r--gcc/libsarifreplay.cc2
-rw-r--r--gcc/lra-constraints.cc13
-rw-r--r--gcc/lto-wrapper.cc8
-rw-r--r--gcc/m2/ChangeLog78
-rw-r--r--gcc/m2/gm2-compiler/P1SymBuild.mod45
-rw-r--r--gcc/m2/gm2-compiler/P2SymBuild.mod26
-rw-r--r--gcc/m2/gm2-compiler/P3SymBuild.mod2
-rw-r--r--gcc/m2/gm2-compiler/PCSymBuild.mod6
-rw-r--r--gcc/m2/gm2-compiler/SymbolTable.def6
-rw-r--r--gcc/m2/gm2-compiler/SymbolTable.mod87
-rw-r--r--gcc/m2/gm2-gcc/m2color.cc2
-rw-r--r--gcc/m2/gm2-gcc/m2linemap.cc15
-rw-r--r--gcc/m2/gm2-gcc/rtegraph.cc21
-rw-r--r--gcc/m2/gm2-libs/ARRAYOFCHAR.mod6
-rw-r--r--gcc/m2/gm2-libs/M2EXCEPTION.mod5
-rw-r--r--gcc/match.pd18
-rw-r--r--gcc/optabs-query.cc6
-rw-r--r--gcc/optc-gen.awk4
-rw-r--r--gcc/opth-gen.awk4
-rw-r--r--gcc/opts-common.cc31
-rw-r--r--gcc/opts-diagnostic.cc24
-rw-r--r--gcc/opts-diagnostic.h23
-rw-r--r--gcc/opts-global.cc6
-rw-r--r--gcc/opts.cc81
-rw-r--r--gcc/opts.h18
-rw-r--r--gcc/output.h2
-rw-r--r--gcc/params.opt2
-rw-r--r--gcc/pretty-print-format-impl.h6
-rw-r--r--gcc/pretty-print-markup.h2
-rw-r--r--gcc/pretty-print.cc8
-rw-r--r--gcc/pretty-print.h2
-rw-r--r--gcc/recog.cc11
-rw-r--r--gcc/rtl-error.cc10
-rw-r--r--gcc/rust/ChangeLog34
-rw-r--r--gcc/rust/backend/rust-tree.cc12
-rw-r--r--gcc/rust/backend/rust-tree.h6
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.cc4
-rw-r--r--gcc/rust/resolve/rust-ice-finalizer.cc10
-rw-r--r--gcc/rust/resolve/rust-ice-finalizer.h6
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.cc4
-rw-r--r--gcc/rust/rust-diagnostics.cc10
-rw-r--r--gcc/selftest-run-tests.cc15
-rw-r--r--gcc/selftest.cc5
-rw-r--r--gcc/selftest.h19
-rw-r--r--gcc/simple-diagnostic-path.cc30
-rw-r--r--gcc/simple-diagnostic-path.h49
-rw-r--r--gcc/stmt.cc277
-rw-r--r--gcc/stmt.h9
-rw-r--r--gcc/substring-locations.cc16
-rw-r--r--gcc/substring-locations.h10
-rw-r--r--gcc/symtab.cc1
-rw-r--r--gcc/target.def14
-rw-r--r--gcc/target.h1
-rw-r--r--gcc/targhooks.cc2
-rw-r--r--gcc/targhooks.h2
-rw-r--r--gcc/testsuite/ChangeLog624
-rw-r--r--gcc/testsuite/cobol.dg/group2/_-static__compilation.cob4
-rw-r--r--gcc/testsuite/cobol.dg/group2/_-static__compilation.out2
-rw-r--r--gcc/testsuite/g++.dg/coroutines/torture/pr121219.C149
-rw-r--r--gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda18.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp23/static-operator-call7.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp26/constexpr-new4.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C31
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-traits4.C77
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constexpr-union6.C4
-rw-r--r--gcc/testsuite/g++.dg/diagnostic/static_assert5.C70
-rw-r--r--gcc/testsuite/g++.dg/ext/has_virtual_destructor2.C27
-rw-r--r--gcc/testsuite/g++.dg/ext/is_assignable2.C36
-rw-r--r--gcc/testsuite/g++.dg/ext/is_constructible9.C60
-rw-r--r--gcc/testsuite/g++.dg/ext/is_convertible7.C29
-rw-r--r--gcc/testsuite/g++.dg/ext/is_destructible3.C65
-rw-r--r--gcc/testsuite/g++.dg/ext/is_invocable5.C15
-rw-r--r--gcc/testsuite/g++.dg/ext/is_invocable6.C45
-rw-r--r--gcc/testsuite/g++.dg/ext/is_virtual_base_of_diagnostic2.C13
-rw-r--r--gcc/testsuite/g++.dg/lookup/operator-8.C21
-rw-r--r--gcc/testsuite/g++.dg/missing-return.C4
-rw-r--r--gcc/testsuite/g++.dg/modules/class-11_a.H36
-rw-r--r--gcc/testsuite/g++.dg/modules/class-11_b.C15
-rw-r--r--gcc/testsuite/g++.dg/modules/internal-14_a.C17
-rw-r--r--gcc/testsuite/g++.dg/modules/internal-14_b.C6
-rw-r--r--gcc/testsuite/g++.dg/modules/internal-14_c.C9
-rw-r--r--gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C2
-rw-r--r--gcc/testsuite/g++.dg/plugin/show_template_tree_color_plugin.cc5
-rw-r--r--gcc/testsuite/g++.dg/torture/pr120119-1.C15
-rw-r--r--gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-5.C2
-rw-r--r--gcc/testsuite/g++.target/aarch64/sve/unpacked_binary_bf16_1.C35
-rw-r--r--gcc/testsuite/g++.target/aarch64/sve/unpacked_binary_bf16_2.C15
-rw-r--r--gcc/testsuite/g++.target/aarch64/sve/unpacked_cond_binary_bf16_1.C46
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-1.c85
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-2.c33
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-3.c25
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-4.c50
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-5.c36
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-6.c60
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-7.c41
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-8.c49
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-error-1.c83
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-error-2.c26
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-error-3.c27
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-error-4.c21
-rw-r--r--gcc/testsuite/gcc.dg/asm-hard-reg-error-5.c13
-rw-r--r--gcc/testsuite/gcc.dg/bitint-124.c30
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc4
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc16
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc4
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc4
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py2
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc27
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.cc2
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc16
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.cc2
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.cc13
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc22
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc48
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.cc2
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_text_art.cc4
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.cc2
-rw-r--r--gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.cc17
-rw-r--r--gcc/testsuite/gcc.dg/plugin/location_overflow_plugin.cc22
-rw-r--r--gcc/testsuite/gcc.dg/pr109267-1.c15
-rw-r--r--gcc/testsuite/gcc.dg/pr109267-2.c14
-rw-r--r--gcc/testsuite/gcc.dg/pr121202.c11
-rw-r--r--gcc/testsuite/gcc.dg/pr121216.c9
-rw-r--r--gcc/testsuite/gcc.dg/pr87600-2.c19
-rw-r--r--gcc/testsuite/gcc.dg/pr87600-3.c26
-rw-r--r--gcc/testsuite/gcc.dg/sarif-output/include-chain-2.h2
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr121194.c17
-rw-r--r--gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1b.c5
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/cmp-2.c14
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/max-bitcmp-1.c19
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr117423.c49
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr119085.c37
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr81627.c1
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-23.c21
-rw-r--r--gcc/testsuite/gcc.dg/uninit-pr120924.c34
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr116125.c6
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr121126.c30
-rw-r--r--gcc/testsuite/gcc.dg/vect/slp-28.c9
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-127.c15
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-reduc-cond-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-reduc-cond-2.c1
-rw-r--r--gcc/testsuite/gcc.target/aarch64/asm-hard-reg-1.c55
-rw-r--r--gcc/testsuite/gcc.target/aarch64/asm-hard-reg-2.c17
-rw-r--r--gcc/testsuite/gcc.target/aarch64/inszero_split_1.c18
-rw-r--r--gcc/testsuite/gcc.target/aarch64/simd/mf8_data_1.c10
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/mask_load_2.c23
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmax_1.c44
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmax_2.c20
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmin_1.c44
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmin_2.c20
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_builtin_fmax_1.c51
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_builtin_fmin_1.c51
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_cvtf_1.c51
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fabs_1.c37
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fadd_1.c62
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fcvt_1.c41
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fcvtz_1.c55
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fdiv_1.c47
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fmaxnm_1.c53
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fminnm_1.c53
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fmul_1.c50
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fneg_1.c39
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinta_1.c37
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinta_2.c18
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinti_1.c37
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintm_1.c37
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintp_1.c37
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintx_1.c37
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintz_1.c37
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fsubr_1.c56
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fabs_1.c28
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_1.c52
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_2.c26
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_1.c38
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_2.c15
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_3.c13
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmaxnm_1.c45
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmaxnm_2.c20
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fminnm_1.c46
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fminnm_2.c20
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_1.c43
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_2.c18
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fneg_1.c30
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinta_1.c31
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinta_2.c15
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinti_1.c31
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinti_2.c15
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintm_1.c31
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintm_2.c15
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintp_1.c31
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintp_2.c15
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintx_1.c31
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintx_2.c15
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintz_1.c31
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintz_2.c15
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_1.c46
-rw-r--r--gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_2.c20
-rw-r--r--gcc/testsuite/gcc.target/aarch64/vec-set-zero.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/asm-hard-reg-1.c80
-rw-r--r--gcc/testsuite/gcc.target/i386/asm-hard-reg-2.c43
-rw-r--r--gcc/testsuite/gcc.target/powerpc/vsx-builtin-7.c10
-rw-r--r--gcc/testsuite/gcc.target/pru/pragma-ctable_entry-2.c22
-rw-r--r--gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/interrupt-rnmi.c11
-rw-r--r--gcc/testsuite/gcc.target/riscv/interrupt-umode.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i32-from-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i64-from-i128.c12
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-run-1-i64-from-i128.c16
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_data.h2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i32-from-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i64-from-i128.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/repeat-6.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c4
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c4
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c4
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c4
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmacc-run-1-f16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsac-run-1-f16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmacc-run-1-f16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmadd-run-1-f16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsac-run-1-f16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsub-run-1-f16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmacc-run-1-f16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmsac-run-1-f16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmacc-run-1-f16.c21
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmacc-run-1-f32.c17
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmsac-run-1-f16.c21
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmsac-run-1-f32.c17
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u64.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u8.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u16.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u32.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u64.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u8.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u16.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u32.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u64.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u8.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i16.c7
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i32.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i8.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u8.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i32.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i8.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u8.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i16.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i32.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i64.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i8.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u8.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i16.c23
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i32.c23
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i64.c23
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i8.c23
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u16.c23
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u32.c23
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u64.c23
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u8.c23
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm.h28
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h97
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h392
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i16.c17
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i32.c17
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i64.c17
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i8.c17
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u16.c17
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u32.c17
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u64.c17
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u8.c17
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-5.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-6.c4
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-7.c6
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-8.c5
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-9.c1
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/pr121073.c12
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_arith.h20
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u16.c9
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u32.c9
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u64.c9
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u8.c9
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u16.c9
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u32.c9
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u64.c9
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u8.c9
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u16.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u32.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u64.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u8.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u16.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u32.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u64.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u8.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/xtheadint-push-pop.c6
-rw-r--r--gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c103
-rw-r--r--gcc/testsuite/gcc.target/s390/asm-hard-reg-2.c43
-rw-r--r--gcc/testsuite/gcc.target/s390/asm-hard-reg-3.c42
-rw-r--r--gcc/testsuite/gcc.target/s390/asm-hard-reg-4.c6
-rw-r--r--gcc/testsuite/gcc.target/s390/asm-hard-reg-5.c6
-rw-r--r--gcc/testsuite/gcc.target/s390/asm-hard-reg-6.c152
-rw-r--r--gcc/testsuite/gcc.target/s390/asm-hard-reg-7.c34
-rw-r--r--gcc/testsuite/gcc.target/s390/asm-hard-reg-longdouble.h18
-rw-r--r--gcc/testsuite/gfortran.dg/array_constructor_58.f9017
-rw-r--r--gcc/testsuite/gfortran.dg/assign_13.f9025
-rw-r--r--gcc/testsuite/gfortran.dg/assign_14.f9024
-rw-r--r--gcc/testsuite/gfortran.dg/function_charlen_4.f9034
-rw-r--r--gcc/testsuite/gfortran.dg/pointer_check_15.f9046
-rw-r--r--gcc/testsuite/gm2/switches/pedantic-params/fail/arrayofchar.def12
-rw-r--r--gcc/testsuite/gm2/switches/pedantic-params/fail/arrayofchar.mod30
-rw-r--r--gcc/testsuite/lib/gcc-defs.exp16
-rw-r--r--gcc/testsuite/lib/gcc-dg.exp4
-rw-r--r--gcc/testsuite/lib/sarif.py2
-rw-r--r--gcc/testsuite/lib/scanasm.exp4
-rw-r--r--gcc/testsuite/lib/target-supports.exp22
-rw-r--r--gcc/text-art/style.cc2
-rw-r--r--gcc/toplev.cc37
-rw-r--r--gcc/tree-cfgcleanup.cc24
-rw-r--r--gcc/tree-diagnostic-client-data-hooks.cc31
-rw-r--r--gcc/tree-diagnostic.cc32
-rw-r--r--gcc/tree-diagnostic.h6
-rw-r--r--gcc/tree-logical-location.cc29
-rw-r--r--gcc/tree-logical-location.h22
-rw-r--r--gcc/tree-sra.cc15
-rw-r--r--gcc/tree-ssa-operands.cc4
-rw-r--r--gcc/tree-ssa-sink.cc73
-rw-r--r--gcc/tree-ssa-structalias.cc4
-rw-r--r--gcc/tree-vect-data-refs.cc934
-rw-r--r--gcc/tree-vect-loop.cc265
-rw-r--r--gcc/tree-vect-patterns.cc17
-rw-r--r--gcc/tree-vect-slp.cc61
-rw-r--r--gcc/tree-vect-stmts.cc1969
-rw-r--r--gcc/tree-vectorizer.cc3
-rw-r--r--gcc/tree-vectorizer.h62
-rw-r--r--gcc/varasm.cc7
-rw-r--r--gcc/warning-control.cc2
-rw-r--r--libcc1/ChangeLog10
-rw-r--r--libcc1/context.cc6
-rw-r--r--libcpp/ChangeLog20
-rw-r--r--libcpp/charset.cc2
-rw-r--r--libcpp/include/cpplib.h3
-rw-r--r--libcpp/include/rich-location.h13
-rw-r--r--libcpp/internal.h4
-rw-r--r--libgm2/ChangeLog12
-rw-r--r--libgm2/libm2iso/Makefile.am1
-rw-r--r--libgm2/libm2iso/Makefile.in1
-rw-r--r--libgm2/libm2log/Makefile.am1
-rw-r--r--libgm2/libm2log/Makefile.in1
-rw-r--r--libgm2/libm2min/Makefile.am1
-rw-r--r--libgm2/libm2min/Makefile.in1
-rw-r--r--libgm2/libm2pim/Makefile.am1
-rw-r--r--libgm2/libm2pim/Makefile.in1
-rw-r--r--libgomp/ChangeLog15
-rw-r--r--libgomp/config/gcn/bar.c8
-rw-r--r--libgomp/testsuite/libgomp.c++/target-cdtor-1.C17
-rw-r--r--libgomp/testsuite/libgomp.c++/target-cdtor-2.C17
-rw-r--r--libstdc++-v3/ChangeLog239
-rw-r--r--libstdc++-v3/doc/doxygen/user.cfg.in1
-rw-r--r--libstdc++-v3/doc/html/manual/appendix_contributing.html4
-rw-r--r--libstdc++-v3/doc/html/manual/appendix_porting.html7
-rw-r--r--libstdc++-v3/doc/xml/manual/appendix_contributing.xml4
-rw-r--r--libstdc++-v3/doc/xml/manual/build_hacking.xml11
-rw-r--r--libstdc++-v3/include/Makefile.am1
-rw-r--r--libstdc++-v3/include/Makefile.in1
-rw-r--r--libstdc++-v3/include/bits/chrono_io.h139
-rw-r--r--libstdc++-v3/include/bits/stl_iterator_base_types.h7
-rw-r--r--libstdc++-v3/include/bits/unicode.h150
-rw-r--r--libstdc++-v3/include/bits/unordered_map.h8
-rw-r--r--libstdc++-v3/include/bits/version.def8
-rw-r--r--libstdc++-v3/include/bits/version.h10
-rw-r--r--libstdc++-v3/include/precompiled/stdc++.h1
-rw-r--r--libstdc++-v3/include/std/inplace_vector1379
-rw-r--r--libstdc++-v3/include/std/mdspan34
-rw-r--r--libstdc++-v3/src/c++23/std.cc.in15
-rw-r--r--libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc3
-rw-r--r--libstdc++-v3/testsuite/20_util/expected/illformed_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/20_util/hash/int128.cc4
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/monadic/or_else_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc31
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc24
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc24
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc24
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc24
-rw-r--r--libstdc++-v3/testsuite/23_containers/array/creation/3_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc51
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc115
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc65
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc385
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc177
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc129
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc247
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc49
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc379
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc117
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc43
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc606
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc215
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc42
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc358
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc60
-rw-r--r--libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc20
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc99
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc125
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc20
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc10
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h134
-rw-r--r--libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc78
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc24
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc20
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc13
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc20
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc24
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc76
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc20
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc20
-rw-r--r--libstdc++-v3/testsuite/24_iterators/random_access/string_vector_iterators.cc525
-rw-r--r--libstdc++-v3/testsuite/24_iterators/range_generators/lwg3900.cc3
-rw-r--r--libstdc++-v3/testsuite/29_atomics/atomic/requirements/types_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/ext/unicode/view.cc75
-rw-r--r--libstdc++-v3/testsuite/std/format/arguments/args_neg.cc1
-rw-r--r--libstdc++-v3/testsuite/std/format/string_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/std/time/month/io.cc7
-rw-r--r--libstdc++-v3/testsuite/std/time/weekday/io.cc2
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_allocator.h5
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_iterators.h175
789 files changed, 32751 insertions, 13401 deletions
diff --git a/ChangeLog b/ChangeLog
index eba0608..bc26b2d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2025-07-22 Patrick Palka <ppalka@redhat.com>
+
+ * MAINTAINERS: Add myself as C++ front end reviewer.
+
2025-07-07 Tamar Christina <tamar.christina@arm.com>
* MAINTAINERS: Add myself to AArch64 pot.
diff --git a/MAINTAINERS b/MAINTAINERS
index 2cd2ec6..d4ed308 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -282,6 +282,7 @@ callgraph Martin Jambor <mjambor@suse.cz>
C front end Marek Polacek <polacek@redhat.com>
CTF, BTF Indu Bhagat <indu.bhagat@oracle.com>
CTF, BTF, bpf port David Faust <david.faust@oracle.com>
+c++ Patrick Palka <ppalka@gcc.gnu.org>
dataflow Paolo Bonzini <bonzini@gnu.org>
dataflow Seongbae Park <seongbae.park@gmail.com>
dataflow Kenneth Zadeck <zadeck@naturalbridge.com>
diff --git a/contrib/ChangeLog b/contrib/ChangeLog
index f32cb2b..7a92ede 100644
--- a/contrib/ChangeLog
+++ b/contrib/ChangeLog
@@ -1,3 +1,17 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * filter-clang-warnings.py: Update for move of
+ diagnostic-path-output.cc to diagnostics/paths-output.cc.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.doxy (INPUT): Add gcc/diagnostics subdir.
+
+2025-07-23 Sam James <sam@gentoo.org>
+
+ PR other/105404
+ * gcc-changelog/git_commit.py (ignored_prefixes): Add zlib/.
+
2025-07-16 David Malcolm <dmalcolm@redhat.com>
* gcc.doxy (INPUT): Add directory "gcc/text-art".
diff --git a/contrib/filter-clang-warnings.py b/contrib/filter-clang-warnings.py
index b1b881e..20705b2 100755
--- a/contrib/filter-clang-warnings.py
+++ b/contrib/filter-clang-warnings.py
@@ -46,7 +46,7 @@ def skip_warning(filename, message):
'-Wunused-function', '-Wunneeded-internal-declaration',
'-Wvla-cxx-extension', '-Wunused-command-line-argument'],
- 'diagnostic-path-output.cc': ['m_logical_loc_mgr'],
+ 'diagnostics/paths-output.cc': ['m_logical_loc_mgr'],
'fold-const-call.cc': ['-Wreturn-type'],
'gimple-match': ['-Wunused-', '-Wtautological-compare'],
'generic-match': ['-Wunused-', '-Wtautological-compare'],
diff --git a/contrib/gcc-changelog/git_commit.py b/contrib/gcc-changelog/git_commit.py
index 5645f80..80a3276 100755
--- a/contrib/gcc-changelog/git_commit.py
+++ b/contrib/gcc-changelog/git_commit.py
@@ -152,6 +152,7 @@ ignored_prefixes = {
'libphobos/libdruntime/',
'libphobos/src/',
'libsanitizer/',
+ 'zlib/',
}
wildcard_prefixes = {
diff --git a/contrib/gcc.doxy b/contrib/gcc.doxy
index cf3281f..1595204 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 gcc/analyzer gcc/text-art
+INPUT = gcc gcc/analyzer gcc/diagnostics gcc/text-art
# 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 e09e56a..a3238a3 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,1919 @@
+2025-07-27 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR middle-end/120855
+ * cgraphunit.cc (symbol_table::compile): Assert a transparent
+ alias is not an internal identifier.
+ * symtab.cc (symbol_table::change_decl_assembler_name):
+ Likewise.
+ * varasm.cc (assemble_name_resolve): Check for
+ IDENTIFIER_TRANSPARENT_ALIAS instead of just TREE_CHAIN.
+
+2025-07-26 Thomas Schwinge <tschwinge@baylibre.com>
+
+ * diagnostics/context.cc (context::diagnostic_impl)
+ (context::diagnostic_n_impl): In presence of formal parameter
+ 'kind', explicitly state 'diagnostics::' scope for 'kind' enum.
+
+2025-07-26 Thomas Schwinge <tschwinge@baylibre.com>
+
+ * diagnostics/option-classifier.cc
+ (update_effective_level_from_pragmas): In presence of local
+ variable 'kind', explicitly state 'diagnostics::' scope for 'kind'
+ enum.
+
+2025-07-26 Christoph Müllner <christoph.muellner@vrull.eu>
+
+ * config/riscv/riscv-ext.def: Add allocated group IDs and
+ group bit positions.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostics/context.cc: Eliminate digraphs::lazy_digraph in
+ favor of lazily_created template.
+ * diagnostics/context.h: Likewise.
+ * diagnostics/digraphs.cc: Likewise, also digraphs::lazy_digraphs.
+ * diagnostics/digraphs.h: Likewise.
+ * diagnostics/html-sink.cc: Likewise.
+ * diagnostics/metadata.h: Likewise.
+ * diagnostics/sarif-sink.cc: Likewise.
+ * diagnostics/sink.h: Likewise.
+ * diagnostics/text-sink.h: Likewise.
+ * lazily-created.h: New file.
+ * libgdiagnostics.cc: Eliminate digraphs::lazy_digraph in
+ favor of lazily_created template.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic.h: Use TextOrHtml rather than Sink for template
+ params.
+ * diagnostics/context.h: Likewise.
+ * diagnostics/selftest-context.cc: Use "html_or_text" rather than
+ "sink".
+ * diagnostics/source-printing.cc: Use TextOrHtml rather than Sink
+ for template params. Use "text_out" and "html_out" rather than
+ "sink".
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic.h (diagnostic_set_caret_max_width): Drop forward
+ decl.
+ (diagnostic_same_line): Make
+ diagnostics::context::m_source_printing private.
+ * diagnostics/context.cc (diagnostic_set_caret_max_width): Convert
+ to...
+ (diagnostics::context::set_caret_max_width): ...this.
+ * diagnostics/context.h
+ (diagnostics::context::get_source_printing_options): New
+ accessors.
+ (diagnostics::context::m_source_printing): Make private.
+ * diagnostics/html-sink.cc: Make
+ diagnostics::context::m_source_printing private.
+ * diagnostics/paths-output.cc: Likewise.
+ * diagnostics/sarif-sink.cc: Likewise.
+ * diagnostics/selftest-context.cc: Likewise.
+ * diagnostics/selftest-context.h
+ (diagnostics::selftest::test_context::colorize_source): New.
+ (diagnostics::selftest::test_context::show_labels): New.
+ (diagnostics::selftest::test_context::show_line_numbers): New.
+ (diagnostics::selftest::test_context::show_ruler): New.
+ (diagnostics::selftest::test_context::show_event_links): New.
+ (diagnostics::selftest::test_context::set_caret_char): New.
+ * diagnostics/source-printing.cc: Make
+ diagnostics::context::m_source_printing private.
+ * diagnostics/text-sink.h: Likewise.
+ * libgdiagnostics.cc: Likewise.
+ * opts.cc: Likewise.
+ * toplev.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic.h: Eliminate "diagnostic_info" typedef.
+ * diagnostics/context.cc: Update usage of "diagnostic_info" to
+ explicitly refer to "diagnostics::diagnostic_info".
+ * langhooks.cc: Likewise.
+ * libgdiagnostics.cc: Likewise.
+ * rtl-error.cc: Likewise.
+ * substring-locations.cc: Likewise.
+ * toplev.cc: Likewise.
+ * tree-diagnostic.cc: Likewise.
+ * tree-diagnostic.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic.h (enum diagnostics_column_unit): Move to
+ diagnostics/context-options.h.
+ (enum diagnostics_escape_format): Likewise.
+ (enum diagnostics_output_format): Likewise.
+ (enum diagnostic_path_format): Likewise.
+ (enum diagnostics_extra_output_kind): Likewise.
+ (enum diagnostic_text_art_charset): Likewise.
+ * diagnostics/context-options.h: New file, based on the above
+ material.
+ * diagnostics/context.h: Include it.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Add diagnostics/file-cache.o.
+ * diagnostics/changes.cc: Update for file_cache and char_span
+ moving from input.h to diagnostics/file-cache.h and into the
+ "diagnostics::" namespace.
+ * diagnostics/context.cc: Likewise.
+ * diagnostics/diagnostics-selftests.cc: Likewise.
+ * diagnostics/diagnostics-selftests.h: Likewise.
+ * diagnostics/file-cache.cc: New file, based on the file_cache
+ and file_cache_slot material in input.cc.
+ * diagnostics/file-cache.h: Likewise for input.h.
+ * diagnostics/selftest-source-printing.h: Update for file_cache
+ and char_span moving from input.h to diagnostics/file-cache.h and
+ into the "diagnostics::" namespace.
+ * diagnostics/source-printing.cc: Likewise.
+ * final.cc: Likewise.
+ * gcc-rich-location.cc: Likewise.
+ * input.cc (default_charset_callback): Move to
+ diagnostics/file-cache.cc.
+ (file_cache::initialize_input_context): Likewise.
+ (class file_cache_slot): Likewise.
+ (file_cache::tune): Likewise.
+ (file_cache::lookup_file): Likewise.
+ (file_cache::forcibly_evict_file): Likewise.
+ (file_cache::missing_trailing_newline_p): Likewise.
+ (file_cache::add_buffered_content): Likewise.
+ (file_cache::evicted_cache_tab_entry): Likewise.
+ (file_cache::add_file): Likewise.
+ (file_cache::file_cache): Likewise.
+ (file_cache::dump): Likewise.
+ (file_cache::dump): Likewise.
+ (file_cache::lookup_or_add_file): Likewise.
+ (find_end_of_line): Likewise.
+ (file_cache::get_source_line): Likewise.
+ (check_line): Likewise.
+ (test_replacement): Likewise.
+ (test_reading_source_line): Likewise.
+ (test_reading_source_buffer): Likewise.
+ * input.h (class char_span): Move to diagnostics/file-cache.h and
+ into the "diagnostics::" namespace.
+ (class file_cache_slot): Likewise.
+ (class file_cache): Likewise.
+ * libgdiagnostics.cc: Update for file_cache and char_span moving
+ from input.h to diagnostics/file-cache.h and into the
+ "diagnostics::" namespace.
+ * selftest.cc: Likewise.
+ * selftest.h: Likewise.
+ * substring-locations.h: Likewise.
+ * toplev.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostics/selftest-paths.cc: Don't include "demangle.h"
+ and "backtrace.h".
+ * diagnostics/source-printing.cc: Likewise.
+ * diagnostics/state-graphs.cc: Don't include "graphviz.h",
+ "xml.h", "xml-printer.h", or "intl.h".
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic.h: Move include of "unique-argv.h"
+ and various forward decls into...
+ * diagnostics/context.h: ...here.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic.h (num_digits): Move to...
+ (diagnostics::num_digits): ...here.
+ (get_cwe_url): Move to...
+ (diagnostics::get_cwe_url): ...here.
+ (maybe_line_and_column): Move to...
+ (diagnostics::maybe_line_and_column): ...here.
+ * diagnostic.cc: Move to...
+ * diagnostics/context.cc: ...here.
+ * diagnostics/diagnostics-selftests.cc
+ (run_diagnostics_selftests): Add comment about context_cc_tests.
+ * diagnostics/diagnostics-selftests.h: Add context_cc_tests decl.
+ * diagnostics/sarif-sink.cc: Update for file rename.
+ * diagnostics/source-printing.cc: Update for num_digits moving to
+ diagnostics::num_digits.
+ * errors.cc: Update for file rename.
+ * input.cc: Update for num_digits moving to
+ diagnostics::num_digits.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Replace diagnostic.o with
+ diagnostics/context.o.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in: Replace diagnostic.def with diagnostics/kinds.def.
+ * config/aarch64/aarch64.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * config/i386/i386-options.cc: Likewise.
+ * config/s390/s390.cc: Likewise.
+ * diagnostic-core.h: Replace typedef diagnostic_t with
+ enum class diagnostics::kind in diagnostics/kinds.h and include
+ it.
+ * diagnostic-global-context.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * diagnostic.cc: Likewise.
+ * diagnostic.h: Likewise.
+ * diagnostics/buffering.cc: Likewise.
+ * diagnostics/buffering.h: Likewise.
+ * diagnostics/context.h: Likewise.
+ * diagnostics/diagnostic-info.h: Likewise.
+ * diagnostics/html-sink.cc: Likewise.
+ * diagnostic.def: Move to...
+ * diagnostics/kinds.def: ...here and update for diagnostic_t
+ becoming enum class diagnostics::kind.
+ * diagnostics/kinds.h: New file, based on material in
+ diagnostic-core.h.
+ * diagnostics/lazy-paths.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * diagnostics/option-classifier.cc: Likewise.
+ * diagnostics/option-classifier.h: Likewise.
+ * diagnostics/output-spec.h: Likewise.
+ * diagnostics/paths-output.cc: Likewise.
+ * diagnostics/sarif-sink.cc: Likewise.
+ * diagnostics/selftest-context.cc: Likewise.
+ * diagnostics/selftest-context.h: Likewise.
+ * diagnostics/sink.h: Likewise.
+ * diagnostics/source-printing.cc: Likewise.
+ * diagnostics/text-sink.cc: Likewise.
+ * diagnostics/text-sink.h: Likewise.
+ * gcc.cc: Likewise.
+ * libgdiagnostics.cc: Likewise.
+ * lto-wrapper.cc: Likewise.
+ * opts-common.cc: Likewise.
+ * opts-diagnostic.h: Likewise.
+ * opts.cc: Likewise.
+ * rtl-error.cc: Likewise.
+ * substring-locations.cc: Likewise.
+ * toplev.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic-core.h: Include "diagnostics/option-id.h".
+ (struct diagnostic_option_id): Move there, renaming to
+ diagnostics::option_id.
+ * diagnostic-global-context.cc: Update for renaming of
+ diagnostic_option_id to diagnostics::option_id.
+ * diagnostic.cc: Likewise.
+ * diagnostic.h: Likewise.
+ * diagnostics/context.h: Likewise.
+ * diagnostics/diagnostic-info.h: Likewise.
+ * diagnostics/lazy-paths.cc: Likewise.
+ * diagnostics/option-classifier.cc: Likewise.
+ * diagnostics/option-classifier.h: Likewise.
+ * diagnostics/option-id.h: New file, taken from material in
+ diagnostic-core.h.
+ * diagnostics/selftest-context.cc: Update for renaming of
+ diagnostic_option_id to diagnostics::option_id.
+ * diagnostics/selftest-context.h: Likewise.
+ * ipa-pure-const.cc: Likewise.
+ * lto-wrapper.cc: Likewise.
+ * opts-common.cc: Likewise.
+ * opts-diagnostic.h: Likewise.
+ * opts.cc: Likewise.
+ * substring-locations.cc: Likewise.
+ * substring-locations.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Replace diagnostic-spec.o with
+ gcc-diagnostic-spec.o.
+ (GTFILES): Replace diagnostic-spec.h with gcc-diagnostic-spec.h.
+ * diagnostic-spec.cc: Move to...
+ * gcc-diagnostic-spec.cc: ...here.
+ * diagnostic-spec.h: Move to...
+ * gcc-diagnostic-spec.h: ...here.
+ * gengtype.cc (open_base_files): Replace diagnostic-spec.h with
+ gcc-diagnostic-spec.h.
+ * warning-control.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Replace diagnostics/changes.o with
+ diagnostics/edit-context.o.
+ * diagnostic.cc: Update for move of diagnostics/edit-context.h to
+ diagnostics/changes.h.
+ (diagnostics::context::initialize): Update for renaming of
+ m_edit_context_ptr to m_fixits_change_set.
+ (diagnostics::context::finish): Likewise.
+ (diagnostics::context::create_edit_context): Rename to...
+ (diagnostics::context::initialize_fixits_change_set): ...this and
+ update for other renamings.
+ (diagnostics::context::report_diagnostic): Update for renaming of
+ m_edit_context_ptr to m_fixits_change_set.
+ * diagnostic.h (diagnostics::edit_context): Drop forward decl
+ * diagnostics/edit-context.cc: Move to...
+ * diagnostics/changes.cc: ...here. Update for move of
+ diagnostics/edit-context.h to diagnostics/changes.h.
+ Rename diagnostics::edit_context to
+ diagnostics::changes::change_set. Rename diagnostics::edited_file
+ to diagnostics::changes::changed_file. Rename
+ diagnostics::edited_line to diagnostics::changes::changed_line.
+ * diagnostics/edit-context.h: Move to...
+ * diagnostics/changes.h: ...here, renaming as above.
+ * diagnostics/context.h (diagnostics::changes::change_set): New
+ forward decl.
+ (diagnostics::context::create_edit_context): Rename to...
+ (diagnostics::context::initialize_fixits_change_set): ...this.
+ (diagnostics::context::get_edit_context): Rename to...
+ (diagnostics::context::get_fixits_change_set): ...this.
+ (diagnostics::context::m_edit_context_ptr): Rename to...
+ (diagnostics::context::m_fixits_change_set): ..this and update
+ type.
+ * diagnostics/diagnostics-selftests.cc: Update for renaming.
+ * diagnostics/diagnostics-selftests.h: Likewise.
+ * diagnostics/html-sink.cc: Update for above changes.
+ * libgdiagnostics.cc: Likewise.
+ * toplev.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS): Move diagnostics/lazy-paths.o to...
+ (OBJS-libcommon): ...here. Add
+ diagnostics/diagnostics-selftests.o.
+ * diagnostic.cc: Update for move of
+ selftest::test_diagnostic_context to
+ diagnostics::selftest::test_context.
+ * diagnostics/color.cc: Move selftests from selftest:: to
+ diagnostics::selftest::.
+ * diagnostics/diagnostics-selftests.cc: New file.
+ * diagnostics/diagnostics-selftests.h: New file.
+ * diagnostics/digraphs.cc: Move selftests from selftest:: to
+ diagnostics::selftest::.
+ * diagnostics/edit-context.cc: Likewise.
+ * diagnostics/html-sink.cc: Likewise.
+ * diagnostics/lazy-paths.cc: Likewise. Eliminate use of "tree"
+ by porting selftests from simple-diagnostic-path.h to
+ diagnostics/selftest-paths.h.
+ * diagnostics/output-spec.cc: Move selftests from selftest:: to
+ diagnostics::selftest::.
+ * diagnostics/paths-output.cc: Likewise.
+ * diagnostics/sarif-sink.cc: Likewise.
+ * diagnostics/selftest-context.cc: Move
+ selftest::test_diagnostic_context to
+ diagnostics::selftest::test_context.
+ * diagnostics/selftest-context.h: Likewise.
+ * diagnostics/selftest-logical-locations.cc: Move selftests from
+ selftest:: to diagnostics::logical_locations::selftest::.
+ * diagnostics/selftest-logical-locations.h: Move
+ selftest::logical_location_manager to
+ diagnostics::logical_locations::selftest::logical_location_manager.
+ * diagnostics/selftest-paths.cc: Move
+ selftest::test_diagnostic_path to
+ diagnostics::paths::selftest::test_path. Move
+ selftest::test_diagnostic_event to
+ diagnostics::paths::selftest::test_event.
+ * diagnostics/selftest-paths.h: Likewise, and move
+ selftest::test_diagnostic_thread to
+ diagnostics::paths::selftest::test_thread.
+ * diagnostics/selftest-source-printing.h: Move
+ selftest::diagnostic_show_locus_fixture to
+ diagnostics::selftest::source_printing_fixture.
+ * diagnostics/source-printing.cc: Move selftests from selftest::
+ to diagnostics::selftest:: and update for renames.
+ * diagnostics/state-graphs.cc: Likewise.
+ * selftest-run-tests.cc: Include
+ "diagnostics/diagnostics-selftests.h".
+ (selftest::run_tests): Replace invocation of the various diagnostics
+ selftests with a call to
+ diagnostics::selftest::run_diagnostics_selftests.
+ * selftest.h: Move decls of the various per-file diagnostics
+ invocation functions to diagnostics/diagnostics-selftests.h,
+ renaming due to diagostics prefix being implied by namespace.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * common.opt: Update for move of diagnostic-url.h to
+ diagnostics/url.h.
+ * diagnostic.cc: Likewise.
+ * diagnostics/color.cc: Likewise.
+ * diagnostics/text-sink.cc: Likewise.
+ * diagnostic-url.h: Move to...
+ * diagnostics/url.h: ...here.
+ * libgdiagnostics.cc: Update for move of diagnostic-url.h to
+ diagnostics/url.h.
+ * pretty-print.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Replace diagnostic-color.o with
+ diagnostics/color.o.
+ (PLUGIN_HEADERS): Remove diagnostic-color.h in favor of glob.
+ * common.opt: Update for move of diagnostic-color.h to
+ diagnostics/color.h.
+ * diagnostic.cc: Likewise.
+ * diagnostic-color.cc: Move to...
+ * diagnostics/color.cc: ...here.
+ * diagnostic-color.h: Move to...
+ * diagnostics/color.h: ...here.
+ * diagnostics/edit-context.cc: Update for move of
+ diagnostic-color.h to diagnostics/color.h.
+ * diagnostics/output-spec.cc: Likewise.
+ * diagnostics/paths-output.cc: Likewise.
+ * diagnostics/source-printing.cc: Likewise.
+ * diagnostics/text-sink.cc: Likewise.
+ * libgdiagnostics.cc: Likewise.
+ * opts.cc: Likewise.
+ * pretty-print-markup.h: Likewise.
+ * pretty-print.cc: Likewise.
+ * selftest-run-tests.cc: Likewise.
+ * selftest.h: Likewise.
+ * text-art/style.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Replace selftest-diagnostic.o with
+ diagnostics/selftest-context.o.
+ * diagnostic.cc: Update for move of selftest-diagnostic.h to
+ diagnostics/selftest-context.h.
+ * diagnostics/html-sink.cc: Likewise.
+ * diagnostics/lazy-paths.cc: Likewise.
+ * diagnostics/output-spec.cc: Likewise.
+ * diagnostics/paths-output.cc: Likewise.
+ * diagnostics/sarif-sink.cc: Likewise.
+ * selftest-diagnostic.cc: Move to...
+ * diagnostics/selftest-context.cc: ...here and update for move of
+ header file.
+ * selftest-diagnostic.h: Move to...
+ * diagnostics/selftest-context.h: ...here.
+ * diagnostics/source-printing.cc: Update for move of
+ selftest-diagnostic.h to diagnostics/selftest-context.h.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Add diagnostics/buffering.o.
+ * diagnostic.cc (diagnostics::context::set_diagnostic_buffer): Move to
+ diagnostics/buffering.cc.
+ (diagnostics::context::clear_diagnostic_buffer): Likewise.
+ (diagnostics::context::flush_diagnostic_buffer): Likewise.
+ (diagnostics::buffer::buffer): Likewise.
+ (diagnostics::buffer::~buffer): Likewise.
+ (diagnostics::buffer::dump): Likewise.
+ (diagnostics::buffer::empty_p): Likewise.
+ (diagnostics::buffer::move_to): Likewise.
+ (diagnostics::buffer::ensure_per_sink_buffers): Likewise.
+ * diagnostics/buffering.cc: New file, from material in diagnostic.cc.
+ * diagnostics/buffering.h: Fix comment.
+ * diagnostics/text-sink.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Add
+ diagnostics/option-classifier.o.
+ * diagnostic.cc (diagnostics::option_classifier::init): Move to
+ diagnostics/option-classifier.cc.
+ (diagnostics::option_classifier::fini): Likewise.
+ (diagnostics::option_classifier::pch_save): Likewise.
+ (diagnostics::option_classifier::pch_restore): Likewise.
+ (diagnostics::option_classifier::push): Likewise.
+ (diagnostics::option_classifier::pop): Likewise.
+ (diagnostics::option_classifier::classify_diagnostic): Likewise.
+ (diagnostics::option_classifier::update_effective_level_from_pragmas):
+ Likewise.
+ * diagnostics/context.h: Include
+ "diagnostics/option-classifier.h".
+ (class option_classifier): Move to
+ diagnostics/option-classifier.h.
+ * diagnostics/option-classifier.cc: New file, based on material
+ from diagnostic.cc.
+ * diagnostics/option-classifier.h: New file, based on material
+ from diagnostics/context.h.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * coretypes.h: Update for diagnostic_context becoming
+ diagnostics::context.
+ * diagnostic-global-context.cc: Likewise.
+ * diagnostic.cc: Likewise. Also for diagnostic_option_classifier
+ becoming diagnostics::option_classifier.
+ * diagnostic.h (diagnostic_text_starter_fn): Rename to...
+ (diagnostics::text_starter_fn): ...this, and move to
+ diagnostics/context.h.
+ (get_printer): Rename to...
+ (diagnostics::get_printer): ...this, and move to
+ diagnostics/context.h.
+ (class diagnostic_option_manager): Rename to...
+ (class diagnostics::option_manager): ...this, and move to
+ diagnostics/context.h.
+ (class diagnostic_option_classifier): Rename to...
+ (class diagnostics::option_classifier): ...this, and move to
+ diagnostics/context.h.
+ (struct diagnostic_source_printing_options): Rename to...
+ (struct diagnostics::source_printing_options): ...this, and move
+ to diagnostics/context.h.
+ (class diagnostic_column_policy): Rename to...
+ (class diagnostics::column_policy): ...this, and move to
+ diagnostics/context.h.
+ (class diagnostic_location_print_policy): Rename to...
+ (class diagnostics::location_print_policy): ...this, and move to
+ diagnostics/context.h.
+ (class html_label_writer): Rename to...
+ (class diagnostics::html_label_writer): ...this, and move to
+ diagnostics/context.h.
+ (class diagnostic_source_print_policy): Rename to...
+ (class diagnostics::source_print_policy): ...this, and move to
+ diagnostics/context.h.
+ (struct diagnostic_counters): Rename to...
+ (struct diagnostics::counters): ...this, and move to
+ diagnostics/context.h.
+ (class diagnostic_context): Rename to...
+ (class diagnostics::context): ...this, and move to
+ diagnostics/context.h.
+ (diagnostic_text_starter): Rename to...
+ (diagnostics::text_starter): ...this, and move to
+ diagnostics/context.h.
+ (diagnostic_start_span): Rename to...
+ (diagnostics::start_span): ...this, and move to
+ diagnostics/context.h.
+ (diagnostic_text_finalizer): Rename to...
+ (diagnostics::text_finalizer): ...this, and move to
+ diagnostics/context.h.
+ Include "diagnostics/context.h".
+ * diagnostics/buffering.h: Update for diagnostic_context becoming
+ diagnostics::context; similarly for diagnostic_counters.
+ * diagnostics/client-data-hooks.h: Likewise.
+ * diagnostics/context.h: New file, taken from material in
+ diagnostic.h.
+ * diagnostics/html-sink.cc: : Update for diagnostic_context
+ becoming diagnostics::context.
+ * diagnostics/html-sink.h: Likewise.
+ * diagnostics/lazy-paths.cc: Likewise for
+ diagnostic_option_manager.
+ * diagnostics/output-file.h: Likewise for diagnostic_context.
+ * diagnostics/output-spec.cc: Likewise.
+ * diagnostics/output-spec.h: Likewise.
+ * diagnostics/paths-output.cc: Likewise.
+ * diagnostics/sarif-sink.cc: Likewise.
+ * diagnostics/sarif-sink.h: Likewise.
+ * diagnostics/sink.h: Likewise.
+ * diagnostics/source-printing.cc: Likewise.
+ * diagnostics/text-sink.cc: Likewise.
+ * diagnostics/text-sink.h: Likewise.
+ * gcc-rich-location.h: Likewise.
+ * gcc.cc: Likewise.
+ * gdbinit.in: Likewise.
+ * langhooks-def.h: Likewise.
+ * langhooks.cc: Likewise.
+ * langhooks.h: Likewise.
+ * libgdiagnostics.cc: Likewise.
+ * optc-gen.awk: Likewise.
+ * opth-gen.awk: Likewise.
+ * opts-common.cc: Likewise.
+ * opts-diagnostic.cc: Likewise.
+ * opts-diagnostic.h: Likewise.
+ * opts-global.cc: Likewise.
+ * opts.cc: Likewise.
+ * opts.h: Likewise.
+ * selftest-diagnostic.cc: Likewise.
+ * selftest-diagnostic.h: Likewise.
+ * toplev.cc: Likewise.
+ * tree-diagnostic-client-data-hooks.cc: Likewise.
+ * tree-diagnostic.cc: Likewise.
+ * tree-diagnostic.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic.h (struct diagnostic_info): Move to
+ diagnostics/diagnostic-info.h as diagnostics::diagnostic_info.
+ Add typedef bringing it back into root namespace, for now.
+ * diagnostics/diagnostic-info.h: New file, based on the above.
+ * langhooks-def.h: Update for diagnostic_info moving into
+ namespace diagnostics.
+ * langhooks.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic.cc: Update to add "m_" prefix to fields of
+ diagnostic_info throughout.
+ * diagnostic.h: Likewise.
+ * diagnostics/html-sink.cc: Likewise.
+ * diagnostics/sarif-sink.cc: Likewise.
+ * diagnostics/text-sink.cc: Likewise.
+ * libgdiagnostics.cc: Likewise.
+ * substring-locations.cc: Likewise.
+ * tree-diagnostic.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS): Replace diagnostic-macro-unwinding.o with
+ diagnostics/macro-unwinding.o.
+ * diagnostic-macro-unwinding.cc: Move to...
+ * diagnostics/macro-unwinding.cc: ...here, moving content into
+ namespace diagnostics.
+ * diagnostic-macro-unwinding.h: Move to...
+ * diagnostics/macro-unwinding.h: ...here, moving content into
+ namespace diagnostics.
+ * diagnostics/paths-output.cc: Update for move of
+ "diagnostic-macro-unwinding.h" to "diagnostics/macro-unwinding.h".
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS): Replace diagnostic-show-locus.o with
+ diagnostics/source-printing.o.
+ * diagnostic.h (class diagnostic_source_effect_info): Replace
+ with...
+ (class diagnotics::source_effect_info): ...this.
+ * diagnostics/paths-output.cc: Likewise. Update for move of
+ "diagnostic-label-effects.h" to
+ "diagnostics/source-printing-effects.h".
+ * diagnostics/sarif-sink.cc: Update for move of
+ "selftest-diagnostic-show-locus.h" to
+ "diagnostics/selftest-source-printing.h".
+ * selftest-diagnostic-show-locus.h: Move to...
+ * diagnostics/selftest-source-printing.h: ...here.
+ * diagnostic-label-effects.h: Move to...
+ * diagnostics/source-printing-effects.h: ...here, updating
+ for above changes.
+ * diagnostic-show-locus.cc: Move to...
+ * diagnostics/source-printing.cc: ...here.
+ * gcc-rich-location.h: Likewise.
+ * selftest-run-tests.cc: Likewise.
+ * selftest.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS): Replace diagnostic-format-html.o with
+ diagnostics/html-sink.o, diagnostic-format-sarif.o with
+ diagnostics/sarif-sink.o, and diagnostic-format-text.o with
+ diagnostics/text-sink.o.
+ * coretypes.h (class diagnostic_text_output_format): Replace
+ with...
+ (class diagnostics::text_sink): ...this.
+ * diagnostic-global-context.cc: Update for move of diagnostics
+ output formats into namespace "diagnostics", as "sinks".
+ * diagnostic-macro-unwinding.cc: Likewise.
+ * diagnostic-macro-unwinding.h: Likewise.
+ * diagnostic-show-locus.cc: Likewise.
+ * diagnostic.cc: Likewise.
+ * diagnostic.h: Likewise.
+ * diagnostic-buffer.h: Rename to...
+ * diagnostics/buffering.h: ...this, updating for above changes.
+ * diagnostics/client-data-hooks.h: Likewise.
+ * diagnostics/digraphs.cc: Likewise.
+ * diagnostic-format-html.cc: Rename to...
+ * diagnostics/html-sink.cc: ...this, updating for above changes.
+ * diagnostic-format-html.h: Rename to...
+ * diagnostics/html-sink.h: ...this, updating for above changes.
+ * diagnostics/lazy-paths.cc: Likewise.
+ * diagnostics/metadata.h: Likewise.
+ * diagnostics/output-spec.cc: Likewise.
+ * diagnostics/output-spec.h: Likewise.
+ * diagnostics/paths-output.cc: Likewise.
+ * diagnostics/paths.h: Likewise.
+ * diagnostic-format-sarif.cc: Rename to...
+ * diagnostics/sarif-sink.cc: ...this, updating for above changes.
+ * diagnostic-format-sarif.h: Rename to...
+ * diagnostics/sarif-sink.h: ...this, updating for above changes.
+ * diagnostic-format.h: Rename to...
+ * diagnostics/sink.h: ...this, updating for above changes.
+ * diagnostics/state-graphs-to-dot.cc: Likewise.
+ * diagnostic-format-text.cc: Rename to...
+ * diagnostics/text-sink.cc: ...this, updating for above changes.
+ * diagnostic-format-text.h: Rename to...
+ * diagnostics/text-sink.h: ...this, updating for above changes.
+ * gcc.cc: Likewise.
+ * langhooks-def.h: Likewise.
+ * langhooks.cc: Likewise.
+ * langhooks.h: Likewise.
+ * libgdiagnostics.cc: Likewise.
+ * opts-diagnostic.cc: Likewise.
+ * opts.cc: Likewise.
+ * selftest-diagnostic.cc: Likewise.
+ * selftest-run-tests.cc: Likewise.
+ * selftest.h: Likewise.
+ * tree-diagnostic-client-data-hooks.cc: Likewise.
+ * tree-diagnostic.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS): Replace lazy-diagnostic-path.o with
+ diagnostics/lazy-paths.o.
+ (OBJS-libcommon): Replace diagnostic-path.o with
+ diagnostics/paths.o, diagnostic-path-output.o with
+ diagnostics/paths-output.o, and selftest-diagnostic-path.o with
+ diagnostics/selftest-paths.o.
+ (EXTRA_BACKEND_OBJS): Replace lazy-diagnostic-path.o with
+ diagnostics/lazy-paths.o.
+ * diagnostic-format-html.cc: Update #include for
+ "diagnostic-path.h" moving to "diagnostics/paths.h",
+ diagnostic_thread_id_t to diagnostics::paths::thread_id_t,
+ diagnostic_event_id_t to diagnostics::paths::event_id_t,
+ diagnostic_path to diagnostics::paths::path, and
+ diagnostic_thread to diagnostics::paths::thread, and
+ diagnostic_event to diagnostics::paths::event.
+ * diagnostic-format-html.h: Likewise.
+ * diagnostic-format-sarif.cc: Likewise. Update PROPERTY_PREFIX
+ for threadFlowLocations from "gcc/diagnostic_event/" to
+ "gcc/diagnostics/paths/event/".
+ * diagnostic-format-text.cc: Likewise.
+ * diagnostic-format-text.h: Likewise.
+ * diagnostic.cc: Likewise.
+ * diagnostic.h: Likewise.
+ * diagnostic-event-id.h: Move to...
+ * diagnostics/event-id.h: ...here, updating header guard.
+ (diagnostics:paths:event_id_t): New typedef.
+ (diagnostic_thread_id_t): Replace with...
+ (diagnostics:paths:thread_id_t): New typedef.
+ * lazy-diagnostic-path.cc: Move to...
+ * diagnostics/lazy-paths.cc: ...here. Update for above changes,
+ lazy_diagnostic_path becomes diagnostics::paths::lazy_path.
+ (lazy_diagnostic_path_cc_tests): Rename to...
+ (diagnostics_lazy_paths_cc_tests): ...this.
+ * lazy-diagnostic-path.h: Move to...
+ * diagnostics/lazy-paths.h: ...here, updating header guard.
+ Update for above changes.
+ * diagnostic-path-output.cc: Move to...
+ * diagnostics/paths-output.cc: ...here. Update for above changes.
+ (diagnostic_path_output_cc_tests): Rename to...
+ (diagnostics_paths_output_cc_tests): ...this.
+ * diagnostic-path.cc: Move to...
+ * diagnostics/paths.cc: ...here. Update for above changes.
+ * diagnostic-path.h: Move to...
+ * diagnostics/paths.h: ...here, updating header guard.
+ Update #include for moving "diagnostic-event-id.h" to
+ "diagnostics/event-id.h".
+ (class diagnostic_event): Convert to...
+ (class diagnostics::paths::event): ...this.
+ (class diagnostic_thread): Convert to...
+ (class diagnostics::paths::thread): ...this.
+ (class diagnostic_path): Convert to...
+ (class diagnostics::paths::path): ...this.
+ * diagnostic-show-locus.cc: Update for above changes.
+ * doc/analyzer.texi: Likewise.
+ * selftest-diagnostic-path.cc: Move to...
+ * diagnostics/selftest-paths.cc: ...here. Update for
+ above changes, and for "selftest-diagnostic-path.h" moving to
+ "diagnostics/selftest-paths.h".
+ * selftest-diagnostic-path.h: Move to...
+ * diagnostics/selftest-paths.h: ...here, updating header guard.
+ Update for above changes.
+ * libgdiagnostics.cc: Update for above changes.
+ * libsarifreplay.cc: Update property prefix for
+ threadFlowLocations from "gcc/diagnostic_event/" to
+ "gcc/diagnostics/paths/event/".
+ * pretty-print-format-impl.h: Update for above changes.
+ * pretty-print.cc: Likewise.
+ * selftest-run-tests.cc (selftest::run_tests): Update for
+ renaming of lazy_diagnostic_path_cc_tests to
+ diagnostics_lazy_paths_cc_tests, and of
+ diagnostic_path_output_cc_tests to
+ diagnostics_paths_output_cc_tests.
+ * selftest.h (lazy_diagnostic_path_cc_tests): Replace decl with...
+ (diagnostics_lazy_paths_cc_tests): ...this.
+ (diagnostic_path_output_cc_tests): Replace decl with...
+ (diagnostics_paths_output_cc_tests): ...this.
+ * simple-diagnostic-path.cc: Clarify that this relates to "tree"
+ and thus shouldn't be in "diagnostics". Update for above changes.
+ * simple-diagnostic-path.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Replace diagnostic-output-spec.o
+ with diagnostics/output-spec.o.
+ * diagnostic-output-spec.cc: Move to...
+ * diagnostics/output-spec.cc: ...here. Update #include for
+ move of diagnostic-output-spec.h to diagnostics/output-spec.h.
+ (namespace::diagnostics_output_spec): Replace with...
+ (namespace diagnostics::output_spec): ...this, removing redundant
+ prefixes.
+ (diagnostics_output_spec::gcc_spec_context): Replace with...
+ (diagnostics::output_spec::dc_spec_context): ...this.
+ (diagnostic_output_spec_cc_tests): Rename to...
+ (diagnostics_output_spec_cc_tests): ...this.
+ * diagnostic-output-spec.h: Move to...
+ * diagnostics/output-spec.h: ...here and update inclusion guard.
+ (namespace::diagnostics_output_spec): Replace with...
+ (namespace diagnostics::output_spec): ...this, removing redundant
+ prefixes.
+ (diagnostics_output_spec::gcc_spec_context): Replace with...
+ (diagnostics::output_spec::dc_spec_context): ...this.
+ * libgdiagnostics.cc: Update #include for move of
+ diagnostic-output-spec.h to diagnostics/output-spec.h.
+ * opts-diagnostic.cc: Likewise. Update for namespace and name
+ changes.
+ * selftest-run-tests.cc (selftest::run_tests): Update for renaming
+ of diagnostic_output_spec_cc_tests to
+ diagnostics_output_spec_cc_tests.
+ * selftest.h (diagnostic_output_spec_cc_tests): Rename decl to...
+ (diagnostics_output_spec_cc_tests): ...this.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic-format-html.cc: Update #include for move of
+ diagnostic-output-file.h to diagnostics/output-file.h. Update for
+ move of diagnostic_output_file to diagnostics::output_file.
+ * diagnostic-format-html.h: Likewise.
+ * diagnostic-format-sarif.cc: Likewise.
+ * diagnostic-format-sarif.h: Likewise.
+ * diagnostic-output-spec.cc: Likewise.
+ * diagnostic-output-spec.h (along): Likewise.
+ * diagnostic-output-file.h: Move to...
+ * diagnostics/output-file.h: ...here, updating header guard.
+ (class diagnostic_output_file): Move to...
+ (class diagnostics::output_file): ...here.
+ * libgdiagnostics.cc (sarif_sink::sarif_sink): Update for
+ move of diagnostic_output_file to diagnostics::output_file.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic-format-html.cc: Update #include for move of
+ diagnostic-client-data-hooks.h to diagnostics/client-data-hooks.h.
+ * diagnostic-format-sarif.cc: Likewise. Update for move of
+ diagnostic_client_plugin_info to diagnostics::client_plugin_info.
+ * diagnostic-format-text.cc: Likewise.
+ * diagnostic.cc: Likewise.
+ * diagnostic.h: Likewise.
+ * diagnostic-client-data-hooks.h: Move to...
+ * diagnostics/client-data-hooks.h: ...here, updating header guard.
+ (class diagnostic_client_data_hooks): Move to...
+ (class diagnostics::client_data_hooks): ...here. Remove redundant
+ "diagnostics::" prefixes.
+ (class diagnostic_client_plugin_info): Move to...
+ (class diagnostics::client_plugin_info): ...here.
+ * libgdiagnostics.cc: : Update #include for move of
+ diagnostic-client-data-hooks.h to diagnostics/client-data-hooks.h.
+ Update for move of diagnostic_client_data_hooks to
+ diagnostics::client_data_hooks, and for move of
+ diagnostic_client_version_info to diagnostics::client_version_info.
+ * tree-diagnostic-client-data-hooks.cc: Likewise.
+ * tree-diagnostic.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Replace edit-context.o with
+ diagnostics/edit-context.o.
+ * diagnostic-format-html.cc: Update #include for move
+ of edit-context.h to diagnostics subdir.
+ * diagnostic.cc: Likewise. Update for move of edit_context to
+ diagnostics::edit_context.
+ * diagnostic.h: Likewise.
+ * edit-context.cc: Move to...
+ * diagnostics/edit-context.cc: ...here. Update #include for move
+ of edit-context.h to diagnostics subdir. Move all code
+ within namespace diagnostics.
+ * edit-context.h: Move to...
+ * diagnostics/edit-context.h: ...here, updating header guard.
+ Move all code within namespace diagnostics.
+ * libgdiagnostics.cc: Update #include for move of edit-context.h
+ to diagnostics subdir. Update for move of edit_context
+ to diagnostics::edit_context.
+ * toplev.cc: Update #include for move of edit-context.h
+ to diagnostics subdir.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic-format-html.cc: Update for move of diagnostic_diagram
+ to diagnostics::diagram.
+ * diagnostic-format-sarif.cc: Update #include for move of
+ "diagnostic-diagram.h" to "diagnostics/diagram.h". Update for move
+ of diagnostic_diagram to diagnostics::diagram.
+ * diagnostic-format-text.cc: Likewise.
+ * diagnostic-format-text.h: Update for move of diagnostic_diagram
+ to diagnostics::diagram.
+ * diagnostic-format.h: Likewise.
+ * diagnostic.cc: Update #include for move of
+ "diagnostic-diagram.h" to "diagnostics/diagram.h". Update for move
+ of diagnostic_diagram to diagnostics::diagram.
+ * diagnostic.h: Update for move of diagnostic_diagram to
+ diagnostics::diagram.
+ * diagnostic-diagram.h: Move to...
+ * diagnostics/diagram.h: ...here.
+ (class diagnostic_diagram): Convert to...
+ (class diagnostics::diagram): ...this.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic-core.h: Update for move of diagnostic_metadata to
+ diagnostics::metadata.
+ * diagnostic-format-html.cc: Likewise; also, update #include for
+ move of "diagnostic-metadata.h" to "diagnostics/metadata.h".
+ * diagnostic-format-sarif.cc: Likewise.
+ * diagnostic-format-text.cc: Likewise.
+ * diagnostic-global-context.cc: Likewise.
+ * diagnostic.cc: Likewise.
+ * diagnostic.h: Likewise.
+ * diagnostic-metadata.h: Move to...
+ * diagnostics/metadata.h: ...here, updating header guard.
+ (class diagnostic_metadata): Move to...
+ (class diagnostics::metadata): ...here. Drop redundant
+ "diagnostics::" qualifiers.
+ * libgdiagnostics.cc: : Update #include for move of
+ "diagnostic-metadata.h" to "diagnostics/metadata.h", and update
+ for move of diagnostic_metadata to diagnostics::metadata.
+ * selftest-diagnostic.cc: Update for move of diagnostic_metadata
+ to diagnostics::metadata.
+ * selftest-diagnostic.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Replace
+ selftest-logical-location.o with
+ diagnostics/selftest-logical-locations.o.
+ * diagnostic-client-data-hooks.h: Update #include for move of
+ "logical-location.h" to "diagnostics/logical-locations.h".
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager, and of logical_location
+ to diagnostics::logical_locations::key.
+ * diagnostic-format-html.cc: Add "using namespace diagnostics;",
+ and drop now-redundant "diagnostics::" prefixes.
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager, of logical_location to
+ diagnostics::logical_locations::key, and of
+ enum logical_location_kind to
+ enum diagnostics::logical_locations::kind.
+ * diagnostic-format-sarif.cc: Update #include for move of
+ "logical-location.h" to "diagnostics/logical-locations.h". Add
+ "using namespace diagnostics;", and drop now-redundant
+ "diagnostics::" prefixes.
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager, of logical_location to
+ diagnostics::logical_locations::key, and of
+ enum logical_location_kind to
+ enum diagnostics::logical_locations::kind.
+ * diagnostic-format-sarif.h: Update #include for move of
+ "logical-location.h" to "diagnostics/logical-locations.h".
+ Update for conversion of logical_location to
+ diagnostics::logical_locations::key.
+ * diagnostic-path-output.cc: Add "using namespace diagnostics;".
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager, and
+ of logical_location to diagnostics::logical_locations::key,
+ * diagnostic-path.cc: Add "using namespace diagnostics;".
+ Update for conversion of logical_location to
+ diagnostics::logical_locations::key.
+ * diagnostic-path.h: Update #include for move of
+ "logical-location.h" to "diagnostics/logical-locations.h".
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager, and of logical_location
+ to diagnostics::logical_locations::key,
+ * diagnostic.cc: Update #include for move of
+ "logical-location.h" to "diagnostics/logical-locations.h".
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager and of
+ enum logical_location_kind to
+ enum diagnostics::logical_locations::kind.
+ * diagnostic.h: Reorganize forward decls.
+ (class logical_location_manager): Replace this forward decl
+ with...
+ (class diagnostics::logical_locations::manager): ...this.
+ (diagnostic_context::get_logical_location_manager): Update
+ return type.
+ * diagnostics/digraphs.h: : Update #include for move of
+ "logical-location.h" to "diagnostics/logical-locations.h".
+ Update for conversion of logical_location to
+ diagnostics::logical_locations::key.
+ * logical-location.h: Move to...
+ * diagnostics/logical-locations.h: ...here.
+ (enum class logical_location_kind): Convert to...
+ (enum class diagnostics::logical_locations::kind): ... this.
+ (class logical_location_manager::key): Convert to...
+ (class diagnostics::logical_locations::key): ... this.
+ (class logical_location_manager): Convert to...
+ (class diagnostics::logical_locations::manager): ... this.
+ (logical_location): Drop this typedef in favor of
+ diagnostics::logical_locations::key.
+ * selftest-logical-location.cc: Move to...
+ * diagnostics/selftest-logical-locations.cc: ...here.
+ Update #include for move of "selftest-logical-location.h" to
+ "diagnostics/selftest-logical-locations.h".
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager, of logical_location to
+ diagnostics::logical_locations::key, and of
+ enum logical_location_kind to
+ enum diagnostics::logical_locations::kind.
+ (selftest_logical_location_cc_tests): Rename to...
+ (diagnostics_selftest_logical_locations_cc_tests): ...this.
+ * selftest-logical-location.h: Move to...
+ * diagnostics/selftest-logical-locations.h: ...here, updating
+ include guard.
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager, of logical_location to
+ diagnostics::logical_locations::key, and of
+ enum logical_location_kind to
+ enum diagnostics::logical_locations::kind.
+ * diagnostics/state-graphs-to-dot.cc: Add
+ "using namespace diagnostics;" and drop now-redundant
+ "diagnostics::" prefixes.
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager.
+ * diagnostics/state-graphs.h: Update #include for move of
+ "logical-location.h" to "diagnostics/logical-locations.h".
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager,
+ of logical_location to diagnostics::logical_locations::key.
+ * libgdiagnostics.cc: Update #include for move of
+ "logical-location.h" to "diagnostics/logical-locations.h".
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager, and of logical_location
+ to diagnostics::logical_locations::key.
+ * selftest-diagnostic-path.cc: Update for conversion of
+ logical_location to diagnostics::logical_locations::key.
+ * selftest-diagnostic-path.h: Update #include for move of
+ "logical-location.h" to "diagnostics/logical-locations.h".
+ Update for conversion of logical_location to
+ diagnostics::logical_locations::key.
+ * selftest-run-tests.cc (selftest::run_tests): Update for
+ renaming of selftest_logical_location_cc_tests to
+ diagnostics_selftest_logical_locations_cc_tests.
+ * selftest.h: Likewise.
+ * simple-diagnostic-path.h: Update for conversion of
+ logical_location to diagnostics::logical_locations::key.
+ * tree-diagnostic-client-data-hooks.cc: Update for conversion of
+ logical_location_manager to
+ diagnostics::logical_locations::manager, and of logical_location
+ to diagnostics::logical_locations::key.
+ * tree-logical-location.cc: Update for conversions.
+ Update for conversion of logical_location to
+ diagnostics::logical_locations::key, and of
+ enum logical_location_kind to
+ enum diagnostics::logical_locations::kind.
+ * tree-logical-location.h: Update #include for move of
+ "logical-location.h" to "diagnostics/logical-locations.h".
+ Update for conversion of logical_location_manager to
+ diagnostics::logical_locations::manager, of logical_location
+ to diagnostics::logical_locations::key, and of
+ enum logical_location_kind to
+ enum diagnostics::logical_locations::kind.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS-libcommon): Rename diagnostic-digraphs.o to
+ diagnostics/digraphs.o. Rename diagnostic-state-graphs.o to
+ diagnostics/state-graphs.o. Rename diagnostic-state-to-dot.o to
+ diagnostics/state-graphs-to-dot.o.
+ (PLUGIN_HEADERS): Add $(srcdir)/diagnostics/*.h.
+ (install-plugin:): Likewise.
+ * configure: Regenerate.
+ * configure.ac (gccdepdir): Add "diagnostics" to directories.
+ * diagnostic-format-html.cc: Update #includes for move of
+ "diagnostic-digraphs.h" to "diagnostics/digraphs.h" and of
+ move of "diagnostic-state-graphs.h" to
+ "diagnostics/state-graphs.h".
+ * diagnostic-format-sarif.cc: Likewise.
+ * diagnostic-path.cc: Likewise for state-graphs.h
+ * diagnostic-digraphs.cc: Move...
+ * diagnostics/digraphs.cc: ...to here. Update #include
+ for renaming of digraphs.h.
+ (selftest::diagnostic_digraphs_cc_tests): Rename to...
+ (selftest::diagnostics_digraphs_cc_tests): ...this.
+ * diagnostic-digraphs.h: Move...
+ * diagnostics/digraphs.h: ...to here, updating header guard.
+ * diagnostic-state-to-dot.cc: Move...
+ * diagnostics/state-graphs-to-dot.cc: ...to here. Update #include
+ of state-graphs.h.
+ * diagnostic-state-graphs.cc: Move...
+ * diagnostics/state-graphs.cc: ...to here. Update #include
+ of state-graphs.h.
+ (selftest::diagnostic_state_graphs_cc_tests): Rename...
+ (selftest::diagnostics_state_graphs_cc_tests): ...to this.
+ * diagnostic-state-graphs.h: Move...
+ * diagnostics/state-graphs.h: ...to here, updating header guard.
+ * libgdiagnostics.cc: Update #includes for move of
+ "diagnostic-digraphs.h" to "diagnostics/digraphs.h" and of
+ move of "diagnostic-state-graphs.h" to
+ "diagnostics/state-graphs.h".
+ * selftest-run-tests.cc (selftest::run_tests): Update for
+ function renamings that reflect file renamings.
+ * selftest.h (selftest::diagnostic_digraphs_cc_tests): Rename
+ to...
+ (selftest::diagnostics_digraphs_cc_tests): ...this.
+ (selftest::diagnostic_state_graphs_cc_tests): Rename...
+ (selftest::diagnostics_state_graphs_cc_tests): ...to this.
+
+2025-07-25 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (vect_get_vec_defs): Remove overload
+ with operand vector type. Remove stmt_vec_info and
+ ncopies argument.
+ * tree-vect-stmts.cc (vect_get_vec_defs): Likewise.
+ (vectorizable_conversion): Adjust by not passing in
+ vector types, stmt_vec_info and ncopies.
+ (vectorizable_bswap): Likewise.
+ (vectorizable_assignment): Likewise.
+ (vectorizable_shift): Likewise.
+ (vectorizable_operation): Likewise.
+ (vectorizable_scan_store): Likewise.
+ (vectorizable_store): Likewise.
+ (vectorizable_condition): Likewise.
+ (vectorizable_comparison_1): Likewise.
+ * tree-vect-loop.cc (vect_transform_reduction): Likewise.
+ (vect_transform_lc_phi): Likewise.
+
+2025-07-25 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (vect_is_simple_use): Remove stmt-info
+ with vectype output overload and remove stmt-info argument
+ from SLP based API.
+ * tree-vect-loop.cc (vectorizable_lane_reducing): Remove
+ unused def_stmt_info output argument to vect_is_simple_use.
+ Adjust.
+ * tree-vect-stmts.cc (get_group_load_store_type): Get
+ the gather/scatter offset vector type from the SLP child.
+ (vect_check_scalar_mask): Remove stmt_info argument. Adjust.
+ (vect_check_store_rhs): Likewise.
+ (vectorizable_call): Likewise.
+ (vectorizable_simd_clone_call): Likewise.
+ (vectorizable_conversion): Likewise.
+ (vectorizable_assignment): Likewise.
+ (vectorizable_shift): Likewise.
+ (vectorizable_operation): Likewise.
+ (vectorizable_load): Likewise.
+ (vect_is_simple_cond): Remove stmt_info argument. Adjust.
+ (vectorizable_condition): Likewise.
+ (vectorizable_comparison_1): Likewise.
+ (vectorizable_store): Likewise.
+ (vect_is_simple_use): Remove overload and non-SLP path.
+
+2025-07-25 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-stmts.cc (vect_model_simple_cost): Removed code
+ when no SLP node is passed, remove then unused dt and ndts
+ parameters and fix the number of vector stmts calculation.
+ (vectorizable_call): Adjust.
+ (vectorizable_simd_clone_call): Likewise.
+ (vectorizable_conversion): Likewise.
+ (vectorizable_assignment): Likewise.
+ (vectorizable_shift): Likewise.
+ (vectorizable_operation): Likewise.
+ (vectorizable_condition): Likewise.
+ (vectorizable_comparison_1): Likewise.
+
+2025-07-25 Robin Dapp <rdapp@ventanamicro.com>
+
+ * config/riscv/riscv-vector-costs.cc (get_live_range):
+ Move compute_local_program_points to cost class.
+ (variable_vectorized_p): Add slp node parameter.
+ (need_additional_vector_vars_p): Move from here...
+ (costs::need_additional_vector_vars_p): ... to here and add slp
+ parameter.
+ (compute_estimated_lmul): Move update_local_live_ranges to cost
+ class.
+ (has_unexpected_spills_p): Move from here...
+ (costs::has_unexpected_spills_p): ... to here.
+ (costs::record_lmul_spills): New function.
+ (costs::add_stmt_cost): Add stmt_info, slp mapping.
+ (costs::finish_cost): Analyze loop.
+ * config/riscv/riscv-vector-costs.h: Move declarations to class.
+
+2025-07-25 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-loop.cc (vect_analyze_loop_2): Get vectype
+ from the SLP node.
+ (vectorize_fold_left_reduction): Likewise.
+ (vect_transform_reduction): Likewise.
+ (vect_transform_cycle_phi): Likewise.
+ (vect_transform_lc_phi): Likewise.
+ * tree-vect-slp.cc (vect_analyze_slp): Likewise.
+ * tree-vect-stmts.cc (vect_truncate_gather_scatter_offset):
+ Pass in vectype and use that.
+ (vect_use_strided_gather_scatters_p): Likewise.
+ (get_group_load_store_type): Adjust.
+ (vect_check_scalar_mask): We always have a SLP node.
+ Use vectype from the SLP node.
+ (vect_check_store_rhs): Likewise.
+ (vect_build_one_gather_load_call): Pass in the vector type
+ and use that.
+ (vect_get_strided_load_store_ops): Likewise.
+ (vectorizable_store): Adjust.
+ (vectorizable_load): Use the vector type from the SLP node
+ and adjust.
+
+2025-07-25 Richard Biener <rguenther@suse.de>
+
+ * target.h (stmt_vectype): Remove.
+ * tree-vect-stmts.cc (stmt_vectype): Likewise.
+
+2025-07-25 Christoph Müllner <christoph.muellner@vrull.eu>
+
+ * config/riscv/riscv.cc (enum riscv_privilege_levels): Remove USER_MODE.
+ (riscv_handle_type_attribute): Remove "user" interrupts.
+ (riscv_expand_epilogue): Likewise.
+ (riscv_get_interrupt_type): Likewise.
+ * config/riscv/riscv.md (riscv_uret): Remove URET pattern.
+ * doc/extend.texi: Remove documentation of user interrupts.
+
+2025-07-25 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (_stmt_vec_info::vec_stmts): Remove.
+ (STMT_VINFO_VEC_STMTS): Likewise.
+ * tree-vectorizer.cc (vec_info::new_stmt_vec_info): Do not
+ initialize it.
+ (vec_info::free_stmt_vec_info): Nor free it.
+ * tree-vect-data-refs.cc (vect_vfa_access_size): Remove
+ check on STMT_VINFO_VEC_STMTS.
+
+2025-07-25 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (vect_transform_grouped_load): Remove.
+ (vect_record_grouped_load_vectors): Likewise.
+ * tree-vect-data-refs.cc (vect_permute_load_chain): Likewise.
+ (vect_shift_permute_load_chain): Likewise.
+ (vect_transform_grouped_load): Likewise.
+ (vect_record_grouped_load_vectors): Likewise.
+ * tree-vect-stmts.cc (vectorizable_load): Remove comments
+ about load interleaving.
+
+2025-07-25 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (vect_permute_store_chain): Remove.
+ * tree-vect-data-refs.cc (vect_permute_store_chain): Likewise.
+ * tree-vect-stmts.cc (vectorizable_store): Remove comment
+ about store interleaving.
+
+2025-07-25 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (vect_get_vec_defs_for_operand): Remove.
+ * tree-vect-stmts.cc (vect_get_vec_defs_for_operand): Likewise.
+ (vect_get_vec_defs): Remove non-SLP path.
+ (check_load_store_for_partial_vectors): We always have an
+ SLP node.
+ (vect_check_store_rhs): Likewise.
+ (vect_get_gather_scatter_ops): Likewise.
+ (vect_create_vectorized_demotion_stmts): Likewise.
+ (vectorizable_store): Adjust.
+ (vectorizable_load): Likewise.
+
+2025-07-25 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (VMAT_CONTIGUOUS_PERMUTE): Remove.
+ * tree-vect-stmts.cc (check_load_store_for_partial_vectors):
+ Remove checks on VMAT_CONTIGUOUS_PERMUTE.
+ (vectorizable_load): Likewise.
+ (vectorizable_store): Likewise. Prune dead code.
+
+2025-07-25 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-stmts.cc (vectorizable_store): Remove trivially
+ dead code.
+
+2025-07-25 Tobias Burnus <tburnus@baylibre.com>
+
+ * config/gcn/gcn-opts.h (TARGET_NO_MANUAL_NOPS,
+ TARGET_CDNA3_NOPS): Define.
+ * config/gcn/gcn.md (define_attr "laneselect): Change 'yes' to
+ 'read' and 'write'.
+ (define_attr "flatmemaccess"): Add with values store, storex34,
+ load, atomic, atomicwait, cmpswapx2, and no. Replacing ...
+ (define_attr "delayeduse"): Remove.
+ (define_attr "transop"): Add with values yes and no.
+ (various insns): Update 'laneselect', add flatmemaccess and transop,
+ remove delayeduse; fixing an issue for s_load_dwordx4 vs.
+ flat_store_dwordx4 related to delayeduse (now: flatmemaccess).
+ * config/gcn/gcn-valu.md: Update laneselect attribute and add
+ flatmemaccess.
+ * config/gcn/gcn.cc (gcn_cmpx_insn_p): New.
+ (gcn_md_reorg): Update for MI300 to add additional s_nop.
+ Skip s_nop-insertion part for RDNA{2,3}; add "VALU writes EXEC
+ followed by VALU DPP" unconditionally for CDNA2/CDNA3/GCN5.
+
+2025-07-25 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ PR middle-end/121214
+ * genpreds.cc (constraint_max_namelen): Delete.
+ (write_tm_preds_h): Always write insn_constraint_len() and
+ define CONSTRAINT_LEN to it, i.e., remove guard
+ constraint_max_namelen>1. Remove outer guard
+ constraint_max_namelen>0 and re-indent.
+ (write_insn_preds_c): Remove guard
+ constraint_max_namelen>0 and re-indent.
+
+2025-07-25 Christoph Müllner <christoph.muellner@vrull.eu>
+
+ * config/riscv/riscv.cc (enum riscv_privilege_levels): Add
+ RNMI_MODE.
+ (riscv_handle_type_attribute): Handle 'rnmi' interrupt attribute.
+ (riscv_expand_epilogue): Generate nmret for RNMI handlers.
+ (riscv_get_interrupt_type): Handle 'rnmi' interrupt attribute.
+ * config/riscv/riscv.md (riscv_rnmi): Add nmret INSN.
+ * doc/extend.texi: Add documentation for 'rnmi' interrupt attribute.
+
+2025-07-24 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (vectorizable_induction): Remove
+ gimple **vec_stmt argument.
+ (vectorizable_phi): Likewise.
+ (vectorizable_recurr): Likewise.
+ (vectorizable_early_exit): Likewise.
+ * tree-vect-loop.cc (vectorizable_phi): Likewise and adjust.
+ (vectorizable_recurr): Likewise.
+ (vectorizable_nonlinear_induction): Likewise.
+ (vectorizable_induction): Likewise.
+ * tree-vect-stmts.cc (vectorizable_bswap): Likewise.
+ (vectorizable_call): Likewise.
+ (vectorizable_simd_clone_call): Likewise.
+ (vectorizable_conversion): Likewise.
+ (vectorizable_assignment): Likewise.
+ (vectorizable_shift): Likewise.
+ (vectorizable_operation): Likewise.
+ (vectorizable_store): Likewise.
+ (vectorizable_load): Likewise.
+ (vectorizable_condition): Likewise.
+ (vectorizable_comparison_1): Likewise.
+ (vectorizable_comparison): Likewise.
+ (vectorizable_early_exit): Likewise.
+ (vect_analyze_stmt): Adjust.
+ (vect_transform_stmt): Likewise.
+ * tree-vect-slp.cc (vect_slp_analyze_operations): Adjust.
+ (vectorize_slp_instance_root_stmt): Likewise.
+
+2025-07-24 Andrew Pinski <quic_apinski@quicinc.com>
+
+ * doc/cpp.texi (#ifdef): Correct typo.
+
+2025-07-24 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-stmts.cc (vectorizable_early_exit): Remove non-SLP
+ path.
+
+2025-07-24 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (_stmt_vec_info::simd_clone_info): Remove.
+ (STMT_VINFO_SIMD_CLONE_INFO): Likewise.
+ * tree-vectorizer.cc (vec_info::free_stmt_vec_info): Do not
+ release it.
+ * tree-vect-stmts.cc (vectorizable_simd_clone_call): Remove
+ non-SLP path.
+
+2025-07-24 Robin Dapp <rdapp@ventanamicro.com>
+
+ * internal-fn.cc (internal_fn_len_index): Adjust indices for new
+ alias_ptr param.
+ (internal_fn_else_index): Ditto.
+ (internal_fn_mask_index): Ditto.
+ (internal_fn_stored_value_index): Ditto.
+ (internal_fn_alias_ptr_index): Ditto.
+ (internal_fn_offset_index): Ditto.
+ (internal_fn_scale_index): Ditto.
+ (internal_gather_scatter_fn_supported_p): Ditto.
+ * internal-fn.h (internal_fn_alias_ptr_index): Ditto.
+ * optabs-query.cc (supports_vec_gather_load_p): Ditto.
+ * tree-vect-data-refs.cc (vect_check_gather_scatter): Add alias
+ pointer.
+ * tree-vect-patterns.cc (vect_recog_gather_scatter_pattern): Add
+ alias pointer.
+ * tree-vect-slp.cc (vect_get_operand_map): Adjust for alias
+ pointer.
+ * tree-vect-stmts.cc (vect_truncate_gather_scatter_offset): Add
+ alias pointer and misalignment handling.
+ (get_load_store_type): Move from here...
+ (get_group_load_store_type): ...To here.
+ (vectorizable_store): Add alias pointer.
+ (vectorizable_load): Ditto.
+ * tree-vectorizer.h (struct gather_scatter_info): Ditto.
+
+2025-07-24 Robin Dapp <rdapp@ventanamicro.com>
+
+ * config/aarch64/aarch64.cc (aarch64_builtin_support_vector_misalignment):
+ Return true for gather/scatter.
+ * config/arm/arm.cc (arm_builtin_support_vector_misalignment):
+ Ditto.
+ * config/epiphany/epiphany.cc (epiphany_support_vector_misalignment):
+ Ditto.
+ * config/gcn/gcn.cc (gcn_vectorize_support_vector_misalignment):
+ Ditto.
+ * config/loongarch/loongarch.cc (loongarch_builtin_support_vector_misalignment):
+ Ditto.
+ * config/riscv/riscv.cc (riscv_support_vector_misalignment):
+ Add gather/scatter argument.
+ * config/rs6000/rs6000.cc (rs6000_builtin_support_vector_misalignment):
+ Return true for gather/scatter.
+ * config/s390/s390.cc (s390_support_vector_misalignment):
+ Ditto.
+ * doc/tm.texi: Add argument.
+ * target.def: Ditto.
+ * targhooks.cc (default_builtin_support_vector_misalignment):
+ Ditto.
+ * targhooks.h (default_builtin_support_vector_misalignment):
+ Ditto.
+ * tree-vect-data-refs.cc (vect_supportable_dr_alignment):
+ Ditto.
+
+2025-07-24 Robin Dapp <rdapp@ventanamicro.com>
+
+ * tree-vect-slp.cc (GATHER_SCATTER_OFFSET): New define.
+ (vect_get_and_check_slp_defs): Use.
+ * tree-vectorizer.h (GATHER_SCATTER_LEGACY_P): New define.
+ (GATHER_SCATTER_IFN_P): Ditto.
+ (GATHER_SCATTER_EMULATED_P): Ditto.
+ * tree-vect-stmts.cc (vectorizable_store): Use.
+ (vectorizable_load): Use.
+
+2025-07-24 Robin Dapp <rdapp@ventanamicro.com>
+
+ * internal-fn.cc (expand_scatter_store_optab_fn): Use new
+ function.
+ (expand_gather_load_optab_fn): Ditto.
+ (internal_fn_offset_index): Ditto.
+ (internal_fn_scale_index): Ditto.
+ * internal-fn.h (internal_fn_offset_index): New function.
+ (internal_fn_scale_index): Ditto.
+ * tree-vect-data-refs.cc (vect_describe_gather_scatter_call):
+ Use new function.
+
+2025-07-24 Alfie Richards <alfie.richards@arm.com>
+
+ * tree-vect-data-refs.cc (vect_create_data_ref_ptr): Remove unnecessary
+ casts to aggr_ptr_type.
+
+2025-07-24 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-stmts.cc (vectorizable_comparison_1): Remove
+ non-SLP path.
+ (vectorizable_comparison): Likewise.
+
+2025-07-24 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-stmts.cc (vectorizable_condition): Remove
+ non-SLP paths.
+
+2025-07-24 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-stmts.cc (vectorizable_scan_store): Remove
+ non-SLP path and unused parameters.
+ (vectorizable_store): Adjust.
+
+2025-07-24 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-stmts.cc (vectorizable_shift): Remove non-SLP paths.
+
+2025-07-24 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-stmts.cc (vectorizable_assignment): Remove
+ non-SLP paths.
+
+2025-07-24 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-stmts.cc (vectorizable_call): Remove non-SLP path.
+
+2025-07-24 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-stmts.cc (vectorizable_bswap): Remove non-SLP path.
+
+2025-07-24 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-loop.cc (vectorizable_recurr): Remove non-SLP path.
+
+2025-07-24 Spencer Abson <spencer.abson@arm.com>
+
+ * config/aarch64/aarch64-sve.md (*cond_<optab><mode>_2_relaxed):
+ Extend from SVE_FULL_F_B16B16 to SVE_F_B16B16.
+ (*cond_<optab><mode>_3_relaxed): Likewise.
+ (*cond_<optab><mode>_any_relaxed): Likwise.
+ (*cond_<optab><mode>_any_const_relaxed): Extend from SVE_FULL_F
+ to SVE_F.
+ (*cond_add<mode>_2_const_relaxed): Likewise.
+ (*cond_add<mode>_any_const_relaxed): Likewise.
+ (*cond_sub<mode>_3_const_relaxed): Likewise.
+ (*cond_sub<mode>_const_relaxed): Likewise.
+
+2025-07-24 Spencer Abson <spencer.abson@arm.com>
+
+ * config/aarch64/aarch64-sve.md: (@aarch64_sve_<optab><mode>):
+ Extend from SVE_FULL_F to SVE_F, use aarch64_predicate_operand.
+ (@aarch64_frecpe<mode>): Extend from SVE_FULL_F to SVE_F.
+ (@aarch64_frecps<mode>): Likewise.
+ (div<mode>3): Likewise, use aarch64_sve_fp_pred.
+ * config/aarch64/iterators.md: Add warnings above SVE_FP_UNARY
+ and SVE_FP_BINARY.
+
+2025-07-24 Spencer Abson <spencer.abson@arm.com>
+
+ * config/aarch64/aarch64-sve.md (<optab><mode>3): Extend from
+ SVE_FULL_F to SVE_F, use aarch64_sve_fp_pred.
+ (*post_ra_<sve_fp_op><mode>3): Extend from SVE_FULL_F to SVE_F.
+ (@aarch64_pred_<optab><mode>): Extend from SVE_FULL_F to SVE_F,
+ use aarch64_predicate_operand (ADD/SUB/MUL/MAX/MIN).
+ (split for using unpredicated insns): Move SVE_RELAXED_GP into
+ the pattern, rather than testing for it in the condition.
+ * config/aarch64/aarch64-sve2.md (@aarch64_pred_<optab><mode>):
+ Extend from VNx8BF_ONLY to SVE_BF.
+
+2025-07-24 Pan Li <pan2.li@intel.com>
+
+ * config/riscv/autovec-opt.md (*uavg_floor_vx_<mode>): Rename
+ from...
+ (*<sat_op_v_vdup>_vx_<mode>): Rename to...
+ (*<sat_op_vdup_v>_vx_<mode>): Rename to...
+ * config/riscv/riscv-protos.h (enum insn_flags): Add vxrm
+ RNE, ROD type.
+ (enum insn_type): Add RNE_P, ROD_P type.
+ (expand_vx_binary_vxrm_vec_vec_dup): Add new func decl.
+ (expand_vx_binary_vxrm_vec_dup_vec): Ditto.
+ * config/riscv/riscv-v.cc (get_insn_type_by_vxrm_val): Add
+ helper to get insn type by vxrm value.
+ (expand_vx_binary_vxrm_vec_vec_dup): Add new func impl
+ to expand vec + vec_dup pattern.
+ (expand_vx_binary_vxrm_vec_dup_vec): Ditto but for
+ vec_dup + vec pattern.
+ * config/riscv/vector-iterators.md: Add helper iterator
+ for sat vx combine.
+
+2025-07-23 Spencer Abson <spencer.abson@arm.com>
+
+ * config/aarch64/aarch64-sve.md (*cond_<optab><mode>_2_relaxed):
+ Extend from SVE_FULL_F to SVE_F.
+ (*cond_<optab><mode>_any_relaxed): Likewise.
+
+2025-07-23 Spencer Abson <spencer.abson@arm.com>
+
+ * config/aarch64/aarch64-sve.md (<optab><mode>2): Replace use of
+ aarch64_ptrue_reg with aarch64_sve_fp_pred.
+ (@aarch64_pred_<optab><mode>): Extend from SVE_FULL_F to SVE_F,
+ and use aarch64_predicate_operand.
+ * config/aarch64/iterators.md: Split FABS/FNEG out of
+ SVE_COND_FP_UNARY (into new SVE_COND_FP_UNARY_BITWISE).
+
+2025-07-23 Spencer Abson <spencer.abson@arm.com>
+
+ * config/aarch64/aarch64-sve.md
+ (*cond_<optab>_nontrunc<SVE_PARTIAL_F:mode><SVE_HSDI:mode>_relaxed):
+ New FCVT/SEL combiner pattern.
+ (*cond_<optab>_trunc<VNx2DF_ONLY:mode><VNx2SI_ONLY:mode>_relaxed):
+ New FCVTZ{S,U}/SEL combiner pattern.
+ (*cond_<optab>_nonextend<SVE_HSDI:mode><SVE_PARTIAL_F:mode>_relaxed):
+ New {S,U}CVTF/SEL combiner pattern.
+ (*cond_<optab>_trunc<SVE_SDF:mode><SVE_PARTIAL_HSF:mode>):
+ New FCVT/SEL combiner pattern.
+ (*cond_<optab>_nontrunc<SVE_PARTIAL_HSF:mode><SVE_SDF:mode>_relaxed):
+ New FCVTZ{S,U}/SEL combiner pattern.
+ * config/aarch64/iterators.md: New mode iterator for VNx2SI.
+
+2025-07-23 Robin Dapp <rdapp@ventanamicro.com>
+
+ PR target/121073
+ * config/riscv/autovec-opt.md: Use new helpers.
+ * config/riscv/autovec.md: Ditto.
+ * config/riscv/predicates.md (strided_broadcast_mask_operand):
+ New predicate.
+ (strided_broadcast_operand): Ditto.
+ (any_broadcast_operand): Ditto.
+ * config/riscv/riscv-protos.h (expand_broadcast): Declare.
+ (expand_set_first): Ditto.
+ (expand_set_first_tu): Ditto.
+ (strided_broadcast_p): Ditto.
+ * config/riscv/riscv-string.cc (expand_vec_setmem): Use new
+ helpers.
+ * config/riscv/riscv-v.cc (expand_broadcast): New functionk.
+ (expand_set_first): Ditto.
+ (expand_set_first_tu): Ditto.
+ (expand_const_vec_duplicate): Use new helpers.
+ (expand_const_vector_duplicate_repeating): Ditto.
+ (expand_const_vector_duplicate_default): Ditto.
+ (sew64_scalar_helper): Ditto.
+ (expand_vector_init_merge_repeating_sequence): Ditto.
+ (expand_reduction): Ditto.
+ (strided_broadcast_p): New function.
+ (whole_reg_to_reg_move_p): Use new helpers.
+ * config/riscv/riscv-vector-builtins-bases.cc: Use either
+ broadcast or strided broadcast.
+ * config/riscv/riscv-vector-builtins.cc (function_expander::use_ternop_insn):
+ Ditto.
+ (function_expander::use_widen_ternop_insn): Ditto.
+ (function_expander::use_scalar_broadcast_insn): Ditto.
+ * config/riscv/riscv-vector-builtins.h: Declare scalar
+ broadcast.
+ * config/riscv/vector.md (*pred_broadcast<mode>): Split into
+ regular and strided broadcast.
+ (*pred_broadcast<mode>_zvfh): Split.
+ (pred_broadcast<mode>_zvfh): Ditto.
+ (*pred_broadcast<mode>_zvfhmin): Ditto.
+ (@pred_strided_broadcast<mode>): Ditto.
+ (*pred_strided_broadcast<mode>): Ditto.
+ (*pred_strided_broadcast<mode>_zvfhmin): Ditto.
+
+2025-07-23 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR target/120119
+ * config/aarch64/cortex-a57-fma-steering.cc (func_fma_steering::analyze):
+ Skip if renaming fails.
+
+2025-07-23 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/121220
+ * tree-ssa-sink.cc (statement_sink_location): For stores
+ handle sinking to paths ending in a store. Skip loads
+ that do not use the store.
+
+2025-07-23 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/119085
+ * tree-sra.cc (sort_and_splice_var_accesses): Prevent total
+ scalarization if two incompatible aggregates access the same place.
+
+2025-07-23 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * config.gcc <sparc*-*-solaris2*> (with_cpu): Default to ultrasparc3.
+
+2025-07-23 Richard Biener <rguenther@suse.de>
+
+ * config/aarch64/aarch64.cc (aarch64_vector_costs::add_stmt_cost):
+ Check vectype is non-NULL before accessing it.
+
+2025-07-23 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/121216
+ * expr.cc (constant_byte_string): Check the string type
+ size fits an uhwi before converting to uhwi.
+
+2025-07-22 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR middle-end/109267
+ * tree-cfgcleanup.cc (execute_cleanup_cfg_post_optimizing): If the first
+ non debug statement in the first (and only) basic block is a call
+ to __builtin_unreachable change it to a call to __builtin_trap or an
+ infinite loop.
+
+2025-07-22 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp>
+
+ * config/xtensa/xtensa.cc (xtensa_is_insn_L32R_p):
+ Rewrite to capture insns that could be L32R machine instructions
+ wherever possible.
+ (xtensa_rtx_costs): Fix to consider that moves larger than a
+ natural word can take multiple L32R machine instructions.
+ (constantpool_address_p): Cosmetics.
+ * config/xtensa/xtensa.md (movdi_internal, movdf_internal):
+ Add missing insn attributes.
+
+2025-07-22 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp>
+
+ * config/xtensa/xtensa.md
+ (movsi_internal, movhi_internal, movsf_internal):
+ Change the value of the "type" attribute from "move" to "load"
+ when the source operand constraint is "Y".
+
+2025-07-22 Karl Meakin <karl.meakin@arm.com>
+
+ * tree-vect-data-refs.cc (vect_check_gather_scatter): Swap
+ `base` and `off` in more scenarios. Also assert at the end of
+ the function that `base` and `off` are loop-invariant and not
+ loop-invariant respectively.
+
+2025-07-22 Jeff Law <jlaw@ventanamicro.com>
+
+ * config/riscv/generic-vector-ooo.md: Restrict insn reservations to
+ generic_ooo and generic tuning models.
+
+2025-07-22 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/121202
+ * tree-vect-slp.cc (vect_schedule_slp_node): Do not take
+ an out-of-region stmt as "last".
+
+2025-07-22 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * genpreds.cc (write_insn_constraint_len): Replace rawmemchr by
+ a loop.
+
+2025-07-21 Jeff Law <jlaw@ventanamicro.com>
+
+ * config/riscv/mips-p8700.md: Add support for "ghost" insn types.
+ * config/riscv/xiangshan.md: Add support for "sf_vc" and "sf_vc_se"
+ insn types.
+
+2025-07-21 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR tree-optimization/110949
+ PR tree-optimization/95906
+ * match.pd (cmp - 1): New pattern.
+
+2025-07-21 Andreas Schwab <schwab@suse.de>
+
+ PR target/121121
+ * config/riscv/riscv.cc (riscv_allocate_and_probe_stack_space):
+ Use temp2 instead of temp1 for the CFA note.
+
+2025-07-21 Pan Li <pan2.li@intel.com>
+
+ * config/riscv/vector.md: Allow VLS DImode for sat_op vx pattern.
+
+2025-07-21 Pan Li <pan2.li@intel.com>
+
+ * config/riscv/autovec-opt.md (*uavg_floor_vx_<mode>): Add
+ pattern for vaaddu.vx combine.
+ * config/riscv/riscv.cc (get_vector_binary_rtx_cost): Add UNSPEC
+ handling for UNSPEC_VAADDU.
+ (riscv_rtx_costs): Ditto.
+
+2025-07-21 Kyrylo Tkachov <ktkachov@nvidia.com>
+
+ * config/aarch64/aarch64-simd.md (aarch64_simd_vec_set_zero<mode>):
+ Enable only when optimizing for size.
+
+2025-07-21 Kyrylo Tkachov <ktkachov@nvidia.com>
+
+ * config/aarch64/aarch64.cc (aarch64_rtx_costs): Add extra_cost values
+ only when speed is true for CONST_VECTOR, VEC_DUPLICATE, VEC_SELECT
+ cases.
+ * config/aarch64/aarch64-cost-tables.h (qdf24xx_extra_costs,
+ thunderx_extra_costs, thunderx2t99_extra_costs,
+ thunderx3t110_extra_costs, tsv110_extra_costs, a64fx_extra_costs,
+ ampere1_extra_costs, ampere1a_extra_costs, ampere1b_extra_costs):
+ Reduce cost of movi, dup, extract fields by COSTS_N_INSNS (1).
+ * config/arm/aarch-cost-tables.h (generic_extra_costs,
+ cortexa53_extra_costs, cortexa57_extra_costs, cortexa76_extra_costs,
+ exynosm1_extra_costs, xgene1_extra_costs): Likewise.
+
+2025-07-21 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/121194
+ * tree-vect-loop.cc (vectorizable_lc_phi): Verify
+ vector types are compatible.
+
+2025-07-21 Andrew Stubbs <ams@baylibre.com>
+
+ * config/gcn/gcn-valu.md (gather_load<mode><vndi>): New.
+ (scatter_store<mode><vndi>): New.
+ (mask_gather_load<mode><vndi>): New.
+ (mask_scatter_store<mode><vndi>): New.
+ * config/gcn/gcn.cc (gcn_expand_scaled_offsets): Support DImode.
+
+2025-07-21 Andrew Stubbs <ams@baylibre.com>
+
+ * config/gcn/gcn.cc (GEN_VNM_NOEXEC): Use USE_QHF.
+ (GEN_VNM): Likewise, and call for new ashl and mul variants.
+
+2025-07-21 Andrew Stubbs <ams@baylibre.com>
+
+ * config/gcn/gcn-valu.md (add<mode>3_dup): New.
+ (add<mode>3_dup_exec): New.
+ (<su>mul<mode>3_highpart_dup<exec>): New.
+ (mul<mode>3_dup): Move the vec_duplicate to operand 1.
+ (mul<mode>3_dup_exec): New.
+ (vec_series<mode>): Adjust call to gen_mul<mode>3_dup.
+ * config/gcn/gcn.cc (gcn_expand_vector_init): Likewise.
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * genoutput.cc (main): Emit function
+ verify_reg_names_in_constraints() for run-time validation.
+ (mdep_constraint_len): Deal with hard register constraints.
+ * output.h (verify_reg_names_in_constraints): New function
+ declaration.
+ * toplev.cc (backend_init): If checking is enabled, call into
+ verify_reg_names_in_constraints().
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * cfgexpand.cc (n_occurrences): Move this ...
+ (check_operand_nalternatives): and this ...
+ (expand_asm_stmt): and the call to gimplify.cc.
+ * config/s390/s390.cc (s390_md_asm_adjust): Pass null pointer to
+ parse_{input,output}_constraint().
+ * gimple-walk.cc (walk_gimple_asm): Pass null pointer to
+ parse_{input,output}_constraint().
+ (walk_stmt_load_store_addr_ops): Ditto.
+ * gimplify-me.cc (gimple_regimplify_operands): Ditto.
+ * gimplify.cc (num_occurrences): Moved from cfgexpand.cc.
+ (num_alternatives): Ditto.
+ (gimplify_asm_expr): Deal with hard register constraints.
+ * stmt.cc (eliminable_regno_p): New helper.
+ (hardreg_ok_p): Perform a similar check as done in
+ make_decl_rtl().
+ (parse_output_constraint): Add parameter for gimplify_reg_info
+ and validate hard register constrained operands.
+ (parse_input_constraint): Ditto.
+ * stmt.h (class gimplify_reg_info): Forward declaration.
+ (parse_output_constraint): Add parameter.
+ (parse_input_constraint): Ditto.
+ * tree-ssa-operands.cc
+ (operands_scanner::get_asm_stmt_operands): Pass null pointer
+ to parse_{input,output}_constraint().
+ * tree-ssa-structalias.cc (find_func_aliases): Pass null pointer
+ to parse_{input,output}_constraint().
+ * varasm.cc (assemble_asm): Pass null pointer to
+ parse_{input,output}_constraint().
+ * gimplify_reg_info.h: New file.
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * config/cris/cris.cc (cris_md_asm_adjust): Deal with hard
+ register constraint.
+ * config/i386/i386.cc (map_egpr_constraints): Ditto.
+ * config/s390/s390.cc (f_constraint_p): Ditto.
+ * doc/extend.texi: Document hard register constraints.
+ * doc/md.texi: Ditto.
+ * function.cc (match_asm_constraints_2): Have a unique pseudo
+ for each operand with a hard register constraint.
+ (pass_match_asm_constraints::execute): Calling into new helper
+ match_asm_constraints_2().
+ * genoutput.cc (mdep_constraint_len): Return the length of a
+ hard register constraint.
+ * genpreds.cc (write_insn_constraint_len): Support hard register
+ constraints for insn_constraint_len().
+ * ira.cc (valid_replacement_for_asm_input_p_1): New helper.
+ (valid_replacement_for_asm_input_p): New helper.
+ (decrease_live_ranges_number): Similar to
+ match_asm_constraints_2() ensure that each operand has a unique
+ pseudo if constrained by a hard register.
+ * lra-constraints.cc (process_alt_operands): Install hard
+ register filter according to constraint.
+ * recog.cc (asm_operand_ok): Accept register type for hard
+ register constrained asm operands.
+ (constrain_operands): Validate hard register constraints.
+ * stmt.cc (decode_hard_reg_constraint): Parse a hard register
+ constraint into the corresponding register number or bail out.
+ (parse_output_constraint): Parse hard register constraint and
+ set *ALLOWS_REG.
+ (parse_input_constraint): Ditto.
+ * stmt.h (decode_hard_reg_constraint): Declaration of new
+ function.
+
+2025-07-21 Richard Biener <rguenther@suse.de>
+
+ * tree-vectorizer.h (vect_analyze_data_refs): Remove min_vf
+ output.
+ * tree-vect-data-refs.cc (vect_analyze_data_refs): Likewise.
+ * tree-vect-loop.cc (vect_analyze_loop_2): Remove early
+ out based on bogus min_vf.
+ * tree-vect-slp.cc (vect_slp_analyze_bb_1): Adjust.
+
+2025-07-20 Pan Li <pan2.li@intel.com>
+
+ * config/riscv/autovec.md: Add (const_int 1) as the op2 of
+ ashiftrt.
+
+2025-07-19 Dimitar Dimitrov <dimitar@dinux.eu>
+
+ PR target/121124
+ * config/pru/pru-pragma.cc (pru_pragma_ctable_entry): Handle the
+ ctable base address as signed 32-bit value, and sign-extend to
+ HOST_WIDE_INT.
+ * config/pru/pru-protos.h (struct pru_ctable_entry): Store the
+ ctable base address as signed.
+ (pru_get_ctable_exact_base_index): Pass base address as signed.
+ (pru_get_ctable_base_index): Ditto.
+ (pru_get_ctable_base_offset): Ditto.
+ * config/pru/pru.cc (pru_get_ctable_exact_base_index): Ditto.
+ (pru_get_ctable_base_index): Ditto.
+ (pru_get_ctable_base_offset): Ditto.
+ (pru_print_operand_address): Ditto.
+
+2025-07-19 Paul-Antoine Arras <parras@baylibre.com>
+
+ PR target/119100
+ * config/riscv/autovec-opt.md (*vfwnmacc_vf_<mode>): New pattern.
+ (*vfwnmsac_vf_<mode>): New pattern.
+ * config/riscv/riscv.cc (get_vector_binary_rtx_cost): Add support for a
+ vec_duplicate in a neg.
+
+2025-07-19 Artemiy Volkov <artemiyv@acm.org>
+
+ * config/riscv/riscv.cc (riscv_macro_fusion_pair_p): Protect
+ from a NULL PREV_SET or CURR_SET.
+
+2025-07-19 Georg-Johann Lay <avr@gjlay.de>
+
+ * config/avr/avr-passes.cc (avr_optimize_casesi): Fuse
+ get_insns() with end_sequence().
+
+2025-07-18 Pan Li <pan2.li@intel.com>
+
+ * config/riscv/autovec.md (avg<mode>3_ceil): Add new pattern
+ of avg3_ceil for RVV DImode
+
+2025-07-18 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/117423
+ * tree-sra.cc (analyze_access_subtree): Fix computation of grp_covered
+ flag.
+
+2025-07-18 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/121126
+ * tree-vect-stmts.cc (vect_analyze_stmt): Analyze the
+ live lane extract for LC PHIs that are vect_internal_def.
+
+2025-07-18 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-loop.cc (vectorizable_live_operation_1):
+ Remove stmt_info and ncopies parameters. Remove !slp_node
+ paths.
+ (vectorizable_live_operation): Remove !slp_node paths.
+
+2025-07-18 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/120924
+ * params.opt (uninit-max-chain-len): Up from 8 to 12.
+
+2025-07-18 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/121048
+ * tree-vect-loop.cc (vect_determine_vectype_for_stmt_1):
+ Remove rejecting vector(1) vector types.
+ (vect_set_stmts_vectype): Likewise.
+ * tree-vect-slp.cc (vect_make_slp_decision): Only
+ count instances with non-vector(1) root towards whether
+ we have any interesting instances to vectorize.
+
+2025-07-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/121131
+ * gimple-fold.cc (fold_nonarray_ctor_reference): Use
+ TREE_INT_CST_LOW (TYPE_SIZE ()) instead of
+ GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE ()) for BLKmode BITINT_TYPEs.
+ Don't compute encoding_size at all for little endian targets.
+
2025-07-17 Andrew Pinski <quic_apinski@quicinc.com>
PR middle-end/121095
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index 9866b70..bb710d5 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20250718
+20250727
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 05dfa08..7314a3b 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1069,7 +1069,7 @@ TREE_SSA_H = tree-ssa.h tree-ssa-operands.h \
PRETTY_PRINT_H = pretty-print.h $(INPUT_H) $(OBSTACK_H) wide-int-print.h
TREE_PRETTY_PRINT_H = tree-pretty-print.h $(PRETTY_PRINT_H)
GIMPLE_PRETTY_PRINT_H = gimple-pretty-print.h $(TREE_PRETTY_PRINT_H)
-DIAGNOSTIC_CORE_H = diagnostic-core.h $(INPUT_H) bversion.h diagnostic.def
+DIAGNOSTIC_CORE_H = diagnostic-core.h $(INPUT_H) bversion.h diagnostics/kinds.def
DIAGNOSTIC_H = diagnostic.h $(DIAGNOSTIC_CORE_H) $(PRETTY_PRINT_H)
C_PRETTY_PRINT_H = c-family/c-pretty-print.h $(PRETTY_PRINT_H) \
$(C_COMMON_H) $(TREE_H)
@@ -1595,7 +1595,6 @@ OBJS = \
jump.o \
langhooks.o \
late-combine.o \
- lazy-diagnostic-path.o \
lcm.o \
lists.o \
loop-doloop.o \
@@ -1852,30 +1851,39 @@ OBJS = \
# Objects in libcommon.a, potentially used by all host binaries and with
# no target dependencies.
-OBJS-libcommon = diagnostic-spec.o diagnostic.o diagnostic-color.o \
- diagnostic-format-html.o \
- diagnostic-format-sarif.o \
- diagnostic-format-text.o \
+OBJS-libcommon = \
diagnostic-global-context.o \
- diagnostic-digraphs.o \
- diagnostic-macro-unwinding.o \
- diagnostic-output-spec.o \
- diagnostic-path.o \
- diagnostic-path-output.o \
- diagnostic-show-locus.o \
- diagnostic-state-graphs.o \
- diagnostic-state-to-dot.o \
- edit-context.o \
+ diagnostics/buffering.o \
+ diagnostics/changes.o \
+ diagnostics/color.o \
+ diagnostics/context.o \
+ diagnostics/digraphs.o \
+ diagnostics/file-cache.o \
+ diagnostics/output-spec.o \
+ diagnostics/html-sink.o \
+ diagnostics/sarif-sink.o \
+ diagnostics/text-sink.o \
+ diagnostics/lazy-paths.o \
+ diagnostics/macro-unwinding.o \
+ diagnostics/option-classifier.o \
+ diagnostics/paths.o \
+ diagnostics/paths-output.o \
+ diagnostics/source-printing.o \
+ diagnostics/state-graphs.o \
+ diagnostics/state-graphs-to-dot.o \
+ diagnostics/selftest-context.o \
+ diagnostics/selftest-logical-locations.o \
+ diagnostics/selftest-paths.o \
+ diagnostics/diagnostics-selftests.o \
+ gcc-diagnostic-spec.o \
graphviz.o pex.o \
pretty-print.o intl.o \
json.o json-parsing.o \
xml.o \
sbitmap.o \
vec.o input.o hash-table.o ggc-none.o memory-block.o \
- selftest.o selftest-diagnostic.o sort.o \
- selftest-diagnostic-path.o \
+ selftest.o sort.o \
selftest-json.o \
- selftest-logical-location.o \
text-art/box-drawing.o \
text-art/canvas.o \
text-art/ruler.o \
@@ -1922,7 +1930,7 @@ endif
# libbackend.a objs that might not be in some cases linked into the compiler,
# yet they are supposed to be part of the plugin ABI. See PR116143.
-EXTRA_BACKEND_OBJS = simple-diagnostic-path.o lazy-diagnostic-path.o
+EXTRA_BACKEND_OBJS = simple-diagnostic-path.o diagnostics/lazy-paths.o
BACKEND = $(EXTRA_BACKEND_OBJS) libbackend.a main.o libcommon-target.a \
libcommon.a $(CPPLIB) $(LIBDECNUMBER)
@@ -3039,7 +3047,7 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/ipa-modref-tree.h \
$(srcdir)/ipa-locality-cloning.cc \
$(srcdir)/signop.h \
- $(srcdir)/diagnostic-spec.h $(srcdir)/diagnostic-spec.cc \
+ $(srcdir)/gcc-diagnostic-spec.h $(srcdir)/gcc-diagnostic-spec.cc \
$(srcdir)/dwarf2out.h \
$(srcdir)/dwarf2asm.cc \
$(srcdir)/dwarf2cfi.cc \
@@ -4072,7 +4080,7 @@ PLUGIN_HEADERS = $(TREE_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
fold-const.h fold-const-call.h tree-cfg.h tree-into-ssa.h tree-ssanames.h \
print-tree.h varasm.h context.h tree-phinodes.h stor-layout.h \
ssa-iterators.h $(RESOURCE_H) tree-cfgcleanup.h attribs.h calls.h \
- cfgexpand.h diagnostic-color.h gcc-symtab.h gimple-builder.h gimple-low.h \
+ cfgexpand.h gcc-symtab.h gimple-builder.h gimple-low.h \
gimple-walk.h gimplify-me.h pass_manager.h print-rtl.h stmt.h \
tree-dfa.h tree-hasher.h tree-nested.h tree-object-size.h tree-outof-ssa.h \
tree-parloops.h tree-ssa-address.h tree-ssa-coalesce.h tree-ssa-dom.h \
@@ -4082,7 +4090,7 @@ PLUGIN_HEADERS = $(TREE_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
hash-set.h dominance.h cfg.h cfgrtl.h cfganal.h cfgbuild.h cfgcleanup.h \
lcm.h cfgloopmanip.h file-prefix-map.h builtins.def $(INSN_ATTR_H) \
pass-instances.def params.list $(srcdir)/../include/gomp-constants.h \
- $(EXPR_H) $(srcdir)/analyzer/*.h
+ $(EXPR_H) $(srcdir)/analyzer/*.h $(srcdir)/diagnostics/*.h
# generate the 'build fragment' b-header-vars
s-header-vars: Makefile
@@ -4120,6 +4128,7 @@ install-plugin: installdirs lang.install-plugin s-header-vars install-gengtype
fi; \
case $$path in \
"$(srcdir)"/analyzer/* \
+ | "$(srcdir)"/diagnostics/* \
| "$(srcdir)"/config/* | "$(srcdir)"/common/config/* \
| "$(srcdir)"/c-family/* | "$(srcdir)"/*.def ) \
base=`echo "$$path" | sed -e "s|$$srcdirstrip/||"`;; \
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index b66c7ba..6f6a782 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,428 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc-interface/misc.cc: Make
+ diagnostics::context::m_source_printing private.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc-interface/trans.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc-interface/misc.cc: Update for diagnostic_context becoming
+ diagnostics::context.
+
+2025-07-25 Marc Poulhiès <poulhies@adacore.com>
+
+ * gcc-interface/utils.cc (update_pointer_to): Renamed ptr/old_ptr, ref/old_ref.
+
+2025-07-25 Alexandre Oliva <oliva@adacore.com>
+
+ * s-oscons-tmplt.c (CLOCK_RT_Ada) [__vxworks]: Define to
+ CLOCK_REALTIME on VxWorks6.
+ * gsocket.h [__vxworks]: Include strings.h if available.
+ * sysdep.c [__vxworks]: Likewise.
+
+2025-07-25 Steve Baird <baird@adacore.com>
+
+ * exp_ch6.adb (Apply_Access_Discrims_Accessibility_Check): Do
+ nothing and simply return if either Ada_Version <= Ada_95 or if
+ the function being returned from lacks the extra formal parameter
+ needed to perform the check (typically because the result is
+ tagged).
+
+2025-07-25 Bob Duff <duff@adacore.com>
+
+ * sem_ch12.adb (Check_Formal_Package_Instance):
+ Do nothing in case of E_Subprogram_Body.
+
+2025-07-25 Ronan Desplanques <desplanques@adacore.com>
+
+ * sem_ch3.adb (Process_Discriminants): Update comments
+
+2025-07-25 Ronan Desplanques <desplanques@adacore.com>
+
+ * sem_ch3.adb (Build_Derived_Record_Type): Set flag appropriately.
+
+2025-07-25 Eric Botcazou <ebotcazou@adacore.com>
+
+ * libgnat/a-calend.adb (To_Struct_Timespec_64): Deal with negative
+ Duration values and truncate the nanoseconds too.
+ * libgnat/g-calend.adb (timeval_to_duration): Unsuppress overflow
+ checks.
+ (duration_to_timeval): Likewise. Deal with negative Duration values
+ as well as integral Duration values.
+ * libgnat/g-socket.adb (To_Timeval): Simplify the implementation.
+
+2025-07-24 Steve Baird <baird@adacore.com>
+
+ * exp_aggr.adb (Convert_To_Assignments): Add calls to Ensure_Defined
+ before generating assignments to components that could be
+ associated with a not-yet-defined itype.
+
+2025-07-24 Steve Baird <baird@adacore.com>
+
+ * accessibility.adb (Function_Call_Or_Allocator_Level): Handle the
+ case where a function that has an Extra_Accessibility_Of_Result
+ parameter returns as its result a call to another such function.
+ In that case, the extra parameter should be passed along.
+ (Check_Return_Construct_Accessibility): Replace a warning about an
+ inevitable failure of a dynamic check with a legality-rule-violation
+ error message; adjust the text of the message accordingly.
+ * exp_ch6.ads (Apply_Access_Discrims_Accessibility_Check): New
+ procedure, following example of the existing
+ Apply_CW_Accessibility procedure.
+ * exp_ch6.adb (Apply_Access_Discrims_Accessibility_Check): body
+ for new procedure.
+ (Expand_Simple_Function_Return): Add call to new
+ Apply_Access_Discrims_Accessibility_Check procedure.
+ * exp_ch3.adb (Make_Allocator_For_Return): Add call to new
+ Apply_Access_Discrims_Accessibility_Check procedure.
+
+2025-07-24 Tonu Naks <naks@adacore.com>
+
+ * doc/gnat_rm/standard_and_implementation_defined_restrictions.rst:
+ clarify parameter description.
+ * gnat_rm.texi: Regenerate.
+
+2025-07-22 Gary Dismukes <dismukes@adacore.com>
+
+ * sem_ch8.adb (End_Use_Type): Add a test for there not being an earlier
+ use_type_clause for the same type as an additional criterion for turning
+ off In_Use and Current_Use_Clause.
+
+2025-07-22 Piotr Trojanek <trojanek@adacore.com>
+
+ * sem_attr.adb (Eval_Attribute): Only fold array attributes when prefix
+ is static or at least safe to evaluate
+
+2025-07-22 Ronan Desplanques <desplanques@adacore.com>
+
+ * einfo.ads (Is_Controlled_Active): Fix pasto in comment.
+ * sem_util.ads (Propagate_Controlled_Flags): Update comment for
+ Destructor aspect.
+
+2025-07-22 Ronan Desplanques <desplanques@adacore.com>
+
+ * doc/gnat_rm/gnat_language_extensions.rst: Document new extension.
+ * snames.ads-tmpl: Add name for new aspect.
+ * gen_il-fields.ads (Has_Destructor, Is_Destructor): Add new fields.
+ * gen_il-gen-gen_entities.adb (E_Procedure, Type_Kind): Add new fields.
+ * einfo.ads (Has_Destructor, Is_Destructor): Document new fields.
+ * aspects.ads: Add new aspect.
+ * sem_ch13.adb (Analyze_Aspect_Specifications,
+ Check_Aspect_At_Freeze_Point, Check_Aspect_At_End_Of_Declarations):
+ Add semantic analysis for new aspect.
+ (Resolve_Finalization_Procedure): New function.
+ (Resolve_Finalizable_Argument): Use new function above.
+ * sem_util.adb (Propagate_Controlled_Flags): Extend for new field.
+ * freeze.adb (Freeze_Entity): Add legality check for new aspect.
+ * exp_ch3.adb (Expand_Freeze_Record_Type, Predefined_Primitive_Bodies):
+ Use new field.
+ * exp_ch7.adb (Build_Finalize_Statements): Add expansion for
+ destructors.
+ (Make_Final_Call, Build_Record_Deep_Procs): Adapt to new Has_Destructor
+ field.
+ (Build_Adjust_Statements): Tweak to handle cases of empty lists.
+ * gnat_rm.texi: Regenerate.
+
+2025-07-22 Denis Mazzucato <mazzucato@adacore.com>
+
+ * sem_ch6.adb (Might_Need_BIP_Task_Actuals): Before retrieving the original corresponding
+ operation we retrieve first the root of the aliased chain.
+
+2025-07-22 Ronan Desplanques <desplanques@adacore.com>
+
+ * gen_il-fields.ads (Is_Implicit_Full_View): New field.
+ * gen_il-gen-gen_entities.adb (Type_Kind): Use new field.
+ * einfo.ads (Is_Implicit_Full_View): Document new field.
+ * exp_ch7.adb (Make_Adjust_Call, Make_Init_Call, Make_Final_Call): Use
+ new field.
+ * exp_util.adb (Finalize_Address): Likewise.
+ * sem_ch3.adb (Copy_And_Build): Set new field.
+
+2025-07-22 Eric Botcazou <ebotcazou@adacore.com>
+
+ * exp_util.ads (May_Generate_Large_Temp): Delete.
+ * exp_util.adb (May_Generate_Large_Temp): Likewise.
+ (Safe_Unchecked_Type_Conversion): Do not take stack checking into
+ account to compute the result.
+
+2025-07-22 Javier Miranda <miranda@adacore.com>
+
+ * sinfo.ads (Is_Expanded_Dispatching_Call): New flag.
+ (Tag_Propagated): New flag.
+ * exp_ch6.adb (Expand_Call_Helper): Propagate the tag when
+ the dispatching call is placed in conditionl expressions or
+ case-expressions.
+ * sem_ch5.adb (Analyze_Assignment): For assignment of tag-
+ indeterminate expression, do not propagate the tag if
+ previously done.
+ * sem_disp.adb (Is_Tag_Indeterminate): Add missing support
+ for conditional expression and case expression.
+ * exp_disp.ads (Is_Expanded_Dispatching_Call): Removed. Function
+ replaced by a new flag in the nodes.
+ * exp_disp.adb (Expand_Dispatching_Call): Set a flag in the
+ call node to remember that the call has been expanded.
+ (Is_Expanded_Dispatching_Call): Function removed.
+ * gen_il-fields.ads (Tag_Propagated): New flag.
+ (Is_Expanded_Dispatching_Call): New flag.
+ * gen_il-gen-gen_nodes.adb (Tag_Propagated): New flag.
+ (Is_Expanded_Dispatching_Call): New flag.
+
+2025-07-22 Gary Dismukes <dismukes@adacore.com>
+
+ * libgnat/a-cbhama.ads (Empty): Add missing default to Capacity formal.
+ * libgnat/a-cbhama.adb (Empty): Add missing default to Capacity formal.
+ * exp_aggr.adb (Build_Size_Expr): Test for presence of Capacity
+ discriminant as additional criterion for generating the call to
+ the Length function. Update comments.
+
+2025-07-22 Eric Botcazou <ebotcazou@adacore.com>
+
+ * exp_util.adb (Safe_Unchecked_Type_Conversion): Always return True
+ if the expression is the prefix of an N_Selected_Component.
+
+2025-07-22 Denis Mazzucato <mazzucato@adacore.com>
+
+ * sem_ch6.adb (Might_Need_BIP_Task_Actuals): Check whether No_Task_Parts is enabled in any
+ of the derived types, or interfaces, from the user-defined primitive return type.
+ * sem_ch13.adb (Analyze_Aspect_Specifications): Add No_Task_Parts and No_Controlled_Parts to
+ the representation chain to be visible in the full view of private types.
+ * aspects.ads (Nonoverridable_Aspect_Id): As per GNAT RM, No_Task_Parts is nonoverridable.
+ * sem_util.adb (Check_Inherited_Nonoverridable_Aspects): Likewise.
+ * sem_util.ads: Fix typo and style.
+ * sem_disp.adb: Missing comment.
+
+2025-07-22 Javier Miranda <miranda@adacore.com>
+
+ * einfo.ads (Extra_Formals): Complete documentation.
+ (Has_First_Controlling_Parameter_Aspect): Place it in alphabetical order.
+ (Has_Frozen_Extra_Formals): New attribute.
+ * gen_il-fields.ads (Has_Frozen_Extra_Formals): New entity field.
+ * gen_il-gen-gen_entities.adb (Has_Frozen_Extra_Formals): Adding new
+ entity flag to subprograms, subprogram types, and and entries.
+ * gen_il-internals.adb (Image): Adding Has_Frozen_Extra_Formals.
+ * exp_ch3.adb (Build_Array_Init_Proc): Freeze its extra formals.
+ (Build_Init_Procedure): Freeze its extra formals.
+ (Expand_Freeze_Record_Type): For tagged types with foreign convention
+ create the extra formals of primitives with convention Ada.
+ * exp_ch6.ads (Create_Extra_Actuals): New subprogram.
+ * exp_ch6.adb (Check_BIP_Actuals): Adding assertions.
+ (Create_Extra_Actuals): New subprogram that factorizes code from
+ Expand_Call_Helper.
+ (Expand_Call_Helper): Adding support to defer the addition of extra
+ actuals. Move the code that adds the extra actuals to a new subprogram.
+ (Is_Unchecked_Union_Equality): Renamed as Is_Unchecked_Union_Predefined_
+ Equality_Call.
+ * exp_ch7.adb (Create_Finalizer): Freeze its extra formals.
+ (Wrap_Transient_Expression): Link the temporary with its relocated
+ expression to facilitate locating the expression in the expanded code.
+ * exp_ch9.ads (Expand_N_Entry_Declaration): Adding one formal.
+ * exp_ch9.adb (Expand_N_Entry_Declaration): Defer the expansion of
+ the entry if the extra formals are not available; analyze the built
+ declarations for the record type that holds all the parameters if
+ the expansion of the entry declaration was deferred.
+ * exp_disp.adb (Expand_Dispatching_Call): Handle deferred extra formals.
+ (Set_CPP_Constructors): Freeze its extra formals.
+ * freeze.adb (Freeze_Entity): Create the extra actuals of acccess to
+ subprograms whose designated type is a subprogram type.
+ (Freeze_Subprogram): Adjust assertion to support deferred extra formals,
+ and freeze extra formals of non-dispatching subprograms with foreign
+ convention. Added assertion to check matching of formals in thunks.
+ * sem_aux.adb (Get_Called_Entity): Adding documentation.
+ * sem_ch3.adb (Analyze_Full_Type_Declaration): Create the extra formals
+ of deferred subprograms, subprogram types and entries; create also the
+ extra actuals of deferred calls.
+ * sem_ch6.ads (Freeze_Extra_Formals): New subprogram.
+ (Deferred_Extra_Formals_Support): New package.
+ * sem_ch6.adb (Analyze_Subprogram_Body_Helper): Create the extra formals
+ of subprograms without separate spec.
+ (Add_Extra_Formal): Add documentation.
+ (Has_Extra_Formals): Removed.
+ (Parent_Subprogram): Adding documentation.
+ (Create_Extra_Formals): Defer adding extra formals if the underlying_type
+ of some formal type or return type is not available.
+ (Extra_Formals_Match_OK): Add missing check on the extra formals of
+ unchecked unions.
+ (Freeze_Extra_Formals): New subprogram.
+ (Deferred_Extra_Formals_Support): New package.
+ * sem_ch9.adb (Analyze_Entry_Declaration): Freeze its extra formals.
+ * sem_ch13.adb (New_Put_Image_Subprogram): ditto.
+ * sem_util.ads (Is_Unchecked_Union_Equality): New subprogram.
+ * sem_util.adb (Is_Unchecked_Union_Equality): ditto.
+
+2025-07-22 Piotr Trojanek <trojanek@adacore.com>
+
+ * sem_util.adb (Get_Actual_Subtype): Do the same for GCC and GNATprove
+ backends.
+
+2025-07-22 Martin Clochard <clochard@adacore.com>
+
+ * exp_spark.adb (Expand_SPARK): Add expansion of continue statements.
+ (Expand_SPARK_N_Continue_Statement): Expand continue statements resolved
+ as procedure calls into said procedure calls.
+
+2025-07-22 Piotr Trojanek <trojanek@adacore.com>
+
+ * sem_res.adb (Resolve_Call): Look at the base type of actual parameter
+ when checking call to Set_Handler.
+
+2025-07-22 Eric Botcazou <ebotcazou@adacore.com>
+
+ * sem_util.adb (Get_Actual_Subtype): Only create a new subtype when
+ the expander is active. Remove a useless test of type inequality,
+ as well as a useless call to Set_Has_Delayed_Freeze on the subtype.
+
+2025-07-22 Gary Dismukes <dismukes@adacore.com>
+
+ * exp_aggr.adb (Build_Size_Expr): Change test of "not Present (...)"
+ to "No (...)".
+
+2025-07-22 Gary Dismukes <dismukes@adacore.com>
+
+ * exp_aggr.adb (Build_Size_Expr): Determine the length of a container
+ aggregate association in the case where it's an iteration over an
+ object of a container type coming from an instantiation of a predefined
+ container generic. Minor updates to existing comments.
+
+2025-07-22 Ghjuvan Lacambre <lacambre@adacore.com>
+
+ * exp_util.adb (Finalize_Address): Prevent infinite loop
+
+2025-07-22 Steve Baird <baird@adacore.com>
+
+ * sem_aux.ads: Declare new function Unique_Component_Name.
+ * sem_aux.adb: Implement new function Unique_Component_Name.
+
+2025-07-22 Viljar Indus <indus@adacore.com>
+
+ * sem_ch13.adb (Check_Aspect_At_End_Of_Declarations):
+ Ensure the Expression_Copy always has a parent before
+ calling any analyze.
+
+2025-07-22 Steve Baird <baird@adacore.com>
+
+ * exp_aggr.adb (Build_Record_Aggr_Code.Gen_Assign): In the case of
+ an aggregate component where the component type is mutably tagged
+ and the component value is provided by a qualified aggregate (and
+ qualified with a specific type), avoid incorrectly rejecting the
+ inner aggregate for violating the rule that the type of an
+ aggregate shall not be class-wide.
+ * exp_attr.adb: For a predefined streaming operation (i.e., Read,
+ Write, Input, or Output) of a class-wide type, the external name
+ of the tag of the value is normally written out by Output and read
+ in by Input. In the case of a mutably tagged type, this is instead
+ done in Write and Read.
+ * exp_ch4.adb (Expand_Composite_Equality): In the case of an
+ equality comparison for a type having a mutably tagged component,
+ we want the component comparison to compare two values of the
+ mutably tagged type, not two values of the corresponding
+ array-of-bytes-ish representation type. Even if there are no
+ user-defined equality functions anywhere in sight, comparing the
+ array values still doesn't work because undefined bits may end up
+ participating in the comparison (resulting in an incorrect result
+ of False).
+ * exp_put_image.adb: In the case of a class-wide type, the
+ predefined Image attribute includes the name of the specific type
+ (and a "'" character, to follow qualified expression syntax) to
+ indicate the tag of the value. With the introduction of mutably
+ tagged types, this case can now arise in the case of a component
+ (of either an enclosing array or an enclosing record), not just
+ for a top-level object. So we factor the code to do this into a
+ new procedure, Put_Specific_Type_Name_Qualifier, so that it can be
+ called from more than one place. This reorganization also involves
+ replacing the procedure Put_String_Exp with a new procedure,
+ Put_String_Exp_To_Buffer, declared in a less nested scope. For
+ mutably tagged components (at the source level) the component type
+ (at the GNAT tree level) is an array of bytes (actually a two
+ field record containing an array of bytes, but that's a detail).
+ Appropriate conversions need to be generated so that we don't end
+ up generating an image for an array of bytes; this is done at the
+ same places where Put_Specific_Type_Name_Qualifier is called
+ (for components) by calling Make_Mutably_Tagged_Conversion.
+ * exp_strm.adb (Make_Field_Attribute): Add
+ Make_Mutably_Tagged_Conversion call where we construct a
+ Selected_Component node and the corresponding component type is
+ the internal representation type for a mutably tagged type.
+ (Stream_Base_Type): Return the mutably
+ tagged type if given the corresponding internal representation type.
+ * sem_ch3.adb (Array_Type_Declaration): In the case where the
+ source-level component type of an array type is mutably tagged,
+ set the Component_Type field of the base type of the declared
+ array type (as opposed to that of the first subtype of the array
+ type) to the corresponding internal representation type.
+ * sem_ch4.adb (Analyze_Selected_Component): In the case of a
+ selected component name which references a component whose type is
+ the internal representation type of a mutably tagged type,
+ generate a conversion to the mutably tagged type.
+
+2025-07-21 Eric Botcazou <ebotcazou@gcc.gnu.org>
+
+ PR ada/121184
+ * styleg.adb (Check_Comment): Use consistent warning message.
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * gcc-interface/trans.cc (gnat_to_gnu): Pass null pointer to
+ parse_{input,output}_constraint().
+
+2025-07-18 Steve Baird <baird@adacore.com>
+
+ * sem_ch12.adb (Validate_Derived_Type_Instance): Cope with the case
+ where the ancestor type for a formal derived type is declared in
+ an earlier formal package but Get_Instance_Of does not return the
+ corresponding type from the corresponding actual package.
+
+2025-07-18 Bob Duff <duff@adacore.com>
+
+ * tbuild.adb (Unchecked_Convert_To): Back out
+ change.
+
+2025-07-18 Marc Poulhiès <poulhies@adacore.com>
+ Eric Botcazou <botcazou@adacore.com>
+
+ * exp_ch6.adb (Convert): Do not call Expand_Inlined_Call for
+ unsupported cases.
+ * inline.adb (Expand_Inlined_Call): Add assert to catch unsupported
+ case.
+
+2025-07-18 Gary Dismukes <dismukes@adacore.com>
+
+ * einfo.ads: Document new field Overridden_Inherited_Operation and
+ list it as a field for the entity kinds that it applies to.
+ * gen_il-fields.ads (type Opt_Field_Enum): Add new literal
+ Overridden_Inherited_Operation to the type.
+ * gen_il-gen-gen_entities.adb: Add Overridden_Inherited_Operation as
+ a field of entities of kinds E_Enumeration_Literal and Subprogram_Kind.
+ * sem_ch4.adb (Is_Callable_Private_Overriding): Change name (was
+ Is_Private_Overriding). Replace Is_Hidden test on Overridden_Operation
+ with test of Is_Hidden on the new field Overridden_Inherited_Operation.
+ * sem_ch6.adb (New_Overloaded_Entity): Set the new field
+ Overridden_Inherited_Operation on an operation derived from
+ an interface to refer to the inherited operation of a private
+ extension that's overridden by the derived operation. Also set
+ that field in the more common cases of an explicit subprogram
+ that overrides, to refer to the inherited subprogram that is
+ overridden. (Contrary to its name, the Overridden_Operation
+ field of the overriding subprogram, which is also set in these
+ places, refers to the *parent* subprogram from which the inherited
+ subprogram is derived.) Also, remove a redundant Present (Alias (S))
+ test in an if_statement and the dead "else" part of that statement.
+
+2025-07-18 Piotr Trojanek <trojanek@adacore.com>
+
+ * sem_util.adb (Build_Elaboration_Entity): Set ghost mode to none
+ before creating the elaboration entity; restore the ghost mode
+ afterwards.
+
+2025-07-18 Javier Miranda <miranda@adacore.com>
+
+ * exp_aggr.adb (Gen_Assign): Code cleanup.
+ (Initialize_Component): Do not adjust the tag when the type of
+ the aggregate components is a mutably tagged type.
+
2025-07-14 Eric Botcazou <ebotcazou@adacore.com>
PR ada/121056
diff --git a/gcc/ada/accessibility.adb b/gcc/ada/accessibility.adb
index 0b8d3f7..c780054 100644
--- a/gcc/ada/accessibility.adb
+++ b/gcc/ada/accessibility.adb
@@ -327,8 +327,23 @@ package body Accessibility is
if In_Return_Value (N)
or else In_Return_Context
then
- return Make_Level_Literal
- (Subprogram_Access_Level (Current_Subprogram));
+ if Present (Extra_Accessibility_Of_Result
+ (Current_Subprogram))
+ then
+ -- If a function is passed an extra "level of the
+ -- master of the call" parameter and that function
+ -- returns a call to another such function (or
+ -- possibly to the same function, in the case of a
+ -- recursive call), then that parameter should be
+ -- "passed along".
+
+ return New_Occurrence_Of
+ (Extra_Accessibility_Of_Result
+ (Current_Subprogram), Loc);
+ else
+ return Make_Level_Literal
+ (Subprogram_Access_Level (Current_Subprogram));
+ end if;
end if;
end if;
@@ -1683,16 +1698,14 @@ package body Accessibility is
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.
+ -- ??? Is this how we want to detect RM 6.5(5.9) violations?
if Nkind (Check_Cond) = N_Identifier
and then Entity (Check_Cond) = Standard_True
then
Error_Msg_N
- ("access discriminant in return object could be a dangling"
- & " reference??", Return_Stmt);
+ ("level of type of access discriminant value of return object"
+ & " is statically too deep", Return_Stmt);
end if;
end if;
diff --git a/gcc/ada/aspects.ads b/gcc/ada/aspects.ads
index d8861bf..737f151 100644
--- a/gcc/ada/aspects.ads
+++ b/gcc/ada/aspects.ads
@@ -92,6 +92,7 @@ package Aspects is
Aspect_Default_Value,
Aspect_Depends, -- GNAT
Aspect_Designated_Storage_Model, -- GNAT
+ Aspect_Destructor, -- GNAT
Aspect_Dimension, -- GNAT
Aspect_Dimension_System, -- GNAT
Aspect_Dispatching_Domain,
@@ -259,6 +260,7 @@ package Aspects is
| Aspect_Iterator_Element
| Aspect_Max_Entry_Queue_Length
| Aspect_No_Controlled_Parts
+ | Aspect_No_Task_Parts
| Aspect_Real_Literal
| Aspect_String_Literal
| Aspect_Variable_Indexing;
@@ -293,6 +295,7 @@ package Aspects is
Aspect_CUDA_Global => True,
Aspect_Depends => True,
Aspect_Designated_Storage_Model => True,
+ Aspect_Destructor => True,
Aspect_Dimension => True,
Aspect_Dimension_System => True,
Aspect_Disable_Controlled => True,
@@ -447,6 +450,7 @@ package Aspects is
Aspect_Default_Value => Expression,
Aspect_Depends => Expression,
Aspect_Designated_Storage_Model => Name,
+ Aspect_Destructor => Name,
Aspect_Dimension => Expression,
Aspect_Dimension_System => Expression,
Aspect_Dispatching_Domain => Expression,
@@ -551,6 +555,7 @@ package Aspects is
Aspect_Default_Value => True,
Aspect_Depends => False,
Aspect_Designated_Storage_Model => True,
+ Aspect_Destructor => False,
Aspect_Dimension => False,
Aspect_Dimension_System => False,
Aspect_Dispatching_Domain => False,
@@ -726,6 +731,7 @@ package Aspects is
Aspect_Default_Value => Name_Default_Value,
Aspect_Depends => Name_Depends,
Aspect_Designated_Storage_Model => Name_Designated_Storage_Model,
+ Aspect_Destructor => Name_Destructor,
Aspect_Dimension => Name_Dimension,
Aspect_Dimension_System => Name_Dimension_System,
Aspect_Disable_Controlled => Name_Disable_Controlled,
@@ -994,6 +1000,7 @@ package Aspects is
Aspect_Default_Value => Always_Delay,
Aspect_Default_Component_Value => Always_Delay,
Aspect_Designated_Storage_Model => Always_Delay,
+ Aspect_Destructor => Always_Delay,
Aspect_Discard_Names => Always_Delay,
Aspect_Dispatching_Domain => Always_Delay,
Aspect_Dynamic_Predicate => Always_Delay,
diff --git a/gcc/ada/doc/gnat_rm/gnat_language_extensions.rst b/gcc/ada/doc/gnat_rm/gnat_language_extensions.rst
index f313179..ff111dd 100644
--- a/gcc/ada/doc/gnat_rm/gnat_language_extensions.rst
+++ b/gcc/ada/doc/gnat_rm/gnat_language_extensions.rst
@@ -1793,3 +1793,71 @@ statement in the sequence of statements of the specified loop_statement.
Note that ``continue`` is a keyword but it is not a reserved word. This is a
configuration that does not exist in standard Ada.
+
+Destructors
+-----------
+
+The ``Destructor`` aspect can be applied to any record type, tagged or not.
+It must denote a primitive of the type that is a procedure with one parameter
+of the type and of mode ``in out``:
+
+.. code-block:: ada
+
+ type T is record
+ ...
+ end record with Destructor => Foo;
+
+ procedure Foo (X : in out T);
+
+This is equivalent to the following code that uses ``Finalizable``:
+
+.. code-block:: ada
+
+ type T is record
+ ...
+ end record with Finalizable => (Finalize => Foo);
+
+ procedure Foo (X : in out T);
+
+Unlike ``Finalizable``, however, ``Destructor`` can be specified on a derived
+type. And when it is, the effect of the aspect combines with the destructors of
+the parent type. Take, for example:
+
+.. code-block:: ada
+
+ type T1 is record
+ ...
+ end record with Destructor => Foo;
+
+ procedure Foo (X : in out T1);
+
+ type T2 is new T1 with Destructor => Bar;
+
+ procedure Bar (X : in out T2);
+
+Here, when an object of type ``T2`` is finalized, a call to ``Bar``
+will be performed and it will be followed by a call to ``Foo``.
+
+The ``Destructor`` aspect comes with a legality rule: if a primitive procedure
+of a type is denoted by a ``Destructor`` aspect specification, it is illegal to
+override this procedure in a derived type. For example, the following is illegal:
+
+.. code-block:: ada
+
+ type T1 is record
+ ...
+ end record with Destructor => Foo;
+
+ procedure Foo (X : in out T1);
+
+ type T2 is new T1;
+
+ overriding
+ procedure Foo (X : in out T2); -- Error here
+
+It is possible to specify ``Destructor`` on the completion of a private type,
+but there is one more restriction in that case: the denoted primitive must
+be private to the enclosing package. This is necessary due to the previously
+mentioned legality rule, to prevent breaking the privacy of the type when
+imposing that rule on outside types that derive from the private view of the
+type.
diff --git a/gcc/ada/doc/gnat_rm/standard_and_implementation_defined_restrictions.rst b/gcc/ada/doc/gnat_rm/standard_and_implementation_defined_restrictions.rst
index 0e9162a..1f0aa03 100644
--- a/gcc/ada/doc/gnat_rm/standard_and_implementation_defined_restrictions.rst
+++ b/gcc/ada/doc/gnat_rm/standard_and_implementation_defined_restrictions.rst
@@ -333,9 +333,9 @@ must define with the following profile:
"__gnat_last_chance_handler");
-The parameter is a C null-terminated string representing a message to be
-associated with the exception (typically the source location of the raise
-statement generated by the compiler). The Line parameter when nonzero
+The ``Source_Location`` parameter is a C null-terminated string representing a
+message to be associated with the exception (typically the source location of
+the raise statement generated by the compiler). The Line parameter when nonzero
represents the line number in the source program where the raise occurs.
No_Exception_Propagation
diff --git a/gcc/ada/einfo.ads b/gcc/ada/einfo.ads
index ba79fe4..916d9c6 100644
--- a/gcc/ada/einfo.ads
+++ b/gcc/ada/einfo.ads
@@ -1279,9 +1279,10 @@ package Einfo is
-- that represents an activation record pointer is an extra formal.
-- Extra_Formals
--- Applies to subprograms, subprogram types, entries, and entry
--- families. Returns first extra formal of the subprogram or entry.
--- Returns Empty if there are no extra formals.
+-- Applies to subprograms, subprogram types, entries, and entry families.
+-- Returns the first extra formal of the subprogram or entry. An entity
+-- has no extra formals when this attribute is Empty, and its attribute
+-- Extra_Formals_Known is True.
-- Finalization_Collection [root type only]
-- Defined in access-to-controlled or access-to-class-wide types. The
@@ -1594,6 +1595,11 @@ package Einfo is
-- set, signalling that Freeze.Inherit_Delayed_Rep_Aspects must be called
-- at the freeze point of the derived type.
+-- Has_Destructor
+-- Defined in all type and subtype entities. Set only for record type
+-- entities for which at least one ancestor has the Destructor aspect
+-- specified.
+
-- Has_DIC (synthesized)
-- Defined in all type entities. Set for a private type and its full view
-- when the type is subject to pragma Default_Initial_Condition (DIC), or
@@ -1640,11 +1646,6 @@ package Einfo is
-- that this does not imply a representation with holes, since the rep
-- clause may merely confirm the default 0..N representation.
--- Has_First_Controlling_Parameter_Aspect
--- Defined in tagged types, concurrent types and concurrent record types.
--- Set to indicate that the type has a First_Controlling_Parameter of
--- True (whether by an aspect_specification, a pragma, or inheritance).
-
-- Has_Exit
-- Defined in loop entities. Set if the loop contains an exit statement.
@@ -1654,6 +1655,12 @@ package Einfo is
-- flag prevents double expansion of a contract when a construct is
-- rewritten into something else and subsequently reanalyzed/expanded.
+-- Has_First_Controlling_Parameter_Aspect
+-- Defined in tagged types, concurrent types, and concurrent record
+-- types. Set to indicate that the type has a First_Controlling_Parameter
+-- of True (whether by an aspect_specification, a pragma, or
+-- inheritance).
+
-- Has_Foreign_Convention (synthesized)
-- Applies to all entities. Determines if the Convention for the entity
-- is a foreign convention, i.e. non-native: other than Convention_Ada,
@@ -1668,6 +1675,12 @@ package Einfo is
-- the instance will conflict with the linear elaboration of front-end
-- inlining.
+-- Extra_Formals_Known
+-- Defined in subprograms, subprogram types, entries, and entry families.
+-- Set when the extra formals have been determined. An entity has no
+-- extra formals when this attribute is True, and its attribute
+-- Extra_Formals is Empty.
+
-- Has_Fully_Qualified_Name
-- Defined in all entities. Set if the name in the Chars field has been
-- replaced by the fully qualified name, as used for debug output. See
@@ -2515,11 +2528,12 @@ package Einfo is
-- Is_Controlled_Active [base type only]
-- Defined in all type entities. Indicates that the type is controlled,
--- i.e. has been declared with the Finalizable aspect or has inherited
--- the Finalizable aspect from an ancestor. Can only be set for record
--- types, tagged or untagged. System.Finalization_Root.Root_Controlled
--- is an example of the former case while Ada.Finalization.Controlled
--- and Ada.Finalization.Limited_Controlled are examples of the latter.
+-- i.e. has been declared with the Finalizable or the Destructor aspect
+-- or has inherited the aspect from an ancestor. Can only be set for
+-- record types, tagged or untagged.
+-- System.Finalization_Root.Root_Controlled is an example of the former
+-- case while Ada.Finalization.Controlled and
+-- Ada.Finalization.Limited_Controlled are examples of the latter.
-- Is_Controlled (synth) [base type only]
-- Defined in all type entities. Set if Is_Controlled_Active is set for
@@ -2545,6 +2559,10 @@ package Einfo is
-- Defined in all entities. True if the entity is type System.Address,
-- or (recursively) a subtype or derived type of System.Address.
+-- Is_Destructor
+-- Defined in procedure entities. True if the procedure is denoted by the
+-- Destructor aspect on some type.
+
-- Is_DIC_Procedure
-- Defined in functions and procedures. Set for a generated procedure
-- which verifies the assumption of pragma Default_Initial_Condition at
@@ -2779,6 +2797,10 @@ package Einfo is
-- identifiers in standard library packages, and to implement the
-- restriction No_Implementation_Identifiers.
+-- Is_Implicit_Full_View
+-- Defined in types. Set on types that the compiler generates to act as
+-- full views of types that are derivations of private types.
+
-- Is_Imported
-- Defined in all entities. Set if the entity is imported. For now we
-- only allow the import of exceptions, functions, procedures, packages,
@@ -3940,9 +3962,21 @@ package Einfo is
-- Defined in constants and variables. Set if there is an address clause
-- that causes the entity to overlay a constant object.
+-- Overridden_Inherited_Operation
+-- Defined in subprograms and enumeration literals. When set on a
+-- subprogram S, indicates an inherited subprogram that S overrides.
+-- In the case of a privately declared explicit subprogram E that
+-- overrides a private inherited subprogram, and the inherited
+-- subprogram itself overrides another inherited subprogram declared
+-- for a private extension, the field on E will reference the subprogram
+-- inherited by the private extension. This field is used for properly
+-- handling visibility for such privately declared subprograms. This
+-- field is always Empty for enumeration literal entities.
+
-- Overridden_Operation
-- Defined in subprograms. For overriding operations, points to the
--- user-defined parent subprogram that is being overridden.
+-- user-defined parent subprogram from which the inherited subprogram
+-- that is being overridden is derived.
-- Package_Instantiation
-- Defined in packages and generic packages. When defined, this field
@@ -5381,11 +5415,12 @@ package Einfo is
-- Scope_Depth_Value
-- Protection_Object (protected kind)
-- Contract_Wrapper
- -- Extra_Formals
-- Contract
-- SPARK_Pragma (protected kind)
-- Default_Expressions_Processed
-- Entry_Accepted
+ -- Extra_Formals
+ -- Extra_Formals_Known
-- Has_Yield_Aspect
-- Has_Expanded_Contract
-- Ignore_SPARK_Mode_Pragmas
@@ -5413,6 +5448,7 @@ package Einfo is
-- Enumeration_Pos
-- Enumeration_Rep
-- Alias
+ -- Overridden_Inherited_Operation
-- Enumeration_Rep_Expr
-- Interface_Name $$$
-- Renamed_Object $$$
@@ -5502,9 +5538,11 @@ package Einfo is
-- Subps_Index (non-generic case only)
-- Interface_Alias
-- LSP_Subprogram (non-generic case only)
+ -- Overridden_Inherited_Operation
-- Overridden_Operation
-- Wrapped_Entity (non-generic case only)
-- Extra_Formals
+ -- Extra_Formals_Known (non-generic case only)
-- Anonymous_Collections (non-generic case only)
-- Corresponding_Equality (implicit /= only)
-- Thunk_Entity (thunk case only)
@@ -5705,9 +5743,12 @@ package Einfo is
-- Extra_Accessibility_Of_Result
-- Last_Entity
-- Subps_Index
+ -- Overridden_Inherited_Operation
-- Overridden_Operation
-- Linker_Section_Pragma
-- Contract
+ -- Extra_Formals
+ -- Extra_Formals_Known
-- Import_Pragma
-- LSP_Subprogram
-- SPARK_Pragma
@@ -5858,9 +5899,11 @@ package Einfo is
-- Subps_Index (non-generic case only)
-- Interface_Alias
-- LSP_Subprogram (non-generic case only)
+ -- Overridden_Inherited_Operation
-- Overridden_Operation (never for init proc)
-- Wrapped_Entity (non-generic case only)
-- Extra_Formals
+ -- Extra_Formals_Known (non-generic case only)
-- Anonymous_Collections (non-generic case only)
-- Static_Initialization (init_proc only)
-- Thunk_Entity (thunk case only)
@@ -5899,6 +5942,7 @@ package Einfo is
-- Is_Class_Wide_Wrapper
-- Is_Constructor
-- Is_CUDA_Kernel
+ -- Is_Destructor (non-generic case only)
-- Is_DIC_Procedure (non-generic case only)
-- Is_Elaboration_Checks_OK_Id
-- Is_Elaboration_Warnings_OK_Id
@@ -6088,6 +6132,7 @@ package Einfo is
-- Last_Entity
-- Scope_Depth_Value
-- Extra_Formals
+ -- Extra_Formals_Known
-- Anonymous_Collections
-- Contract
-- SPARK_Pragma
@@ -6101,6 +6146,7 @@ package Einfo is
-- Extra_Accessibility_Of_Result
-- Directly_Designated_Type
-- Extra_Formals
+ -- Extra_Formals_Known
-- Access_Subprogram_Wrapper
-- First_Formal (synth)
-- First_Formal_With_Extras (synth)
diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb
index 9ff69ec..cd98369 100644
--- a/gcc/ada/exp_aggr.adb
+++ b/gcc/ada/exp_aggr.adb
@@ -1422,8 +1422,11 @@ package body Exp_Aggr is
elsif Is_Mutably_Tagged_Type (Comp_Typ)
and then Nkind (Expr) = N_Qualified_Expression
then
- Analyze_And_Resolve (Expr_Q, Etype (Expr));
+ -- Avoid class-wide expected type for aggregate
+ -- (which would be rejected as illegal)
+ -- if the aggregate is explicitly qualified.
+ Analyze_And_Resolve (Expr_Q, Etype (Expr));
else
Analyze_And_Resolve (Expr_Q, Comp_Typ);
end if;
@@ -1457,54 +1460,12 @@ package body Exp_Aggr is
end if;
if Present (Expr) then
-
- -- For mutably tagged abstract class-wide types, we rely on the
- -- type of the initializing expression to initialize the tag of
- -- each array component.
-
- -- Generate:
- -- expr_type!(Indexed_Comp) := expr;
- -- expr_type!(Indexed_Comp)._tag := expr_type'Tag;
-
- if Is_Mutably_Tagged_Type (Comp_Typ)
- and then Is_Abstract_Type (Root_Type (Comp_Typ))
- then
- declare
- Expr_Type : Entity_Id;
-
- begin
- if Nkind (Expr) in N_Has_Etype
- and then Present (Etype (Expr))
- then
- Expr_Type := Etype (Expr);
-
- elsif Nkind (Expr) = N_Qualified_Expression then
- Analyze (Subtype_Mark (Expr));
- Expr_Type := Etype (Subtype_Mark (Expr));
-
- -- Unsupported case
-
- else
- pragma Assert (False);
- raise Program_Error;
- end if;
-
- Initialize_Component
- (N => N,
- Comp => Unchecked_Convert_To (Expr_Type,
- Indexed_Comp),
- Comp_Typ => Expr_Type,
- Init_Expr => Expr,
- Stmts => Stmts);
- end;
- else
- Initialize_Component
- (N => N,
- Comp => Indexed_Comp,
- Comp_Typ => Comp_Typ,
- Init_Expr => Expr,
- Stmts => Stmts);
- end if;
+ Initialize_Component
+ (N => N,
+ Comp => Indexed_Comp,
+ Comp_Typ => Comp_Typ,
+ Init_Expr => Expr,
+ Stmts => Stmts);
-- Ada 2005 (AI-287): In case of default initialized component, call
-- the initialization subprogram associated with the component type.
@@ -1519,10 +1480,10 @@ package body Exp_Aggr is
else
-- For mutably tagged class-wide types, default initialization is
- -- performed by the init procedure of their root type.
+ -- performed by the init procedure of their specific type.
if Is_Mutably_Tagged_Type (Comp_Typ) then
- Comp_Typ := Root_Type (Comp_Typ);
+ Comp_Typ := Find_Specific_Type (Comp_Typ);
end if;
if Present (Base_Init_Proc (Comp_Typ)) then
@@ -4388,6 +4349,7 @@ package body Exp_Aggr is
and then Is_Limited_Type (Typ)
then
Target_Expr := New_Copy_Tree (Name (Parent_Node));
+ Ensure_Defined (Typ, Parent_Node);
Insert_Actions (Parent_Node,
Build_Record_Aggr_Code (N, Typ, Target_Expr));
Rewrite (Parent_Node, Make_Null_Statement (Loc));
@@ -4413,6 +4375,7 @@ package body Exp_Aggr is
if Nkind (N) in N_Aggregate | N_Extension_Aggregate then
Target_Expr := New_Copy_Tree (Lhs);
+ Ensure_Defined (Typ, Parent_Node);
Insert_Actions (Parent_Node,
Build_Record_Aggr_Code (N, Typ, Target_Expr));
Rewrite (Parent_Node, Make_Null_Statement (Loc));
@@ -6771,6 +6734,7 @@ package body Exp_Aggr is
function Build_Size_Expr (Comp : Node_Id) return Node_Id is
Lo, Hi : Node_Id;
It : Node_Id;
+ It_Subt : Entity_Id;
Siz_Exp : Node_Id := Empty;
Choice : Node_Id;
Temp_Siz_Exp : Node_Id;
@@ -6845,20 +6809,22 @@ package body Exp_Aggr is
elsif Nkind (Comp) = N_Iterated_Component_Association then
if Present (Iterator_Specification (Comp)) then
- -- If the static size of the iterable object is known,
+ -- If the size of the iterable object can be determined,
-- attempt to return it.
It := Name (Iterator_Specification (Comp));
Preanalyze (It);
- -- Handle the simplest cases for now where It denotes an array
- -- object.
+ It_Subt := Etype (It);
+
+ -- Handle the simplest cases for now, where It denotes an array
+ -- object or a container object.
if Nkind (It) in N_Identifier
- and then Ekind (Etype (It)) = E_Array_Subtype
+ and then Ekind (It_Subt) = E_Array_Subtype
then
declare
- Idx_N : Node_Id := First_Index (Etype (It));
+ Idx_N : Node_Id := First_Index (It_Subt);
Siz_Exp : Node_Id := Empty;
begin
while Present (Idx_N) loop
@@ -6892,6 +6858,96 @@ package body Exp_Aggr is
return Siz_Exp;
end;
+
+ -- Case of iterating over a container object. Note that this
+ -- must be a simple object, and not something like a function
+ -- call (which might have side effects, and we wouldn't want
+ -- it to be evaluated more than once). We take advantage of
+ -- RM22 4.3.5(40/5), which allows implementation-defined
+ -- behavior for the parameter passed to the Empty function,
+ -- and here use the container Length function when available.
+ -- Class-wide objects are also excluded, since those would
+ -- lead to dispatching, which could call a user-defined
+ -- overriding of Length that might have arbitrary effects.
+
+ elsif Is_Entity_Name (It)
+ and then Is_Object (Entity (It))
+ and then Ekind (It_Subt) in Record_Kind
+ and then not Is_Class_Wide_Type (It_Subt)
+ then
+ declare
+ Aggr_Base : constant Entity_Id := Base_Type (Typ);
+ It_Base : constant Entity_Id := Base_Type (It_Subt);
+ Empty_Formal : constant Entity_Id :=
+ First_Formal (Entity (Empty_Subp));
+ Length_Subp : Entity_Id;
+ Param_List : List_Id;
+
+ begin
+ -- We only determine a nondefault capacity in the case
+ -- of containers of predefined container types, which
+ -- generally have a Length function. User-defined
+ -- containers don't necessarily have such a function,
+ -- or it may be named differently, or it may have
+ -- the wrong semantics. The base subtypes are tested,
+ -- since their Sloc will refer to the original container
+ -- generics in the predefined library, even though the
+ -- types are declared in a package instantiation in some
+ -- other unit. Also, this is only done when Empty_Subp
+ -- has a formal parameter (generally named Capacity),
+ -- and not in the case of a parameterless Empty function.
+ -- Finally, we test for the container aggregate's type
+ -- having a first discriminant with the name Capacity,
+ -- since determining capacity via Length is only sensible
+ -- for container types with that discriminant (bounded
+ -- containers).
+
+ if Present (Empty_Formal)
+ and then In_Predefined_Unit (It_Base)
+ and then In_Predefined_Unit (Aggr_Base)
+ and then Has_Discriminants (Aggr_Base)
+ and then
+ Get_Name_String
+ (Chars (First_Discriminant (Aggr_Base)))
+ = "capacity"
+ then
+ -- Look for the container type's Length function in
+ -- the package where it's defined.
+
+ Push_Scope (Scope (It_Base));
+
+ Length_Subp := Current_Entity_In_Scope (Name_Length);
+
+ Pop_Scope;
+
+ -- If we found a Length function that has a single
+ -- parameter of the iterator object's container type,
+ -- then expand a call to that, passing the object,
+ -- and return that call, which will be used as the
+ -- "size" of the current element association of the
+ -- bounded container aggregate.
+
+ if Present (Length_Subp)
+ and then Ekind (Length_Subp) = E_Function
+ and then
+ Present (First_Entity (Length_Subp))
+ and then
+ No (Next_Entity (First_Entity (Length_Subp)))
+ and then
+ Base_Type
+ (Etype (First_Entity (Length_Subp))) = It_Base
+ then
+ Param_List :=
+ New_List (New_Occurrence_Of (Entity (It), Loc));
+
+ return
+ Make_Function_Call (Loc,
+ Name =>
+ New_Occurrence_Of (Length_Subp, Loc),
+ Parameter_Associations => Param_List);
+ end if;
+ end if;
+ end;
end if;
return Empty;
@@ -8864,7 +8920,15 @@ package body Exp_Aggr is
else
Set_No_Ctrl_Actions (Init_Stmt);
- if Tagged_Type_Expansion and then Is_Tagged_Type (Comp_Typ) then
+ if Tagged_Type_Expansion
+ and then Is_Tagged_Type (Comp_Typ)
+
+ -- Cannot adjust the tag when the expected type of the component is
+ -- a mutably tagged (and therefore class-wide) type; each component
+ -- of the aggregate has the tag of its initializing expression.
+
+ and then not Is_Mutably_Tagged_Type (Comp_Typ)
+ then
declare
Typ : Entity_Id := Underlying_Type (Comp_Typ);
diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb
index 4f9f16c..810248d 100644
--- a/gcc/ada/exp_attr.adb
+++ b/gcc/ada/exp_attr.adb
@@ -1915,6 +1915,15 @@ package body Exp_Attr is
-- call to the appropriate TSS procedure. Pname is the entity for the
-- procedure to call.
+ procedure Read_Controlling_Tag
+ (P_Type : Entity_Id; Cntrl : out Node_Id);
+ -- Read the external tag from the stream and use it to construct the
+ -- controlling operand for a dispatching call.
+
+ procedure Write_Controlling_Tag (P_Type : Entity_Id);
+ -- Write the external tag of the given attribute prefix type to
+ -- the stream. Also perform the accompanying accessibility check.
+
-------------------------------------
-- Build_And_Insert_Type_Attr_Subp --
-------------------------------------
@@ -2175,6 +2184,153 @@ package body Exp_Attr is
Analyze (N);
end Rewrite_Attribute_Proc_Call;
+ --------------------------
+ -- Read_Controlling_Tag --
+ --------------------------
+
+ procedure Read_Controlling_Tag
+ (P_Type : Entity_Id; Cntrl : out Node_Id)
+ is
+ Strm : constant Node_Id := First (Exprs);
+ Expr : Node_Id; -- call to Descendant_Tag
+ Get_Tag : Node_Id; -- expression to read the 'Tag
+
+ begin
+ -- Read the internal tag (RM 13.13.2(34)) and use it to
+ -- initialize a dummy tag value. We used to unconditionally
+ -- generate:
+ --
+ -- Descendant_Tag (String'Input (Strm), P_Type);
+ --
+ -- which turns into a call to String_Input_Blk_IO. However,
+ -- if the input is malformed, that could try to read an
+ -- enormous String, causing chaos. So instead we call
+ -- String_Input_Tag, which does the same thing as
+ -- String_Input_Blk_IO, except that if the String is
+ -- absurdly long, it raises an exception.
+ --
+ -- However, if the No_Stream_Optimizations restriction
+ -- is active, we disable this unnecessary attempt at
+ -- robustness; we really need to read the string
+ -- character-by-character.
+ --
+ -- This value is used only to provide a controlling
+ -- argument for the eventual _Input call. Descendant_Tag is
+ -- called rather than Internal_Tag to ensure that we have a
+ -- tag for a type that is descended from the prefix type and
+ -- declared at the same accessibility level (the exception
+ -- Tag_Error will be raised otherwise). The level check is
+ -- required for Ada 2005 because tagged types can be
+ -- extended in nested scopes (AI-344).
+
+ -- Note: we used to generate an explicit declaration of a
+ -- constant Ada.Tags.Tag object, and use an occurrence of
+ -- this constant in Cntrl, but this caused a secondary stack
+ -- leak.
+
+ if Restriction_Active (No_Stream_Optimizations) then
+ Get_Tag :=
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Occurrence_Of (Standard_String, Loc),
+ Attribute_Name => Name_Input,
+ Expressions => New_List (
+ Relocate_Node (Duplicate_Subexpr (Strm))));
+ else
+ Get_Tag :=
+ Make_Function_Call (Loc,
+ Name =>
+ New_Occurrence_Of
+ (RTE (RE_String_Input_Tag), Loc),
+ Parameter_Associations => New_List (
+ Relocate_Node (Duplicate_Subexpr (Strm))));
+ end if;
+
+ Expr :=
+ Make_Function_Call (Loc,
+ Name =>
+ New_Occurrence_Of (RTE (RE_Descendant_Tag), Loc),
+ Parameter_Associations => New_List (
+ Get_Tag,
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Occurrence_Of (P_Type, Loc),
+ Attribute_Name => Name_Tag)));
+
+ Set_Etype (Expr, RTE (RE_Tag));
+
+ -- Construct a controlling operand for a dispatching call.
+
+ Cntrl := Unchecked_Convert_To (P_Type, Expr);
+ Set_Etype (Cntrl, P_Type);
+ Set_Parent (Cntrl, N);
+ end Read_Controlling_Tag;
+
+ ----------------------------
+ -- Write_Controlling_Tag --
+ ----------------------------
+
+ procedure Write_Controlling_Tag (P_Type : Entity_Id) is
+ Strm : constant Node_Id := First (Exprs);
+ Item : constant Node_Id := Next (Strm);
+ begin
+ -- Ada 2005 (AI-344): Check that the accessibility level
+ -- of the type of the output object is not deeper than
+ -- that of the attribute's prefix type.
+
+ -- if Get_Access_Level (Item'Tag)
+ -- /= Get_Access_Level (P_Type'Tag)
+ -- then
+ -- raise Tag_Error;
+ -- end if;
+
+ -- String'Output (Strm, External_Tag (Item'Tag));
+
+ -- We cannot figure out a practical way to implement this
+ -- accessibility check on virtual machines, so we omit it.
+
+ if Ada_Version >= Ada_2005
+ and then Tagged_Type_Expansion
+ then
+ Insert_Action (N,
+ Make_Implicit_If_Statement (N,
+ Condition =>
+ Make_Op_Ne (Loc,
+ Left_Opnd =>
+ Build_Get_Access_Level (Loc,
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ Relocate_Node (
+ Duplicate_Subexpr (Item,
+ Name_Req => True)),
+ Attribute_Name => Name_Tag)),
+
+ Right_Opnd =>
+ Make_Integer_Literal (Loc,
+ Type_Access_Level (P_Type))),
+
+ Then_Statements =>
+ New_List (Make_Raise_Statement (Loc,
+ New_Occurrence_Of (
+ RTE (RE_Tag_Error), Loc)))));
+ end if;
+
+ Insert_Action (N,
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Occurrence_Of (Standard_String, Loc),
+ Attribute_Name => Name_Output,
+ Expressions => New_List (
+ Relocate_Node (Duplicate_Subexpr (Strm)),
+ Make_Function_Call (Loc,
+ Name =>
+ New_Occurrence_Of (RTE (RE_External_Tag), Loc),
+ Parameter_Associations => New_List (
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ Relocate_Node
+ (Duplicate_Subexpr (Item, Name_Req => True)),
+ Attribute_Name => Name_Tag))))));
+ end Write_Controlling_Tag;
+
Typ : constant Entity_Id := Etype (N);
Btyp : constant Entity_Id := Base_Type (Typ);
Ptyp : constant Entity_Id := Etype (Pref);
@@ -4487,94 +4643,57 @@ package body Exp_Attr is
elsif Is_Class_Wide_Type (P_Type) then
- -- No need to do anything else compiling under restriction
- -- No_Dispatching_Calls. During the semantic analysis we
- -- already notified such violation.
+ if Is_Mutably_Tagged_Type (P_Type) then
- if Restriction_Active (No_Dispatching_Calls) then
- return;
- end if;
+ -- In mutably tagged case, rewrite
+ -- T'Class'Input (Strm)
+ -- as (roughly)
+ -- declare
+ -- Result : T'Class;
+ -- T'Class'Read (Strm, Result);
+ -- begin
+ -- Result;
+ -- end;
- declare
- Rtyp : constant Entity_Id := Root_Type (P_Type);
+ declare
+ Result_Temp : constant Entity_Id :=
+ Make_Temporary (Loc, 'I');
- Expr : Node_Id; -- call to Descendant_Tag
- Get_Tag : Node_Id; -- expression to read the 'Tag
+ -- Gets default initialization
+ Result_Temp_Decl : constant Node_Id :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Result_Temp,
+ Object_Definition =>
+ New_Occurrence_Of (P_Type, Loc));
- begin
- -- Read the internal tag (RM 13.13.2(34)) and use it to
- -- initialize a dummy tag value. We used to unconditionally
- -- generate:
- --
- -- Descendant_Tag (String'Input (Strm), P_Type);
- --
- -- which turns into a call to String_Input_Blk_IO. However,
- -- if the input is malformed, that could try to read an
- -- enormous String, causing chaos. So instead we call
- -- String_Input_Tag, which does the same thing as
- -- String_Input_Blk_IO, except that if the String is
- -- absurdly long, it raises an exception.
- --
- -- However, if the No_Stream_Optimizations restriction
- -- is active, we disable this unnecessary attempt at
- -- robustness; we really need to read the string
- -- character-by-character.
- --
- -- This value is used only to provide a controlling
- -- argument for the eventual _Input call. Descendant_Tag is
- -- called rather than Internal_Tag to ensure that we have a
- -- tag for a type that is descended from the prefix type and
- -- declared at the same accessibility level (the exception
- -- Tag_Error will be raised otherwise). The level check is
- -- required for Ada 2005 because tagged types can be
- -- extended in nested scopes (AI-344).
-
- -- Note: we used to generate an explicit declaration of a
- -- constant Ada.Tags.Tag object, and use an occurrence of
- -- this constant in Cntrl, but this caused a secondary stack
- -- leak.
-
- if Restriction_Active (No_Stream_Optimizations) then
- Get_Tag :=
- Make_Attribute_Reference (Loc,
- Prefix =>
- New_Occurrence_Of (Standard_String, Loc),
- Attribute_Name => Name_Input,
- Expressions => New_List (
- Relocate_Node (Duplicate_Subexpr (Strm))));
- else
- Get_Tag :=
- Make_Function_Call (Loc,
- Name =>
- New_Occurrence_Of
- (RTE (RE_String_Input_Tag), Loc),
- Parameter_Associations => New_List (
- Relocate_Node (Duplicate_Subexpr (Strm))));
- end if;
+ function Result_Temp_Name return Node_Id is
+ (New_Occurrence_Of (Result_Temp, Loc));
- Expr :=
- Make_Function_Call (Loc,
- Name =>
- New_Occurrence_Of (RTE (RE_Descendant_Tag), Loc),
- Parameter_Associations => New_List (
- Get_Tag,
- Make_Attribute_Reference (Loc,
- Prefix => New_Occurrence_Of (P_Type, Loc),
- Attribute_Name => Name_Tag)));
+ Actions : constant List_Id := New_List (
+ Result_Temp_Decl,
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Occurrence_Of (P_Type, Loc),
+ Attribute_Name => Name_Read,
+ Expressions => New_List (
+ Relocate_Node (Strm), Result_Temp_Name)));
+ begin
+ Rewrite (N, Make_Expression_With_Actions (Loc,
+ Actions, Result_Temp_Name));
+ Analyze_And_Resolve (N, P_Type);
+ return;
+ end;
+ end if;
- Set_Etype (Expr, RTE (RE_Tag));
+ -- No need to do anything else compiling under restriction
+ -- No_Dispatching_Calls. During the semantic analysis we
+ -- already notified such violation.
- -- Now we need to get the entity for the call, and construct
- -- a function call node, where we preset a reference to Dnn
- -- as the controlling argument (doing an unchecked convert
- -- to the class-wide tagged type to make it look like a real
- -- tagged object).
+ if Restriction_Active (No_Dispatching_Calls) then
+ return;
+ end if;
- Fname := Find_Prim_Op (Rtyp, TSS_Stream_Input);
- Cntrl := Unchecked_Convert_To (P_Type, Expr);
- Set_Etype (Cntrl, P_Type);
- Set_Parent (Cntrl, N);
- end;
+ Read_Controlling_Tag (P_Type, Cntrl);
+ Fname := Find_Prim_Op (Root_Type (P_Type), TSS_Stream_Input);
-- For tagged types, use the primitive Input function
@@ -5957,6 +6076,14 @@ package body Exp_Attr is
Attr_Ref => N);
end;
+ -- In the mutably tagged case, T'Class'Output calls T'Class'Write;
+ -- T'Write will take care of writing out the external tag.
+
+ elsif Is_Mutably_Tagged_Type (P_Type) then
+ Set_Attribute_Name (N, Name_Write);
+ Analyze (N);
+ return;
+
-- Class-wide case, first output external tag, then dispatch
-- to the appropriate primitive Output function (RM 13.13.2(31)).
@@ -5970,68 +6097,7 @@ package body Exp_Attr is
return;
end if;
- Tag_Write : declare
- Strm : constant Node_Id := First (Exprs);
- Item : constant Node_Id := Next (Strm);
-
- begin
- -- Ada 2005 (AI-344): Check that the accessibility level
- -- of the type of the output object is not deeper than
- -- that of the attribute's prefix type.
-
- -- if Get_Access_Level (Item'Tag)
- -- /= Get_Access_Level (P_Type'Tag)
- -- then
- -- raise Tag_Error;
- -- end if;
-
- -- String'Output (Strm, External_Tag (Item'Tag));
-
- -- We cannot figure out a practical way to implement this
- -- accessibility check on virtual machines, so we omit it.
-
- if Ada_Version >= Ada_2005
- and then Tagged_Type_Expansion
- then
- Insert_Action (N,
- Make_Implicit_If_Statement (N,
- Condition =>
- Make_Op_Ne (Loc,
- Left_Opnd =>
- Build_Get_Access_Level (Loc,
- Make_Attribute_Reference (Loc,
- Prefix =>
- Relocate_Node (
- Duplicate_Subexpr (Item,
- Name_Req => True)),
- Attribute_Name => Name_Tag)),
-
- Right_Opnd =>
- Make_Integer_Literal (Loc,
- Type_Access_Level (P_Type))),
-
- Then_Statements =>
- New_List (Make_Raise_Statement (Loc,
- New_Occurrence_Of (
- RTE (RE_Tag_Error), Loc)))));
- end if;
-
- Insert_Action (N,
- Make_Attribute_Reference (Loc,
- Prefix => New_Occurrence_Of (Standard_String, Loc),
- Attribute_Name => Name_Output,
- Expressions => New_List (
- Relocate_Node (Duplicate_Subexpr (Strm)),
- Make_Function_Call (Loc,
- Name =>
- New_Occurrence_Of (RTE (RE_External_Tag), Loc),
- Parameter_Associations => New_List (
- Make_Attribute_Reference (Loc,
- Prefix =>
- Relocate_Node
- (Duplicate_Subexpr (Item, Name_Req => True)),
- Attribute_Name => Name_Tag))))));
- end Tag_Write;
+ Write_Controlling_Tag (P_Type);
Pname := Find_Prim_Op (U_Type, TSS_Stream_Output);
@@ -6793,6 +6859,7 @@ package body Exp_Attr is
P_Type : constant Entity_Id := Entity (Pref);
B_Type : constant Entity_Id := Base_Type (P_Type);
U_Type : constant Entity_Id := Underlying_Type (P_Type);
+ Cntrl : Node_Id := Empty; -- nonempty only if P_Type mutably tagged
Pname : Entity_Id;
Decl : Node_Id;
Prag : Node_Id;
@@ -6941,6 +7008,11 @@ package body Exp_Attr is
-- this will dispatch in the class-wide case which is what we want
elsif Is_Tagged_Type (U_Type) then
+
+ if Is_Mutably_Tagged_Type (U_Type) then
+ Read_Controlling_Tag (P_Type, Cntrl);
+ end if;
+
Pname := Find_Prim_Op (U_Type, TSS_Stream_Read);
-- All other record type cases, including protected records. The
@@ -7001,6 +7073,46 @@ package body Exp_Attr is
Rewrite_Attribute_Proc_Call (Pname);
+ if Present (Cntrl) then
+ pragma Assert (Is_Mutably_Tagged_Type (U_Type));
+ pragma Assert (Nkind (N) = N_Procedure_Call_Statement);
+
+ -- Assign the Tag value that was read from the stream
+ -- to the tag of the out-mode actual parameter so that
+ -- we dispatch correctly. This isn't quite right.
+ -- We should assign a complete object (not just
+ -- the tag), but that would require a dispatching call to
+ -- perform default initialization of the source object and
+ -- dispatching default init calls are currently not supported.
+
+ declare
+ function Select_Tag (Prefix : Node_Id) return Node_Id is
+ (Make_Selected_Component (Loc,
+ Prefix => Prefix,
+ Selector_Name =>
+ New_Occurrence_Of (First_Tag_Component
+ (Etype (Prefix)), Loc)));
+
+ Controlling_Actual : constant Node_Id :=
+ Next (First (Parameter_Associations (N)));
+
+ pragma Assert (Is_Controlling_Actual (Controlling_Actual));
+
+ Assign_Tag : Node_Id;
+ begin
+ Remove_Side_Effects (Controlling_Actual, Name_Req => True);
+
+ Assign_Tag :=
+ Make_Assignment_Statement (Loc,
+ Name =>
+ Select_Tag (New_Copy_Tree (Controlling_Actual)),
+ Expression => Select_Tag (Cntrl));
+
+ Insert_Before (Before => N, Node => Assign_Tag);
+ Analyze (Assign_Tag);
+ end;
+ end if;
+
if not Is_Tagged_Type (P_Type) then
Cached_Attribute_Ops.Read_Map.Set (U_Type, Pname);
end if;
@@ -8611,6 +8723,14 @@ package body Exp_Attr is
-- this will dispatch in the class-wide case which is what we want
elsif Is_Tagged_Type (U_Type) then
+
+ -- If T'Class is mutably tagged, then the external tag
+ -- is written out by T'Class'Write, not by T'Class'Output.
+
+ if Is_Mutably_Tagged_Type (U_Type) then
+ Write_Controlling_Tag (P_Type);
+ end if;
+
Pname := Find_Prim_Op (U_Type, TSS_Stream_Write);
-- All other record type cases, including protected records.
diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb
index 5a47a5a..6cf7c9c 100644
--- a/gcc/ada/exp_ch3.adb
+++ b/gcc/ada/exp_ch3.adb
@@ -942,10 +942,11 @@ package body Exp_Ch3 is
Make_Handled_Sequence_Of_Statements (Loc,
Statements => Body_Stmts)));
- Mutate_Ekind (Proc_Id, E_Procedure);
- Set_Is_Public (Proc_Id, Is_Public (A_Type));
- Set_Is_Internal (Proc_Id);
- Set_Has_Completion (Proc_Id);
+ Mutate_Ekind (Proc_Id, E_Procedure);
+ Set_Is_Public (Proc_Id, Is_Public (A_Type));
+ Set_Is_Internal (Proc_Id);
+ Set_Has_Completion (Proc_Id);
+ Freeze_Extra_Formals (Proc_Id);
if not Debug_Generated_Code then
Set_Debug_Info_Off (Proc_Id);
@@ -3204,6 +3205,7 @@ package body Exp_Ch3 is
end if;
Set_Parameter_Specifications (Proc_Spec_Node, Parameters);
+ Freeze_Extra_Formals (Proc_Id);
Set_Specification (Body_Node, Proc_Spec_Node);
Set_Declarations (Body_Node, Decls);
@@ -6496,7 +6498,7 @@ package body Exp_Ch3 is
end;
end if;
- if Has_Controlled_Component (Typ) then
+ if Has_Controlled_Component (Typ) or else Has_Destructor (Typ) then
Build_Controlling_Procs (Typ);
end if;
@@ -6570,17 +6572,16 @@ package body Exp_Ch3 is
-- procedure, because a self-referential type might call one of these
-- primitives in the body of the init_proc itself.
--
- -- This is not needed:
- -- 1) If expansion is disabled, because extra formals are only added
- -- when we are generating code.
+ -- This is not needed when expansion is disabled, because extra formals
+ -- are only added when we are generating code.
--
- -- 2) For types with foreign convention since primitives with foreign
- -- convention don't have extra formals and AI95-117 requires that
- -- all primitives of a tagged type inherit the convention.
+ -- Notice that for tagged types with foreign convention this is also
+ -- required because (although primitives with foreign convention don't
+ -- have extra formals), a tagged type with foreign convention may have
+ -- primitives with convention Ada.
if Expander_Active
and then Is_Tagged_Type (Typ)
- and then not Has_Foreign_Convention (Typ)
then
declare
Elmt : Elmt_Id;
@@ -7500,6 +7501,12 @@ package body Exp_Ch3 is
Apply_CW_Accessibility_Check (Expr, Func_Id);
end if;
+ if Has_Anonymous_Access_Discriminant (Etype (Expr)) then
+ -- Check that access discrims do not designate entities
+ -- that the function result could outlive.
+ Apply_Access_Discrims_Accessibility_Check (Expr, Func_Id);
+ end if;
+
Alloc_Expr := New_Copy_Tree (Expr);
if Etype (Alloc_Expr) /= Alloc_Typ then
@@ -9058,6 +9065,10 @@ package body Exp_Ch3 is
if Is_Class_Wide_Type (Etype (Func_Id)) then
Apply_CW_Accessibility_Check (Expr_Q, Func_Id);
end if;
+
+ -- ??? Usually calls to Apply_CW_Accessibility_Check and to
+ -- Apply_Access_Discrims_Accessibility_Check come in pairs.
+ -- Do we need a (conditional) call here to A_A_D_A_C ?
end;
end if;
@@ -12845,25 +12856,27 @@ package body Exp_Ch3 is
Append_To (Res, Decl);
end if;
- Fin_Call := Empty;
- Decl := Predef_Deep_Spec (Loc, Tag_Typ, TSS_Deep_Finalize, True);
+ if not Has_Destructor (Tag_Typ) then
+ Fin_Call := Empty;
+ Decl := Predef_Deep_Spec (Loc, Tag_Typ, TSS_Deep_Finalize, True);
- if Is_Controlled (Tag_Typ) then
- Fin_Call :=
- Make_Final_Call
- (Obj_Ref => Make_Identifier (Loc, Name_V),
- Typ => Tag_Typ);
- end if;
+ if Is_Controlled (Tag_Typ) then
+ Fin_Call :=
+ Make_Final_Call
+ (Obj_Ref => Make_Identifier (Loc, Name_V), Typ => Tag_Typ);
+ end if;
- if No (Fin_Call) then
- Fin_Call := Make_Null_Statement (Loc);
- end if;
+ if No (Fin_Call) then
+ Fin_Call := Make_Null_Statement (Loc);
+ end if;
- Set_Handled_Statement_Sequence (Decl,
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Fin_Call)));
+ Set_Handled_Statement_Sequence
+ (Decl,
+ Make_Handled_Sequence_Of_Statements
+ (Loc, Statements => New_List (Fin_Call)));
- Append_To (Res, Decl);
+ Append_To (Res, Decl);
+ end if;
end if;
return Res;
diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb
index 76386fc..43c94f3 100644
--- a/gcc/ada/exp_ch4.adb
+++ b/gcc/ada/exp_ch4.adb
@@ -2354,6 +2354,7 @@ package body Exp_Ch4 is
Rhs : Node_Id) return Node_Id
is
Loc : constant Source_Ptr := Sloc (Nod);
+ CW_Comp : Boolean := False;
Full_Type : Entity_Id;
Eq_Op : Entity_Id;
@@ -2383,10 +2384,17 @@ package body Exp_Ch4 is
Full_Type := Underlying_Type (Full_Type);
end if;
+ if Is_Class_Wide_Equivalent_Type (Full_Type) then
+ CW_Comp := True;
+ Full_Type :=
+ Get_Corresponding_Mutably_Tagged_Type_If_Present (Full_Type);
+ pragma Assert (Is_Tagged_Type (Full_Type));
+ end if;
+
-- Case of tagged record types
if Is_Tagged_Type (Full_Type) then
- Eq_Op := Find_Primitive_Eq (Comp_Type);
+ Eq_Op := Find_Primitive_Eq (if CW_Comp then Full_Type else Comp_Type);
pragma Assert (Present (Eq_Op));
return
diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb
index c24c8c6..eb7422c 100644
--- a/gcc/ada/exp_ch6.adb
+++ b/gcc/ada/exp_ch6.adb
@@ -734,6 +734,258 @@ package body Exp_Ch6 is
Add_Extra_Actual_To_Call (Function_Call, Chain_Formal, Chain_Actual);
end Add_Task_Actuals_To_Build_In_Place_Call;
+ ----------------------------------------------
+ -- Apply_Access_Discrims_Accesibility_Check --
+ ----------------------------------------------
+
+ procedure Apply_Access_Discrims_Accessibility_Check
+ (Exp : Node_Id; Func : Entity_Id)
+ is
+ Loc : constant Source_Ptr := Sloc (Exp);
+
+ -- Some of the code here in this procedure may need to be factored
+ -- out at some point because it seems like some of the same
+ -- functionality would be needed for accessibility checking of a
+ -- return statement when the function result type is an anonymous
+ -- access type (as opposed to a type that has an anonymous access
+ -- discriminant).
+ --
+ -- Another case that is not addressed today is the case where
+ -- we need to check an access discriminant subcomponent of the
+ -- function result other than a discriminant of the function result.
+ -- This can only happen if the function result type has an unconstrained
+ -- subcomponent subtype that has an access discriminant (which implies
+ -- that the function result type must be limited).
+ --
+ -- A further corner case of that corner case arises if the limited
+ -- function result type is class-wide and it is not known statically
+ -- that this access-discriminant-bearing subcomponent exists. The
+ -- easiest way to address this properly would probably involve adding
+ -- a new compiler-generated dispatching procedure; a dispatching call
+ -- could then be used to perform the check in a context where we know
+ -- statically the specific type of the function result. Finding a
+ -- less important unimplemented case would be challenging.
+
+ function Constraint_Bearing_Subtype_If_Any
+ (Exp : Node_Id) return Node_Id;
+ -- If we can locate a constrained subtype whose constraint applies
+ -- to Exp, then return that. Otherwise, return Etype (Exp).
+
+ function Discr_Expression
+ (Typ : Entity_Id; Discr_Index : Positive) return Node_Id;
+ -- Typ is a constrained discriminated subtype.
+ -- Return the constraint expression for the indexed discriminant.
+
+ function Has_Level_Tied_To_Explicitly_Aliased_Param
+ (Constraint_Exp : Node_Id) return Boolean;
+ -- Constraint_Exp is the value given for an access discriminant
+ -- in a discriminant constraint for Exp. Return True iff the
+ -- accessibility of the type of that discriminant of Exp is the level
+ -- of an explicitly aliased parameter of Func. If true, this indicates
+ -- that no check should be performed for this discriminant.
+
+ ---------------------------------------
+ -- Constraint_Bearing_Subtype_If_Any --
+ ---------------------------------------
+
+ function Constraint_Bearing_Subtype_If_Any
+ (Exp : Node_Id) return Entity_Id
+ is
+ Result : Entity_Id := Etype (Exp);
+ begin
+ if Is_Constrained (Result) then
+ return Result;
+ end if;
+
+ -- Look through expansion-generated levels of indirection
+ -- to find a constrained subtype. Yuck. This comes up in
+ -- some cases when the unexpanded source returns an aggregate.
+
+ if Nkind (Exp) = N_Explicit_Dereference
+ and then Nkind (Prefix (Exp)) = N_Identifier
+ and then Ekind (Entity (Prefix (Exp))) = E_Constant
+ then
+ declare
+ Acc_Const : Entity_Id := Entity (Prefix (Exp));
+ Acc_Const_Value : Node_Id := Empty;
+ begin
+ -- look through constants initialized to constants
+ loop
+ exit when Nkind (Parent (Acc_Const)) /= N_Object_Declaration;
+
+ Acc_Const_Value := Expression (Parent (Acc_Const));
+
+ if Nkind (Acc_Const_Value) = N_Identifier
+ and then Ekind (Entity (Acc_Const_Value)) = E_Constant
+ then
+ Acc_Const := Entity (Acc_Const_Value);
+ else
+ exit;
+ end if;
+ end loop;
+
+ if Nkind (Acc_Const_Value) = N_Allocator
+ and then Nkind (Expression (Acc_Const_Value))
+ = N_Qualified_Expression
+ then
+ Result :=
+ Etype (Expression (Acc_Const_Value));
+ end if;
+ end;
+ end if;
+
+ if Is_Constrained (Result) then
+ return Result;
+ end if;
+
+ -- no constrained subtype found
+ return Etype (Exp);
+ end Constraint_Bearing_Subtype_If_Any;
+
+ ----------------------
+ -- Discr_Expression --
+ ----------------------
+
+ function Discr_Expression
+ (Typ : Entity_Id; Discr_Index : Positive) return Node_Id
+ is
+ Constraint_Elmt : Elmt_Id :=
+ First_Elmt (Discriminant_Constraint (Typ));
+ begin
+ for Skip in 1 .. Discr_Index - 1 loop
+ Next_Elmt (Constraint_Elmt);
+ end loop;
+ return Node (Constraint_Elmt);
+ end Discr_Expression;
+
+ -------------------------------------------------
+ -- Has_Level_Tied_To_Explicitly_Aliased_Param --
+ -------------------------------------------------
+
+ function Has_Level_Tied_To_Explicitly_Aliased_Param
+ (Constraint_Exp : Node_Id) return Boolean
+ is
+ Discr_Exp : Node_Id := Constraint_Exp;
+ Attr_Prefix : Node_Id;
+ begin
+ -- look through constants
+ while Nkind (Discr_Exp) = N_Identifier
+ and then Ekind (Entity (Discr_Exp)) = E_Constant
+ and then Nkind (Parent (Entity (Discr_Exp))) = N_Object_Declaration
+ loop
+ Discr_Exp := Expression (Parent (Entity (Discr_Exp)));
+ end loop;
+
+ if Nkind (Discr_Exp) = N_Attribute_Reference
+ and then Get_Attribute_Id
+ (Attribute_Name (Discr_Exp)) = Attribute_Access
+ then
+ Attr_Prefix := Ultimate_Prefix (Prefix (Discr_Exp));
+ if Is_Entity_Name (Attr_Prefix)
+ and then Is_Explicitly_Aliased (Entity (Attr_Prefix))
+ and then Scope (Entity (Attr_Prefix)) = Func
+ then
+ return True;
+ end if;
+ end if;
+
+ return False;
+ end Has_Level_Tied_To_Explicitly_Aliased_Param;
+
+ Discr : Entity_Id := First_Discriminant (Etype (Exp));
+ Discr_Index : Positive := 1;
+ Discr_Exp : Node_Id;
+
+ Constrained_Subtype : constant Entity_Id :=
+ Constraint_Bearing_Subtype_If_Any (Exp);
+ begin
+ -- ??? Do not generate a check if version is Ada 95 (or earlier).
+ -- It is unclear whether this is really correct, or is just a stopgap
+ -- measure. Investigation is needed to decide how post-Ada-95 binding
+ -- interpretation changes in RM 3.10.2 should interact with Ada 95's
+ -- return-by-reference model for functions with limited result types
+ -- (which was abandoned in Ada 2005).
+
+ if Ada_Version <= Ada_95 then
+ return;
+ end if;
+
+ -- If we are returning a function call then that function will
+ -- perform the needed check.
+
+ if Nkind (Unqualify (Exp)) = N_Function_Call then
+ return;
+ end if;
+
+ -- ??? Cope with the consequences of the Disable_Tagged_Cases flag
+ -- in accessibility.adb (which can cause the extra formal parameter
+ -- needed for the check(s) generated here to be missing in the case
+ -- of a tagged result type); this is a workaround and can
+ -- prevent generation of a required check.
+
+ if No (Extra_Accessibility_Of_Result (Func)) then
+ return;
+ end if;
+
+ Remove_Side_Effects (Exp);
+
+ while Present (Discr) loop
+ if Is_Anonymous_Access_Type (Etype (Discr)) then
+ if Is_Constrained (Constrained_Subtype) then
+ Discr_Exp :=
+ New_Copy_Tree
+ (Discr_Expression (Constrained_Subtype, Discr_Index));
+ else
+ Discr_Exp :=
+ Make_Selected_Component (Loc,
+ Prefix => New_Copy_Tree (Exp),
+ Selector_Name => New_Occurrence_Of (Discr, Loc));
+ end if;
+
+ if not Has_Level_Tied_To_Explicitly_Aliased_Param (Discr_Exp) then
+ declare
+ -- We could do this min operation earlier, as is done
+ -- for other implicit level parameters. Motivation for
+ -- doing this min operation (earlier or not) is as for
+ -- Generate_Minimum_Accessibility (see sem_ch6.adb):
+ -- if a level value is too big, then the caller and the
+ -- callee disagree about what it means.
+
+ Level_Of_Master_Of_Call : constant Node_Id :=
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Occurrence_Of (Standard_Natural, Loc),
+ Attribute_Name => Name_Min,
+ Expressions => New_List (
+ Make_Integer_Literal (Loc, Scope_Depth (Func)),
+ New_Occurrence_Of
+ (Extra_Accessibility_Of_Result (Func), Loc)));
+
+ Discrim_Level : Node_Id;
+ begin
+ Analyze (Level_Of_Master_Of_Call);
+ Analyze (Discr_Exp);
+
+ Discrim_Level :=
+ Accessibility_Level (Discr_Exp, Level => Dynamic_Level);
+ Analyze (Discrim_Level);
+
+ Insert_Action (Exp,
+ Make_Raise_Program_Error (Loc,
+ Condition =>
+ Make_Op_Gt (Loc,
+ Left_Opnd => Discrim_Level,
+ Right_Opnd => Level_Of_Master_Of_Call),
+ Reason => PE_Accessibility_Check_Failed),
+ Suppress => Access_Check);
+ end;
+ end if;
+ end if;
+
+ Next_Discriminant (Discr);
+ Discr_Index := Discr_Index + 1;
+ end loop;
+ end Apply_Access_Discrims_Accessibility_Check;
+
----------------------------------
-- Apply_CW_Accessibility_Check --
----------------------------------
@@ -1155,13 +1407,18 @@ package body Exp_Ch6 is
(Subp_Call : Node_Id;
Subp_Id : Entity_Id) return Boolean
is
- Formal : Entity_Id;
+ use Deferred_Extra_Formals_Support;
+
Actual : Node_Id;
+ Formal : Entity_Id;
begin
pragma Assert (Nkind (Subp_Call) in N_Entry_Call_Statement
| N_Function_Call
| N_Procedure_Call_Statement);
+ pragma Assert (Extra_Formals_Known (Subp_Id)
+ or else not Expander_Active
+ or else Is_Unsupported_Extra_Actuals_Call (Subp_Call, Subp_Id));
-- In CodePeer_Mode, the tree for `'Elab_Spec` procedures will be
-- malformed because GNAT does not perform the usual expansion that
@@ -2866,15 +3123,17 @@ package body Exp_Ch6 is
-----------------
procedure Expand_Call (N : Node_Id) is
- function Is_Unchecked_Union_Equality (N : Node_Id) return Boolean;
+ function Is_Unchecked_Union_Predefined_Equality_Call
+ (N : Node_Id) return Boolean;
-- Return True if N is a call to the predefined equality operator of an
-- unchecked union type, or a renaming thereof.
- ---------------------------------
- -- Is_Unchecked_Union_Equality --
- ---------------------------------
+ -------------------------------------------------
+ -- Is_Unchecked_Union_Predefined_Equality_Call --
+ -------------------------------------------------
- function Is_Unchecked_Union_Equality (N : Node_Id) return Boolean is
+ function Is_Unchecked_Union_Predefined_Equality_Call
+ (N : Node_Id) return Boolean is
begin
if Is_Entity_Name (Name (N))
and then Ekind (Entity (Name (N))) = E_Function
@@ -2899,7 +3158,7 @@ package body Exp_Ch6 is
else
return False;
end if;
- end Is_Unchecked_Union_Equality;
+ end Is_Unchecked_Union_Predefined_Equality_Call;
-- If this is an indirect call through an Access_To_Subprogram
-- with contract specifications, it is rewritten as a call to
@@ -2996,7 +3255,7 @@ package body Exp_Ch6 is
-- Case of a call to the predefined equality operator of an unchecked
-- union type, which requires specific processing.
- elsif Is_Unchecked_Union_Equality (N) then
+ elsif Is_Unchecked_Union_Predefined_Equality_Call (N) then
declare
Eq : constant Entity_Id := Entity (Name (N));
@@ -3020,29 +3279,12 @@ package body Exp_Ch6 is
end if;
end Expand_Call;
- ------------------------
- -- Expand_Call_Helper --
- ------------------------
-
- -- This procedure handles expansion of function calls and procedure call
- -- statements (i.e. it serves as the body for Expand_N_Function_Call and
- -- Expand_N_Procedure_Call_Statement). Processing for calls includes:
-
- -- Replace call to Raise_Exception by Raise_Exception_Always if possible
- -- Provide values of actuals for all formals in Extra_Formals list
- -- Replace "call" to enumeration literal function by literal itself
- -- Rewrite call to predefined operator as operator
- -- Replace actuals to in-out parameters that are numeric conversions,
- -- with explicit assignment to temporaries before and after the call.
-
- -- Note that the list of actuals has been filled with default expressions
- -- during semantic analysis of the call. Only the extra actuals required
- -- for the 'Constrained attribute and for accessibility checks are added
- -- at this point.
+ --------------------------
+ -- Create_Extra_Actuals --
+ --------------------------
- procedure Expand_Call_Helper (N : Node_Id; Post_Call : out List_Id) is
- Loc : constant Source_Ptr := Sloc (N);
- Call_Node : Node_Id := N;
+ procedure Create_Extra_Actuals (Call_Node : Node_Id) is
+ Loc : constant Source_Ptr := Sloc (Call_Node);
Extra_Actuals : List_Id := No_List;
Prev : Node_Id := Empty;
@@ -3072,88 +3314,6 @@ package body Exp_Ch6 is
-- expression for the value of the actual, EF is the entity for the
-- extra formal.
- procedure Add_View_Conversion_Invariants
- (Formal : Entity_Id;
- Actual : Node_Id);
- -- Adds invariant checks for every intermediate type between the range
- -- of a view converted argument to its ancestor (from parent to child).
-
- function Can_Fold_Predicate_Call (P : Entity_Id) return Boolean;
- -- Try to constant-fold a predicate check, which often enough is a
- -- simple arithmetic expression that can be computed statically if
- -- its argument is static. This cleans up the output of CCG, even
- -- though useless predicate checks will be generally removed by
- -- back-end optimizations.
-
- procedure Check_Subprogram_Variant;
- -- Emit a call to the internally generated procedure with checks for
- -- aspect Subprogram_Variant, if present and enabled.
-
- function Inherited_From_Formal (S : Entity_Id) return Entity_Id;
- -- Within an instance, a type derived from an untagged formal derived
- -- type inherits from the original parent, not from the actual. The
- -- current derivation mechanism has the derived type inherit from the
- -- actual, which is only correct outside of the instance. If the
- -- subprogram is inherited, we test for this particular case through a
- -- convoluted tree traversal before setting the proper subprogram to be
- -- called.
-
- function In_Unfrozen_Instance (E : Entity_Id) return Boolean;
- -- Return true if E comes from an instance that is not yet frozen
-
- function Is_Class_Wide_Interface_Type (E : Entity_Id) return Boolean;
- -- Return True when E is a class-wide interface type or an access to
- -- a class-wide interface type.
-
- function Is_Direct_Deep_Call (Subp : Entity_Id) return Boolean;
- -- Determine if Subp denotes a non-dispatching call to a Deep routine
-
- function New_Value (From : Node_Id) return Node_Id;
- -- From is the original Expression. New_Value is equivalent to a call
- -- to Duplicate_Subexpr with an explicit dereference when From is an
- -- access parameter.
-
- --------------------------
- -- Add_Actual_Parameter --
- --------------------------
-
- procedure Add_Actual_Parameter (Insert_Param : Node_Id) is
- Actual_Expr : constant Node_Id :=
- Explicit_Actual_Parameter (Insert_Param);
-
- begin
- -- Case of insertion is first named actual
-
- if No (Prev) or else
- Nkind (Parent (Prev)) /= N_Parameter_Association
- then
- Set_Next_Named_Actual
- (Insert_Param, First_Named_Actual (Call_Node));
- Set_First_Named_Actual (Call_Node, Actual_Expr);
-
- if No (Prev) then
- if No (Parameter_Associations (Call_Node)) then
- Set_Parameter_Associations (Call_Node, New_List);
- end if;
-
- Append (Insert_Param, Parameter_Associations (Call_Node));
-
- else
- Insert_After (Prev, Insert_Param);
- end if;
-
- -- Case of insertion is not first named actual
-
- else
- Set_Next_Named_Actual
- (Insert_Param, Next_Named_Actual (Parent (Prev)));
- Set_Next_Named_Actual (Parent (Prev), Actual_Expr);
- Append (Insert_Param, Parameter_Associations (Call_Node));
- end if;
-
- Prev := Actual_Expr;
- end Add_Actual_Parameter;
-
--------------------------------------
-- Add_Cond_Expression_Extra_Actual --
--------------------------------------
@@ -3368,14 +3528,14 @@ package body Exp_Ch6 is
if Etype (Formal) = Standard_Natural then
Actual := Make_Integer_Literal (Loc, Uint_0);
Analyze_And_Resolve (Actual, Standard_Natural);
- Add_Extra_Actual_To_Call (N, Formal, Actual);
+ Add_Extra_Actual_To_Call (Call_Node, Formal, Actual);
-- BIPtaskmaster
elsif Etype (Formal) = Standard_Integer then
Actual := Make_Integer_Literal (Loc, Uint_0);
Analyze_And_Resolve (Actual, Standard_Integer);
- Add_Extra_Actual_To_Call (N, Formal, Actual);
+ Add_Extra_Actual_To_Call (Call_Node, Formal, Actual);
-- BIPstoragepool, BIPcollection, BIPactivationchain,
-- and BIPaccess.
@@ -3383,7 +3543,7 @@ package body Exp_Ch6 is
elsif Is_Access_Type (Etype (Formal)) then
Actual := Make_Null (Loc);
Analyze_And_Resolve (Actual, Etype (Formal));
- Add_Extra_Actual_To_Call (N, Formal, Actual);
+ Add_Extra_Actual_To_Call (Call_Node, Formal, Actual);
else
pragma Assert (False);
@@ -3402,6 +3562,47 @@ package body Exp_Ch6 is
pragma Assert (Check_BIP_Actuals (Call_Node, Function_Id));
end Add_Dummy_Build_In_Place_Actuals;
+ --------------------------
+ -- Add_Actual_Parameter --
+ --------------------------
+
+ procedure Add_Actual_Parameter (Insert_Param : Node_Id) is
+ Actual_Expr : constant Node_Id :=
+ Explicit_Actual_Parameter (Insert_Param);
+
+ begin
+ -- Case of insertion is first named actual
+
+ if No (Prev)
+ or else Nkind (Parent (Prev)) /= N_Parameter_Association
+ then
+ Set_Next_Named_Actual
+ (Insert_Param, First_Named_Actual (Call_Node));
+ Set_First_Named_Actual (Call_Node, Actual_Expr);
+
+ if No (Prev) then
+ if No (Parameter_Associations (Call_Node)) then
+ Set_Parameter_Associations (Call_Node, New_List);
+ end if;
+
+ Append (Insert_Param, Parameter_Associations (Call_Node));
+
+ else
+ Insert_After (Prev, Insert_Param);
+ end if;
+
+ -- Case of insertion is not first named actual
+
+ else
+ Set_Next_Named_Actual
+ (Insert_Param, Next_Named_Actual (Parent (Prev)));
+ Set_Next_Named_Actual (Parent (Prev), Actual_Expr);
+ Append (Insert_Param, Parameter_Associations (Call_Node));
+ end if;
+
+ Prev := Actual_Expr;
+ end Add_Actual_Parameter;
+
----------------------
-- Add_Extra_Actual --
----------------------
@@ -3427,6 +3628,421 @@ package body Exp_Ch6 is
end if;
end Add_Extra_Actual;
+ -- Local variables
+
+ use Deferred_Extra_Formals_Support;
+
+ Actual : Node_Id;
+ Formal : Entity_Id;
+ Param_Count : Positive;
+ Subp : constant Entity_Id := Get_Called_Entity (Call_Node);
+
+ -- Start of processing for Create_Extra_Actuals
+
+ begin
+ -- Special case: Thunks must not compute the extra actuals; they must
+ -- just propagate their extra actuals to the target primitive.
+
+ if Is_Thunk (Current_Scope)
+ and then Thunk_Entity (Current_Scope) = Subp
+ then
+ declare
+ Target_Formal : Entity_Id;
+ Thunk_Formal : Entity_Id;
+
+ begin
+ pragma Assert (Extra_Formals_Known (Subp)
+ and then Extra_Formals_Match_OK (Current_Scope, Subp));
+
+ Target_Formal := Extra_Formals (Subp);
+ Thunk_Formal := Extra_Formals (Current_Scope);
+ while Present (Target_Formal) loop
+ Add_Extra_Actual
+ (Expr => New_Occurrence_Of (Thunk_Formal, Loc),
+ EF => Thunk_Formal);
+
+ Target_Formal := Extra_Formal (Target_Formal);
+ Thunk_Formal := Extra_Formal (Thunk_Formal);
+ end loop;
+
+ while Is_Non_Empty_List (Extra_Actuals) loop
+ Add_Actual_Parameter (Remove_Head (Extra_Actuals));
+ end loop;
+
+ return;
+ end;
+ end if;
+
+ pragma Assert (Extra_Formals_Known (Subp)
+ or else Is_Unsupported_Extra_Formals_Entity (Subp));
+
+ -- First step, compute extra actuals, corresponding to any Extra_Formals
+ -- present. Note that we do not access Extra_Formals directly; instead
+ -- we generate and collect the corresponding actuals in Extra_Actuals.
+
+ Formal := First_Formal (Subp);
+ Actual := First_Actual (Call_Node);
+ Param_Count := 1;
+ while Present (Formal) loop
+ -- Prepare to examine current entry
+
+ Prev := Actual;
+
+ -- Create possible extra actual for constrained case. Usually, the
+ -- extra actual is of the form actual'constrained, but since this
+ -- attribute is only available for unconstrained records, TRUE is
+ -- expanded if the type of the formal happens to be constrained (for
+ -- instance when this procedure is inherited from an unconstrained
+ -- record to a constrained one) or if the actual has no discriminant
+ -- (its type is constrained). An exception to this is the case of a
+ -- private type without discriminants. In this case we pass FALSE
+ -- because the object has underlying discriminants with defaults.
+
+ if Present (Extra_Constrained (Formal)) then
+ if Is_Mutably_Tagged_Type (Etype (Actual))
+ or else (Is_Private_Type (Etype (Prev))
+ and then not Has_Discriminants
+ (Base_Type (Etype (Prev))))
+ then
+ Add_Extra_Actual
+ (Expr => New_Occurrence_Of (Standard_False, Loc),
+ EF => Extra_Constrained (Formal));
+
+ elsif Is_Constrained (Etype (Formal))
+ or else not Has_Discriminants (Etype (Prev))
+ then
+ Add_Extra_Actual
+ (Expr => New_Occurrence_Of (Standard_True, Loc),
+ EF => Extra_Constrained (Formal));
+
+ -- Do not produce extra actuals for Unchecked_Union parameters.
+ -- Jump directly to the end of the loop.
+
+ elsif Is_Unchecked_Union (Base_Type (Etype (Actual))) then
+ goto Skip_Extra_Actual_Generation;
+
+ else
+ -- If the actual is a type conversion, then the constrained
+ -- test applies to the actual, not the target type.
+
+ declare
+ Act_Prev : Node_Id;
+
+ begin
+ -- Test for unchecked conversions as well, which can occur
+ -- as out parameter actuals on calls to stream procedures.
+
+ Act_Prev := Prev;
+ while Nkind (Act_Prev) in N_Type_Conversion
+ | N_Unchecked_Type_Conversion
+ loop
+ Act_Prev := Expression (Act_Prev);
+ end loop;
+
+ -- If the expression is a conversion of a dereference, this
+ -- is internally generated code that manipulates addresses,
+ -- e.g. when building interface tables. No check should
+ -- occur in this case, and the discriminated object is not
+ -- directly at hand.
+
+ if not Comes_From_Source (Actual)
+ and then Nkind (Actual) = N_Unchecked_Type_Conversion
+ and then Nkind (Act_Prev) = N_Explicit_Dereference
+ then
+ Add_Extra_Actual
+ (Expr => New_Occurrence_Of (Standard_False, Loc),
+ EF => Extra_Constrained (Formal));
+
+ else
+ Add_Extra_Actual
+ (Expr =>
+ Make_Attribute_Reference (Sloc (Prev),
+ Prefix =>
+ Duplicate_Subexpr_No_Checks
+ (Act_Prev, Name_Req => True),
+ Attribute_Name => Name_Constrained),
+ EF => Extra_Constrained (Formal));
+ end if;
+ end;
+ end if;
+ end if;
+
+ -- Create possible extra actual for accessibility level
+
+ if Present (Extra_Accessibility (Formal)) then
+
+ -- Ada 2005 (AI-251): Thunks must propagate the extra actuals of
+ -- accessibility levels.
+
+ if Is_Thunk (Current_Scope) then
+ declare
+ Parm_Ent : Entity_Id;
+
+ begin
+ if Is_Controlling_Actual (Actual) then
+
+ -- Find the corresponding actual of the thunk
+
+ Parm_Ent := First_Entity (Current_Scope);
+ for J in 2 .. Param_Count loop
+ Next_Entity (Parm_Ent);
+ end loop;
+
+ -- Handle unchecked conversion of access types generated
+ -- in thunks (cf. Expand_Interface_Thunk).
+
+ elsif Is_Access_Type (Etype (Actual))
+ and then Nkind (Actual) = N_Unchecked_Type_Conversion
+ then
+ Parm_Ent := Entity (Expression (Actual));
+
+ else pragma Assert (Is_Entity_Name (Actual));
+ Parm_Ent := Entity (Actual);
+ end if;
+
+ Add_Extra_Actual
+ (Expr => Accessibility_Level
+ (Expr => Parm_Ent,
+ Level => Dynamic_Level,
+ Allow_Alt_Model => False),
+ EF => Extra_Accessibility (Formal));
+ end;
+
+ -- Conditional expressions
+
+ elsif Nkind (Prev) = N_Expression_With_Actions
+ and then Nkind (Original_Node (Prev)) in
+ N_If_Expression | N_Case_Expression
+ then
+ Add_Cond_Expression_Extra_Actual (Formal);
+
+ -- Internal constant generated to remove side effects (normally
+ -- from the expansion of dispatching calls).
+
+ -- First verify the actual is internal
+
+ elsif not Comes_From_Source (Prev)
+ and then not Is_Rewrite_Substitution (Prev)
+
+ -- Next check that the actual is a constant
+
+ and then Nkind (Prev) = N_Identifier
+ and then Ekind (Entity (Prev)) = E_Constant
+ and then Nkind (Parent (Entity (Prev))) = N_Object_Declaration
+ then
+ -- Generate the accessibility level based on the expression in
+ -- the constant's declaration.
+
+ declare
+ Ent : Entity_Id := Entity (Prev);
+
+ begin
+ -- Handle deferred constants
+
+ if Present (Full_View (Ent)) then
+ Ent := Full_View (Ent);
+ end if;
+
+ Add_Extra_Actual
+ (Expr => Accessibility_Level
+ (Expr => Expression (Parent (Ent)),
+ Level => Dynamic_Level,
+ Allow_Alt_Model => False),
+ EF => Extra_Accessibility (Formal));
+ end;
+
+ -- Normal case
+
+ else
+ Add_Extra_Actual
+ (Expr => Accessibility_Level
+ (Expr => Prev,
+ Level => Dynamic_Level,
+ Allow_Alt_Model => False),
+ EF => Extra_Accessibility (Formal));
+ end if;
+ end if;
+
+ -- This label is required when skipping extra actual generation for
+ -- Unchecked_Union parameters.
+
+ <<Skip_Extra_Actual_Generation>>
+
+ Param_Count := Param_Count + 1;
+ Next_Actual (Actual);
+ Next_Formal (Formal);
+ end loop;
+
+ -- If we are calling an Ada 2012 function which needs to have the
+ -- "accessibility level determined by the point of call" (AI05-0234)
+ -- passed in to it, then pass it in.
+
+ if Ekind (Subp) in E_Function | E_Operator | E_Subprogram_Type
+ and then
+ Present (Extra_Accessibility_Of_Result (Ultimate_Alias (Subp)))
+ then
+ declare
+ Extra_Form : Node_Id := Empty;
+ Level : Node_Id := Empty;
+
+ begin
+ -- Detect cases where the function call has been internally
+ -- generated by examining the original node and return library
+ -- level - taking care to avoid ignoring function calls expanded
+ -- in prefix notation.
+
+ if Nkind (Original_Node (Call_Node)) not in N_Function_Call
+ | N_Selected_Component
+ | N_Indexed_Component
+ then
+ Level := Make_Integer_Literal
+ (Loc, Scope_Depth (Standard_Standard));
+
+ -- Otherwise get the level normally based on the call node
+
+ else
+ Level := Accessibility_Level
+ (Expr => Call_Node,
+ Level => Dynamic_Level,
+ Allow_Alt_Model => False);
+ end if;
+
+ -- It may be possible that we are re-expanding an already
+ -- expanded call when are are dealing with dispatching ???
+
+ if No (Parameter_Associations (Call_Node))
+ or else Nkind (Last (Parameter_Associations (Call_Node)))
+ /= N_Parameter_Association
+ or else not Is_Accessibility_Actual
+ (Last (Parameter_Associations (Call_Node)))
+ then
+ Extra_Form := Extra_Accessibility_Of_Result
+ (Ultimate_Alias (Subp));
+
+ Add_Extra_Actual
+ (Expr => Level,
+ EF => Extra_Form);
+ end if;
+ end;
+ end if;
+
+ -- Second step: In the previous loop we gathered the extra actuals (the
+ -- ones that correspond to Extra_Formals), so now they can be appended.
+
+ if Is_Non_Empty_List (Extra_Actuals) then
+ declare
+ Num_Extra_Actuals : constant Nat := List_Length (Extra_Actuals);
+
+ begin
+ while Is_Non_Empty_List (Extra_Actuals) loop
+ Add_Actual_Parameter (Remove_Head (Extra_Actuals));
+ end loop;
+
+ -- Add dummy extra BIP actuals if we are calling a function that
+ -- inherited the BIP extra actuals but does not require them.
+
+ if Nkind (Call_Node) = N_Function_Call
+ and then Is_Function_Call_With_BIP_Formals (Call_Node)
+ and then not Is_Build_In_Place_Function_Call (Call_Node)
+ then
+ Add_Dummy_Build_In_Place_Actuals (Subp,
+ Num_Added_Extra_Actuals => Num_Extra_Actuals);
+ end if;
+ end;
+
+ -- Add dummy extra BIP actuals if we are calling a function that
+ -- inherited the BIP extra actuals but does not require them.
+
+ elsif Nkind (Call_Node) = N_Function_Call
+ and then Is_Function_Call_With_BIP_Formals (Call_Node)
+ and then not Is_Build_In_Place_Function_Call (Call_Node)
+ then
+ Add_Dummy_Build_In_Place_Actuals (Subp);
+ end if;
+
+ -- For non build-in-place calls formals and actuals must match;
+ -- for build-in-place function calls, the pending bip actuals are
+ -- added by the following subprograms as part of the bottom-up
+ -- expansion of the call (and this check will be performed there):
+ -- Make_Build_In_Place_Call_In_Allocator
+ -- Make_Build_In_Place_Call_In_Anonymous_Context
+ -- Make_Build_In_Place_Call_In_Assignment
+ -- Make_Build_In_Place_Call_In_Object_Declaration
+ -- Make_Build_In_Place_Iface_Call_In_Allocator
+ -- Make_Build_In_Place_Iface_Call_In_Anonymous_Context
+ -- Make_Build_In_Place_Iface_Call_In_Object_Declaration
+
+ pragma Assert (Is_Build_In_Place_Function_Call (Call_Node)
+ or else (Check_Number_Of_Actuals (Call_Node, Subp)
+ and then Check_BIP_Actuals (Call_Node, Subp)));
+ end Create_Extra_Actuals;
+
+ ------------------------
+ -- Expand_Call_Helper --
+ ------------------------
+
+ -- This procedure handles expansion of function calls and procedure call
+ -- statements (i.e. it serves as the body for Expand_N_Function_Call and
+ -- Expand_N_Procedure_Call_Statement). Processing for calls includes:
+
+ -- Replace call to Raise_Exception by Raise_Exception_Always if possible
+ -- Provide values of actuals for all formals in Extra_Formals list
+ -- Replace "call" to enumeration literal function by literal itself
+ -- Rewrite call to predefined operator as operator
+ -- Replace actuals to in-out parameters that are numeric conversions,
+ -- with explicit assignment to temporaries before and after the call.
+
+ -- Note that the list of actuals has been filled with default expressions
+ -- during semantic analysis of the call. Only the extra actuals required
+ -- for the 'Constrained attribute and for accessibility checks are added
+ -- at this point.
+
+ procedure Expand_Call_Helper (N : Node_Id; Post_Call : out List_Id) is
+ Loc : constant Source_Ptr := Sloc (N);
+ Call_Node : Node_Id := N;
+ Prev : Node_Id := Empty;
+
+ procedure Add_View_Conversion_Invariants
+ (Formal : Entity_Id;
+ Actual : Node_Id);
+ -- Adds invariant checks for every intermediate type between the range
+ -- of a view converted argument to its ancestor (from parent to child).
+
+ function Can_Fold_Predicate_Call (P : Entity_Id) return Boolean;
+ -- Try to constant-fold a predicate check, which often enough is a
+ -- simple arithmetic expression that can be computed statically if
+ -- its argument is static. This cleans up the output of CCG, even
+ -- though useless predicate checks will be generally removed by
+ -- back-end optimizations.
+
+ procedure Check_Subprogram_Variant;
+ -- Emit a call to the internally generated procedure with checks for
+ -- aspect Subprogram_Variant, if present and enabled.
+
+ function Inherited_From_Formal (S : Entity_Id) return Entity_Id;
+ -- Within an instance, a type derived from an untagged formal derived
+ -- type inherits from the original parent, not from the actual. The
+ -- current derivation mechanism has the derived type inherit from the
+ -- actual, which is only correct outside of the instance. If the
+ -- subprogram is inherited, we test for this particular case through a
+ -- convoluted tree traversal before setting the proper subprogram to be
+ -- called.
+
+ function In_Unfrozen_Instance (E : Entity_Id) return Boolean;
+ -- Return true if E comes from an instance that is not yet frozen
+
+ function Is_Class_Wide_Interface_Type (E : Entity_Id) return Boolean;
+ -- Return True when E is a class-wide interface type or an access to
+ -- a class-wide interface type.
+
+ function Is_Direct_Deep_Call (Subp : Entity_Id) return Boolean;
+ -- Determine if Subp denotes a non-dispatching call to a Deep routine
+
+ function New_Value (From : Node_Id) return Node_Id;
+ -- From is the original Expression. New_Value is equivalent to a call
+ -- to Duplicate_Subexpr with an explicit dereference when From is an
+ -- access parameter.
+
------------------------------------
-- Add_View_Conversion_Invariants --
------------------------------------
@@ -3943,6 +4559,9 @@ package body Exp_Ch6 is
Subp : Entity_Id;
CW_Interface_Formals_Present : Boolean := False;
+ Defer_Extra_Actuals : Boolean := False;
+
+ use Deferred_Extra_Formals_Support;
-- Start of processing for Expand_Call_Helper
@@ -4029,12 +4648,6 @@ package body Exp_Ch6 is
end if;
end if;
- -- Ensure that the called subprogram has all its formals
-
- if not Is_Frozen (Subp) then
- Create_Extra_Formals (Subp);
- end if;
-
-- Ada 2005 (AI-345): We have a procedure call as a triggering
-- alternative in an asynchronous select or as an entry call in
-- a conditional or timed select. Check whether the procedure call
@@ -4080,6 +4693,50 @@ package body Exp_Ch6 is
end;
end if;
+ -- Ensure that the called subprogram has all its formals; extra formals
+ -- of init procs were added when they were built.
+
+ if not Extra_Formals_Known (Subp) then
+ Create_Extra_Formals (Subp);
+
+ -- If the previous call to Create_Extra_Formals could not add the
+ -- extra formals, then we must defer adding the extra actuals of
+ -- this call until we know the underlying type of all the formals
+ -- and return type of the called subprogram or entry. Deferral of
+ -- extra actuals occurs in two cases:
+ -- 1) In the body of internally built dynamic call helpers of
+ -- class-wide preconditions.
+ -- 2) In the body of expanded expression functions.
+
+ if not Extra_Formals_Known (Subp) then
+ declare
+ Scop_Id : Entity_Id := Current_Scope;
+
+ begin
+ -- Locate the enclosing subprogram or entry since it is
+ -- required to register this deferred call.
+
+ Scop_Id := Current_Scope;
+ while Present (Scop_Id)
+ and then Scop_Id /= Standard_Standard
+ and then not Is_Subprogram_Or_Entry (Scop_Id)
+ loop
+ Scop_Id := Scope (Scop_Id);
+ end loop;
+
+ pragma Assert (Is_Subprogram_Or_Entry (Scop_Id));
+ pragma Assert (Is_Deferred_Extra_Formals_Entity (Subp));
+ Register_Deferred_Extra_Formals_Call (Call_Node, Scop_Id);
+
+ Defer_Extra_Actuals := True;
+ end;
+ end if;
+ end if;
+
+ pragma Assert (Extra_Formals_Known (Subp)
+ or else Is_Deferred_Extra_Formals_Entity (Subp)
+ or else Is_Unsupported_Extra_Formals_Entity (Subp));
+
-- If this is a call to a predicate function, try to constant fold it
if Nkind (Call_Node) = N_Function_Call
@@ -4091,56 +4748,39 @@ package body Exp_Ch6 is
end if;
-- First step, compute extra actuals, corresponding to any Extra_Formals
- -- present. Note that we do not access Extra_Formals directly, instead
+ -- present. Note that we do not access Extra_Formals directly; instead
-- we simply note the presence of the extra formals as we process the
-- regular formals collecting corresponding actuals in Extra_Actuals.
- -- We also generate any required range checks for actuals for in formals
- -- as we go through the loop, since this is a convenient place to do it.
- -- (Though it seems that this would be better done in Expand_Actuals???)
+ -- We also generate any required range checks for actuals for in-mode
+ -- formals as we go through the loop, since this is a convenient place
+ -- to do it. (Though it seems that this would be better done in
+ -- Expand_Actuals???)
-- Special case: Thunks must not compute the extra actuals; they must
- -- just propagate to the target primitive their extra actuals.
+ -- just propagate their extra actuals to the target primitive (this
+ -- propagation is performed by Create_Extra_Actuals).
if Is_Thunk (Current_Scope)
and then Thunk_Entity (Current_Scope) = Subp
+ and then Extra_Formals_Known (Subp)
and then Present (Extra_Formals (Subp))
then
- pragma Assert (Extra_Formals_Match_OK (Current_Scope, Subp));
+ Create_Extra_Actuals (N);
- declare
- Target_Formal : Entity_Id;
- Thunk_Formal : Entity_Id;
-
- begin
- Target_Formal := Extra_Formals (Subp);
- Thunk_Formal := Extra_Formals (Current_Scope);
- while Present (Target_Formal) loop
- Add_Extra_Actual
- (Expr => New_Occurrence_Of (Thunk_Formal, Loc),
- EF => Thunk_Formal);
-
- Target_Formal := Extra_Formal (Target_Formal);
- Thunk_Formal := Extra_Formal (Thunk_Formal);
- end loop;
-
- while Is_Non_Empty_List (Extra_Actuals) loop
- Add_Actual_Parameter (Remove_Head (Extra_Actuals));
- end loop;
+ -- Mark the call as an expanded build-in-place call; required
+ -- to avoid adding the extra formals twice.
- -- Mark the call as processed build-in-place call; required
- -- to avoid adding the extra formals twice.
+ if Nkind (Call_Node) = N_Function_Call then
+ Set_Is_Expanded_Build_In_Place_Call (Call_Node);
+ end if;
- if Nkind (Call_Node) = N_Function_Call then
- Set_Is_Expanded_Build_In_Place_Call (Call_Node);
- end if;
+ Expand_Actuals (Call_Node, Subp, Post_Call);
- Expand_Actuals (Call_Node, Subp, Post_Call);
- pragma Assert (Is_Empty_List (Post_Call));
- pragma Assert (Check_Number_Of_Actuals (Call_Node, Subp));
- pragma Assert (Check_BIP_Actuals (Call_Node, Subp));
- return;
- end;
+ pragma Assert (Is_Empty_List (Post_Call));
+ pragma Assert (Check_Number_Of_Actuals (Call_Node, Subp));
+ pragma Assert (Check_BIP_Actuals (Call_Node, Subp));
+ return;
end if;
Formal := First_Formal (Subp);
@@ -4158,180 +4798,6 @@ package body Exp_Ch6 is
CW_Interface_Formals_Present
or else Is_Class_Wide_Interface_Type (Etype (Formal));
- -- Create possible extra actual for constrained case. Usually, the
- -- extra actual is of the form actual'constrained, but since this
- -- attribute is only available for unconstrained records, TRUE is
- -- expanded if the type of the formal happens to be constrained (for
- -- instance when this procedure is inherited from an unconstrained
- -- record to a constrained one) or if the actual has no discriminant
- -- (its type is constrained). An exception to this is the case of a
- -- private type without discriminants. In this case we pass FALSE
- -- because the object has underlying discriminants with defaults.
-
- if Present (Extra_Constrained (Formal)) then
- if Is_Mutably_Tagged_Type (Etype (Actual))
- or else (Is_Private_Type (Etype (Prev))
- and then not Has_Discriminants
- (Base_Type (Etype (Prev))))
- then
- Add_Extra_Actual
- (Expr => New_Occurrence_Of (Standard_False, Loc),
- EF => Extra_Constrained (Formal));
-
- elsif Is_Constrained (Etype (Formal))
- or else not Has_Discriminants (Etype (Prev))
- then
- Add_Extra_Actual
- (Expr => New_Occurrence_Of (Standard_True, Loc),
- EF => Extra_Constrained (Formal));
-
- -- Do not produce extra actuals for Unchecked_Union parameters.
- -- Jump directly to the end of the loop.
-
- elsif Is_Unchecked_Union (Base_Type (Etype (Actual))) then
- goto Skip_Extra_Actual_Generation;
-
- else
- -- If the actual is a type conversion, then the constrained
- -- test applies to the actual, not the target type.
-
- declare
- Act_Prev : Node_Id;
-
- begin
- -- Test for unchecked conversions as well, which can occur
- -- as out parameter actuals on calls to stream procedures.
-
- Act_Prev := Prev;
- while Nkind (Act_Prev) in N_Type_Conversion
- | N_Unchecked_Type_Conversion
- loop
- Act_Prev := Expression (Act_Prev);
- end loop;
-
- -- If the expression is a conversion of a dereference, this
- -- is internally generated code that manipulates addresses,
- -- e.g. when building interface tables. No check should
- -- occur in this case, and the discriminated object is not
- -- directly at hand.
-
- if not Comes_From_Source (Actual)
- and then Nkind (Actual) = N_Unchecked_Type_Conversion
- and then Nkind (Act_Prev) = N_Explicit_Dereference
- then
- Add_Extra_Actual
- (Expr => New_Occurrence_Of (Standard_False, Loc),
- EF => Extra_Constrained (Formal));
-
- else
- Add_Extra_Actual
- (Expr =>
- Make_Attribute_Reference (Sloc (Prev),
- Prefix =>
- Duplicate_Subexpr_No_Checks
- (Act_Prev, Name_Req => True),
- Attribute_Name => Name_Constrained),
- EF => Extra_Constrained (Formal));
- end if;
- end;
- end if;
- end if;
-
- -- Create possible extra actual for accessibility level
-
- if Present (Extra_Accessibility (Formal)) then
- -- Ada 2005 (AI-251): Thunks must propagate the extra actuals of
- -- accessibility levels.
-
- if Is_Thunk (Current_Scope) then
- declare
- Parm_Ent : Entity_Id;
-
- begin
- if Is_Controlling_Actual (Actual) then
-
- -- Find the corresponding actual of the thunk
-
- Parm_Ent := First_Entity (Current_Scope);
- for J in 2 .. Param_Count loop
- Next_Entity (Parm_Ent);
- end loop;
-
- -- Handle unchecked conversion of access types generated
- -- in thunks (cf. Expand_Interface_Thunk).
-
- elsif Is_Access_Type (Etype (Actual))
- and then Nkind (Actual) = N_Unchecked_Type_Conversion
- then
- Parm_Ent := Entity (Expression (Actual));
-
- else pragma Assert (Is_Entity_Name (Actual));
- Parm_Ent := Entity (Actual);
- end if;
-
- Add_Extra_Actual
- (Expr => Accessibility_Level
- (Expr => Parm_Ent,
- Level => Dynamic_Level,
- Allow_Alt_Model => False),
- EF => Extra_Accessibility (Formal));
- end;
-
- -- Conditional expressions
-
- elsif Nkind (Prev) = N_Expression_With_Actions
- and then Nkind (Original_Node (Prev)) in
- N_If_Expression | N_Case_Expression
- then
- Add_Cond_Expression_Extra_Actual (Formal);
-
- -- Internal constant generated to remove side effects (normally
- -- from the expansion of dispatching calls).
-
- -- First verify the actual is internal
-
- elsif not Comes_From_Source (Prev)
- and then not Is_Rewrite_Substitution (Prev)
-
- -- Next check that the actual is a constant
-
- and then Nkind (Prev) = N_Identifier
- and then Ekind (Entity (Prev)) = E_Constant
- and then Nkind (Parent (Entity (Prev))) = N_Object_Declaration
- then
- -- Generate the accessibility level based on the expression in
- -- the constant's declaration.
-
- declare
- Ent : Entity_Id := Entity (Prev);
-
- begin
- -- Handle deferred constants
-
- if Present (Full_View (Ent)) then
- Ent := Full_View (Ent);
- end if;
-
- Add_Extra_Actual
- (Expr => Accessibility_Level
- (Expr => Expression (Parent (Ent)),
- Level => Dynamic_Level,
- Allow_Alt_Model => False),
- EF => Extra_Accessibility (Formal));
- end;
-
- -- Normal case
-
- else
- Add_Extra_Actual
- (Expr => Accessibility_Level
- (Expr => Prev,
- Level => Dynamic_Level,
- Allow_Alt_Model => False),
- EF => Extra_Accessibility (Formal));
- end if;
- end if;
-
-- Perform the check of 4.6(49) that prevents a null value from being
-- passed as an actual to an access parameter. Note that the check
-- is elided in the common cases of passing an access attribute or
@@ -4525,66 +4991,11 @@ package body Exp_Ch6 is
-- This label is required when skipping extra actual generation for
-- Unchecked_Union parameters.
- <<Skip_Extra_Actual_Generation>>
-
Param_Count := Param_Count + 1;
Next_Actual (Actual);
Next_Formal (Formal);
end loop;
- -- If we are calling an Ada 2012 function which needs to have the
- -- "accessibility level determined by the point of call" (AI05-0234)
- -- passed in to it, then pass it in.
-
- if Ekind (Subp) in E_Function | E_Operator | E_Subprogram_Type
- and then
- Present (Extra_Accessibility_Of_Result (Ultimate_Alias (Subp)))
- then
- declare
- Extra_Form : Node_Id := Empty;
- Level : Node_Id := Empty;
-
- begin
- -- Detect cases where the function call has been internally
- -- generated by examining the original node and return library
- -- level - taking care to avoid ignoring function calls expanded
- -- in prefix notation.
-
- if Nkind (Original_Node (Call_Node)) not in N_Function_Call
- | N_Selected_Component
- | N_Indexed_Component
- then
- Level := Make_Integer_Literal
- (Loc, Scope_Depth (Standard_Standard));
-
- -- Otherwise get the level normally based on the call node
-
- else
- Level := Accessibility_Level
- (Expr => Call_Node,
- Level => Dynamic_Level,
- Allow_Alt_Model => False);
- end if;
-
- -- It may be possible that we are re-expanding an already
- -- expanded call when are are dealing with dispatching ???
-
- if No (Parameter_Associations (Call_Node))
- or else Nkind (Last (Parameter_Associations (Call_Node)))
- /= N_Parameter_Association
- or else not Is_Accessibility_Actual
- (Last (Parameter_Associations (Call_Node)))
- then
- Extra_Form := Extra_Accessibility_Of_Result
- (Ultimate_Alias (Subp));
-
- Add_Extra_Actual
- (Expr => Level,
- EF => Extra_Form);
- end if;
- end;
- end if;
-
-- If we are expanding the RHS of an assignment we need to check if tag
-- propagation is needed. You might expect this processing to be in
-- Analyze_Assignment but has to be done earlier (bottom-up) because the
@@ -4597,27 +5008,34 @@ package body Exp_Ch6 is
then
declare
Ass : Node_Id := Empty;
+ Par : Node_Id := Parent (Call_Node);
begin
- if Nkind (Parent (Call_Node)) = N_Assignment_Statement then
- Ass := Parent (Call_Node);
+ -- Search for the LHS of an enclosing assignment statement to a
+ -- classwide type object (if present) and propagate the tag to
+ -- this function call.
+
+ while Nkind (Par) in N_Case_Expression
+ | N_Case_Expression_Alternative
+ | N_Explicit_Dereference
+ | N_If_Expression
+ | N_Qualified_Expression
+ | N_Unchecked_Type_Conversion
+ loop
+ if Nkind (Par) = N_Case_Expression_Alternative then
+ Par := Parent (Par);
+ end if;
- elsif Nkind (Parent (Call_Node)) = N_Qualified_Expression
- and then Nkind (Parent (Parent (Call_Node))) =
- N_Assignment_Statement
- then
- Ass := Parent (Parent (Call_Node));
+ exit when not Is_Tag_Indeterminate (Par);
- elsif Nkind (Parent (Call_Node)) = N_Explicit_Dereference
- and then Nkind (Parent (Parent (Call_Node))) =
- N_Assignment_Statement
- then
- Ass := Parent (Parent (Call_Node));
- end if;
+ Par := Parent (Par);
+ end loop;
- if Present (Ass)
- and then Is_Class_Wide_Type (Etype (Name (Ass)))
+ if Nkind (Par) = N_Assignment_Statement
+ and then Is_Class_Wide_Type (Etype (Name (Par)))
then
+ Ass := Par;
+
-- Move the error messages below to sem???
if Is_Access_Type (Etype (Call_Node)) then
@@ -4630,6 +5048,12 @@ package body Exp_Ch6 is
Call_Node, Root_Type (Etype (Name (Ass))));
else
Propagate_Tag (Name (Ass), Call_Node);
+
+ -- Remember that the tag has been propagated to avoid
+ -- propagating it again, as part of the (bottom-up)
+ -- analysis of the enclosing assignment.
+
+ Set_Tag_Propagated (Name (Ass));
end if;
elsif Etype (Call_Node) /= Root_Type (Etype (Name (Ass))) then
@@ -4640,6 +5064,12 @@ package body Exp_Ch6 is
else
Propagate_Tag (Name (Ass), Call_Node);
+
+ -- Remember that the tag has been propagated to avoid
+ -- propagating it again, as part of the (bottom-up)
+ -- analysis of the enclosing assignment.
+
+ Set_Tag_Propagated (Name (Ass));
end if;
-- The call will be rewritten as a dispatching call, and
@@ -4778,38 +5208,12 @@ package body Exp_Ch6 is
then
null;
- -- During that loop we gathered the extra actuals (the ones that
- -- correspond to Extra_Formals), so now they can be appended.
-
- elsif Is_Non_Empty_List (Extra_Actuals) then
- declare
- Num_Extra_Actuals : constant Nat := List_Length (Extra_Actuals);
-
- begin
- while Is_Non_Empty_List (Extra_Actuals) loop
- Add_Actual_Parameter (Remove_Head (Extra_Actuals));
- end loop;
-
- -- Add dummy extra BIP actuals if we are calling a function that
- -- inherited the BIP extra actuals but does not require them.
-
- if Nkind (Call_Node) = N_Function_Call
- and then Is_Function_Call_With_BIP_Formals (Call_Node)
- and then not Is_Build_In_Place_Function_Call (Call_Node)
- then
- Add_Dummy_Build_In_Place_Actuals (Subp,
- Num_Added_Extra_Actuals => Num_Extra_Actuals);
- end if;
- end;
-
- -- Add dummy extra BIP actuals if we are calling a function that
- -- inherited the BIP extra actuals but does not require them.
+ elsif not Defer_Extra_Actuals then
+ Create_Extra_Formals (Subp);
- elsif Nkind (Call_Node) = N_Function_Call
- and then Is_Function_Call_With_BIP_Formals (Call_Node)
- and then not Is_Build_In_Place_Function_Call (Call_Node)
- then
- Add_Dummy_Build_In_Place_Actuals (Subp);
+ if Extra_Formals_Known (Subp) then
+ Create_Extra_Actuals (N);
+ end if;
end if;
-- At this point we have all the actuals, so this is the point at which
@@ -5227,6 +5631,10 @@ package body Exp_Ch6 is
-- also Build_Renamed_Body) cannot be expanded here because this may
-- give rise to order-of-elaboration issues for the types of the
-- parameters of the subprogram, if any.
+ --
+ -- Expand_Inlined_Call procedure does not support the frontend
+ -- inlining of calls that return unconstrained types used as actuals
+ -- or in return statements.
elsif Present (Unit_Declaration_Node (Subp))
and then Nkind (Unit_Declaration_Node (Subp)) =
@@ -5235,6 +5643,8 @@ package body Exp_Ch6 is
and then
Nkind (Body_To_Inline (Unit_Declaration_Node (Subp))) not in
N_Entity
+ and then Nkind (Parent (N)) /= N_Function_Call
+ and then Nkind (Parent (N)) /= N_Simple_Return_Statement
then
Expand_Inlined_Call (Call_Node, Subp, Orig_Subp);
@@ -7159,6 +7569,16 @@ package body Exp_Ch6 is
then
Apply_CW_Accessibility_Check (Exp, Scope_Id);
+ -- Check that result's access discrims (if any) do not designate
+ -- entities that the function result could outlive. See preceding
+ -- comment about extended return statements and thunks.
+
+ elsif Has_Anonymous_Access_Discriminant (Exp_Typ)
+ and then not Comes_From_Extended_Return_Statement (N)
+ and then not Is_Thunk (Scope_Id)
+ then
+ Apply_Access_Discrims_Accessibility_Check (Exp, Scope_Id);
+
-- Ada 2012 (AI05-0073): If the result subtype of the function is
-- defined by an access_definition designating a specific tagged
-- type T, a check is made that the result value is null or the tag
@@ -8557,6 +8977,8 @@ package body Exp_Ch6 is
Rewrite (Allocator, New_Occurrence_Of (Return_Obj_Access, Loc));
Analyze_And_Resolve (Allocator, Acc_Type);
+
+ pragma Assert (Returns_By_Ref (Function_Id));
pragma Assert (Check_Number_Of_Actuals (Func_Call, Function_Id));
pragma Assert (Check_BIP_Actuals (Func_Call, Function_Id));
end Make_Build_In_Place_Call_In_Allocator;
@@ -8662,6 +9084,7 @@ package body Exp_Ch6 is
Set_Is_Expanded_Build_In_Place_Call (Func_Call);
+ pragma Assert (Returns_By_Ref (Function_Id));
pragma Assert (Check_Number_Of_Actuals (Func_Call, Function_Id));
pragma Assert (Check_BIP_Actuals (Func_Call, Function_Id));
end if;
@@ -8763,6 +9186,8 @@ package body Exp_Ch6 is
Insert_After_And_Analyze (Ptr_Typ_Decl, Obj_Decl);
Rewrite (Assign, Make_Null_Statement (Loc));
+
+ pragma Assert (Returns_By_Ref (Func_Id));
pragma Assert (Check_Number_Of_Actuals (Func_Call, Func_Id));
pragma Assert (Check_BIP_Actuals (Func_Call, Func_Id));
end Make_Build_In_Place_Call_In_Assignment;
@@ -9187,6 +9612,7 @@ package body Exp_Ch6 is
end if;
end if;
+ pragma Assert (Returns_By_Ref (Function_Id));
pragma Assert (Check_Number_Of_Actuals (Func_Call, Function_Id));
pragma Assert (Check_BIP_Actuals (Func_Call, Function_Id));
end Make_Build_In_Place_Call_In_Object_Declaration;
@@ -9824,35 +10250,16 @@ package body Exp_Ch6 is
=>
declare
Call_Node : Node_Id renames Nod;
- Subp : Entity_Id;
+ Subp : constant Entity_Id := Get_Called_Entity (Nod);
begin
- -- Call using access to subprogram with explicit dereference
-
- if Nkind (Name (Call_Node)) = N_Explicit_Dereference then
- Subp := Etype (Name (Call_Node));
-
- -- Prefix notation calls
-
- elsif Nkind (Name (Call_Node)) = N_Selected_Component then
- Subp := Entity (Selector_Name (Name (Call_Node)));
-
- -- Call to member of entry family, where Name is an indexed
- -- component, with the prefix being a selected component
- -- giving the task and entry family name, and the index
- -- being the entry index.
-
- elsif Nkind (Name (Call_Node)) = N_Indexed_Component then
- Subp :=
- Entity (Selector_Name (Prefix (Name (Call_Node))));
+ pragma Assert (Check_BIP_Actuals (Call_Node, Subp));
- -- Normal case
+ -- Build-in-place function calls return their result by
+ -- reference.
- else
- Subp := Entity (Name (Call_Node));
- end if;
-
- pragma Assert (Check_BIP_Actuals (Call_Node, Subp));
+ pragma Assert (not Is_Build_In_Place_Function (Subp)
+ or else Returns_By_Ref (Subp));
end;
-- Skip generic bodies
diff --git a/gcc/ada/exp_ch6.ads b/gcc/ada/exp_ch6.ads
index 118d994..5919627 100644
--- a/gcc/ada/exp_ch6.ads
+++ b/gcc/ada/exp_ch6.ads
@@ -101,7 +101,20 @@ package Exp_Ch6 is
-- Adds Extra_Actual as a named parameter association for the formal
-- Extra_Formal in Subprogram_Call.
+ procedure Create_Extra_Actuals (Call_Node : Node_Id);
+ -- Create the extra actuals of the given call and add them to its
+ -- actual parameters list.
+
+ procedure Apply_Access_Discrims_Accessibility_Check
+ (Exp : Node_Id; Func : Entity_Id);
+ -- Exp is an expression being returned from a function Func.
+ -- If the result type of the function has access discriminants, insert
+ -- checks that the accessibility level of each entity designated by an
+ -- access discriminant of the result is not deeper than the level of the
+ -- master of the call.
+
procedure Apply_CW_Accessibility_Check (Exp : Node_Id; Func : Entity_Id);
+ -- Exp is an expression being returned from a function Func.
-- 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
diff --git a/gcc/ada/exp_ch7.adb b/gcc/ada/exp_ch7.adb
index 009bee4..dd864b7 100644
--- a/gcc/ada/exp_ch7.adb
+++ b/gcc/ada/exp_ch7.adb
@@ -59,6 +59,7 @@ with Sinfo.Nodes; use Sinfo.Nodes;
with Sinfo.Utils; use Sinfo.Utils;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
+with Sem_Ch6; use Sem_Ch6;
with Sem_Ch7; use Sem_Ch7;
with Sem_Ch8; use Sem_Ch8;
with Sem_Res; use Sem_Res;
@@ -2331,6 +2332,8 @@ package body Exp_Ch7 is
Ensure_Freeze_Node (Fin_Id);
Insert_After (Fin_Spec, Freeze_Node (Fin_Id));
+ Mutate_Ekind (Fin_Id, E_Procedure);
+ Freeze_Extra_Formals (Fin_Id);
Set_Is_Frozen (Fin_Id);
Append_To (Stmts, Fin_Body);
@@ -3586,18 +3589,22 @@ package body Exp_Ch7 is
procedure Build_Record_Deep_Procs (Typ : Entity_Id) is
begin
- Set_TSS (Typ,
- Make_Deep_Proc
- (Prim => Initialize_Case,
- Typ => Typ,
- Stmts => Make_Deep_Record_Body (Initialize_Case, Typ)));
-
- if not Is_Inherently_Limited_Type (Typ) then
- Set_TSS (Typ,
- Make_Deep_Proc
- (Prim => Adjust_Case,
- Typ => Typ,
- Stmts => Make_Deep_Record_Body (Adjust_Case, Typ)));
+ if Has_Controlled_Component (Typ) then
+ Set_TSS
+ (Typ,
+ Make_Deep_Proc
+ (Prim => Initialize_Case,
+ Typ => Typ,
+ Stmts => Make_Deep_Record_Body (Initialize_Case, Typ)));
+
+ if not Is_Inherently_Limited_Type (Typ) then
+ Set_TSS
+ (Typ,
+ Make_Deep_Proc
+ (Prim => Adjust_Case,
+ Typ => Typ,
+ Stmts => Make_Deep_Record_Body (Adjust_Case, Typ)));
+ end if;
end if;
-- Do not generate Deep_Finalize and Finalize_Address if finalization is
@@ -5598,7 +5605,10 @@ package body Exp_Ch7 is
-- Deal with untagged derivation of private views
- if Present (Utyp) and then Is_Untagged_Derivation (Typ) then
+ if Present (Utyp)
+ and then Is_Untagged_Derivation (Typ)
+ and then Is_Implicit_Full_View (Utyp)
+ then
Utyp := Underlying_Type (Root_Type (Base_Type (Typ)));
Ref := Unchecked_Convert_To (Utyp, Ref);
Set_Assignment_OK (Ref);
@@ -6635,6 +6645,16 @@ package body Exp_Ch7 is
-- Raised : Boolean := False;
--
-- begin
+ -- begin
+ -- <Destructor_Proc> (V); -- If applicable
+ -- exception
+ -- when others =>
+ -- if not Raised then
+ -- Raised := True;
+ -- Save_Occurrence (E, Get_Current_Excep.all.all);
+ -- end if;
+ -- end;
+ --
-- if F then
-- begin
-- Finalize (V); -- If applicable
@@ -6690,6 +6710,8 @@ package body Exp_Ch7 is
--
-- begin
-- Deep_Finalize (V._parent, False); -- If applicable
+ -- or
+ -- Deep_Finalize (Parent_Type (V), False); -- Untagged case
-- exception
-- when Id : others =>
-- if not Raised then
@@ -7094,7 +7116,7 @@ package body Exp_Ch7 is
-- or the type is not controlled.
if Is_Empty_List (Bod_Stmts) then
- Append_To (Bod_Stmts, Make_Null_Statement (Loc));
+ Append_New_To (Bod_Stmts, Make_Null_Statement (Loc));
return Bod_Stmts;
@@ -7581,9 +7603,13 @@ package body Exp_Ch7 is
-- Deep_Finalize (Obj._parent, False);
- if Is_Tagged_Type (Typ) and then Is_Derived_Type (Typ) then
+ if Is_Derived_Type (Typ) then
declare
- Par_Typ : constant Entity_Id := Parent_Field_Type (Typ);
+ Tagd : constant Boolean := Is_Tagged_Type (Typ);
+ Par_Typ : constant Entity_Id :=
+ (if Tagd
+ then Parent_Field_Type (Typ)
+ else Etype (Base_Type (Typ)));
Call : Node_Id;
Fin_Stmt : Node_Id;
@@ -7592,10 +7618,16 @@ package body Exp_Ch7 is
Call :=
Make_Final_Call
(Obj_Ref =>
- Make_Selected_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Selector_Name =>
- Make_Identifier (Loc, Name_uParent)),
+ (if Tagd
+ then
+ Make_Selected_Component
+ (Loc,
+ Prefix => Make_Identifier (Loc, Name_V),
+ Selector_Name =>
+ Make_Identifier (Loc, Name_uParent))
+ else
+ Convert_To
+ (Par_Typ, Make_Identifier (Loc, Name_V))),
Typ => Par_Typ,
Skip_Self => True);
@@ -7611,6 +7643,21 @@ package body Exp_Ch7 is
-- Get_Current_Excep.all.all);
-- end if;
-- end;
+ --
+ -- in the tagged case. In the untagged case, which arises
+ -- with the Destructor aspect, generate:
+ --
+ -- begin
+ -- Deep_Finalize (Parent_Type (V), False);
+
+ -- exception
+ -- when Id : others =>
+ -- if not Raised then
+ -- Raised := True;
+ -- Save_Occurrence (E,
+ -- Get_Current_Excep.all.all);
+ -- end if;
+ -- end;
if Present (Call) then
Fin_Stmt := Call;
@@ -7656,7 +7703,7 @@ package body Exp_Ch7 is
-- than before, the extension components. That might
-- be more intuitive (as discussed in preceding
-- comment), but it is not required.
- Prepend_To (Bod_Stmts, Fin_Stmt);
+ Prepend_New_To (Bod_Stmts, Fin_Stmt);
end if;
end if;
end if;
@@ -7707,12 +7754,58 @@ package body Exp_Ch7 is
(Finalizer_Data))));
end if;
- Prepend_To (Bod_Stmts,
+ Prepend_New_To (Bod_Stmts,
Make_If_Statement (Loc,
Condition => Make_Identifier (Loc, Name_F),
Then_Statements => New_List (Fin_Stmt)));
end if;
end;
+
+ declare
+ ASN : constant Opt_N_Aspect_Specification_Id :=
+ Get_Rep_Item (Typ, Name_Destructor, False);
+
+ Stmt : Node_Id;
+ Proc : Entity_Id;
+ begin
+ if Present (ASN) then
+ -- Generate:
+ -- begin
+ -- <Destructor_Proc> (V);
+
+ -- exception
+ -- when others =>
+ -- if not Raised then
+ -- Raised := True;
+ -- Save_Occurrence (E,
+ -- Get_Current_Excep.all.all);
+ -- end if;
+ -- end;
+
+ Proc := Entity (Expression (ASN));
+ Stmt :=
+ Make_Procedure_Call_Statement
+ (Loc,
+ Name => New_Occurrence_Of (Proc, Loc),
+ Parameter_Associations =>
+ New_List (Make_Identifier (Loc, Name_V)));
+ if Exceptions_OK then
+ Stmt :=
+ Make_Block_Statement
+ (Loc,
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements
+ (Loc,
+ Statements => New_List (Stmt),
+ Exception_Handlers =>
+ New_List
+ (Build_Exception_Handler
+ (Finalizer_Data))));
+ end if;
+
+ Prepend_New_To (Bod_Stmts, Stmt);
+ end if;
+ end;
end if;
-- At this point either all finalization statements have been
@@ -7906,16 +7999,12 @@ package body Exp_Ch7 is
if Is_Untagged_Derivation (Typ) then
if Is_Protected_Type (Typ) then
Utyp := Corresponding_Record_Type (Root_Type (Base_Type (Typ)));
+ elsif Is_Implicit_Full_View (Utyp) then
+ Utyp := Underlying_Type (Root_Type (Base_Type (Typ)));
- else
- declare
- Root : constant Entity_Id :=
- Underlying_Type (Root_Type (Base_Type (Typ)));
- begin
- if Is_Protected_Type (Root) then
- Utyp := Corresponding_Record_Type (Root);
- end if;
- end;
+ if Is_Protected_Type (Utyp) then
+ Utyp := Corresponding_Record_Type (Utyp);
+ end if;
end if;
Ref := Unchecked_Convert_To (Utyp, Ref);
@@ -7970,7 +8059,7 @@ package body Exp_Ch7 is
return Empty;
elsif Skip_Self then
- if Has_Controlled_Component (Utyp) then
+ if Has_Controlled_Component (Utyp) or else Has_Destructor (Utyp) then
if Is_Tagged_Type (Utyp) then
Fin_Id := Find_Optional_Prim_Op (Utyp, TSS_Deep_Finalize);
else
@@ -7983,6 +8072,7 @@ package body Exp_Ch7 is
elsif Is_Class_Wide_Type (Typ)
or else Is_Interface (Typ)
or else Has_Controlled_Component (Utyp)
+ or else Has_Destructor (Utyp)
then
if Is_Tagged_Type (Utyp) then
Fin_Id := Find_Optional_Prim_Op (Utyp, TSS_Deep_Finalize);
@@ -8480,7 +8570,10 @@ package body Exp_Ch7 is
-- Deal with untagged derivation of private views
- if Is_Untagged_Derivation (Typ) and then not Is_Conc then
+ if Is_Untagged_Derivation (Typ)
+ and then not Is_Conc
+ and then Is_Implicit_Full_View (Utyp)
+ then
Utyp := Underlying_Type (Root_Type (Base_Type (Typ)));
Ref := Unchecked_Convert_To (Utyp, Ref);
@@ -9448,9 +9541,16 @@ package body Exp_Ch7 is
procedure Wrap_Transient_Expression (N : Node_Id) is
Loc : constant Source_Ptr := Sloc (N);
Expr : Node_Id := Relocate_Node (N);
- Temp : constant Entity_Id := Make_Temporary (Loc, 'E', N);
Typ : constant Entity_Id := Etype (N);
+ Temp : constant Entity_Id := Make_Temporary (Loc, 'E',
+ Related_Node => Expr);
+ -- We link the temporary with its relocated expression to facilitate
+ -- locating the expression in the expanded code; this simplifies the
+ -- implementation of the function that searchs in the expanded code
+ -- for a function call that has been wrapped in a transient block
+ -- (see Get_Relocated_Function_Call).
+
begin
-- Generate:
diff --git a/gcc/ada/exp_ch9.adb b/gcc/ada/exp_ch9.adb
index 9cfc6b5..c979cf6 100644
--- a/gcc/ada/exp_ch9.adb
+++ b/gcc/ada/exp_ch9.adb
@@ -4691,11 +4691,11 @@ package body Exp_Ch9 is
-- The availability of the activation chain entity does not ensure
-- that we have tasks to activate because it may have been declared
- -- by the frontend to pass a required extra formal to a build-in-place
+ -- by the front end to pass a required extra formal to a build-in-place
-- subprogram call. If we are within the scope of a protected type and
-- pragma Detect_Blocking is active we can assume that no tasks will be
-- activated; if tasks are created in a protected object and this pragma
- -- is active then the frontend emits a warning and Program_Error is
+ -- is active then the front end emits a warning and Program_Error is
-- raised at runtime.
elsif Detect_Blocking and then Within_Protected_Type (Current_Scope) then
@@ -8094,12 +8094,18 @@ package body Exp_Ch9 is
-- access type. Finally the Entry_Component of each formal is set to
-- reference the corresponding record component.
- procedure Expand_N_Entry_Declaration (N : Node_Id) is
+ procedure Expand_N_Entry_Declaration
+ (N : Node_Id;
+ Was_Deferred : Boolean := False)
+ is
+ use Deferred_Extra_Formals_Support;
+
Loc : constant Source_Ptr := Sloc (N);
Entry_Ent : constant Entity_Id := Defining_Identifier (N);
Components : List_Id;
Formal : Node_Id;
Ftype : Entity_Id;
+ First_Decl : Node_Id;
Last_Decl : Node_Id;
Component : Entity_Id;
Ctype : Entity_Id;
@@ -8108,7 +8114,21 @@ package body Exp_Ch9 is
Acc_Ent : Entity_Id;
begin
+ -- No action if the addition of the extra formals was deferred,
+ -- since it means that the underlying type of some formal is not
+ -- available, and hence we cannot build the record type that will
+ -- hold all the parameter values.
+
+ if Present (First_Formal (Entry_Ent))
+ and then not Extra_Formals_Known (Entry_Ent)
+ and then not Is_Unsupported_Extra_Formals_Entity (Entry_Ent)
+ then
+ pragma Assert (Is_Deferred_Extra_Formals_Entity (Entry_Ent));
+ return;
+ end if;
+
Formal := First_Formal (Entry_Ent);
+ First_Decl := N;
Last_Decl := N;
-- Most processing is done only if parameters are present
@@ -8184,6 +8204,24 @@ package body Exp_Ch9 is
Subtype_Indication => New_Occurrence_Of (Rec_Ent, Loc)));
Insert_After (Last_Decl, Decl);
+ Last_Decl := Decl;
+
+ -- Analyze all the inserted declarations. This is required when
+ -- the entry has formals and the addition of its extra formals
+ -- was deferred; otherwise their analysis will be performed as
+ -- as part of the regular flow of the front end at the end of
+ -- analysis of the enclosing task/protected type declaration.
+
+ if Was_Deferred then
+ Push_Scope (Scope (Entry_Ent));
+
+ while First_Decl /= Last_Decl loop
+ Next (First_Decl);
+ Analyze (First_Decl);
+ end loop;
+
+ End_Scope;
+ end if;
end if;
end Expand_N_Entry_Declaration;
diff --git a/gcc/ada/exp_ch9.ads b/gcc/ada/exp_ch9.ads
index cae6cb3..6811141 100644
--- a/gcc/ada/exp_ch9.ads
+++ b/gcc/ada/exp_ch9.ads
@@ -227,9 +227,16 @@ package Exp_Ch9 is
procedure Expand_N_Delay_Until_Statement (N : Node_Id);
procedure Expand_N_Entry_Body (N : Node_Id);
procedure Expand_N_Entry_Call_Statement (N : Node_Id);
- procedure Expand_N_Entry_Declaration (N : Node_Id);
procedure Expand_N_Protected_Body (N : Node_Id);
+ procedure Expand_N_Entry_Declaration
+ (N : Node_Id;
+ Was_Deferred : Boolean := False);
+ -- Expands an entry declaration, building a record type to hold all the
+ -- parameter values. Was_Deferred is True when this expansion was deferred
+ -- because the underlying type of some formal was not available to build
+ -- the record.
+
procedure Expand_N_Protected_Type_Declaration (N : Node_Id);
-- Expands protected type declarations. This results, among other things,
-- in the declaration of a record type for the representation of protected
diff --git a/gcc/ada/exp_disp.adb b/gcc/ada/exp_disp.adb
index 080a2e1..619ac40 100644
--- a/gcc/ada/exp_disp.adb
+++ b/gcc/ada/exp_disp.adb
@@ -801,7 +801,7 @@ package body Exp_Disp is
-- No action needed if the dispatching call has been already expanded
- or else Is_Expanded_Dispatching_Call (Name (Call_Node))
+ or else Is_Expanded_Dispatching_Call (Call_Node)
then
return;
end if;
@@ -926,6 +926,8 @@ package body Exp_Disp is
New_Formal : Entity_Id;
Last_Formal : Entity_Id := Empty;
+ use Deferred_Extra_Formals_Support;
+
begin
if Present (Old_Formal) then
New_Formal := New_Copy (Old_Formal);
@@ -962,51 +964,21 @@ package body Exp_Disp is
end if;
-- Now that the explicit formals have been duplicated, any extra
- -- formals needed by the subprogram must be duplicated; we know
- -- that extra formals are available because they were added when
- -- the tagged type was frozen (see Expand_Freeze_Record_Type).
+ -- formals needed by the subprogram must be added; we know that
+ -- extra formals are available because they were added when the
+ -- tagged type was frozen (see Expand_Freeze_Record_Type).
pragma Assert (Is_Frozen (Typ));
- -- Warning: The addition of the extra formals cannot be performed
- -- here invoking Create_Extra_Formals since we must ensure that all
- -- the extra formals of the pointer type and the target subprogram
- -- match (and for functions that return a tagged type the profile of
- -- the built subprogram type always returns a class-wide type, which
- -- may affect the addition of some extra formals).
-
- if Present (Last_Formal)
- and then Present (Extra_Formal (Last_Formal))
- then
- Old_Formal := Extra_Formal (Last_Formal);
- New_Formal := New_Copy (Old_Formal);
- Set_Scope (New_Formal, Subp_Typ);
-
- Set_Extra_Formal (Last_Formal, New_Formal);
- Set_Extra_Formals (Subp_Typ, New_Formal);
-
- if Ekind (Subp) = E_Function
- and then Present (Extra_Accessibility_Of_Result (Subp))
- and then Extra_Accessibility_Of_Result (Subp) = Old_Formal
- then
- Set_Extra_Accessibility_Of_Result (Subp_Typ, New_Formal);
- end if;
-
- Old_Formal := Extra_Formal (Old_Formal);
- while Present (Old_Formal) loop
- Set_Extra_Formal (New_Formal, New_Copy (Old_Formal));
- New_Formal := Extra_Formal (New_Formal);
- Set_Scope (New_Formal, Subp_Typ);
+ if Extra_Formals_Known (Subp) then
+ Create_Extra_Formals (Subp_Typ);
- if Ekind (Subp) = E_Function
- and then Present (Extra_Accessibility_Of_Result (Subp))
- and then Extra_Accessibility_Of_Result (Subp) = Old_Formal
- then
- Set_Extra_Accessibility_Of_Result (Subp_Typ, New_Formal);
- end if;
+ -- Extra formals were previously deferred
- Old_Formal := Extra_Formal (Old_Formal);
- end loop;
+ else
+ pragma Assert (Is_Deferred_Extra_Formals_Entity (Subp));
+ Register_Deferred_Extra_Formals_Entity (Subp_Typ);
+ Register_Deferred_Extra_Formals_Call (Call_Node, Current_Scope);
end if;
end;
@@ -1237,6 +1209,8 @@ package body Exp_Disp is
-- the generation of spurious warnings under ZFP run-time.
Analyze_And_Resolve (Call_Node, Call_Typ, Suppress => All_Checks);
+
+ Set_Is_Expanded_Dispatching_Call (Call_Node);
end Expand_Dispatching_Call;
---------------------------------
@@ -2378,17 +2352,6 @@ package body Exp_Disp is
and then not Restriction_Active (No_Dispatching_Calls);
end Has_DT;
- ----------------------------------
- -- Is_Expanded_Dispatching_Call --
- ----------------------------------
-
- function Is_Expanded_Dispatching_Call (N : Node_Id) return Boolean is
- begin
- return Nkind (N) in N_Subprogram_Call
- and then Nkind (Name (N)) = N_Explicit_Dereference
- and then Is_Dispatch_Table_Entity (Etype (Name (N)));
- end Is_Expanded_Dispatching_Call;
-
-------------------------------------
-- Is_Predefined_Dispatching_Alias --
-------------------------------------
@@ -8345,13 +8308,15 @@ package body Exp_Disp is
Defining_Unit_Name => IP,
Parameter_Specifications => Parms)));
- Set_Init_Proc (Typ, IP);
- Set_Is_Imported (IP);
- Set_Is_Constructor (IP);
- Set_Interface_Name (IP, Interface_Name (E));
- Set_Convention (IP, Convention_CPP);
- Set_Is_Public (IP);
- Set_Has_Completion (IP);
+ Set_Init_Proc (Typ, IP);
+ Set_Is_Imported (IP);
+ Set_Is_Constructor (IP);
+ Set_Interface_Name (IP, Interface_Name (E));
+ Set_Convention (IP, Convention_CPP);
+ Set_Is_Public (IP);
+ Set_Has_Completion (IP);
+ Mutate_Ekind (IP, E_Procedure);
+ Freeze_Extra_Formals (IP);
-- Case 2: Constructor of a tagged type
@@ -8484,6 +8449,8 @@ package body Exp_Disp is
Discard_Node (IP_Body);
Set_Init_Proc (Typ, IP);
+ Mutate_Ekind (IP, E_Procedure);
+ Freeze_Extra_Formals (IP);
end;
end if;
@@ -8549,6 +8516,8 @@ package body Exp_Disp is
Discard_Node (IP_Body);
Set_Init_Proc (Typ, IP);
+ Mutate_Ekind (IP, E_Procedure);
+ Freeze_Extra_Formals (IP);
end;
end if;
diff --git a/gcc/ada/exp_disp.ads b/gcc/ada/exp_disp.ads
index 3cba8ca..76f5923 100644
--- a/gcc/ada/exp_disp.ads
+++ b/gcc/ada/exp_disp.ads
@@ -236,9 +236,6 @@ package Exp_Disp is
function Has_CPP_Constructors (Typ : Entity_Id) return Boolean;
-- Returns true if the type has CPP constructors
- function Is_Expanded_Dispatching_Call (N : Node_Id) return Boolean;
- -- Returns true if N is the expanded code of a dispatching call
-
function Make_DT (Typ : Entity_Id) return List_Id;
-- Expand the declarations for the Dispatch Table of Typ
diff --git a/gcc/ada/exp_put_image.adb b/gcc/ada/exp_put_image.adb
index 40b2a65..ce3390b 100644
--- a/gcc/ada/exp_put_image.adb
+++ b/gcc/ada/exp_put_image.adb
@@ -77,8 +77,28 @@ package body Exp_Put_Image is
-- reference). The Loc parameter is used as the Sloc of the created entity.
function Put_Image_Base_Type (E : Entity_Id) return Entity_Id;
- -- Returns the base type, except for an array type whose whose first
- -- subtype is constrained, in which case it returns the first subtype.
+ -- For an array type whose whose first subtype is constrained, return
+ -- the first subtype. For the internal representation type corresponding
+ -- to a mutably tagged type, return the mutably tagged type. Otherwise,
+ -- return the base type. Similar to Exp_Strm.Stream_Base_Type.
+
+ procedure Put_Specific_Type_Name_Qualifier
+ (Loc : Source_Ptr;
+ Stms : List_Id;
+ Tagged_Obj : Node_Id;
+ Buffer_Name : Node_Id;
+ Is_Interface_Type : Boolean);
+ -- Append to the given statement list calls to add into the
+ -- buffer the name of the given object's tag and then a "'".
+
+ function Put_String_Exp_To_Buffer
+ (Loc : Source_Ptr;
+ String_Exp : Node_Id;
+ Buffer_Name : Node_Id;
+ Wide_Wide : Boolean := False) return Node_Id;
+ -- Generate a call to evaluate a String (or Wide_Wide_String, depending
+ -- on the Wide_Wide Boolean parameter) expression and output it into
+ -- the buffer.
-------------------------------------
-- Build_Array_Put_Image_Procedure --
@@ -189,7 +209,7 @@ package body Exp_Put_Image is
Ndim : constant Pos := Number_Dimensions (Typ);
Ctyp : constant Entity_Id := Component_Type (Typ);
- Stm : Node_Id;
+ Stms : List_Id := New_List;
Exl : constant List_Id := New_List;
PI_Entity : Entity_Id;
@@ -220,15 +240,36 @@ package body Exp_Put_Image is
Append_To (Exl, Make_Identifier (Loc, New_External_Name ('L', Dim)));
end loop;
- Stm :=
- Make_Attribute_Reference (Loc,
- Prefix => New_Occurrence_Of (Put_Image_Base_Type (Ctyp), Loc),
- Attribute_Name => Name_Put_Image,
- Expressions => New_List (
- Make_Identifier (Loc, Name_S),
- Make_Indexed_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Expressions => Exl)));
+ declare
+ Ctype_For_Call : constant Entity_Id := Put_Image_Base_Type (Ctyp);
+ Indexed_Comp : constant Node_Id :=
+ Make_Indexed_Component (Loc,
+ Prefix => Make_Identifier (Loc, Name_V),
+ Expressions => Exl);
+ begin
+ if Is_Mutably_Tagged_Type (Ctype_For_Call) then
+ pragma Assert (not Is_Mutably_Tagged_Type (Component_Type (Typ)));
+
+ Make_Mutably_Tagged_Conversion (Indexed_Comp,
+ Typ => Ctype_For_Call);
+
+ pragma Assert (Is_Mutably_Tagged_Type (Etype (Indexed_Comp)));
+
+ Put_Specific_Type_Name_Qualifier (Loc,
+ Stms => Stms,
+ Tagged_Obj => Indexed_Comp,
+ Buffer_Name => Make_Identifier (Loc, Name_S),
+ Is_Interface_Type => False);
+ end if;
+
+ Append_To (Stms,
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Occurrence_Of (Ctype_For_Call, Loc),
+ Attribute_Name => Name_Put_Image,
+ Expressions => New_List (
+ Make_Identifier (Loc, Name_S),
+ Indexed_Comp)));
+ end;
-- The corresponding attribute for the component type of the array might
-- be user-defined, and frozen after the array type. In that case,
@@ -245,46 +286,42 @@ package body Exp_Put_Image is
-- Loop through the dimensions, innermost first, generating a loop for
-- each dimension.
- declare
- Stms : List_Id := New_List (Stm);
- begin
- for Dim in reverse 1 .. Ndim loop
- declare
- New_Stms : constant List_Id := New_List;
- Between_Proc : RE_Id;
- begin
- -- For a one-dimensional array of elementary type, use
- -- RE_Simple_Array_Between. The same applies to the last
- -- dimension of a multidimensional array.
+ for Dim in reverse 1 .. Ndim loop
+ declare
+ New_Stms : constant List_Id := New_List;
+ Between_Proc : RE_Id;
+ begin
+ -- For a one-dimensional array of elementary type, use
+ -- RE_Simple_Array_Between. The same applies to the last
+ -- dimension of a multidimensional array.
- if Is_Elementary_Type (Ctyp) and then Dim = Ndim then
- Between_Proc := RE_Simple_Array_Between;
- else
- Between_Proc := RE_Array_Between;
- end if;
+ if Is_Elementary_Type (Ctyp) and then Dim = Ndim then
+ Between_Proc := RE_Simple_Array_Between;
+ else
+ Between_Proc := RE_Array_Between;
+ end if;
- Append_To (New_Stms,
- Make_Procedure_Call_Statement (Loc,
- Name => New_Occurrence_Of (RTE (RE_Array_Before), Loc),
- Parameter_Associations => New_List
- (Make_Identifier (Loc, Name_S))));
+ Append_To (New_Stms,
+ Make_Procedure_Call_Statement (Loc,
+ Name => New_Occurrence_Of (RTE (RE_Array_Before), Loc),
+ Parameter_Associations => New_List
+ (Make_Identifier (Loc, Name_S))));
- Append_To
- (New_Stms,
- Wrap_In_Loop (Stms, Dim, Indices (Dim), Between_Proc));
+ Append_To
+ (New_Stms,
+ Wrap_In_Loop (Stms, Dim, Indices (Dim), Between_Proc));
- Append_To (New_Stms,
- Make_Procedure_Call_Statement (Loc,
- Name => New_Occurrence_Of (RTE (RE_Array_After), Loc),
- Parameter_Associations => New_List
- (Make_Identifier (Loc, Name_S))));
+ Append_To (New_Stms,
+ Make_Procedure_Call_Statement (Loc,
+ Name => New_Occurrence_Of (RTE (RE_Array_After), Loc),
+ Parameter_Associations => New_List
+ (Make_Identifier (Loc, Name_S))));
- Stms := New_Stms;
- end;
- end loop;
+ Stms := New_Stms;
+ end;
+ end loop;
- Build_Put_Image_Proc (Loc, Typ, Decl, Pnam, Stms);
- end;
+ Build_Put_Image_Proc (Loc, Typ, Decl, Pnam, Stms);
end Build_Array_Put_Image_Procedure;
-------------------------------------
@@ -379,7 +416,8 @@ package body Exp_Put_Image is
begin
-- We have built a dispatching call to handle calls to
-- descendants (since they are not available through rtsfind).
- -- Further details available in the body of Put_String_Exp.
+ -- Further details available in the body of
+ -- Put_String_Exp_To_Buffer.
return Put_Call;
end;
@@ -691,19 +729,33 @@ package body Exp_Put_Image is
---------------------------
procedure Append_Component_Attr (Clist : List_Id; C : Entity_Id) is
- Component_Typ : constant Entity_Id :=
- Put_Image_Base_Type
- (Get_Corresponding_Mutably_Tagged_Type_If_Present (Etype (C)));
+ Component_Typ : constant Entity_Id := Put_Image_Base_Type (Etype (C));
+ Selected_Comp : constant Node_Id :=
+ Make_Selected_Component (Loc,
+ Prefix => Make_Identifier (Loc, Name_V),
+ Selector_Name => New_Occurrence_Of (C, Loc));
begin
+ if Is_Mutably_Tagged_Type (Component_Typ) then
+ pragma Assert (not Is_Mutably_Tagged_Type (Etype (C)));
+
+ Make_Mutably_Tagged_Conversion (Selected_Comp,
+ Typ => Component_Typ);
+
+ pragma Assert (Is_Mutably_Tagged_Type (Etype (Selected_Comp)));
+
+ Put_Specific_Type_Name_Qualifier (Loc,
+ Stms => Clist,
+ Tagged_Obj => Selected_Comp,
+ Buffer_Name => Make_Identifier (Loc, Name_S),
+ Is_Interface_Type => False);
+ end if;
+
Append_To (Clist,
Make_Attribute_Reference (Loc,
Prefix => New_Occurrence_Of (Component_Typ, Loc),
Attribute_Name => Name_Put_Image,
- Expressions => New_List (
- Make_Identifier (Loc, Name_S),
- Make_Selected_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Selector_Name => New_Occurrence_Of (C, Loc)))));
+ Expressions => New_List (Make_Identifier (Loc, Name_S),
+ Selected_Comp)));
end Append_Component_Attr;
-------------------------------
@@ -1303,105 +1355,20 @@ package body Exp_Put_Image is
New_Occurrence_Of (Sink_Entity, Loc))));
Actions : List_Id;
- function Put_String_Exp (String_Exp : Node_Id;
- Wide_Wide : Boolean := False) return Node_Id;
- -- Generate a call to evaluate a String (or Wide_Wide_String, depending
- -- on the Wide_Wide Boolean parameter) expression and output it into
- -- the buffer.
-
- --------------------
- -- Put_String_Exp --
- --------------------
-
- function Put_String_Exp (String_Exp : Node_Id;
- Wide_Wide : Boolean := False) return Node_Id is
- Put_Id : constant RE_Id :=
- (if Wide_Wide then RE_Wide_Wide_Put else RE_Put_UTF_8);
-
- -- We could build a nondispatching call here, but to make
- -- that work we'd have to change Rtsfind spec to make available
- -- corresponding callees out of Ada.Strings.Text_Buffers.Unbounded
- -- (as opposed to from Ada.Strings.Text_Buffers). Seems simpler to
- -- introduce a type conversion and leave it to the optimizer to
- -- eliminate the dispatching. This does not *introduce* any problems
- -- if a no-dispatching-allowed restriction is in effect, since we
- -- are already in the middle of generating a call to T'Class'Image.
-
- Sink_Exp : constant Node_Id :=
- Make_Type_Conversion (Loc,
- Subtype_Mark =>
- New_Occurrence_Of
- (Class_Wide_Type (RTE (RE_Root_Buffer_Type)), Loc),
- Expression => New_Occurrence_Of (Sink_Entity, Loc));
- begin
- return
- Make_Procedure_Call_Statement (Loc,
- Name => New_Occurrence_Of (RTE (Put_Id), Loc),
- Parameter_Associations => New_List (Sink_Exp, String_Exp));
- end Put_String_Exp;
-
- -- Local variables
-
- Tag_Node : Node_Id;
-
-- Start of processing for Build_Image_Call
begin
if Is_Class_Wide_Type (U_Type) then
+ Actions := New_List (Sink_Decl);
- -- For interface types we must generate code to displace the pointer
- -- to the object to reference the base of the underlying object.
-
- -- Generate:
- -- To_Tag_Ptr (Image_Prefix'Address).all
-
- -- Note that Image_Prefix'Address is recursively expanded into a
- -- call to Ada.Tags.Base_Address (Image_Prefix'Address).
-
- if Is_Interface (U_Type) then
- Tag_Node :=
- Make_Explicit_Dereference (Loc,
- Unchecked_Convert_To (RTE (RE_Tag_Ptr),
- Make_Attribute_Reference (Loc,
- Prefix => Duplicate_Subexpr (Image_Prefix),
- Attribute_Name => Name_Address)));
+ Put_Specific_Type_Name_Qualifier (Loc,
+ Stms => Actions,
+ Tagged_Obj => Image_Prefix,
+ Buffer_Name => New_Occurrence_Of (Sink_Entity, Loc),
+ Is_Interface_Type => Is_Interface (U_Type));
- -- Common case
-
- else
- Tag_Node :=
- Make_Attribute_Reference (Loc,
- Prefix => Duplicate_Subexpr (Image_Prefix),
- Attribute_Name => Name_Tag);
- end if;
-
- -- Generate qualified-expression syntax; qualification name comes
- -- from calling Ada.Tags.Wide_Wide_Expanded_Name.
-
- declare
- -- The copy of Image_Prefix will be evaluated before the
- -- original, which is ok if no side effects are involved.
-
- pragma Assert (Side_Effect_Free (Image_Prefix));
-
- Specific_Type_Name : constant Node_Id :=
- Put_String_Exp
- (Make_Function_Call (Loc,
- Name => New_Occurrence_Of
- (RTE (RE_Wide_Wide_Expanded_Name), Loc),
- Parameter_Associations => New_List (Tag_Node)),
- Wide_Wide => True);
-
- Qualification : constant Node_Id :=
- Put_String_Exp (Make_String_Literal (Loc, "'"));
- begin
- Actions := New_List
- (Sink_Decl,
- Specific_Type_Name,
- Qualification,
- Put_Im,
- Result_Decl);
- end;
+ Append_To (Actions, Put_Im);
+ Append_To (Actions, Result_Decl);
else
Actions := New_List (Sink_Decl, Put_Im, Result_Decl);
end if;
@@ -1485,9 +1452,89 @@ package body Exp_Put_Image is
return E;
elsif Is_Private_Type (Base_Type (E)) and not Is_Private_Type (E) then
return Implementation_Base_Type (E);
+ elsif Is_Mutably_Tagged_CW_Equivalent_Type (E) then
+ return Get_Corresponding_Mutably_Tagged_Type_If_Present (E);
else
return Base_Type (E);
end if;
end Put_Image_Base_Type;
+ --------------------------------------
+ -- Put_Specific_Type_Name_Qualifier --
+ --------------------------------------
+
+ procedure Put_Specific_Type_Name_Qualifier
+ (Loc : Source_Ptr;
+ Stms : List_Id;
+ Tagged_Obj : Node_Id;
+ Buffer_Name : Node_Id;
+ Is_Interface_Type : Boolean)
+ is
+ Tag_Node : Node_Id;
+ begin
+ if Is_Interface_Type then
+ Tag_Node :=
+ Make_Explicit_Dereference (Loc,
+ Unchecked_Convert_To (RTE (RE_Tag_Ptr),
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Copy_Tree (Tagged_Obj),
+ Attribute_Name => Name_Address)));
+ else
+ Tag_Node :=
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Copy_Tree (Tagged_Obj),
+ Attribute_Name => Name_Tag);
+ end if;
+
+ Append_To (Stms,
+ Put_String_Exp_To_Buffer (Loc,
+ String_Exp =>
+ Make_Function_Call (Loc,
+ Name => New_Occurrence_Of
+ (RTE (RE_Wide_Wide_Expanded_Name), Loc),
+ Parameter_Associations => New_List (Tag_Node)),
+ Buffer_Name => Buffer_Name,
+ Wide_Wide => True));
+
+ Append_To (Stms,
+ Put_String_Exp_To_Buffer (Loc,
+ String_Exp => Make_String_Literal (Loc, "'"),
+ Buffer_Name => New_Copy_Tree (Buffer_Name)));
+ end Put_Specific_Type_Name_Qualifier;
+
+ ------------------------------
+ -- Put_String_Exp_To_Buffer --
+ ------------------------------
+
+ function Put_String_Exp_To_Buffer
+ (Loc : Source_Ptr;
+ String_Exp : Node_Id;
+ Buffer_Name : Node_Id;
+ Wide_Wide : Boolean := False) return Node_Id
+ is
+ Put_Id : constant RE_Id :=
+ (if Wide_Wide then RE_Wide_Wide_Put else RE_Put_UTF_8);
+
+ -- We could build a nondispatching call here, but to make
+ -- that work we'd have to change Rtsfind spec to make available
+ -- corresponding callees out of Ada.Strings.Text_Buffers.Unbounded
+ -- (as opposed to from Ada.Strings.Text_Buffers). Seems simpler to
+ -- introduce a type conversion and leave it to the optimizer to
+ -- eliminate the dispatching. This does not *introduce* any problems
+ -- if a no-dispatching-allowed restriction is in effect, since we
+ -- are already in the middle of generating a call to T'Class'Image.
+
+ Sink_Exp : constant Node_Id :=
+ Make_Type_Conversion (Loc,
+ Subtype_Mark =>
+ New_Occurrence_Of
+ (Class_Wide_Type (RTE (RE_Root_Buffer_Type)), Loc),
+ Expression => Buffer_Name);
+ begin
+ return
+ Make_Procedure_Call_Statement (Loc,
+ Name => New_Occurrence_Of (RTE (Put_Id), Loc),
+ Parameter_Associations => New_List (Sink_Exp, String_Exp));
+ end Put_String_Exp_To_Buffer;
+
end Exp_Put_Image;
diff --git a/gcc/ada/exp_spark.adb b/gcc/ada/exp_spark.adb
index 6e1c86a..a75a507 100644
--- a/gcc/ada/exp_spark.adb
+++ b/gcc/ada/exp_spark.adb
@@ -73,6 +73,10 @@ package body Exp_SPARK is
procedure Expand_SPARK_N_Attribute_Reference (N : Node_Id);
-- Perform attribute-reference-specific expansion
+ procedure Expand_SPARK_N_Continue_Statement (N : Node_Id);
+ -- Expand continue statements which are resolved as procedure calls, into
+ -- said procedure calls. Real continue statements are left as-is.
+
procedure Expand_SPARK_N_Delta_Aggregate (N : Node_Id);
-- Perform delta-aggregate-specific expansion
@@ -191,6 +195,9 @@ package body Exp_SPARK is
-- In SPARK mode, no other constructs require expansion
+ when N_Continue_Statement =>
+ Expand_SPARK_N_Continue_Statement (N);
+
when others =>
null;
end case;
@@ -435,6 +442,23 @@ package body Exp_SPARK is
end if;
end Expand_SPARK_Delta_Or_Update;
+ ---------------------------------------
+ -- Expand_SPARK_N_Continue_Statement --
+ ---------------------------------------
+
+ procedure Expand_SPARK_N_Continue_Statement (N : Node_Id) is
+ X : constant Node_Id := Call_Or_Target_Loop (N);
+ begin
+ if No (X) then
+ return;
+ end if;
+
+ if Nkind (X) = N_Procedure_Call_Statement then
+ Replace (N, X);
+ Analyze (N);
+ end if;
+ end Expand_SPARK_N_Continue_Statement;
+
------------------------------
-- Expand_SPARK_N_Aggregate --
------------------------------
diff --git a/gcc/ada/exp_strm.adb b/gcc/ada/exp_strm.adb
index 250efd2..5e1c913 100644
--- a/gcc/ada/exp_strm.adb
+++ b/gcc/ada/exp_strm.adb
@@ -29,6 +29,7 @@ with Einfo.Entities; use Einfo.Entities;
with Einfo.Utils; use Einfo.Utils;
with Elists; use Elists;
with Exp_Util; use Exp_Util;
+with Mutably_Tagged; use Mutably_Tagged;
with Namet; use Namet;
with Nlists; use Nlists;
with Nmake; use Nmake;
@@ -101,13 +102,10 @@ package body Exp_Strm is
-- Loc parameter is used as the Sloc of the created entity.
function Stream_Base_Type (E : Entity_Id) return Entity_Id;
- -- Stream attributes work on the basis of the base type except for the
- -- array case. For the array case, we do not go to the base type, but
- -- to the first subtype if it is constrained. This avoids problems with
- -- incorrect conversions in the packed array case. Stream_Base_Type is
- -- exactly this function (returns the base type, unless we have an array
- -- type whose first subtype is constrained, in which case it returns the
- -- first subtype).
+ -- For an array type whose whose first subtype is constrained, return
+ -- the first subtype. For the internal representation type corresponding
+ -- to a mutably tagged type, return the mutably tagged type. Otherwise,
+ -- return the base type. Similar to Exp_Put_Image.Put_Image_Base_Type.
--------------------------------
-- Build_Array_Input_Function --
@@ -1502,6 +1500,7 @@ package body Exp_Strm is
function Make_Field_Attribute (C : Entity_Id) return Node_Id is
Field_Typ : constant Entity_Id := Stream_Base_Type (Etype (C));
+ Selected : Node_Id;
TSS_Names : constant array (Name_Input .. Name_Write) of
TSS_Name_Type :=
@@ -1524,15 +1523,23 @@ package body Exp_Strm is
return Make_Null_Statement (Loc);
end if;
+ Selected := Make_Selected_Component (Loc,
+ Prefix => Make_Identifier (Loc, Name_V),
+ Selector_Name => New_Occurrence_Of (C, Loc));
+
+ if Is_Mutably_Tagged_CW_Equivalent_Type (Etype (C)) then
+ Make_Mutably_Tagged_Conversion
+ (Selected,
+ Typ => Get_Corresponding_Mutably_Tagged_Type_If_Present
+ (Etype (C)));
+ end if;
+
return
Make_Attribute_Reference (Loc,
Prefix => New_Occurrence_Of (Field_Typ, Loc),
Attribute_Name => Nam,
- Expressions => New_List (
- Make_Identifier (Loc, Name_S),
- Make_Selected_Component (Loc,
- Prefix => Make_Identifier (Loc, Name_V),
- Selector_Name => New_Occurrence_Of (C, Loc))));
+ Expressions => New_List (Make_Identifier (Loc, Name_S),
+ Selected));
end Make_Field_Attribute;
---------------------------
@@ -1808,6 +1815,10 @@ package body Exp_Strm is
function Stream_Base_Type (E : Entity_Id) return Entity_Id is
begin
+ if Is_Class_Wide_Equivalent_Type (E) then
+ return Corresponding_Mutably_Tagged_Type (E);
+ end if;
+
if Is_Array_Type (E)
and then Is_First_Subtype (E)
then
diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb
index 2172ce7..5a6fca0 100644
--- a/gcc/ada/exp_util.adb
+++ b/gcc/ada/exp_util.adb
@@ -6189,18 +6189,12 @@ package body Exp_Util is
if Is_Protected_Type (Btyp) then
Utyp := Corresponding_Record_Type (Root_Type (Btyp));
- else
- declare
- Root : constant Entity_Id := Underlying_Type (Root_Type (Btyp));
- begin
- if Is_Protected_Type (Root) then
- Utyp := Corresponding_Record_Type (Root);
- else
- while No (TSS (Utyp, TSS_Finalize_Address)) loop
- Utyp := Underlying_Type (Base_Type (Etype (Utyp)));
- end loop;
- end if;
- end;
+ elsif Is_Implicit_Full_View (Utyp) then
+ Utyp := Underlying_Type (Root_Type (Btyp));
+
+ if Is_Protected_Type (Utyp) then
+ Utyp := Corresponding_Record_Type (Utyp);
+ end if;
end if;
end if;
@@ -11736,34 +11730,6 @@ package body Exp_Util is
end if;
end Matching_Standard_Type;
- -----------------------------
- -- May_Generate_Large_Temp --
- -----------------------------
-
- -- At the current time, the only types that we return False for (i.e. where
- -- we decide we know they cannot generate large temps) are ones where we
- -- know the size is 256 bits or less at compile time, and we are still not
- -- doing a thorough job on arrays and records.
-
- function May_Generate_Large_Temp (Typ : Entity_Id) return Boolean is
- begin
- if not Size_Known_At_Compile_Time (Typ) then
- return False;
- end if;
-
- if Known_Esize (Typ) and then Esize (Typ) <= 256 then
- return False;
- end if;
-
- if Is_Array_Type (Typ)
- and then Present (Packed_Array_Impl_Type (Typ))
- then
- return May_Generate_Large_Temp (Packed_Array_Impl_Type (Typ));
- end if;
-
- return True;
- end May_Generate_Large_Temp;
-
---------------------------------------
-- Move_To_Initialization_Statements --
---------------------------------------
@@ -13766,11 +13732,12 @@ package body Exp_Util is
-- The above requirements should be documented in Sinfo ???
function Safe_Unchecked_Type_Conversion (Exp : Node_Id) return Boolean is
+ Pexp : constant Node_Id := Parent (Exp);
+
Otyp : Entity_Id;
Ityp : Entity_Id;
Oalign : Uint;
Ialign : Uint;
- Pexp : constant Node_Id := Parent (Exp);
begin
-- If the expression is the RHS of an assignment or object declaration
@@ -13788,18 +13755,12 @@ package body Exp_Util is
return True;
-- If the expression is the prefix of an N_Selected_Component we should
- -- also be OK because GCC knows to look inside the conversion except if
- -- the type is discriminated. We assume that we are OK anyway if the
- -- type is not set yet or if it is controlled since we can't afford to
- -- introduce a temporary in this case.
+ -- also be OK because GCC knows to look inside the conversion.
elsif Nkind (Pexp) = N_Selected_Component
and then Prefix (Pexp) = Exp
then
- return No (Etype (Pexp))
- or else not Is_Type (Etype (Pexp))
- or else not Has_Discriminants (Etype (Pexp))
- or else Is_Constrained (Etype (Pexp));
+ return True;
end if;
-- Set the output type, this comes from Etype if it is set, otherwise we
@@ -13872,14 +13833,7 @@ package body Exp_Util is
-- known size, but we can't consider them that way here, because we are
-- talking about the actual size of the object.
- -- We also make sure that in addition to the size being known, we do not
- -- have a case which might generate an embarrassingly large temp in
- -- stack checking mode.
-
elsif Size_Known_At_Compile_Time (Otyp)
- and then
- (not Stack_Checking_Enabled
- or else not May_Generate_Large_Temp (Otyp))
and then not (Is_Record_Type (Otyp) and then not Is_Constrained (Otyp))
then
return True;
diff --git a/gcc/ada/exp_util.ads b/gcc/ada/exp_util.ads
index b8b7525..4226fcc 100644
--- a/gcc/ada/exp_util.ads
+++ b/gcc/ada/exp_util.ads
@@ -1064,16 +1064,6 @@ package Exp_Util is
-- typically return Standard_Short_Integer. For fixed-point types, this
-- will return integer types of the corresponding size.
- function May_Generate_Large_Temp (Typ : Entity_Id) return Boolean;
- -- Determines if the given type, Typ, may require a large temporary of the
- -- kind that causes back-end trouble if stack checking is enabled. The
- -- result is True only the size of the type is known at compile time and
- -- large, where large is defined heuristically by the body of this routine.
- -- The purpose of this routine is to help avoid generating troublesome
- -- temporaries that interfere with stack checking mechanism. Note that the
- -- caller has to check whether stack checking is actually enabled in order
- -- to guide the expansion (typically of a function call).
-
procedure Move_To_Initialization_Statements (Decl, Stop : Node_Id);
-- Decl is an N_Object_Declaration node and Stop is a node past Decl in
-- the same list. Move all the nodes on the list between Decl and Stop
diff --git a/gcc/ada/freeze.adb b/gcc/ada/freeze.adb
index 3755d9e..dbd7cf4 100644
--- a/gcc/ada/freeze.adb
+++ b/gcc/ada/freeze.adb
@@ -7231,6 +7231,35 @@ package body Freeze is
end if;
Inherit_Aspects_At_Freeze_Point (E);
+
+ -- Destructor legality check
+
+ if Present (Primitive_Operations (E)) then
+ declare
+ Subp : Entity_Id;
+ Parent_Operation : Entity_Id;
+
+ Elmt : Elmt_Id := First_Elmt (Primitive_Operations (E));
+
+ begin
+ while Present (Elmt) loop
+ Subp := Node (Elmt);
+
+ if Present (Overridden_Operation (Subp)) then
+ Parent_Operation := Overridden_Operation (Subp);
+
+ if Ekind (Parent_Operation) = E_Procedure
+ and then Is_Destructor (Parent_Operation)
+ then
+ Error_Msg_N ("cannot override destructor", Subp);
+ end if;
+ end if;
+
+ Next_Elmt (Elmt);
+ end loop;
+ end;
+ end if;
+
end if;
-- Case of array type
@@ -8130,6 +8159,7 @@ package body Freeze is
if Ekind (E) = E_Anonymous_Access_Subprogram_Type
and then Ekind (Designated_Type (E)) = E_Subprogram_Type
then
+ Create_Extra_Formals (Designated_Type (E));
Layout_Type (Etype (Designated_Type (E)));
end if;
@@ -10393,6 +10423,8 @@ package body Freeze is
-- Local variables
+ use Deferred_Extra_Formals_Support;
+
F : Entity_Id;
Retype : Entity_Id;
@@ -10493,8 +10525,11 @@ package body Freeze is
Create_Extra_Formals (E);
pragma Assert
- ((Ekind (E) = E_Subprogram_Type
- and then Extra_Formals_OK (E))
+ ((Extra_Formals_Known (E)
+ or else Is_Deferred_Extra_Formals_Entity (E))
+ or else
+ (Ekind (E) = E_Subprogram_Type
+ and then Extra_Formals_OK (E))
or else
(Is_Subprogram (E)
and then Extra_Formals_OK (E)
@@ -10523,6 +10558,10 @@ package body Freeze is
else
Set_Mechanisms (E);
+ if not Extra_Formals_Known (E) then
+ Freeze_Extra_Formals (E);
+ end if;
+
-- For foreign conventions, warn about return of unconstrained array
if Ekind (E) = E_Function then
@@ -10578,6 +10617,11 @@ package body Freeze is
end if;
end if;
+ -- Check formals matching in thunks
+
+ pragma Assert (not Is_Thunk (E)
+ or else Extra_Formals_Match_OK (Thunk_Entity (E), E));
+
-- Pragma Inline_Always is disallowed for dispatching subprograms
-- because the address of such subprograms is saved in the dispatch
-- table to support dispatching calls, and dispatching calls cannot
diff --git a/gcc/ada/gcc-interface/misc.cc b/gcc/ada/gcc-interface/misc.cc
index 128040e..7711f8b 100644
--- a/gcc/ada/gcc-interface/misc.cc
+++ b/gcc/ada/gcc-interface/misc.cc
@@ -271,7 +271,7 @@ gnat_post_options (const char **pfilename ATTRIBUTE_UNUSED)
/* No caret by default for Ada. */
if (!OPTION_SET_P (flag_diagnostics_show_caret))
- global_dc->m_source_printing.enabled = false;
+ global_dc->get_source_printing_options ().enabled = false;
/* Copy global settings to local versions. */
gnat_encodings = global_options.x_gnat_encodings;
@@ -292,7 +292,7 @@ gnat_post_options (const char **pfilename ATTRIBUTE_UNUSED)
/* Here is the function to handle the compiler error processing in GCC. */
static void
-internal_error_function (diagnostic_context *context, const char *msgid,
+internal_error_function (diagnostics::context *context, const char *msgid,
va_list *ap)
{
char *buffer, *p, *loc;
diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc
index a7254fe..ef5ec75 100644
--- a/gcc/ada/gcc-interface/trans.cc
+++ b/gcc/ada/gcc-interface/trans.cc
@@ -1510,7 +1510,7 @@ Pragma_to_gnu (Node_Id gnat_node)
const location_t location = input_location;
struct cl_option_handlers handlers;
unsigned int option_index;
- diagnostic_t kind;
+ enum diagnostics::kind kind;
bool imply;
gnat_temp = First (Pragma_Argument_Associations (gnat_node));
@@ -1521,12 +1521,12 @@ Pragma_to_gnu (Node_Id gnat_node)
switch (id)
{
case Pragma_Warning_As_Error:
- kind = DK_ERROR;
+ kind = diagnostics::kind::error;
imply = false;
break;
case Pragma_Warnings:
- kind = DK_WARNING;
+ kind = diagnostics::kind::warning;
imply = true;
break;
@@ -1543,11 +1543,11 @@ Pragma_to_gnu (Node_Id gnat_node)
switch (Chars (Expression (gnat_temp)))
{
case Name_Off:
- kind = DK_IGNORED;
+ kind = diagnostics::kind::ignored;
break;
case Name_On:
- kind = DK_WARNING;
+ kind = diagnostics::kind::warning;
break;
default:
@@ -1569,7 +1569,7 @@ Pragma_to_gnu (Node_Id gnat_node)
gnat_expr = Empty;
/* For pragma Warnings (Off), we save the current state... */
- if (kind == DK_IGNORED)
+ if (kind == diagnostics::kind::ignored)
diagnostic_push_diagnostics (global_dc, location);
/* ...so that, for pragma Warnings (On), we do not enable all
@@ -8476,7 +8476,8 @@ gnat_to_gnu (Node_Id gnat_node)
oconstraints[i] = constraint;
if (parse_output_constraint (&constraint, i, ninputs, noutputs,
- &allows_mem, &allows_reg, &fake))
+ &allows_mem, &allows_reg, &fake,
+ nullptr))
{
/* If the operand is going to end up in memory,
mark it addressable. Note that we don't test
@@ -8504,9 +8505,9 @@ gnat_to_gnu (Node_Id gnat_node)
constraint
= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
- if (parse_input_constraint (&constraint, i, ninputs, noutputs,
- 0, oconstraints,
- &allows_mem, &allows_reg))
+ if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
+ oconstraints, &allows_mem,
+ &allows_reg, nullptr))
{
/* If the operand is going to end up in memory,
mark it addressable. */
diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc
index 7324bee..f501915 100644
--- a/gcc/ada/gcc-interface/utils.cc
+++ b/gcc/ada/gcc-interface/utils.cc
@@ -4510,8 +4510,8 @@ build_unc_object_type_from_ptr (tree thin_fat_ptr_type, tree object_type,
void
update_pointer_to (tree old_type, tree new_type)
{
- tree ptr = TYPE_POINTER_TO (old_type);
- tree ref = TYPE_REFERENCE_TO (old_type);
+ const tree old_ptr = TYPE_POINTER_TO (old_type);
+ const tree old_ref = TYPE_REFERENCE_TO (old_type);
tree t;
/* If this is the main variant, process all the other variants first. */
@@ -4520,7 +4520,7 @@ update_pointer_to (tree old_type, tree new_type)
update_pointer_to (t, new_type);
/* If no pointers and no references, we are done. */
- if (!ptr && !ref)
+ if (!old_ptr && !old_ref)
return;
/* Merge the old type qualifiers in the new type.
@@ -4554,12 +4554,13 @@ update_pointer_to (tree old_type, tree new_type)
if (TREE_CODE (new_type) != UNCONSTRAINED_ARRAY_TYPE)
{
tree new_ptr, new_ref;
+ tree ptr, ref;
/* If pointer or reference already points to new type, nothing to do.
This can happen as update_pointer_to can be invoked multiple times
on the same couple of types because of the type variants. */
- if ((ptr && TREE_TYPE (ptr) == new_type)
- || (ref && TREE_TYPE (ref) == new_type))
+ if ((old_ptr && TREE_TYPE (old_ptr) == new_type)
+ || (old_ref && TREE_TYPE (old_ref) == new_type))
return;
/* Chain PTR and its variants at the end. */
@@ -4568,13 +4569,13 @@ update_pointer_to (tree old_type, tree new_type)
{
while (TYPE_NEXT_PTR_TO (new_ptr))
new_ptr = TYPE_NEXT_PTR_TO (new_ptr);
- TYPE_NEXT_PTR_TO (new_ptr) = ptr;
+ TYPE_NEXT_PTR_TO (new_ptr) = old_ptr;
}
else
- TYPE_POINTER_TO (new_type) = ptr;
+ TYPE_POINTER_TO (new_type) = old_ptr;
/* Now adjust them. */
- for (; ptr; ptr = TYPE_NEXT_PTR_TO (ptr))
+ for (ptr = old_ptr; ptr; ptr = TYPE_NEXT_PTR_TO (ptr))
for (t = TYPE_MAIN_VARIANT (ptr); t; t = TYPE_NEXT_VARIANT (t))
{
TREE_TYPE (t) = new_type;
@@ -4589,13 +4590,13 @@ update_pointer_to (tree old_type, tree new_type)
{
while (TYPE_NEXT_REF_TO (new_ref))
new_ref = TYPE_NEXT_REF_TO (new_ref);
- TYPE_NEXT_REF_TO (new_ref) = ref;
+ TYPE_NEXT_REF_TO (new_ref) = old_ref;
}
else
- TYPE_REFERENCE_TO (new_type) = ref;
+ TYPE_REFERENCE_TO (new_type) = old_ref;
/* Now adjust them. */
- for (; ref; ref = TYPE_NEXT_REF_TO (ref))
+ for (ref = old_ref; ref; ref = TYPE_NEXT_REF_TO (ref))
for (t = TYPE_MAIN_VARIANT (ref); t; t = TYPE_NEXT_VARIANT (t))
{
TREE_TYPE (t) = new_type;
@@ -4614,20 +4615,20 @@ update_pointer_to (tree old_type, tree new_type)
{
tree new_ptr = TYPE_POINTER_TO (new_type);
- gcc_assert (TYPE_IS_FAT_POINTER_P (ptr));
+ gcc_assert (TYPE_IS_FAT_POINTER_P (old_ptr));
/* If PTR already points to NEW_TYPE, nothing to do. This can happen
since update_pointer_to can be invoked multiple times on the same
couple of types because of the type variants. */
- if (TYPE_UNCONSTRAINED_ARRAY (ptr) == new_type)
+ if (TYPE_UNCONSTRAINED_ARRAY (old_ptr) == new_type)
return;
update_pointer_to
- (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (ptr))),
+ (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (old_ptr))),
TREE_TYPE (TREE_TYPE (TYPE_FIELDS (new_ptr))));
update_pointer_to
- (TREE_TYPE (TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (ptr)))),
+ (TREE_TYPE (TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (old_ptr)))),
TREE_TYPE (TREE_TYPE (DECL_CHAIN (TYPE_FIELDS (new_ptr)))));
update_pointer_to (TYPE_OBJECT_RECORD_TYPE (old_type),
diff --git a/gcc/ada/gen_il-fields.ads b/gcc/ada/gen_il-fields.ads
index 2d16e12..a1e284f 100644
--- a/gcc/ada/gen_il-fields.ads
+++ b/gcc/ada/gen_il-fields.ads
@@ -255,6 +255,7 @@ package Gen_IL.Fields is
Is_Entry_Barrier_Function,
Is_Expanded_Build_In_Place_Call,
Is_Expanded_Constructor_Call,
+ Is_Expanded_Dispatching_Call,
Is_Expanded_Prefixed_Call,
Is_Folded_In_Parser,
Is_Generic_Contract_Pragma,
@@ -400,6 +401,7 @@ package Gen_IL.Fields is
Suppress_Loop_Warnings,
Synchronized_Present,
Tagged_Present,
+ Tag_Propagated,
Target,
Call_Or_Target_Loop,
Target_Type,
@@ -539,6 +541,7 @@ package Gen_IL.Fields is
Extra_Constrained,
Extra_Formal,
Extra_Formals,
+ Extra_Formals_Known,
Finalization_Collection,
Finalization_Master_Node,
Finalize_Storage_Only,
@@ -572,6 +575,7 @@ package Gen_IL.Fields is
Has_Delayed_Aspects,
Has_Delayed_Freeze,
Has_Delayed_Rep_Aspects,
+ Has_Destructor,
Has_Discriminants,
Has_Dispatch_Table,
Has_Dynamic_Predicate_Aspect,
@@ -699,6 +703,7 @@ package Gen_IL.Fields is
Is_CPP_Class,
Is_CUDA_Kernel,
Is_Descendant_Of_Address,
+ Is_Destructor,
Is_DIC_Procedure,
Is_Discrim_SO_Function,
Is_Discriminant_Check_Function,
@@ -730,6 +735,7 @@ package Gen_IL.Fields is
Is_Ignored_Ghost_Entity,
Is_Immediately_Visible,
Is_Implementation_Defined,
+ Is_Implicit_Full_View,
Is_Imported,
Is_Independent,
Is_Initial_Condition_Procedure,
@@ -850,6 +856,7 @@ package Gen_IL.Fields is
Original_Protected_Subprogram,
Original_Record_Component,
Overlays_Constant,
+ Overridden_Inherited_Operation,
Overridden_Operation,
Package_Instantiation,
Packed_Array_Impl_Type,
diff --git a/gcc/ada/gen_il-gen-gen_entities.adb b/gcc/ada/gen_il-gen-gen_entities.adb
index 8cbed8a..0fedfbc 100644
--- a/gcc/ada/gen_il-gen-gen_entities.adb
+++ b/gcc/ada/gen_il-gen-gen_entities.adb
@@ -467,6 +467,7 @@ begin -- Gen_IL.Gen.Gen_Entities
Sm (Full_View, Node_Id),
Sm (Has_Completion_In_Body, Flag),
Sm (Has_Constrained_Partial_View, Flag, Base_Type_Only),
+ Sm (Has_Destructor, Flag, Base_Type_Only),
Sm (Has_Discriminants, Flag),
Sm (Has_Dispatch_Table, Flag,
Pre => "Is_Tagged_Type (N)"),
@@ -502,6 +503,7 @@ begin -- Gen_IL.Gen.Gen_Entities
Sm (Is_Fixed_Lower_Bound_Array_Subtype, Flag),
Sm (Is_Fixed_Lower_Bound_Index_Subtype, Flag),
Sm (Is_Generic_Actual_Type, Flag),
+ Sm (Is_Implicit_Full_View, Flag),
Sm (Is_Mutably_Tagged_Type, Flag),
Sm (Is_Non_Static_Subtype, Flag),
Sm (Is_Private_Composite, Flag),
@@ -935,11 +937,13 @@ begin -- Gen_IL.Gen.Gen_Entities
(Sm (Access_Subprogram_Wrapper, Node_Id),
Sm (Extra_Accessibility_Of_Result, Node_Id),
Sm (Extra_Formals, Node_Id),
+ Sm (Extra_Formals_Known, Flag),
Sm (Needs_No_Actuals, Flag)));
Ab (Overloadable_Kind, Entity_Kind,
(Sm (Renamed_Or_Alias, Node_Id),
Sm (Extra_Formals, Node_Id),
+ Sm (Extra_Formals_Known, Flag),
Sm (Is_Abstract_Subprogram, Flag),
Sm (Is_Primitive, Flag),
Sm (Needs_No_Actuals, Flag),
@@ -953,6 +957,7 @@ begin -- Gen_IL.Gen.Gen_Entities
Sm (Enumeration_Rep_Expr, Node_Id),
Sm (Esize, Uint),
Sm (Alignment, Unat),
+ Sm (Overridden_Inherited_Operation, Node_Id),
Sm (Interface_Name, Node_Id)));
Ab (Subprogram_Kind, Overloadable_Kind,
@@ -981,6 +986,7 @@ begin -- Gen_IL.Gen.Gen_Entities
Sm (Is_Machine_Code_Subprogram, Flag),
Sm (Last_Entity, Node_Id),
Sm (Linker_Section_Pragma, Node_Id),
+ Sm (Overridden_Inherited_Operation, Node_Id),
Sm (Overridden_Operation, Node_Id),
Sm (Protected_Body_Subprogram, Node_Id),
Sm (No_Raise, Flag),
@@ -1050,6 +1056,7 @@ begin -- Gen_IL.Gen.Gen_Entities
Sm (Is_Asynchronous, Flag),
Sm (Is_Called, Flag),
Sm (Is_CUDA_Kernel, Flag),
+ Sm (Is_Destructor, Flag),
Sm (Is_DIC_Procedure, Flag),
Sm (Is_Generic_Actual_Subprogram, Flag),
Sm (Is_Initial_Condition_Procedure, Flag),
@@ -1125,6 +1132,7 @@ begin -- Gen_IL.Gen.Gen_Entities
Sm (Entry_Accepted, Flag),
Sm (Entry_Parameters_Type, Node_Id),
Sm (Extra_Formals, Node_Id),
+ Sm (Extra_Formals_Known, Flag),
Sm (First_Entity, Node_Id),
Sm (Has_Out_Or_In_Out_Parameter, Flag),
Sm (Ignore_SPARK_Mode_Pragmas, Flag),
@@ -1326,6 +1334,7 @@ begin -- Gen_IL.Gen.Gen_Entities
(Sm (Anonymous_Collections, Elist_Id),
Sm (Contract, Node_Id),
Sm (Extra_Formals, Node_Id),
+ Sm (Extra_Formals_Known, Flag),
Sm (First_Entity, Node_Id),
Sm (Ignore_SPARK_Mode_Pragmas, Flag),
Sm (Interface_Name, Node_Id),
diff --git a/gcc/ada/gen_il-gen-gen_nodes.adb b/gcc/ada/gen_il-gen-gen_nodes.adb
index f4e7917..412565f 100644
--- a/gcc/ada/gen_il-gen-gen_nodes.adb
+++ b/gcc/ada/gen_il-gen-gen_nodes.adb
@@ -149,6 +149,7 @@ begin -- Gen_IL.Gen.Gen_Nodes
Sm (Is_Controlling_Actual, Flag),
Sm (Is_Overloaded, Flag),
Sm (Is_Static_Expression, Flag),
+ Sm (Is_Expanded_Dispatching_Call, Flag),
Sm (Must_Not_Freeze, Flag),
Sm (Raises_Constraint_Error, Flag)));
@@ -181,7 +182,8 @@ begin -- Gen_IL.Gen.Gen_Nodes
Sm (Is_Elaboration_Warnings_OK_Node, Flag),
Sm (Is_SPARK_Mode_On_Node, Flag),
Sm (Original_Discriminant, Node_Id),
- Sm (Redundant_Use, Flag)));
+ Sm (Redundant_Use, Flag),
+ Sm (Tag_Propagated, Flag)));
Cc (N_Operator_Symbol, N_Direct_Name,
(Sy (Strval, String_Id)));
@@ -346,7 +348,8 @@ begin -- Gen_IL.Gen.Gen_Nodes
(Sy (Prefix, Node_Id),
Sm (Actual_Designated_Subtype, Node_Id),
Sm (Atomic_Sync_Required, Flag),
- Sm (Has_Dereference_Action, Flag)));
+ Sm (Has_Dereference_Action, Flag),
+ Sm (Tag_Propagated, Flag)));
Cc (N_Expression_With_Actions, N_Subexpr,
(Sy (Actions, List_Id, Default_No_List),
@@ -463,6 +466,7 @@ begin -- Gen_IL.Gen.Gen_Nodes
Sm (Do_Length_Check, Flag),
Sm (Do_Overflow_Check, Flag),
Sm (Float_Truncate, Flag),
+ Sm (Tag_Propagated, Flag),
Sm (Rounded_Result, Flag)));
Cc (N_Unchecked_Type_Conversion, N_Subexpr,
@@ -905,6 +909,7 @@ begin -- Gen_IL.Gen.Gen_Nodes
Sm (Cleanup_Actions, List_Id),
Sm (Exception_Junk, Flag),
Sm (Is_Abort_Block, Flag),
+ Sm (Is_Expanded_Dispatching_Call, Flag),
Sm (Is_Initialization_Block, Flag),
Sm (Is_Task_Master, Flag)));
diff --git a/gcc/ada/gen_il-internals.adb b/gcc/ada/gen_il-internals.adb
index 8d0dfc7..3fa8b94 100644
--- a/gcc/ada/gen_il-internals.adb
+++ b/gcc/ada/gen_il-internals.adb
@@ -277,6 +277,8 @@ package body Gen_IL.Internals is
return "DT_Offset_To_Top_Func";
when DT_Position =>
return "DT_Position";
+ when Extra_Formals_Known =>
+ return "Extra_Formals_Known";
when Forwards_OK =>
return "Forwards_OK";
when Has_First_Controlling_Parameter_Aspect =>
diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi
index b0a14b0..5d7bedc 100644
--- a/gcc/ada/gnat_rm.texi
+++ b/gcc/ada/gnat_rm.texi
@@ -19,7 +19,7 @@
@copying
@quotation
-GNAT Reference Manual , Jul 03, 2025
+GNAT Reference Manual , Jul 24, 2025
AdaCore
@@ -931,6 +931,7 @@ Experimental Language Extensions
* External_Initialization Aspect::
* Finally construct::
* Continue statement::
+* Destructors::
Storage Model
@@ -13071,9 +13072,9 @@ pragma Export (C, Last_Chance_Handler,
"__gnat_last_chance_handler");
@end example
-The parameter is a C null-terminated string representing a message to be
-associated with the exception (typically the source location of the raise
-statement generated by the compiler). The Line parameter when nonzero
+The @code{Source_Location} parameter is a C null-terminated string representing a
+message to be associated with the exception (typically the source location of
+the raise statement generated by the compiler). The Line parameter when nonzero
represents the line number in the source program where the raise occurs.
@node No_Exception_Propagation,No_Exception_Registration,No_Exception_Handlers,Partition-Wide Restrictions
@@ -31236,6 +31237,7 @@ Features activated via @code{-gnatX0} or
* External_Initialization Aspect::
* Finally construct::
* Continue statement::
+* Destructors::
@end menu
@@ -32588,7 +32590,7 @@ Abort/ATC (asynchronous transfer of control) cannot interrupt a finally block, n
execution, that is the finally block must be executed in full even if the containing task is
aborted, or if the control is transferred out of the block.
-@node Continue statement,,Finally construct,Experimental Language Extensions
+@node Continue statement,Destructors,Finally construct,Experimental Language Extensions
@anchor{gnat_rm/gnat_language_extensions continue-statement}@anchor{472}
@subsection Continue statement
@@ -32606,8 +32608,78 @@ statement in the sequence of statements of the specified loop_statement.
Note that @code{continue} is a keyword but it is not a reserved word. This is a
configuration that does not exist in standard Ada.
+@node Destructors,,Continue statement,Experimental Language Extensions
+@anchor{gnat_rm/gnat_language_extensions destructors}@anchor{473}
+@subsection Destructors
+
+
+The @code{Destructor} aspect can be applied to any record type, tagged or not.
+It must denote a primitive of the type that is a procedure with one parameter
+of the type and of mode @code{in out}:
+
+@example
+type T is record
+ ...
+end record with Destructor => Foo;
+
+procedure Foo (X : in out T);
+@end example
+
+This is equivalent to the following code that uses @code{Finalizable}:
+
+@example
+type T is record
+ ...
+end record with Finalizable => (Finalize => Foo);
+
+procedure Foo (X : in out T);
+@end example
+
+Unlike @code{Finalizable}, however, @code{Destructor} can be specified on a derived
+type. And when it is, the effect of the aspect combines with the destructors of
+the parent type. Take, for example:
+
+@example
+type T1 is record
+ ...
+end record with Destructor => Foo;
+
+procedure Foo (X : in out T1);
+
+type T2 is new T1 with Destructor => Bar;
+
+procedure Bar (X : in out T2);
+@end example
+
+Here, when an object of type @code{T2} is finalized, a call to @code{Bar}
+will be performed and it will be followed by a call to @code{Foo}.
+
+The @code{Destructor} aspect comes with a legality rule: if a primitive procedure
+of a type is denoted by a @code{Destructor} aspect specification, it is illegal to
+override this procedure in a derived type. For example, the following is illegal:
+
+@example
+type T1 is record
+ ...
+end record with Destructor => Foo;
+
+procedure Foo (X : in out T1);
+
+type T2 is new T1;
+
+overriding
+procedure Foo (X : in out T2); -- Error here
+@end example
+
+It is possible to specify @code{Destructor} on the completion of a private type,
+but there is one more restriction in that case: the denoted primitive must
+be private to the enclosing package. This is necessary due to the previously
+mentioned legality rule, to prevent breaking the privacy of the type when
+imposing that rule on outside types that derive from the private view of the
+type.
+
@node Security Hardening Features,Obsolescent Features,GNAT language extensions,Top
-@anchor{gnat_rm/security_hardening_features doc}@anchor{473}@anchor{gnat_rm/security_hardening_features id1}@anchor{474}@anchor{gnat_rm/security_hardening_features security-hardening-features}@anchor{15}
+@anchor{gnat_rm/security_hardening_features doc}@anchor{474}@anchor{gnat_rm/security_hardening_features id1}@anchor{475}@anchor{gnat_rm/security_hardening_features security-hardening-features}@anchor{15}
@chapter Security Hardening Features
@@ -32629,7 +32701,7 @@ change.
@end menu
@node Register Scrubbing,Stack Scrubbing,,Security Hardening Features
-@anchor{gnat_rm/security_hardening_features register-scrubbing}@anchor{475}
+@anchor{gnat_rm/security_hardening_features register-scrubbing}@anchor{476}
@section Register Scrubbing
@@ -32665,7 +32737,7 @@ programming languages, see @cite{Using the GNU Compiler Collection (GCC)}.
@c Stack Scrubbing:
@node Stack Scrubbing,Hardened Conditionals,Register Scrubbing,Security Hardening Features
-@anchor{gnat_rm/security_hardening_features stack-scrubbing}@anchor{476}
+@anchor{gnat_rm/security_hardening_features stack-scrubbing}@anchor{477}
@section Stack Scrubbing
@@ -32809,7 +32881,7 @@ Bar_Callable_Ptr.
@c Hardened Conditionals:
@node Hardened Conditionals,Hardened Booleans,Stack Scrubbing,Security Hardening Features
-@anchor{gnat_rm/security_hardening_features hardened-conditionals}@anchor{477}
+@anchor{gnat_rm/security_hardening_features hardened-conditionals}@anchor{478}
@section Hardened Conditionals
@@ -32899,7 +32971,7 @@ be used with other programming languages supported by GCC.
@c Hardened Booleans:
@node Hardened Booleans,Control Flow Redundancy,Hardened Conditionals,Security Hardening Features
-@anchor{gnat_rm/security_hardening_features hardened-booleans}@anchor{478}
+@anchor{gnat_rm/security_hardening_features hardened-booleans}@anchor{479}
@section Hardened Booleans
@@ -32960,7 +33032,7 @@ and more details on that attribute, see @cite{Using the GNU Compiler Collection
@c Control Flow Redundancy:
@node Control Flow Redundancy,,Hardened Booleans,Security Hardening Features
-@anchor{gnat_rm/security_hardening_features control-flow-redundancy}@anchor{479}
+@anchor{gnat_rm/security_hardening_features control-flow-redundancy}@anchor{47a}
@section Control Flow Redundancy
@@ -33128,7 +33200,7 @@ see @cite{Using the GNU Compiler Collection (GCC)}. These options
can be used with other programming languages supported by GCC.
@node Obsolescent Features,Compatibility and Porting Guide,Security Hardening Features,Top
-@anchor{gnat_rm/obsolescent_features doc}@anchor{47a}@anchor{gnat_rm/obsolescent_features id1}@anchor{47b}@anchor{gnat_rm/obsolescent_features obsolescent-features}@anchor{16}
+@anchor{gnat_rm/obsolescent_features doc}@anchor{47b}@anchor{gnat_rm/obsolescent_features id1}@anchor{47c}@anchor{gnat_rm/obsolescent_features obsolescent-features}@anchor{16}
@chapter Obsolescent Features
@@ -33147,7 +33219,7 @@ compatibility purposes.
@end menu
@node pragma No_Run_Time,pragma Ravenscar,,Obsolescent Features
-@anchor{gnat_rm/obsolescent_features id2}@anchor{47c}@anchor{gnat_rm/obsolescent_features pragma-no-run-time}@anchor{47d}
+@anchor{gnat_rm/obsolescent_features id2}@anchor{47d}@anchor{gnat_rm/obsolescent_features pragma-no-run-time}@anchor{47e}
@section pragma No_Run_Time
@@ -33160,7 +33232,7 @@ preferred usage is to use an appropriately configured run-time that
includes just those features that are to be made accessible.
@node pragma Ravenscar,pragma Restricted_Run_Time,pragma No_Run_Time,Obsolescent Features
-@anchor{gnat_rm/obsolescent_features id3}@anchor{47e}@anchor{gnat_rm/obsolescent_features pragma-ravenscar}@anchor{47f}
+@anchor{gnat_rm/obsolescent_features id3}@anchor{47f}@anchor{gnat_rm/obsolescent_features pragma-ravenscar}@anchor{480}
@section pragma Ravenscar
@@ -33169,7 +33241,7 @@ The pragma @code{Ravenscar} has exactly the same effect as pragma
is part of the new Ada 2005 standard.
@node pragma Restricted_Run_Time,pragma Task_Info,pragma Ravenscar,Obsolescent Features
-@anchor{gnat_rm/obsolescent_features id4}@anchor{480}@anchor{gnat_rm/obsolescent_features pragma-restricted-run-time}@anchor{481}
+@anchor{gnat_rm/obsolescent_features id4}@anchor{481}@anchor{gnat_rm/obsolescent_features pragma-restricted-run-time}@anchor{482}
@section pragma Restricted_Run_Time
@@ -33179,7 +33251,7 @@ preferred since the Ada 2005 pragma @code{Profile} is intended for
this kind of implementation dependent addition.
@node pragma Task_Info,package System Task_Info s-tasinf ads,pragma Restricted_Run_Time,Obsolescent Features
-@anchor{gnat_rm/obsolescent_features id5}@anchor{482}@anchor{gnat_rm/obsolescent_features pragma-task-info}@anchor{483}
+@anchor{gnat_rm/obsolescent_features id5}@anchor{483}@anchor{gnat_rm/obsolescent_features pragma-task-info}@anchor{484}
@section pragma Task_Info
@@ -33205,7 +33277,7 @@ in the spec of package System.Task_Info in the runtime
library.
@node package System Task_Info s-tasinf ads,,pragma Task_Info,Obsolescent Features
-@anchor{gnat_rm/obsolescent_features package-system-task-info}@anchor{484}@anchor{gnat_rm/obsolescent_features package-system-task-info-s-tasinf-ads}@anchor{485}
+@anchor{gnat_rm/obsolescent_features package-system-task-info}@anchor{485}@anchor{gnat_rm/obsolescent_features package-system-task-info-s-tasinf-ads}@anchor{486}
@section package System.Task_Info (@code{s-tasinf.ads})
@@ -33215,7 +33287,7 @@ to support the @code{Task_Info} pragma. The predefined Ada package
standard replacement for GNAT’s @code{Task_Info} functionality.
@node Compatibility and Porting Guide,GNU Free Documentation License,Obsolescent Features,Top
-@anchor{gnat_rm/compatibility_and_porting_guide doc}@anchor{486}@anchor{gnat_rm/compatibility_and_porting_guide compatibility-and-porting-guide}@anchor{17}@anchor{gnat_rm/compatibility_and_porting_guide id1}@anchor{487}
+@anchor{gnat_rm/compatibility_and_porting_guide doc}@anchor{487}@anchor{gnat_rm/compatibility_and_porting_guide compatibility-and-porting-guide}@anchor{17}@anchor{gnat_rm/compatibility_and_porting_guide id1}@anchor{488}
@chapter Compatibility and Porting Guide
@@ -33237,7 +33309,7 @@ applications developed in other Ada environments.
@end menu
@node Writing Portable Fixed-Point Declarations,Compatibility with Ada 83,,Compatibility and Porting Guide
-@anchor{gnat_rm/compatibility_and_porting_guide id2}@anchor{488}@anchor{gnat_rm/compatibility_and_porting_guide writing-portable-fixed-point-declarations}@anchor{489}
+@anchor{gnat_rm/compatibility_and_porting_guide id2}@anchor{489}@anchor{gnat_rm/compatibility_and_porting_guide writing-portable-fixed-point-declarations}@anchor{48a}
@section Writing Portable Fixed-Point Declarations
@@ -33359,7 +33431,7 @@ If you follow this scheme you will be guaranteed that your fixed-point
types will be portable.
@node Compatibility with Ada 83,Compatibility between Ada 95 and Ada 2005,Writing Portable Fixed-Point Declarations,Compatibility and Porting Guide
-@anchor{gnat_rm/compatibility_and_porting_guide compatibility-with-ada-83}@anchor{48a}@anchor{gnat_rm/compatibility_and_porting_guide id3}@anchor{48b}
+@anchor{gnat_rm/compatibility_and_porting_guide compatibility-with-ada-83}@anchor{48b}@anchor{gnat_rm/compatibility_and_porting_guide id3}@anchor{48c}
@section Compatibility with Ada 83
@@ -33387,7 +33459,7 @@ following subsections treat the most likely issues to be encountered.
@end menu
@node Legal Ada 83 programs that are illegal in Ada 95,More deterministic semantics,,Compatibility with Ada 83
-@anchor{gnat_rm/compatibility_and_porting_guide id4}@anchor{48c}@anchor{gnat_rm/compatibility_and_porting_guide legal-ada-83-programs-that-are-illegal-in-ada-95}@anchor{48d}
+@anchor{gnat_rm/compatibility_and_porting_guide id4}@anchor{48d}@anchor{gnat_rm/compatibility_and_porting_guide legal-ada-83-programs-that-are-illegal-in-ada-95}@anchor{48e}
@subsection Legal Ada 83 programs that are illegal in Ada 95
@@ -33487,7 +33559,7 @@ the fix is usually simply to add the @code{(<>)} to the generic declaration.
@end itemize
@node More deterministic semantics,Changed semantics,Legal Ada 83 programs that are illegal in Ada 95,Compatibility with Ada 83
-@anchor{gnat_rm/compatibility_and_porting_guide id5}@anchor{48e}@anchor{gnat_rm/compatibility_and_porting_guide more-deterministic-semantics}@anchor{48f}
+@anchor{gnat_rm/compatibility_and_porting_guide id5}@anchor{48f}@anchor{gnat_rm/compatibility_and_porting_guide more-deterministic-semantics}@anchor{490}
@subsection More deterministic semantics
@@ -33515,7 +33587,7 @@ which open select branches are executed.
@end itemize
@node Changed semantics,Other language compatibility issues,More deterministic semantics,Compatibility with Ada 83
-@anchor{gnat_rm/compatibility_and_porting_guide changed-semantics}@anchor{490}@anchor{gnat_rm/compatibility_and_porting_guide id6}@anchor{491}
+@anchor{gnat_rm/compatibility_and_porting_guide changed-semantics}@anchor{491}@anchor{gnat_rm/compatibility_and_porting_guide id6}@anchor{492}
@subsection Changed semantics
@@ -33557,7 +33629,7 @@ covers only the restricted range.
@end itemize
@node Other language compatibility issues,,Changed semantics,Compatibility with Ada 83
-@anchor{gnat_rm/compatibility_and_porting_guide id7}@anchor{492}@anchor{gnat_rm/compatibility_and_porting_guide other-language-compatibility-issues}@anchor{493}
+@anchor{gnat_rm/compatibility_and_porting_guide id7}@anchor{493}@anchor{gnat_rm/compatibility_and_porting_guide other-language-compatibility-issues}@anchor{494}
@subsection Other language compatibility issues
@@ -33590,7 +33662,7 @@ include @code{pragma Interface} and the floating point type attributes
@end itemize
@node Compatibility between Ada 95 and Ada 2005,Implementation-dependent characteristics,Compatibility with Ada 83,Compatibility and Porting Guide
-@anchor{gnat_rm/compatibility_and_porting_guide compatibility-between-ada-95-and-ada-2005}@anchor{494}@anchor{gnat_rm/compatibility_and_porting_guide id8}@anchor{495}
+@anchor{gnat_rm/compatibility_and_porting_guide compatibility-between-ada-95-and-ada-2005}@anchor{495}@anchor{gnat_rm/compatibility_and_porting_guide id8}@anchor{496}
@section Compatibility between Ada 95 and Ada 2005
@@ -33662,7 +33734,7 @@ can declare a function returning a value from an anonymous access type.
@end itemize
@node Implementation-dependent characteristics,Compatibility with Other Ada Systems,Compatibility between Ada 95 and Ada 2005,Compatibility and Porting Guide
-@anchor{gnat_rm/compatibility_and_porting_guide id9}@anchor{496}@anchor{gnat_rm/compatibility_and_porting_guide implementation-dependent-characteristics}@anchor{497}
+@anchor{gnat_rm/compatibility_and_porting_guide id9}@anchor{497}@anchor{gnat_rm/compatibility_and_porting_guide implementation-dependent-characteristics}@anchor{498}
@section Implementation-dependent characteristics
@@ -33685,7 +33757,7 @@ transition from certain Ada 83 compilers.
@end menu
@node Implementation-defined pragmas,Implementation-defined attributes,,Implementation-dependent characteristics
-@anchor{gnat_rm/compatibility_and_porting_guide id10}@anchor{498}@anchor{gnat_rm/compatibility_and_porting_guide implementation-defined-pragmas}@anchor{499}
+@anchor{gnat_rm/compatibility_and_porting_guide id10}@anchor{499}@anchor{gnat_rm/compatibility_and_porting_guide implementation-defined-pragmas}@anchor{49a}
@subsection Implementation-defined pragmas
@@ -33707,7 +33779,7 @@ avoiding compiler rejection of units that contain such pragmas; they are not
relevant in a GNAT context and hence are not otherwise implemented.
@node Implementation-defined attributes,Libraries,Implementation-defined pragmas,Implementation-dependent characteristics
-@anchor{gnat_rm/compatibility_and_porting_guide id11}@anchor{49a}@anchor{gnat_rm/compatibility_and_porting_guide implementation-defined-attributes}@anchor{49b}
+@anchor{gnat_rm/compatibility_and_porting_guide id11}@anchor{49b}@anchor{gnat_rm/compatibility_and_porting_guide implementation-defined-attributes}@anchor{49c}
@subsection Implementation-defined attributes
@@ -33721,7 +33793,7 @@ Ada 83, GNAT supplies the attributes @code{Bit}, @code{Machine_Size} and
@code{Type_Class}.
@node Libraries,Elaboration order,Implementation-defined attributes,Implementation-dependent characteristics
-@anchor{gnat_rm/compatibility_and_porting_guide id12}@anchor{49c}@anchor{gnat_rm/compatibility_and_porting_guide libraries}@anchor{49d}
+@anchor{gnat_rm/compatibility_and_porting_guide id12}@anchor{49d}@anchor{gnat_rm/compatibility_and_porting_guide libraries}@anchor{49e}
@subsection Libraries
@@ -33750,7 +33822,7 @@ be preferable to retrofit the application using modular types.
@end itemize
@node Elaboration order,Target-specific aspects,Libraries,Implementation-dependent characteristics
-@anchor{gnat_rm/compatibility_and_porting_guide elaboration-order}@anchor{49e}@anchor{gnat_rm/compatibility_and_porting_guide id13}@anchor{49f}
+@anchor{gnat_rm/compatibility_and_porting_guide elaboration-order}@anchor{49f}@anchor{gnat_rm/compatibility_and_porting_guide id13}@anchor{4a0}
@subsection Elaboration order
@@ -33786,7 +33858,7 @@ pragmas either globally (as an effect of the `-gnatE' switch) or locally
@end itemize
@node Target-specific aspects,,Elaboration order,Implementation-dependent characteristics
-@anchor{gnat_rm/compatibility_and_porting_guide id14}@anchor{4a0}@anchor{gnat_rm/compatibility_and_porting_guide target-specific-aspects}@anchor{4a1}
+@anchor{gnat_rm/compatibility_and_porting_guide id14}@anchor{4a1}@anchor{gnat_rm/compatibility_and_porting_guide target-specific-aspects}@anchor{4a2}
@subsection Target-specific aspects
@@ -33799,10 +33871,10 @@ on the robustness of the original design. Moreover, Ada 95 (and thus
Ada 2005, Ada 2012, and Ada 2022) are sometimes
incompatible with typical Ada 83 compiler practices regarding implicit
packing, the meaning of the Size attribute, and the size of access values.
-GNAT’s approach to these issues is described in @ref{4a2,,Representation Clauses}.
+GNAT’s approach to these issues is described in @ref{4a3,,Representation Clauses}.
@node Compatibility with Other Ada Systems,Representation Clauses,Implementation-dependent characteristics,Compatibility and Porting Guide
-@anchor{gnat_rm/compatibility_and_porting_guide compatibility-with-other-ada-systems}@anchor{4a3}@anchor{gnat_rm/compatibility_and_porting_guide id15}@anchor{4a4}
+@anchor{gnat_rm/compatibility_and_porting_guide compatibility-with-other-ada-systems}@anchor{4a4}@anchor{gnat_rm/compatibility_and_porting_guide id15}@anchor{4a5}
@section Compatibility with Other Ada Systems
@@ -33845,7 +33917,7 @@ far beyond this minimal set, as described in the next section.
@end itemize
@node Representation Clauses,Compatibility with HP Ada 83,Compatibility with Other Ada Systems,Compatibility and Porting Guide
-@anchor{gnat_rm/compatibility_and_porting_guide id16}@anchor{4a5}@anchor{gnat_rm/compatibility_and_porting_guide representation-clauses}@anchor{4a2}
+@anchor{gnat_rm/compatibility_and_porting_guide id16}@anchor{4a6}@anchor{gnat_rm/compatibility_and_porting_guide representation-clauses}@anchor{4a3}
@section Representation Clauses
@@ -33938,7 +34010,7 @@ with thin pointers.
@end itemize
@node Compatibility with HP Ada 83,,Representation Clauses,Compatibility and Porting Guide
-@anchor{gnat_rm/compatibility_and_porting_guide compatibility-with-hp-ada-83}@anchor{4a6}@anchor{gnat_rm/compatibility_and_porting_guide id17}@anchor{4a7}
+@anchor{gnat_rm/compatibility_and_porting_guide compatibility-with-hp-ada-83}@anchor{4a7}@anchor{gnat_rm/compatibility_and_porting_guide id17}@anchor{4a8}
@section Compatibility with HP Ada 83
@@ -33968,7 +34040,7 @@ extension of package System.
@end itemize
@node GNU Free Documentation License,Index,Compatibility and Porting Guide,Top
-@anchor{share/gnu_free_documentation_license doc}@anchor{4a8}@anchor{share/gnu_free_documentation_license gnu-fdl}@anchor{1}@anchor{share/gnu_free_documentation_license gnu-free-documentation-license}@anchor{4a9}
+@anchor{share/gnu_free_documentation_license doc}@anchor{4a9}@anchor{share/gnu_free_documentation_license gnu-fdl}@anchor{1}@anchor{share/gnu_free_documentation_license gnu-free-documentation-license}@anchor{4aa}
@chapter GNU Free Documentation License
diff --git a/gcc/ada/gsocket.h b/gcc/ada/gsocket.h
index 79836e8..5a553d1 100644
--- a/gcc/ada/gsocket.h
+++ b/gcc/ada/gsocket.h
@@ -64,6 +64,12 @@
#include <ioLib.h>
#include <hostLib.h>
+#if __has_include ("strings.h")
+/* On VxWorks6, FD_ZERO uses bzero, but since it's not a standard header, don't
+ require it. */
+#include "strings.h"
+#endif
+
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2
diff --git a/gcc/ada/inline.adb b/gcc/ada/inline.adb
index e8eeebd..5e2f033 100644
--- a/gcc/ada/inline.adb
+++ b/gcc/ada/inline.adb
@@ -3797,6 +3797,17 @@ package body Inline is
and then Is_Unc;
end if;
+ -- Inlining function calls returning an object of unconstrained type as
+ -- function actuals or in a return statement is not supported: a
+ -- temporary variable will be declared of unconstrained type without
+ -- initializing expression.
+
+ pragma Assert
+ (not Uses_Back_End
+ or else Nkind (Parent (N)) not in
+ N_Function_Call | N_Simple_Return_Statement
+ or else not Is_Unc);
+
-- Check for an illegal attempt to inline a recursive procedure. If the
-- subprogram has parameters this is detected when trying to supply a
-- binding for parameters that already have one. For parameterless
diff --git a/gcc/ada/libgnat/a-calend.adb b/gcc/ada/libgnat/a-calend.adb
index 4f89a40..0be5673 100644
--- a/gcc/ada/libgnat/a-calend.adb
+++ b/gcc/ada/libgnat/a-calend.adb
@@ -1068,19 +1068,28 @@ is
tv_nsec : out Long_Integer)
is
pragma Unsuppress (Overflow_Check);
- Secs : Duration;
- Nano_Secs : Duration;
begin
- -- Seconds extraction, avoid potential rounding errors
-
- Secs := D - 0.5;
- tv_sec := Long_Long_Integer (Secs);
-
- -- Nanoseconds extraction
+ if D = 0.0 then
+ tv_sec := 0;
+ tv_nsec := 0;
+
+ elsif D < 0.0 then
+ tv_sec := Long_Long_Integer (D + 0.5);
+ if D = Duration (tv_sec) then
+ tv_nsec := 0;
+ else
+ tv_nsec := Long_Integer ((D - Duration (tv_sec)) * Nano + 0.5);
+ end if;
- Nano_Secs := D - Duration (tv_sec);
- tv_nsec := Long_Integer (Nano_Secs * Nano);
+ else
+ tv_sec := Long_Long_Integer (D - 0.5);
+ if D = Duration (tv_sec) then
+ tv_nsec := 0;
+ else
+ tv_nsec := Long_Integer ((D - Duration (tv_sec)) * Nano - 0.5);
+ end if;
+ end if;
end To_Struct_Timespec_64;
------------------
diff --git a/gcc/ada/libgnat/a-cbhama.adb b/gcc/ada/libgnat/a-cbhama.adb
index ee6584d..b2d7964 100644
--- a/gcc/ada/libgnat/a-cbhama.adb
+++ b/gcc/ada/libgnat/a-cbhama.adb
@@ -368,7 +368,7 @@ is
-- Empty --
-----------
- function Empty (Capacity : Count_Type) return Map is
+ function Empty (Capacity : Count_Type := 10) return Map is
begin
return Result : Map (Capacity, 0) do
null;
diff --git a/gcc/ada/libgnat/a-cbhama.ads b/gcc/ada/libgnat/a-cbhama.ads
index 6ffc815..c741b40 100644
--- a/gcc/ada/libgnat/a-cbhama.ads
+++ b/gcc/ada/libgnat/a-cbhama.ads
@@ -71,7 +71,7 @@ is
-- Map objects declared without an initialization expression are
-- initialized to the value Empty_Map.
- function Empty (Capacity : Count_Type) return Map;
+ function Empty (Capacity : Count_Type := 10) return Map;
No_Element : constant Cursor;
-- Cursor objects declared without an initialization expression are
diff --git a/gcc/ada/libgnat/g-calend.adb b/gcc/ada/libgnat/g-calend.adb
index e410c3e..a2bc77c 100644
--- a/gcc/ada/libgnat/g-calend.adb
+++ b/gcc/ada/libgnat/g-calend.adb
@@ -344,6 +344,8 @@ package body GNAT.Calendar is
sec : aliased C.Extensions.long_long;
usec : aliased C.long;
+ pragma Unsuppress (Overflow_Check);
+
begin
timeval_to_duration (T, sec'Access, usec'Access);
pragma Annotate (CodePeer, Modified, sec);
@@ -369,13 +371,28 @@ package body GNAT.Calendar is
sec : C.Extensions.long_long;
usec : C.long;
+ pragma Unsuppress (Overflow_Check);
+
begin
if D = 0.0 then
sec := 0;
usec := 0;
+
+ elsif D < 0.0 then
+ sec := C.Extensions.long_long (D + 0.5);
+ if D = Duration (sec) then
+ usec := 0;
+ else
+ usec := C.long ((D - Duration (sec)) * Micro + 0.5);
+ end if;
+
else
- sec := C.Extensions.long_long (D - 0.5);
- usec := C.long ((D - Duration (sec)) * Micro - 0.5);
+ sec := C.Extensions.long_long (D - 0.5);
+ if D = Duration (sec) then
+ usec := 0;
+ else
+ usec := C.long ((D - Duration (sec)) * Micro - 0.5);
+ end if;
end if;
duration_to_timeval (sec, usec, Result'Access);
diff --git a/gcc/ada/libgnat/g-socket.adb b/gcc/ada/libgnat/g-socket.adb
index 5042dac..0fed791 100644
--- a/gcc/ada/libgnat/g-socket.adb
+++ b/gcc/ada/libgnat/g-socket.adb
@@ -3059,12 +3059,11 @@ package body GNAT.Sockets is
-- Normal case where we do round down
else
- S := time_t (Val - 0.5);
- uS := suseconds_t (1_000_000 * (Val - Selector_Duration (S)) - 0.5);
-
- if uS = -1 then
- -- It happen on integer duration
+ S := time_t (Val - 0.5);
+ if Val = Timeval_Duration (S) then
uS := 0;
+ else
+ uS := suseconds_t ((Val - Timeval_Duration (S)) * 1_000_000 - 0.5);
end if;
end if;
diff --git a/gcc/ada/s-oscons-tmplt.c b/gcc/ada/s-oscons-tmplt.c
index 97537ef..7a5e987 100644
--- a/gcc/ada/s-oscons-tmplt.c
+++ b/gcc/ada/s-oscons-tmplt.c
@@ -1976,7 +1976,7 @@ CND(CLOCK_THREAD_CPUTIME_ID, "Thread CPU clock")
#if defined(__linux__) || defined(__FreeBSD__) \
|| (defined(_AIX) && defined(_AIXVERSION_530)) \
|| defined(__DragonFly__) || defined(__QNX__) \
- || defined (__vxworks)
+ || (defined (__vxworks) && /* VxWorks7 */ defined (_VSB_CONFIG_FILE))
/** On these platforms use system provided monotonic clock instead of
** the default CLOCK_REALTIME. We then need to set up cond var attributes
** appropriately (see thread.c).
@@ -1985,6 +1985,10 @@ CND(CLOCK_THREAD_CPUTIME_ID, "Thread CPU clock")
** pthread_cond_timedwait (and does not have pthread_condattr_setclock),
** hence the conditionalization on AIX version above). _AIXVERSION_530
** is defined in AIX 5.3 and more recent versions.
+ **
+ ** VxWorks6 lacks pthread_condattr_setclock, so define CLOCK_RT_Ada to
+ ** CLOCK_REALTIME to get the dummy definition of __gnat_pthread_condattr_setup
+ ** in libgnarl/thread.c.
**/
# define CLOCK_RT_Ada "CLOCK_MONOTONIC"
diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb
index 9602944..f38380c 100644
--- a/gcc/ada/sem_attr.adb
+++ b/gcc/ada/sem_attr.adb
@@ -9359,6 +9359,20 @@ package body Sem_Attr is
when Attribute_First =>
Set_Bounds;
+ -- In GNATprove mode we only fold array attributes when prefix is
+ -- static (because that's required by the Ada rules) or at least can
+ -- be evaluated without checks (because GNATprove would miss them).
+
+ if GNATprove_Mode
+ and then
+ not (Static
+ or else (Is_Entity_Name (P) and then Is_Type (Entity (P)))
+ or else Statically_Names_Object (P)
+ or else Ekind (P_Type) = E_String_Literal_Subtype)
+ then
+ return;
+ end if;
+
if Compile_Time_Known_Value (Lo_Bound) then
if Is_Real_Type (P_Type) then
Fold_Ureal (N, Expr_Value_R (Lo_Bound), Static);
@@ -9572,6 +9586,20 @@ package body Sem_Attr is
when Attribute_Last =>
Set_Bounds;
+ -- In GNATprove mode we only fold array attributes when prefix is
+ -- static (because that's required by the Ada rules) or at least can
+ -- be evaluated without checks (because GNATprove would miss them).
+
+ if GNATprove_Mode
+ and then
+ not (Static
+ or else (Is_Entity_Name (P) and then Is_Type (Entity (P)))
+ or else Statically_Names_Object (P)
+ or else Ekind (P_Type) = E_String_Literal_Subtype)
+ then
+ return;
+ end if;
+
if Compile_Time_Known_Value (Hi_Bound) then
if Is_Real_Type (P_Type) then
Fold_Ureal (N, Expr_Value_R (Hi_Bound), Static);
@@ -9655,6 +9683,20 @@ package body Sem_Attr is
Set_Bounds;
+ -- In GNATprove mode we only fold array attributes when prefix is
+ -- static (because that's required by the Ada rules) or at least can
+ -- be evaluated without checks (because GNATprove would miss them).
+
+ if GNATprove_Mode
+ and then
+ not (Static
+ or else (Is_Entity_Name (P) and then Is_Type (Entity (P)))
+ or else Statically_Names_Object (P)
+ or else Ekind (P_Type) = E_String_Literal_Subtype)
+ then
+ return;
+ end if;
+
-- For two compile time values, we can compute length
if Compile_Time_Known_Value (Lo_Bound)
diff --git a/gcc/ada/sem_aux.adb b/gcc/ada/sem_aux.adb
index bb1624d..0aa74e3 100644
--- a/gcc/ada/sem_aux.adb
+++ b/gcc/ada/sem_aux.adb
@@ -25,7 +25,6 @@
with Atree; use Atree;
with Einfo; use Einfo;
-with Einfo.Entities; use Einfo.Entities;
with Einfo.Utils; use Einfo.Utils;
with Nlists; use Nlists;
with Sinfo; use Sinfo;
@@ -454,16 +453,28 @@ package body Sem_Aux is
Id : Entity_Id;
begin
+ -- Call using access to subprogram with explicit dereference
+
if Nkind (Nam) = N_Explicit_Dereference then
Id := Etype (Nam);
pragma Assert (Ekind (Id) = E_Subprogram_Type);
+ -- Case of call to simple entry, where the Name is a selected component
+ -- whose prefix is the task or protected record, and whose selector name
+ -- is the entry name.
+
elsif Nkind (Nam) = N_Selected_Component then
Id := Entity (Selector_Name (Nam));
+ -- Case of call to member of entry family, where Name is an indexed
+ -- component, with the prefix being a selected component giving the
+ -- task and entry family name, and the index being the entry index.
+
elsif Nkind (Nam) = N_Indexed_Component then
Id := Entity (Selector_Name (Prefix (Nam)));
+ -- Normal case
+
else
Id := Entity (Nam);
end if;
@@ -1546,6 +1557,81 @@ package body Sem_Aux is
return E;
end Ultimate_Alias;
+ ---------------------------
+ -- Unique_Component_Name --
+ ---------------------------
+
+ function Unique_Component_Name
+ (Component : Record_Field_Kind_Id) return Name_Id
+ is
+ Homographic_Component_Count : Pos := 1;
+ Hcc : Pos renames Homographic_Component_Count;
+ Enclosing_Type : Entity_Id :=
+ Underlying_Type (Base_Type (Scope (Component)));
+ begin
+ if Ekind (Enclosing_Type) = E_Record_Type
+ and then Is_Tagged_Type (Enclosing_Type)
+ and then Has_Private_Ancestor (Enclosing_Type)
+ then
+ -- traverse ancestors to determine Hcc value
+ loop
+ declare
+ Type_Decl : constant Node_Id :=
+ Parent (Underlying_Type (Base_Type (Enclosing_Type)));
+ Type_Def : constant Node_Id := Type_Definition (Type_Decl);
+ begin
+ exit when Nkind (Type_Def) /= N_Derived_Type_Definition;
+ Enclosing_Type :=
+ Underlying_Type (Base_Type (Etype (Enclosing_Type)));
+
+ declare
+ Ancestor_Comp : Opt_Record_Field_Kind_Id :=
+ First_Component_Or_Discriminant (Enclosing_Type);
+ begin
+ while Present (Ancestor_Comp) loop
+ if Chars (Ancestor_Comp) = Chars (Component) then
+ Hcc := Hcc + 1;
+ exit; -- exit not required, but might as well
+ end if;
+ Next_Component_Or_Discriminant (Ancestor_Comp);
+ end loop;
+ end;
+ end;
+ end loop;
+ end if;
+
+ if Hcc = 1 then
+ -- the usual case
+ return Chars (Component);
+ else
+ declare
+ Buff : Bounded_String;
+ begin
+ Append (Buff, Chars (Component));
+
+ Append (Buff, "__");
+ -- A double underscore in an identifier is legal in C, not in Ada.
+ -- Returning a result that is not a legal Ada identifier
+ -- ensures that we won't have problems with collisions.
+ -- If we have a component named Foo and we just append a
+ -- number (without any underscores), that new name might match
+ -- the name of another component (which would be bad).
+ -- The result of this function is intended for use as an
+ -- identifier in generated C code, so it needs to be a
+ -- legal C identifer.
+
+ Append (Buff, Hcc);
+ -- Should we instead append Hcc - 1 here? This is a human
+ -- readability question. If parent type and extension each
+ -- have a Foo component, do we want the name returned for the
+ -- second Foo to be "foo__2" or "foo__1" ? Does it matter?
+ -- Either way, the name returned for the first Foo will be "foo".
+
+ return Name_Find (Buff);
+ end;
+ end if;
+ end Unique_Component_Name;
+
--------------------------
-- Unit_Declaration_Node --
--------------------------
diff --git a/gcc/ada/sem_aux.ads b/gcc/ada/sem_aux.ads
index aad5d32..1a298a9 100644
--- a/gcc/ada/sem_aux.ads
+++ b/gcc/ada/sem_aux.ads
@@ -31,6 +31,7 @@
-- require more than minimal semantic knowledge.
with Alloc;
+with Einfo.Entities; use Einfo.Entities;
with Namet; use Namet;
with Table;
with Types; use Types;
@@ -405,6 +406,19 @@ package Sem_Aux is
-- Return the last entity in the chain of aliased entities of Prim. If Prim
-- has no alias return Prim.
+ function Unique_Component_Name
+ (Component : Record_Field_Kind_Id) return Name_Id;
+ -- Usually, a record type cannot have two components with the same name.
+ -- But in the case of a component declared in an extension of a tagged
+ -- private (or private extension) parent type, it is possible that some
+ -- ancestor type also has a (non-visible) component with the same name.
+ -- In the common case, this function simply returns the Chars attribute
+ -- of its argument.
+ -- But in the multiple-components-with-the-same-name case, it appends
+ -- a uniquifying suffix. The result in this case will not be a
+ -- syntactically valid Ada identifier, but it will be a syntactically
+ -- valid C identifier.
+
function Unit_Declaration_Node (Unit_Id : Entity_Id) return Node_Id;
-- Unit_Id is the simple name of a program unit, this function returns the
-- corresponding xxx_Declaration node for the entity. Also applies to the
diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb
index e80aea5..b5c9e88 100644
--- a/gcc/ada/sem_ch12.adb
+++ b/gcc/ada/sem_ch12.adb
@@ -7574,6 +7574,12 @@ package body Sem_Ch12 is
or else not Same_Instantiated_Function (E1, E2));
end if;
+ -- No check is needed if this is the body of a subprogram that is
+ -- implicitly created in the case of class-wide predefined functions.
+
+ elsif Ekind (E1) = E_Subprogram_Body then
+ null;
+
else
raise Program_Error;
end if;
@@ -14371,8 +14377,21 @@ package body Sem_Ch12 is
elsif
Scope (Scope (Base_Type (Etype (A_Gen_T)))) = Scope (A_Gen_T)
then
- Ancestor :=
- Get_Instance_Of (Base_Type (Etype (A_Gen_T)));
+ declare
+ Formal_Ancestor : constant Entity_Id :=
+ Base_Type (Etype (A_Gen_T));
+ begin
+ Ancestor := Get_Instance_Of (Formal_Ancestor);
+
+ -- Handle (rare) case where Get_Instance_Of found nothing in
+ -- the map.
+
+ if Ancestor = Formal_Ancestor then
+ Ancestor :=
+ Get_Instance_Of
+ (Base_Type (Etype (Get_Instance_Of (A_Gen_T))));
+ end if;
+ end;
-- The type may be a local derivation, or a type extension of a
-- previous formal, or of a formal of a parent package.
diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb
index 99acbf8..b7ada50 100644
--- a/gcc/ada/sem_ch13.adb
+++ b/gcc/ada/sem_ch13.adb
@@ -337,6 +337,13 @@ package body Sem_Ch13 is
-- Resolve each one of the arguments specified in the specification of
-- aspect Finalizable.
+ function Resolve_Finalization_Procedure
+ (N : Node_Id;
+ Typ : Entity_Id) return Boolean;
+ -- Resolve a procedure argument specified in the specification of one of
+ -- the finalization aspects, i.e. Finalizable and Destructor. Returns True
+ -- if successful, False otherwise.
+
procedure Resolve_Iterable_Operation
(N : Node_Id;
Cursor : Entity_Id;
@@ -4647,6 +4654,20 @@ package body Sem_Ch13 is
goto Continue;
end if;
+ when Aspect_Destructor =>
+ if not All_Extensions_Allowed then
+ Error_Msg_Name_1 := Nam;
+ Error_Msg_GNAT_Extension ("aspect %", Loc);
+ goto Continue;
+
+ elsif not Is_Type (E) then
+ Error_Msg_N ("can only be specified for a type", Aspect);
+ goto Continue;
+ end if;
+
+ Set_Has_Destructor (E);
+ Set_Is_Controlled_Active (E);
+
when Aspect_Storage_Model_Type =>
if not All_Extensions_Allowed then
Error_Msg_Name_1 := Nam;
@@ -5064,6 +5085,14 @@ package body Sem_Ch13 is
Check_Expr_Is_OK_Static_Expression (Expr, Any_Boolean);
end if;
+ -- Record the No_Task_Parts aspects as a rep item so it
+ -- can be consistently looked up on the full view of the
+ -- type.
+
+ if Is_Private_Type (E) then
+ Record_Rep_Item (E, Aspect);
+ end if;
+
goto Continue;
-- Ada 2022 (AI12-0075): static expression functions
@@ -11241,6 +11270,13 @@ package body Sem_Ch13 is
-- Start of processing for Check_Aspect_At_End_Of_Declarations
begin
+ -- Indicate that the expression comes from an aspect specification,
+ -- which is used in subsequent analysis even if expansion is off.
+
+ if Present (End_Decl_Expr) then
+ Set_Parent (End_Decl_Expr, ASN);
+ end if;
+
-- In an instance we do not perform the consistency check between freeze
-- point and end of declarations, because it was done already in the
-- analysis of the generic. Furthermore, the delayed analysis of an
@@ -11270,6 +11306,7 @@ package body Sem_Ch13 is
-- the one available at at the freeze point.
elsif A_Id in Aspect_Constructor
+ | Aspect_Destructor
| Aspect_Input
| Aspect_Output
| Aspect_Read
@@ -11332,13 +11369,6 @@ package body Sem_Ch13 is
end if;
end if;
- -- Indicate that the expression comes from an aspect specification,
- -- which is used in subsequent analysis even if expansion is off.
-
- if Present (End_Decl_Expr) then
- Set_Parent (End_Decl_Expr, ASN);
- end if;
-
-- In a generic context the original aspect expressions have not
-- been preanalyzed, so do it now. There are no conformance checks
-- to perform in this case. As before, we have to make components
@@ -11734,6 +11764,67 @@ package body Sem_Ch13 is
Analyze (Expression (ASN));
return;
+ when Aspect_Destructor =>
+ if not Is_Record_Type (Entity (ASN)) then
+ Error_Msg_N
+ ("aspect Destructor can only be specified for a "
+ & "record type",
+ ASN);
+ return;
+ end if;
+
+ Set_Has_Destructor (Entity (ASN));
+ Set_Is_Controlled_Active (Entity (ASN));
+
+ Analyze (Expression (ASN));
+
+ if not Resolve_Finalization_Procedure
+ (Expression (ASN), Entity (ASN))
+ then
+ Error_Msg_N
+ ("destructor must be local procedure whose only formal "
+ & "parameter has mode `IN OUT` and is of the type the "
+ & "destructor is for",
+ Expression (ASN));
+ end if;
+
+ Set_Is_Destructor (Entity (Expression (ASN)));
+
+ declare
+ Proc : constant Entity_Id := Entity (Expression (ASN));
+ Overr : constant Opt_N_Entity_Id :=
+ Overridden_Inherited_Operation (Proc);
+ Orig : constant Entity_Id :=
+ (if Present (Overr) then Overr else Proc);
+
+ Decl : constant Node_Id :=
+ Parent
+ (if Nkind (Parent (Orig)) = N_Procedure_Specification
+ then Parent (Orig)
+ else Orig);
+
+ Encl : constant Node_Id := Parent (Decl);
+
+ Is_Private : constant Boolean :=
+ Nkind (Encl) = N_Package_Specification
+ and then Is_List_Member (Decl)
+ and then List_Containing (Decl) = Private_Declarations (Encl);
+
+ begin
+
+ if Has_Private_Declaration (Entity (ASN))
+ and then not Aspect_On_Partial_View (ASN)
+ and then not Is_Private
+ then
+ Error_Msg_N
+ ("aspect Destructor on full view cannot denote public "
+ & "primitive",
+ ASN);
+ end if;
+ end;
+
+ return;
+
when Aspect_Storage_Model_Type =>
-- The aggregate argument of Storage_Model_Type is optional, and
@@ -15887,6 +15978,8 @@ package body Sem_Ch13 is
-- We may freeze Subp_Id immediately since Ent has just been frozen.
-- This will help to shield us from potential late freezing issues.
+ Mutate_Ekind (Subp_Id, E_Procedure);
+ Freeze_Extra_Formals (Subp_Id);
Set_Is_Frozen (Subp_Id);
else
@@ -17334,6 +17427,35 @@ package body Sem_Ch13 is
Typ : Entity_Id;
Nam : Name_Id)
is
+ begin
+ if Nam = Name_Relaxed_Finalization then
+ Resolve (N, Any_Boolean);
+
+ if Is_OK_Static_Expression (N) then
+ Set_Has_Relaxed_Finalization (Typ, Is_True (Static_Boolean (N)));
+
+ else
+ Flag_Non_Static_Expr
+ ("expression of aspect Finalizable must be static!", N);
+ end if;
+
+ return;
+ end if;
+
+ if Resolve_Finalization_Procedure (N, Typ) then
+ return;
+ end if;
+
+ Error_Msg_N
+ ("finalizable primitive must be local procedure whose only formal " &
+ "parameter has mode `IN OUT` and is of the finalizable type", N);
+ end Resolve_Finalizable_Argument;
+
+ function Resolve_Finalization_Procedure
+ (N : Node_Id;
+ Typ : Entity_Id)
+ return Boolean
+ is
function Is_Finalizable_Primitive (E : Entity_Id) return Boolean;
-- Check whether E is a finalizable primitive for Typ
@@ -17351,29 +17473,15 @@ package body Sem_Ch13 is
and then No (Next_Formal (First_Formal (E)));
end Is_Finalizable_Primitive;
- -- Start of processing for Resolve_Finalizable_Argument
+ -- Start of processing for Resolve_Finalization_Procedure
begin
- if Nam = Name_Relaxed_Finalization then
- Resolve (N, Any_Boolean);
-
- if Is_OK_Static_Expression (N) then
- Set_Has_Relaxed_Finalization (Typ, Is_True (Static_Boolean (N)));
-
- else
- Flag_Non_Static_Expr
- ("expression of aspect Finalizable must be static!", N);
- end if;
-
- return;
- end if;
-
if not Is_Entity_Name (N) then
null;
elsif not Is_Overloaded (N) then
if Is_Finalizable_Primitive (Entity (N)) then
- return;
+ return True;
end if;
else
@@ -17389,7 +17497,7 @@ package body Sem_Ch13 is
while Present (It.Typ) loop
if Is_Finalizable_Primitive (It.Nam) then
Set_Entity (N, It.Nam);
- return;
+ return True;
end if;
Get_Next_Interp (I, It);
@@ -17397,10 +17505,8 @@ package body Sem_Ch13 is
end;
end if;
- Error_Msg_N
- ("finalizable primitive must be local procedure whose only formal " &
- "parameter has mode `IN OUT` and is of the finalizable type", N);
- end Resolve_Finalizable_Argument;
+ return False;
+ end Resolve_Finalization_Procedure;
--------------------------------
-- Resolve_Iterable_Operation --
diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb
index 5354d82..3726169 100644
--- a/gcc/ada/sem_ch3.adb
+++ b/gcc/ada/sem_ch3.adb
@@ -3020,6 +3020,8 @@ package body Sem_Ch3 is
-----------------------------------
procedure Analyze_Full_Type_Declaration (N : Node_Id) is
+ use Deferred_Extra_Formals_Support;
+
Def : constant Node_Id := Type_Definition (N);
Def_Id : constant Entity_Id := Defining_Identifier (N);
T : Entity_Id;
@@ -3558,6 +3560,16 @@ package body Sem_Ch3 is
end if;
end if;
+ -- If we have some subprogram, subprogram type, or entry, with deferred
+ -- addition of its extra formals (because the underlying type of this
+ -- type was not previously available), then try creating now its extra
+ -- formals. Create also the extra actuals of deferred calls to entities
+ -- with deferred extra formals.
+
+ if Has_Deferred_Extra_Formals (T) then
+ Add_Deferred_Extra_Params (T);
+ end if;
+
if Ekind (T) = E_Record_Type
and then Is_Large_Unconstrained_Definite (T)
and then not Is_Limited_Type (T)
@@ -6819,7 +6831,7 @@ package body Sem_Ch3 is
-- that the element type is constrained.
if Is_Mutably_Tagged_Type (Element_Type) then
- Set_Component_Type (T,
+ Set_Component_Type (Base_Type (T),
Class_Wide_Equivalent_Type (Element_Type));
elsif not Is_Definite_Subtype (Element_Type) then
@@ -8440,15 +8452,17 @@ package body Sem_Ch3 is
Set_Has_Private_Declaration (Full_Der);
Set_Has_Private_Declaration (Derived_Type);
- Set_Scope (Full_Der, Scope (Derived_Type));
- Set_Is_First_Subtype (Full_Der, Is_First_Subtype (Derived_Type));
- Set_Has_Size_Clause (Full_Der, False);
- Set_Has_Alignment_Clause (Full_Der, False);
- Set_Has_Delayed_Freeze (Full_Der);
- Set_Is_Frozen (Full_Der, False);
- Set_Freeze_Node (Full_Der, Empty);
- Set_Depends_On_Private (Full_Der, Has_Private_Component (Full_Der));
- Set_Is_Public (Full_Der, Is_Public (Derived_Type));
+ Set_Scope (Full_Der, Scope (Derived_Type));
+ Set_Is_First_Subtype (Full_Der, Is_First_Subtype (Derived_Type));
+ Set_Has_Size_Clause (Full_Der, False);
+ Set_Has_Alignment_Clause (Full_Der, False);
+ Set_Has_Delayed_Freeze (Full_Der);
+ Set_Is_Frozen (Full_Der, False);
+ Set_Freeze_Node (Full_Der, Empty);
+ Set_Depends_On_Private
+ (Full_Der, Has_Private_Component (Full_Der));
+ Set_Is_Public (Full_Der, Is_Public (Derived_Type));
+ Set_Is_Implicit_Full_View (Full_Der);
-- The convention on the base type may be set in the private part
-- and not propagated to the subtype until later, so we obtain the
@@ -9646,6 +9660,8 @@ package body Sem_Ch3 is
(New_Decl, Parent_Base, New_Base,
Is_Completion => False, Derive_Subps => False);
+ Set_Is_Implicit_Full_View (New_Base);
+
-- ??? This needs re-examination to determine whether the
-- following call can simply be replaced by a call to Analyze.
@@ -21279,8 +21295,8 @@ package body Sem_Ch3 is
-- On entry, the current scope is the composite type.
-- The discriminants are initially entered into the scope of the type
- -- via Enter_Name with the default Ekind of E_Void to prevent premature
- -- use, as explained at the end of this procedure.
+ -- via Enter_Name with Is_Not_Self_Hidden set to False to prevent
+ -- premature use, as explained at the end of this procedure.
Discr := First (Discriminant_Specifications (N));
while Present (Discr) loop
@@ -21553,12 +21569,12 @@ package body Sem_Ch3 is
-- expressions of a discriminant part if the specification of the
-- discriminant is itself given in the discriminant part. (RM 3.7.1)
- -- To detect this, the discriminant names are entered initially with an
- -- Ekind of E_Void (which is the default Ekind given by Enter_Name). Any
- -- attempt to use a void entity (for example in an expression that is
- -- type-checked) produces the error message: premature usage. Now after
- -- completing the semantic analysis of the discriminant part, we can set
- -- the Ekind of all the discriminants appropriately.
+ -- To detect this, the discriminant names are entered initially with
+ -- Is_Not_Self_Hidden set to False. Any attempt to use a self-hidden
+ -- entity (for example in an expression that is type-checked) produces
+ -- the error message: premature usage. Now after completing the semantic
+ -- analysis of the discriminant part, we can set Is_Not_Self_Hidden on
+ -- all the discriminants appropriately.
Discr := First (Discriminant_Specifications (N));
Discr_Number := Uint_1;
diff --git a/gcc/ada/sem_ch4.adb b/gcc/ada/sem_ch4.adb
index 56dc7c6..018c8a0 100644
--- a/gcc/ada/sem_ch4.adb
+++ b/gcc/ada/sem_ch4.adb
@@ -5603,6 +5603,10 @@ package body Sem_Ch4 is
if No (Act_Decl) then
Set_Etype (N, Etype (Comp));
+ if Is_Mutably_Tagged_CW_Equivalent_Type (Etype (N)) then
+ Make_Mutably_Tagged_Conversion (N);
+ end if;
+
else
-- If discriminants were present in the component
-- declaration, they have been replaced by the
@@ -10406,11 +10410,14 @@ package body Sem_Ch4 is
-- may be candidates, so that Try_Primitive_Operations can examine
-- them if no real primitive is found.
- function Is_Private_Overriding (Op : Entity_Id) return Boolean;
+ function Is_Callable_Private_Overriding
+ (Op : Entity_Id) return Boolean;
-- An operation that overrides an inherited operation in the private
-- part of its package may be hidden, but if the inherited operation
- -- is visible a direct call to it will dispatch to the private one,
- -- which is therefore a valid candidate.
+ -- that it overrides is visible, then a direct call to it will
+ -- dispatch to the private one, which is therefore a valid candidate.
+ -- Returns True if the operation can be called from outside the
+ -- enclosing package.
function Names_Match
(Obj_Type : Entity_Id;
@@ -10581,11 +10588,13 @@ package body Sem_Ch4 is
return Op_List;
end Extended_Primitive_Ops;
- ---------------------------
- -- Is_Private_Overriding --
- ---------------------------
+ ------------------------------------
+ -- Is_Callable_Private_Overriding --
+ ------------------------------------
- function Is_Private_Overriding (Op : Entity_Id) return Boolean is
+ function Is_Callable_Private_Overriding
+ (Op : Entity_Id) return Boolean
+ is
Visible_Op : Entity_Id;
begin
@@ -10607,7 +10616,10 @@ package body Sem_Ch4 is
-- have found what we're looking for.
if not Is_Hidden (Visible_Op)
- or else not Is_Hidden (Overridden_Operation (Op))
+ or else
+ (Present (Overridden_Inherited_Operation (Op))
+ and then not Is_Hidden
+ (Overridden_Inherited_Operation (Op)))
then
return True;
end if;
@@ -10617,7 +10629,7 @@ package body Sem_Ch4 is
end loop;
return False;
- end Is_Private_Overriding;
+ end Is_Callable_Private_Overriding;
-----------------
-- Names_Match --
@@ -10760,13 +10772,15 @@ package body Sem_Ch4 is
-- Do not consider hidden primitives unless the type is in an
-- open scope or we are within an instance, where visibility
- -- is known to be correct, or else if this is an overriding
- -- operation in the private part for an inherited operation.
+ -- is known to be correct, or else if this is an operation
+ -- declared in the private part that overrides a visible
+ -- inherited operation.
or else (Is_Hidden (Prim_Op)
and then not Is_Immediately_Visible (Obj_Type)
and then not In_Instance
- and then not Is_Private_Overriding (Prim_Op))
+ and then
+ not Is_Callable_Private_Overriding (Prim_Op))
then
goto Continue;
end if;
diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb
index e1d6be4..0661e64 100644
--- a/gcc/ada/sem_ch5.adb
+++ b/gcc/ada/sem_ch5.adb
@@ -807,7 +807,14 @@ package body Sem_Ch5 is
if Is_Tag_Indeterminate (Rhs) then
if Is_Class_Wide_Type (T1) then
- Propagate_Tag (Lhs, Rhs);
+
+ -- No need to propagate the tag when the RHS has function calls
+ -- that already propagated it (see Expand_Call_Helper), or if
+ -- some error was reported analyzing RHS.
+
+ if not (Error_Posted (Rhs) or else Tag_Propagated (Lhs)) then
+ Propagate_Tag (Lhs, Rhs);
+ end if;
elsif Nkind (Rhs) = N_Function_Call
and then Is_Entity_Name (Name (Rhs))
diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb
index 48dcf8e..709f625 100644
--- a/gcc/ada/sem_ch6.adb
+++ b/gcc/ada/sem_ch6.adb
@@ -3864,9 +3864,14 @@ package body Sem_Ch6 is
Spec_Id := Build_Internal_Protected_Declaration (N);
end if;
- -- If a separate spec is present, then deal with freezing issues
+ -- Separate spec is not present
- if Present (Spec_Id) then
+ if No (Spec_Id) then
+ Create_Extra_Formals (Body_Id);
+
+ -- Separate spec is present; deal with freezing issues
+
+ else
Spec_Decl := Unit_Declaration_Node (Spec_Id);
Verify_Overriding_Indicator;
@@ -3882,6 +3887,8 @@ package body Sem_Ch6 is
and then not Has_BIP_Formals (Spec_Id)
then
Create_Extra_Formals (Spec_Id);
+ pragma Assert (not Expander_Active
+ or else Extra_Formals_Known (Spec_Id));
Compute_Returns_By_Ref (Spec_Id);
end if;
@@ -8564,14 +8571,13 @@ package body Sem_Ch6 is
-- without coordinating with CodePeer, which makes use of these to
-- provide better messages.
+ -- A and B denote extra formals for unchecked unions equality. See
+ -- exp_ch3.Build_Variant_Record_Equality.
-- O denotes the Constrained bit.
-- L denotes the accessibility level.
-- BIP_xxx denotes an extra formal for a build-in-place function. See
-- the full list in exp_ch6.BIP_Formal_Kind.
- function Has_Extra_Formals (E : Entity_Id) return Boolean;
- -- Determines if E has its extra formals
-
function Might_Need_BIP_Task_Actuals (E : Entity_Id) return Boolean;
-- Determines if E is a function or an access to a function returning a
-- limited tagged type object. On dispatching primitives this predicate
@@ -8610,14 +8616,6 @@ package body Sem_Ch6 is
EF : Entity_Id;
begin
- -- A little optimization. Never generate an extra formal for the
- -- _init operand of an initialization procedure, since it could
- -- never be used.
-
- if Chars (Formal) = Name_uInit then
- return Empty;
- end if;
-
EF := Make_Defining_Identifier (Sloc (Assoc_Entity),
Chars => New_External_Name (Chars (Assoc_Entity),
Suffix => Suffix));
@@ -8643,25 +8641,22 @@ package body Sem_Ch6 is
return EF;
end Add_Extra_Formal;
- -----------------------
- -- Has_Extra_Formals --
- -----------------------
-
- function Has_Extra_Formals (E : Entity_Id) return Boolean is
- begin
- return Present (Extra_Formals (E))
- or else
- (Ekind (E) = E_Function
- and then Present (Extra_Accessibility_Of_Result (E)));
- end Has_Extra_Formals;
-
---------------------------------
-- Might_Need_BIP_Task_Actuals --
---------------------------------
function Might_Need_BIP_Task_Actuals (E : Entity_Id) return Boolean is
Subp_Id : Entity_Id;
- Func_Typ : Entity_Id;
+ Original : Entity_Id;
+ Root : Entity_Id;
+
+ function Has_No_Task_Parts_Enabled (E : Entity_Id) return Boolean
+ is (Has_Enabled_Aspect (E, Aspect_No_Task_Parts));
+
+ function Collect_Ancestors_With_No_Task_Parts is new
+ Collect_Types_In_Hierarchy (Predicate => Has_No_Task_Parts_Enabled);
+
+ -- Start of processing for Might_Need_BIP_Task_Actuals
begin
if Global_No_Tasking or else No_Run_Time_Mode then
@@ -8689,21 +8684,29 @@ package body Sem_Ch6 is
then
Subp_Id := Protected_Body_Subprogram (E);
- else
+ -- For access-to-subprogram types we look at the return type of the
+ -- subprogram type itself, as it cannot be overridden or inherited.
+
+ elsif Ekind (E) = E_Subprogram_Type then
Subp_Id := E;
- end if;
- -- We check the root type of the return type since the same
- -- decision must be taken for all descendants overriding a
- -- dispatching operation.
+ -- Otherwise, we need to return the same value we would return for
+ -- the original corresponding operation of the root of the aliased
+ -- chain.
+
+ else
+ Subp_Id := Original_Corresponding_Operation (Ultimate_Alias (E));
+ end if;
- Func_Typ := Root_Type (Underlying_Type (Etype (Subp_Id)));
+ Original := Underlying_Type (Etype (Subp_Id));
+ Root := Underlying_Type (Root_Type (Original));
return Ekind (Subp_Id) in E_Function | E_Subprogram_Type
- and then not Has_Foreign_Convention (Func_Typ)
- and then Is_Tagged_Type (Func_Typ)
- and then Is_Limited_Type (Func_Typ)
- and then not Has_Aspect (Func_Typ, Aspect_No_Task_Parts);
+ and then Is_Inherently_Limited_Type (Original)
+ and then not Has_Foreign_Convention (Root)
+ and then Is_Tagged_Type (Root)
+ and then Is_Empty_Elmt_List
+ (Collect_Ancestors_With_No_Task_Parts (Original));
end Might_Need_BIP_Task_Actuals;
-------------------------------------
@@ -8792,10 +8795,12 @@ package body Sem_Ch6 is
-- we have no direct way to climb to the corresponding parent
-- subprogram but this internal entity has the extra formals
-- (if any) required for the purpose of checking the extra
- -- formals of Subp_Id.
+ -- formals of Subp_Id because its extra formals are shared
+ -- with its parent subprogram (see Sem_Ch3.Derive_Subprogram).
else
pragma Assert (not Comes_From_Source (Ovr_E));
+ Freeze_Extra_Formals (Ovr_E);
end if;
-- Use as our reference entity the ultimate renaming of the
@@ -8818,10 +8823,14 @@ package body Sem_Ch6 is
-- Local variables
- Formal_Type : Entity_Id;
- May_Have_Alias : Boolean;
+ use Deferred_Extra_Formals_Support;
+
+ Can_Be_Deferred : constant Boolean :=
+ not Is_Unsupported_Extra_Formals_Entity (E);
Alias_Formal : Entity_Id := Empty;
Alias_Subp : Entity_Id := Empty;
+ Formal_Type : Entity_Id;
+ May_Have_Alias : Boolean;
Parent_Formal : Entity_Id := Empty;
Parent_Subp : Entity_Id := Empty;
Ref_E : Entity_Id;
@@ -8832,10 +8841,18 @@ package body Sem_Ch6 is
pragma Assert (Is_Subprogram_Or_Entry (E)
or else Ekind (E) in E_Subprogram_Type);
+ -- No action needed if extra formals were already handled. This
+ -- situation may arise because of a previous call to create the
+ -- extra formals, and also for subprogram types created as part
+ -- of dispatching calls (see Expand_Dispatching_Call).
+
+ if Extra_Formals_Known (E) then
+ return;
+
-- We never generate extra formals if expansion is not active because we
-- don't need them unless we are generating code.
- if not Expander_Active then
+ elsif not Expander_Active then
return;
-- Enumeration literals have no extra formal; this case occurs when
@@ -8844,25 +8861,38 @@ package body Sem_Ch6 is
elsif Ekind (E) = E_Function
and then Ekind (Ultimate_Alias (E)) = E_Enumeration_Literal
then
+ Freeze_Extra_Formals (E);
return;
- -- Extra formals of Initialization procedures are added by the function
- -- Exp_Ch3.Init_Formals
+ -- Extra formals of init procs are added by Exp_Ch3.Init_Formals and
+ -- Set_CPP_Constructors when they are built, but we must handle here
+ -- aliased init procs.
elsif Is_Init_Proc (E) then
+ pragma Assert (Present (Alias (E)));
+ pragma Assert (Extra_Formals_Known (Ultimate_Alias (E)));
+ Freeze_Extra_Formals (E);
return;
-- No need to generate extra formals in thunks whose target has no extra
-- formals, but we can have two of them chained (interface and stack).
- elsif Is_Thunk (E) and then No (Extra_Formals (Thunk_Target (E))) then
+ elsif Is_Thunk (E)
+ and then Extra_Formals_Known (Thunk_Target (E))
+ and then No (Extra_Formals (Thunk_Target (E)))
+ then
+ Freeze_Extra_Formals (E);
return;
- -- If Extra_Formals were already created, don't do it again. This
- -- situation may arise for subprogram types created as part of
- -- dispatching calls (see Expand_Dispatching_Call).
+ -- Handle alias of unchecked union equality with frozen extra formals
- elsif Has_Extra_Formals (E) then
+ elsif Is_Overloadable (E)
+ and then Present (Alias (E))
+ and then Extra_Formals_Known (Ultimate_Alias (E))
+ and then Is_Unchecked_Union_Equality (Ultimate_Alias (E))
+ then
+ Set_Extra_Formals (E, Extra_Formals (Ultimate_Alias (E)));
+ Freeze_Extra_Formals (E);
return;
-- Extra formals of renamings of generic actual subprograms and
@@ -8880,6 +8910,8 @@ package body Sem_Ch6 is
= Is_Generic_Instance (Ultimate_Alias (E)));
Create_Extra_Formals (Ultimate_Alias (E));
+ pragma Assert (not Expander_Active
+ or else Extra_Formals_Known (Ultimate_Alias (E)));
-- Share the extra formals
@@ -8891,17 +8923,72 @@ package body Sem_Ch6 is
end if;
pragma Assert (Extra_Formals_OK (E));
+ Freeze_Extra_Formals (E);
return;
end if;
- -- Locate the last formal; required by Add_Extra_Formal.
+ -- Check if the addition of the extra formals must be deferred
Formal := First_Formal (E);
while Present (Formal) loop
- Last_Extra := Formal;
+ if No (Underlying_Type (Etype (Formal)))
+ and then Can_Be_Deferred
+ then
+ Register_Deferred_Extra_Formals_Entity (E);
+ return;
+ end if;
+
Next_Formal (Formal);
end loop;
+ if Ekind (E) in E_Function
+ | E_Subprogram_Type
+ and then No (Underlying_Type (Etype (E)))
+ and then Can_Be_Deferred
+ then
+ Register_Deferred_Extra_Formals_Entity (E);
+ return;
+ end if;
+
+ -- Here we start adding the extra formals
+
+ -- We we know that either the underlying type of all the formals and
+ -- returned results of E are known, or this is an special case where
+ -- some underlying type is still not available.
+
+ -- In the former case, we can already mark functions that return their
+ -- result by reference; in the latter case, we can mark them only if the
+ -- underlying return type is available (and it will be marked later).
+
+ if not Is_Unsupported_Extra_Formals_Entity (E)
+ or else (Ekind (E) in E_Function | E_Subprogram_Type
+ and then Present (Underlying_Type (Etype (E))))
+ then
+ Compute_Returns_By_Ref (E);
+ end if;
+
+ -- Locate the last formal (required by Add_Extra_Formal)
+
+ if Present (First_Formal (E))
+ and then Is_Unchecked_Union (Etype (First_Formal (E)))
+ and then Present (Extra_Formals (E))
+ and then Has_Suffix (Extra_Formals (E), 'A')
+ then
+ -- An unchecked union equality has two extra formals per discriminant
+
+ First_Extra := Extra_Formals (E);
+ Last_Extra := First_Extra;
+ while Present (Last_Extra) loop
+ pragma Assert (Has_Suffix (Last_Extra, 'A'));
+ Last_Extra := Extra_Formal (Last_Extra);
+
+ pragma Assert (Has_Suffix (Last_Extra, 'B'));
+ Last_Extra := Extra_Formal (Last_Extra);
+ end loop;
+ else
+ Last_Extra := Last_Formal (E);
+ end if;
+
-- We rely on three entities to ensure consistency of extra formals of
-- entity E:
--
@@ -8961,6 +9048,7 @@ package body Sem_Ch6 is
or else (Present (Alias_Subp)
and then Has_Foreign_Convention (Alias_Subp))
then
+ Freeze_Extra_Formals (E);
return;
end if;
@@ -9039,14 +9127,44 @@ package body Sem_Ch6 is
-- Here we establish our priority for deciding on the extra
-- formals: 1) Parent primitive 2) Aliased primitive 3) Identity
- if Present (Parent_Formal) then
- Formal_Type := Etype (Parent_Formal);
+ -- Common case: the underlying type of all the formals is known
+ -- to be available.
+
+ if Can_Be_Deferred then
+ if Present (Parent_Formal) then
+ Formal_Type := Underlying_Type (Etype (Parent_Formal));
+ elsif Present (Alias_Formal) then
+ Formal_Type := Underlying_Type (Etype (Alias_Formal));
+ else
+ Formal_Type := Underlying_Type (Etype (Formal));
+ end if;
+
+ pragma Assert (Present (Formal_Type));
- elsif Present (Alias_Formal) then
- Formal_Type := Etype (Alias_Formal);
+ -- Special case: The underlying type of some formal is not available.
+ -- We use the underlying type when present. More work needed here???
else
- Formal_Type := Etype (Formal);
+ if Present (Parent_Formal) then
+ Formal_Type := Etype (Parent_Formal);
+
+ if Present (Underlying_Type (Formal_Type)) then
+ Formal_Type := Underlying_Type (Formal_Type);
+ end if;
+
+ elsif Present (Alias_Formal) then
+ Formal_Type := Etype (Alias_Formal);
+
+ if Present (Underlying_Type (Formal_Type)) then
+ Formal_Type := Underlying_Type (Formal_Type);
+ end if;
+ else
+ Formal_Type := Etype (Formal);
+
+ if Present (Underlying_Type (Formal_Type)) then
+ Formal_Type := Underlying_Type (Formal_Type);
+ end if;
+ end if;
end if;
-- Create extra formal for supporting the attribute 'Constrained.
@@ -9093,12 +9211,13 @@ package body Sem_Ch6 is
and then (Is_Definite_Subtype (Formal_Type)
or else Is_Mutably_Tagged_Type (Formal_Type))
and then (Ada_Version < Ada_2012
- or else No (Underlying_Type (Formal_Type))
+ or else
+ (not Can_Be_Deferred
+ and then No (Underlying_Type (Formal_Type)))
or else not
(Is_Limited_Type (Formal_Type)
and then
- Is_Tagged_Type
- (Underlying_Type (Formal_Type))))
+ Is_Tagged_Type (Formal_Type)))
then
Set_Extra_Constrained
(Formal, Add_Extra_Formal (Formal, Standard_Boolean, E, "O"));
@@ -9337,6 +9456,8 @@ package body Sem_Ch6 is
Set_Extra_Formals (Alias (E), Extra_Formals (E));
end if;
+ Freeze_Extra_Formals (E);
+
pragma Assert (No (Alias_Subp)
or else Extra_Formals_Match_OK (E, Alias_Subp));
@@ -9651,6 +9772,19 @@ package body Sem_Ch6 is
return False;
end if;
+ -- Extra formals (A and B) of Unchecked_Unions (see Build_Variant_
+ -- Record_Equality)
+
+ elsif Has_Suffix (Formal_1, 'A') then
+ if not Has_Suffix (Formal_2, 'A') then
+ return False;
+ end if;
+
+ elsif Has_Suffix (Formal_1, 'B') then
+ if not Has_Suffix (Formal_2, 'B') then
+ return False;
+ end if;
+
elsif BIP_Suffix_Kind (Formal_1) /= BIP_Suffix_Kind (Formal_2) then
return False;
end if;
@@ -10003,6 +10137,16 @@ package body Sem_Ch6 is
return Empty;
end Find_Corresponding_Spec;
+ --------------------------
+ -- Freeze_Extra_Formals --
+ --------------------------
+
+ procedure Freeze_Extra_Formals (E : Entity_Id) is
+ begin
+ pragma Assert (not Extra_Formals_Known (E));
+ Set_Extra_Formals_Known (E);
+ end Freeze_Extra_Formals;
+
----------------------
-- Fully_Conformant --
----------------------
@@ -10622,6 +10766,10 @@ package body Sem_Ch6 is
Formal : Entity_Id := First_Formal_With_Extras (E);
begin
+ -- It makes no sense to perform this check if the extra formals
+ -- have not been added.
+ pragma Assert (Extra_Formals_Known (E));
+
while Present (Formal) loop
if Is_Build_In_Place_Entity (Formal) then
return True;
@@ -12133,36 +12281,51 @@ package body Sem_Ch6 is
and then Present (Find_Dispatching_Type (Alias (S)))
and then Is_Interface (Find_Dispatching_Type (Alias (S)))
then
- -- For private types, when the full-view is processed we propagate to
- -- the full view the non-overridden entities whose attribute "alias"
- -- references an interface primitive. These entities were added by
- -- Derive_Subprograms to ensure that interface primitives are
- -- covered.
-
- -- Inside_Freeze_Actions is non zero when S corresponds with an
- -- internal entity that links an interface primitive with its
- -- covering primitive through attribute Interface_Alias (see
- -- Add_Internal_Interface_Entities).
-
- if Inside_Freezing_Actions = 0
- and then Is_Package_Or_Generic_Package (Current_Scope)
- and then In_Private_Part (Current_Scope)
- and then Parent_Kind (E) = N_Private_Extension_Declaration
- and then Nkind (Parent (S)) = N_Full_Type_Declaration
- and then Full_View (Defining_Identifier (Parent (E)))
- = Defining_Identifier (Parent (S))
- and then Alias (E) = Alias (S)
- then
- Check_Operation_From_Private_View (S, E);
- Set_Is_Dispatching_Operation (S);
+ declare
+ Private_Operation_Exported_By_Visible_Part : constant Boolean :=
+ Is_Package_Or_Generic_Package (Current_Scope)
+ and then In_Private_Part (Current_Scope)
+ and then Parent_Kind (E) = N_Private_Extension_Declaration
+ and then Nkind (Parent (S)) = N_Full_Type_Declaration
+ and then Full_View (Defining_Identifier (Parent (E)))
+ = Defining_Identifier (Parent (S));
+
+ begin
+ -- For private types, when the full view is processed we propagate
+ -- to the full view the nonoverridden entities whose attribute
+ -- "alias" references an interface primitive. These entities were
+ -- added by Derive_Subprograms to ensure that interface primitives
+ -- are covered.
+
+ -- Inside_Freeze_Actions is nonzero when S corresponds to an
+ -- internal entity that links an interface primitive with its
+ -- covering primitive through attribute Interface_Alias (see
+ -- Add_Internal_Interface_Entities).
+
+ if Inside_Freezing_Actions = 0
+ and then Private_Operation_Exported_By_Visible_Part
+ and then Alias (E) = Alias (S)
+ then
+ Check_Operation_From_Private_View (S, E);
+ Set_Is_Dispatching_Operation (S);
- -- Common case
+ -- Common case
- else
- Enter_Overloaded_Entity (S);
- Check_Dispatching_Operation (S, Empty);
- Check_For_Primitive_Subprogram (Is_Primitive_Subp);
- end if;
+ else
+ Enter_Overloaded_Entity (S);
+ Check_Dispatching_Operation (S, Empty);
+ Check_For_Primitive_Subprogram (Is_Primitive_Subp);
+ end if;
+
+ if Private_Operation_Exported_By_Visible_Part
+ and then Type_Conformant (E, S)
+ then
+ -- Record the actual inherited subprogram that's being
+ -- overridden.
+
+ Set_Overridden_Inherited_Operation (S, E);
+ end if;
+ end;
return;
end if;
@@ -12601,6 +12764,26 @@ package body Sem_Ch6 is
and then not Is_Dispatch_Table_Wrapper (S)))
then
Set_Overridden_Operation (S, Alias (E));
+
+ -- Record the actual inherited subprogram that's being
+ -- overridden. In the case where a subprogram declared
+ -- in a private part overrides an inherited subprogram
+ -- that itself is also declared in the private part,
+ -- and that subprogram in turns overrides a subprogram
+ -- declared in a package visible part (inherited via
+ -- a private extension), we record the visible subprogram
+ -- as the overridden one, so that we can determine
+ -- visibility properly for prefixed calls to the
+ -- subprogram made from outside the package. (See
+ -- Try_Primitive_Operation in Sem_Ch4.)
+
+ if Present (Overridden_Inherited_Operation (E)) then
+ Set_Overridden_Inherited_Operation
+ (S, Overridden_Inherited_Operation (E));
+ else
+ Set_Overridden_Inherited_Operation (S, E);
+ end if;
+
Inherit_Subprogram_Contract (S, Alias (E));
Set_Is_Ada_2022_Only (S, Is_Ada_2022_Only (Alias (E)));
@@ -12760,6 +12943,530 @@ package body Sem_Ch6 is
end if;
end New_Overloaded_Entity;
+ ------------------------------------
+ -- Deferred_Extra_Formals_Support --
+ ------------------------------------
+
+ package body Deferred_Extra_Formals_Support is
+ Calls_List : Elist_Id := No_Elist;
+ Calls_Scope_List : Elist_Id := No_Elist;
+ -- Calls to subprograms or entries with some unknown underlying type
+ -- in their parameters or result type, and the scope where each call
+ -- is performed.
+
+ Entities_List : Elist_Id := No_Elist;
+ -- Subprograms, entries, and subprogram types with some unknown
+ -- underlying type in their formals or result type.
+
+ Types_List : Elist_Id := No_Elist;
+ -- Types with no underlying type
+
+ function Underlying_Types_Available (E : Entity_Id) return Boolean;
+ -- Determines if the underlying type of all the formals and result
+ -- type of the given subprogram, subprogram type, or entry are
+ -- available.
+
+ -------------------------------
+ -- Add_Deferred_Extra_Params --
+ -------------------------------
+
+ procedure Add_Deferred_Extra_Params (Typ : Entity_Id) is
+
+ procedure Check_Registered_Calls;
+ -- Check all the registered calls; for each registered call that
+ -- has the underlying type of all the parameters and result types
+ -- of the called entity available, call Create_Extra_Actuals, and
+ -- unregister the call.
+
+ procedure Check_Registered_Entities;
+ -- Check all the registered entities (subprograms, entries and
+ -- subprogram types); for each registered entity E that has all
+ -- its underlying types available, call Create_Extra_Formals,
+ -- and unregister E.
+
+ ----------------------------
+ -- Check_Registered_Calls --
+ ----------------------------
+
+ procedure Check_Registered_Calls is
+
+ function Get_Relocated_Function_Call (N : Node_Id) return Node_Id;
+ -- Given a node N that references a function call that has been
+ -- relocated to remove possible side effects of the call (see
+ -- Remove_Side_Effects) or to wrap the call in a transient scope
+ -- (see Wrap_Transient_Expression), search and return the function
+ -- call. Notice that this function does not use the Original_Node
+ -- field of N; it searchs for the actual call associated with N
+ -- in the expanded code (since we need to add to such call its
+ -- missing extra actuals).
+
+ ---------------------------------
+ -- Get_Relocated_Function_Call --
+ ---------------------------------
+
+ function Get_Relocated_Function_Call (N : Node_Id) return Node_Id
+ is
+ Current_Node : Node_Id;
+ Decl : Node_Id;
+ Id : Entity_Id;
+
+ begin
+ Current_Node := N;
+
+ while Nkind (Current_Node) /= N_Function_Call loop
+ case Nkind (Current_Node) is
+ when N_Identifier =>
+ Id := Entity (Current_Node);
+ Decl := Parent (Id);
+
+ if Nkind (Decl) = N_Object_Renaming_Declaration then
+ Current_Node := Name (Decl);
+
+ else
+ pragma Assert (Nkind (Decl) = N_Object_Declaration);
+
+ if Present (Expression (Decl)) then
+ Current_Node := Expression (Decl);
+
+ elsif Present (BIP_Initialization_Call (Id)) then
+ Decl := BIP_Initialization_Call (Id);
+ pragma Assert (Present (Expression (Decl)));
+ Current_Node := Expression (Decl);
+
+ elsif Present (Related_Expression (Id)) then
+ Current_Node := Related_Expression (Id);
+
+ else
+ pragma Assert (False);
+ raise Program_Error;
+ end if;
+ end if;
+
+ when N_Explicit_Dereference | N_Reference =>
+ Current_Node := Prefix (Current_Node);
+
+ when others =>
+ pragma Assert (False);
+ raise Program_Error;
+ end case;
+ end loop;
+
+ return Current_Node;
+ end Get_Relocated_Function_Call;
+
+ -- Local variables
+
+ Call_Node : Node_Id;
+ Call_Id : Entity_Id;
+ Elmt_Call : Elmt_Id;
+ Elmt_Scope : Elmt_Id;
+ Remove_Call : Boolean;
+ Scop_Id : Entity_Id;
+
+ -- Start of processing for Check_Registered_Calls
+
+ begin
+ -- Perform a single traversal of both lists simultaneously,
+ -- since they have the same number of elements with a 1-to-1
+ -- relationship.
+
+ Elmt_Scope := First_Elmt (Calls_Scope_List);
+ Elmt_Call := First_Elmt (Calls_List);
+
+ while Present (Elmt_Scope) loop
+ Scop_Id := Node (Elmt_Scope);
+ Remove_Call := False;
+
+ -- Check the enclosing scope of the call: if the underlying
+ -- type of some formal or return type of the enclosing scope
+ -- of this call is not available then we must skip processing
+ -- this call.
+
+ if Underlying_Types_Available (Scop_Id) then
+ Call_Node := Node (Elmt_Call);
+
+ if Nkind (Call_Node) in N_Entry_Call_Statement
+ | N_Function_Call
+ | N_Procedure_Call_Statement
+ then
+ Call_Id := Get_Called_Entity (Call_Node);
+
+ -- Handle expanded function calls that could have side
+ -- effects.
+
+ else
+ pragma Assert
+ (Nkind (Original_Node (Call_Node)) = N_Function_Call);
+
+ Call_Node := Get_Relocated_Function_Call (Call_Node);
+ Call_Id := Get_Called_Entity (Call_Node);
+ end if;
+
+ -- If the underlying types of all the formal and return
+ -- types of this called entity are available then create
+ -- its extra actuals and remove it from the list of
+ -- registered calls.
+
+ if Underlying_Types_Available (Call_Id) then
+
+ -- Given that the call is placed in the body of an
+ -- internally built subprogram, ensure that the extra
+ -- formals of the enclosing scope are available before
+ -- adding the extra actuals of this call.
+
+ Create_Extra_Formals (Scop_Id);
+ Create_Extra_Formals (Call_Id);
+
+ pragma Assert (Extra_Formals_Known (Scop_Id));
+ pragma Assert (Extra_Formals_Known (Call_Id));
+
+ -- Mark functions that return a result by reference
+
+ Compute_Returns_By_Ref (Scop_Id);
+ Compute_Returns_By_Ref (Call_Id);
+
+ Push_Scope (Scop_Id);
+ Create_Extra_Actuals (Call_Node);
+ Pop_Scope;
+
+ Remove_Call := True;
+ end if;
+ end if;
+
+ -- In order to safely remove these elements from their
+ -- containing lists, remember these elements before moving
+ -- to the next list elements.
+
+ if Remove_Call then
+ declare
+ Removed_Call : constant Elmt_Id := Elmt_Call;
+ Removed_Scope : constant Elmt_Id := Elmt_Scope;
+
+ begin
+ Next_Elmt (Elmt_Scope);
+ Next_Elmt (Elmt_Call);
+
+ Remove_Elmt (Calls_List, Removed_Call);
+ Remove_Elmt (Calls_Scope_List, Removed_Scope);
+ end;
+ else
+ Next_Elmt (Elmt_Scope);
+ Next_Elmt (Elmt_Call);
+ end if;
+
+ end loop;
+ end Check_Registered_Calls;
+
+ -------------------------------
+ -- Check_Registered_Entities --
+ -------------------------------
+
+ procedure Check_Registered_Entities is
+ Elmt : Elmt_Id;
+ Found_Elmt : Elmt_Id;
+ Id : Entity_Id;
+
+ begin
+ Elmt := First_Elmt (Entities_List);
+
+ while Present (Elmt) loop
+ Id := Node (Elmt);
+
+ -- If the underlying type of some formal or return type of this
+ -- entity is not available then skip this element.
+
+ if not Underlying_Types_Available (Id) then
+ Next_Elmt (Elmt);
+
+ -- Otherwise, create its extra formals and remove it from the
+ -- list of entities that require adding the extra formals.
+
+ else
+ -- In order to safely remove this element from the list,
+ -- temporarily remember this element, and move to the next
+ -- element.
+
+ Found_Elmt := Elmt;
+ Next_Elmt (Elmt);
+
+ -- Create the extra formals, and mark functions that return
+ -- by reference (not be done before if the underying return
+ -- type was previously unknown).
+
+ Create_Extra_Formals (Id);
+ Compute_Returns_By_Ref (Id);
+
+ Remove_Elmt (Entities_List, Found_Elmt);
+
+ -- For deferred entries and entry families, the expansion of
+ -- their entry declaration was deferred, and must be done
+ -- now (after adding their extra formals).
+
+ if Ekind (Id) in E_Entry | E_Entry_Family then
+ Expand_N_Entry_Declaration (Parent (Id),
+ Was_Deferred => True);
+ end if;
+ end if;
+ end loop;
+ end Check_Registered_Entities;
+
+ -- Start of processing for Add_Deferred_Extra_Params
+
+ begin
+ pragma Assert (Present (Underlying_Type (Typ)));
+
+ if Present (Entities_List) then
+ Check_Registered_Entities;
+ end if;
+
+ if Present (Calls_List) then
+ Check_Registered_Calls;
+ end if;
+
+ Remove (Types_List, Typ);
+ end Add_Deferred_Extra_Params;
+
+ --------------------------------
+ -- Has_Deferred_Extra_Formals --
+ --------------------------------
+
+ function Has_Deferred_Extra_Formals (Typ : Entity_Id) return Boolean is
+ begin
+ return Contains (Types_List, Typ);
+ end Has_Deferred_Extra_Formals;
+
+ --------------------------------------
+ -- Is_Deferred_Extra_Formals_Entity --
+ --------------------------------------
+
+ function Is_Deferred_Extra_Formals_Entity
+ (Id : Entity_Id) return Boolean is
+ begin
+ return Contains (Entities_List, Id);
+ end Is_Deferred_Extra_Formals_Entity;
+
+ ---------------------------------------
+ -- Is_Unsupported_Extra_Actuals_Call --
+ ---------------------------------------
+
+ -- Similarly to Is_Unsupported_Extra_Formals_Entity, we cannot
+ -- determine if the extra formals are needed when the underlying
+ -- type of some formal or result type is not available, and we are
+ -- compiling the body of a subprogram or package. However, for calls
+ -- we must also handle internal calls generated by the compiler as
+ -- part of compiling a package spec. For example, internal calls
+ -- performed in thunks of secondary dispatch table entries.
+ --
+ -- Example
+ -- -------
+ -- package P is
+ -- type T is tagged null record;
+ -- end;
+ --
+ -- limited with P;
+ -- package Q is
+ -- type Iface is interface;
+ -- procedure Prim (Self : Iface; Current : P.T) is abstract;
+ -- end;
+ --
+ -- limited with P;
+ -- with Q;
+ -- package R is
+ -- type Root is tagged null record;
+ -- type DT is new Root and Q.Iface with null record;
+ --
+ -- procedure Prim (Self : DT; Current : P.T);
+ -- end;
+ --
+ -- The initialization of the secondary dispatch table of tagged type
+ -- DT has an internally generated thunk that displaces the pointer to
+ -- the object and calls the primitive Prim (and the underlying type
+ -- of type T is not available).
+
+ function Is_Unsupported_Extra_Actuals_Call
+ (Call_Node : Node_Id; Id : Entity_Id) return Boolean
+ is
+ Comp_Unit : constant Entity_Id :=
+ Cunit_Entity (Get_Source_Unit (Call_Node));
+ begin
+ return not Underlying_Types_Available (Id)
+ and then Is_Compilation_Unit (Comp_Unit)
+ and then Ekind (Comp_Unit) in E_Package
+ | E_Package_Body
+ | E_Subprogram_Body;
+ end Is_Unsupported_Extra_Actuals_Call;
+
+ -----------------------------------------
+ -- Is_Unsupported_Extra_Formals_Entity --
+ -----------------------------------------
+
+ -- We cannot determine if the extra formals are needed when the
+ -- underlying type of some formal or result type is not available,
+ -- and we are compiling the body of a subprogram or package. The
+ -- scenery for this case is a package spec that has a limited_with_
+ -- clause on unit Q, and its body has no regular with-clause on Q
+ -- (AI05-0151-1/08).
+
+ function Is_Unsupported_Extra_Formals_Entity
+ (Id : Entity_Id) return Boolean
+ is
+ Comp_Unit : constant Entity_Id :=
+ Cunit_Entity (Get_Source_Unit (Id));
+ begin
+ return not Underlying_Types_Available (Id)
+ and then Is_Compilation_Unit (Comp_Unit)
+ and then Ekind (Comp_Unit) in E_Package_Body
+ | E_Subprogram_Body;
+ end Is_Unsupported_Extra_Formals_Entity;
+
+ --------------------------------------------
+ -- Register_Deferred_Extra_Formals_Entity --
+ --------------------------------------------
+
+ procedure Register_Deferred_Extra_Formals_Entity (Id : Entity_Id) is
+
+ procedure Register_Type (Typ : Entity_Id);
+ -- Register the given type in Types_List; for types visible though
+ -- limited_with_clauses, register their non-limited view.
+
+ -------------------
+ -- Register_Type --
+ -------------------
+
+ procedure Register_Type (Typ : Entity_Id) is
+ begin
+ -- Handle entities visible through limited_with_clauses
+
+ if Has_Non_Limited_View (Typ) then
+ Append_Unique_Elmt (Non_Limited_View (Typ), Types_List);
+ else
+ Append_Unique_Elmt (Typ, Types_List);
+ end if;
+ end Register_Type;
+
+ -- Local variables
+
+ Formal : Entity_Id;
+
+ -- Start of processing for Register_Deferred_Extra_Formals_Entity
+
+ begin
+ pragma Assert (Is_Subprogram_Or_Entry (Id)
+ or else Ekind (Id) in E_Subprogram_Type);
+
+ if not Is_Deferred_Extra_Formals_Entity (Id) then
+ if No (Types_List) then
+ Types_List := New_Elmt_List;
+ end if;
+
+ if No (Entities_List) then
+ Entities_List := New_Elmt_List;
+ end if;
+
+ -- Register all the types of the subprogram profile that are not
+ -- fully known.
+
+ Formal := First_Formal (Id);
+ while Present (Formal) loop
+
+ if No (Underlying_Type (Etype (Formal))) then
+ Register_Type (Etype (Formal));
+ end if;
+
+ Next_Formal (Formal);
+ end loop;
+
+ if Ekind (Id) in E_Function | E_Subprogram_Type
+ and then No (Underlying_Type (Etype (Id)))
+ then
+ Register_Type (Etype (Id));
+ end if;
+
+ -- Register this subprogram
+
+ Append_Elmt (Id, Entities_List);
+ end if;
+ end Register_Deferred_Extra_Formals_Entity;
+
+ ------------------------------------------
+ -- Register_Deferred_Extra_Formals_Call --
+ ------------------------------------------
+
+ procedure Register_Deferred_Extra_Formals_Call
+ (Call_Node : Node_Id;
+ Scope_Id : Entity_Id) is
+ begin
+ pragma Assert (Nkind (Call_Node) in N_Subprogram_Call
+ | N_Entry_Call_Statement);
+ if No (Calls_List) then
+ Calls_List := New_Elmt_List;
+ Calls_Scope_List := New_Elmt_List;
+ end if;
+
+ -- Avoid registering any call twice; this may occur in dispatching
+ -- calls with deferred extra actuals because Expand_Call_Helper
+ -- registers the call and invokes Expand_Dispatching_Call (which
+ -- tries again to register the expanded call).
+
+ if not Contains (Calls_List, Call_Node) then
+ Append_Elmt (Call_Node, Calls_List);
+ Append_Elmt (Scope_Id, Calls_Scope_List);
+ end if;
+ end Register_Deferred_Extra_Formals_Call;
+
+ --------------------------------
+ -- Underlying_Types_Available --
+ --------------------------------
+
+ function Underlying_Types_Available (E : Entity_Id) return Boolean is
+ Formal : Entity_Id;
+ Formal_Typ : Entity_Id;
+ Func_Typ : Entity_Id;
+
+ begin
+ -- If the extra formals are available, then the nonlimited view
+ -- of all the types referenced in the profile are available.
+
+ if Extra_Formals_Known (E) then
+ return True;
+ end if;
+
+ -- Check the return type
+
+ if Ekind (E) in E_Function | E_Subprogram_Type then
+ Func_Typ := Etype (E);
+
+ if Has_Non_Limited_View (Func_Typ) then
+ Func_Typ := Non_Limited_View (Func_Typ);
+ end if;
+
+ if No (Underlying_Type (Func_Typ)) then
+ return False;
+ end if;
+ end if;
+
+ -- Check the type of the formals
+
+ Formal := First_Formal (E);
+ while Present (Formal) loop
+ Formal_Typ := Etype (Formal);
+
+ if Has_Non_Limited_View (Formal_Typ) then
+ Formal_Typ := Non_Limited_View (Formal_Typ);
+ end if;
+
+ if No (Underlying_Type (Formal_Typ)) then
+ return False;
+ end if;
+
+ Next_Formal (Formal);
+ end loop;
+
+ return True;
+ end Underlying_Types_Available;
+
+ end Deferred_Extra_Formals_Support;
+
---------------------
-- Process_Formals --
---------------------
diff --git a/gcc/ada/sem_ch6.ads b/gcc/ada/sem_ch6.ads
index 7ebbcaa..4ef5b65 100644
--- a/gcc/ada/sem_ch6.ads
+++ b/gcc/ada/sem_ch6.ads
@@ -190,6 +190,14 @@ package Sem_Ch6 is
-- Use the subprogram specification in the body to retrieve the previous
-- subprogram declaration, if any.
+ procedure Freeze_Extra_Formals (E : Entity_Id);
+ -- Given a subprogram, subprogram type, or entry, flag E to indicate that
+ -- its extra formals (if any) are known (by setting Extra_Formals_Known).
+ -- This subprogram serves three purposes: (1) Document the places where
+ -- the extra formals are known, (2) Ensure that extra formals are added
+ -- only once, and (3) Provide a convenient place for setting a debugger
+ -- breakpoint to locate when extra formals are known.
+
function Fully_Conformant (New_Id, Old_Id : Entity_Id) return Boolean;
-- Determine whether two callable entities (subprograms, entries,
-- literals) are fully conformant (RM 6.3.1(17))
@@ -299,4 +307,156 @@ package Sem_Ch6 is
procedure Valid_Operator_Definition (Designator : Entity_Id);
-- Verify that an operator definition has the proper number of formals
+ ------------------------------------
+ -- Deferred_Extra_Formals_Support --
+ ------------------------------------
+
+ -- This package provides support for deferring the addition of extra
+ -- formals to subprograms, entries, and subprogram types; it also provides
+ -- support for deferring the addition of extra actuals to direct calls to
+ -- subprograms and entries, and indirect calls through subprogram types.
+ -- The addition of the extra formals and actuals is deferred until the
+ -- underlying type of all the parameters and result types of registered
+ -- subprograms, entries, and subprogram types is known.
+
+ -- Functional Description
+ -- ----------------------
+ --
+ -- When Create_Extra_Formals identifies that the underlying type of
+ -- some parameter or result type of an entity E is not available, E is
+ -- registered by this package, and the addition of its extra formals is
+ -- deferred. As part of this registration, the types of all the params
+ -- and result types of E with no underlying type are also registered.
+ --
+ -- When Expand_Call_Helper identifies that the underlying type of some
+ -- parameter or result type of a called entity is not available, the call
+ -- is registered by Register_Deferred_Extra_Formals_Call, and the addition
+ -- of its extra actuals is deferred.
+ --
+ -- When the full type declaration of some registered type T is analyzed,
+ -- the subprogram Add_Deferred_Extra_Params is invoked; this subprogram
+ -- does the following actions:
+ -- 1) Check all the registered entities (subprograms, entries, and
+ -- subprogram types); for each registered entity that has all its
+ -- underlying types available, call Create_Extra_Formals, and
+ -- unregister the entity.
+ -- 2) Check all the registered calls; for each registered call that
+ -- has available the underlying type of all the parameters and result
+ -- types of the called entity, call Create_Extra_Actuals, and
+ -- unregister the call.
+ -- 3) Unregister T.
+ --
+ -- Example 1
+ -- ---------
+ -- A package spec has a private type declaration T, and declarations of
+ -- expression functions and/or primitives with class-wide conditions
+ -- invoking primitives of type T before the full view of T is defined.
+ --
+ -- As part of processing the early freezing of the called subprograms
+ -- (and as part of processing the calls) the functions are registered as
+ -- subprograms with deferred extra formals, and the calls are registered
+ -- as calls with deferred extra actuals.
+ --
+ -- When the full type declaration of T is analyzed, extra formals are
+ -- added to all the registered subprograms, and extra actuals are added
+ -- to all the registered calls with deferred extra actuals.
+ --
+ -- Example 2
+ -- ---------
+ -- The specification of package P has a limited_with_clause on package Q,
+ -- and the type of the formals of subprograms defined in P are types
+ -- defined in Q.
+ --
+ -- When compiling the spec of P, similarly to the previous example,
+ -- subprograms with incomplete formals are registered as subprograms
+ -- with deferred extra formals; if the spec of P has calls to these
+ -- subprograms, then these calls are registered as calls with deferred
+ -- extra actuals. That is, when the analysis of package P completes,
+ -- deferred extra formals and actuals have not been added.
+ --
+ -- When another compilation unit is analyzed (including the body of
+ -- package P), and a regular with-clause on Q is processed, when the
+ -- full type declaration of deferred entities is analyzed, deferred
+ -- extra formals and deferred extra actuals are added.
+ --
+ -- This machinery relies on the GNAT Compilation Model; that is, when
+ -- we analyze the spec of P (for which we generally don't generate code),
+ -- it is safe to complete the compilation and still have entities with
+ -- deferred extra formals, and calls with deferred extra actuals.
+ --
+ -- The body package P generally has a regular with-clause on package Q.
+ -- Hence, when we compile the body of package P, the implicit dependence
+ -- on its package spec causes the analysis of the spec of P (thus
+ -- registering deferred entities), followed by the analysis of context
+ -- clauses in the body of P. When the regular with-clause on package Q
+ -- is analyzed, we add the extra formals and extra actuals to deferred
+ -- entities. Thus, the generated code will have all the needed formals.
+ --
+ -- The (still) unsupported case is when the body of package P does not
+ -- have a regular with-clause on package Q (AI05-0151-1/08). This case
+ -- is left documented in the front-end sources by means of calls to
+ -- the following subprograms: Is_Unsupported_Extra_Formals_Entity, and
+ -- Is_Unsupported_Extra_Actuals_Call.
+
+ package Deferred_Extra_Formals_Support is
+
+ procedure Add_Deferred_Extra_Params (Typ : Entity_Id);
+ -- Check all the registered subprograms, entries, and subprogram types
+ -- with deferred addition of their extra formals; if the underlying
+ -- types of all their formals is available then add their extra formals.
+ -- Check also all the registered calls with deferred addition of their
+ -- extra actuals; add their extra actuals if the underlying types of all
+ -- their parameters and result types are available. Finally unregister
+ -- Typ from the list of types used for the deferral of extra formals/
+ -- actuals.
+
+ procedure Register_Deferred_Extra_Formals_Entity (Id : Entity_Id);
+ -- Register the given subprogram, entry, or subprogram type to defer the
+ -- addition of its extra formals.
+
+ procedure Register_Deferred_Extra_Formals_Call
+ (Call_Node : Node_Id;
+ Scope_Id : Entity_Id);
+ -- Register the given call, performed from the given scope, to defer the
+ -- addition of its extra actuals.
+
+ function Has_Deferred_Extra_Formals (Typ : Entity_Id) return Boolean;
+ -- Return True if there some registered subprogram, subprogram type, or
+ -- entry with deferred extra formals that has some formal type or
+ -- result type of type Typ (i.e. which depends on the given type to
+ -- add its extra formals).
+
+ function Is_Deferred_Extra_Formals_Entity
+ (Id : Entity_Id) return Boolean;
+ -- Return True if Id is a subprogram, subprogram type, or entry that has
+ -- been registered to defer the addition of its extra formals.
+
+ function Is_Unsupported_Extra_Formals_Entity
+ (Id : Entity_Id) return Boolean;
+ -- Id is a subprogram, subprogram type, or entry. Return True if Id is
+ -- unsupported for deferring the addition of its extra formals; that is,
+ -- it is defined in a compilation unit that is a package body or a
+ -- subprogram body, and the underlying type of some of its parameters
+ -- or result type is not available.
+ --
+ -- The context for this case is an unsupported case of AI05-0151-1/08
+ -- that allows incomplete tagged types as parameter and result types.
+ -- More concretely, a type T is visible in a package spec through a
+ -- limited_with_clause, and the body of the package has no regular
+ -- with_clause. In such a case, the machinery for deferring the
+ -- addition of extra formals does not work because the underlying
+ -- type of the type is not seen during the compilation of the
+ -- package body.
+ --
+ -- The purpose of this function is to facilitate locating in the sources
+ -- the places where the front end performs the current (incomplete)
+ -- management of such case (to facilitate further work) ???
+
+ function Is_Unsupported_Extra_Actuals_Call
+ (Call_Node : Node_Id; Id : Entity_Id) return Boolean;
+ -- Same as previous function but applicable to a call to the given
+ -- entity Id.
+
+ end Deferred_Extra_Formals_Support;
+
end Sem_Ch6;
diff --git a/gcc/ada/sem_ch8.adb b/gcc/ada/sem_ch8.adb
index 54066b4..e6ef658 100644
--- a/gcc/ada/sem_ch8.adb
+++ b/gcc/ada/sem_ch8.adb
@@ -5444,7 +5444,15 @@ package body Sem_Ch8 is
elsif In_Open_Scopes (Scope (Base_Type (T))) then
null;
- elsif not Redundant_Use (Id) then
+ -- Turn off the use_type_clause on the type unless the clause is
+ -- redundant, or there's a previous use_type_clause. (The case where
+ -- a use_type_clause without "all" is followed by one with "all" in
+ -- a more nested scope is not considered redundant, necessitating
+ -- the test for a previous clause. One might expect the latter test
+ -- to suffice, but it turns out there are cases where Redundant_Use
+ -- is set, but Prev_Use_Clause is not set. ???)
+
+ elsif not Redundant_Use (Id) and then No (Prev_Use_Clause (N)) then
Set_In_Use (T, False);
Set_In_Use (Base_Type (T), False);
Set_Current_Use_Clause (T, Empty);
diff --git a/gcc/ada/sem_ch9.adb b/gcc/ada/sem_ch9.adb
index e32612e..bf387d3 100644
--- a/gcc/ada/sem_ch9.adb
+++ b/gcc/ada/sem_ch9.adb
@@ -1700,6 +1700,12 @@ package body Sem_Ch9 is
Process_Formals (Formals, N);
Create_Extra_Formals (Def_Id);
End_Scope;
+
+ -- If the entry has no formals, extra formals are definitely not
+ -- required.
+
+ else
+ Freeze_Extra_Formals (Def_Id);
end if;
if Ekind (Def_Id) = E_Entry then
diff --git a/gcc/ada/sem_disp.adb b/gcc/ada/sem_disp.adb
index 9d03eff..5a8bd58 100644
--- a/gcc/ada/sem_disp.adb
+++ b/gcc/ada/sem_disp.adb
@@ -2416,6 +2416,8 @@ package body Sem_Disp is
Formal : Entity_Id;
Ctrl_Type : Entity_Id;
+ -- Start of processing for Find_Dispatching_Type
+
begin
if Ekind (Subp) in E_Function | E_Procedure
and then Present (DTC_Entity (Subp))
@@ -3083,6 +3085,52 @@ package body Sem_Disp is
then
return Is_Tag_Indeterminate (Prefix (Orig_Node));
+ -- An if-expression is tag-indeterminate if all of the dependent
+ -- expressions are tag-indeterminate (RM 4.5.7 (17/3)).
+
+ elsif Nkind (Orig_Node) = N_If_Expression then
+ declare
+ Cond : constant Node_Id := First (Expressions (Orig_Node));
+ Expr : Node_Id := Next (Cond);
+
+ begin
+ if not Is_Tag_Indeterminate (Original_Node (Expr)) then
+ return False;
+ end if;
+
+ Next (Expr);
+
+ if Present (Expr)
+ and then not Is_Tag_Indeterminate (Original_Node (Expr))
+ then
+ return False;
+ end if;
+
+ return True;
+ end;
+
+ -- A case-expression is tag-indeterminate if all of the dependent
+ -- expressions are tag-indeterminate (RM 4.5.7 (17/3)).
+
+ elsif Nkind (Orig_Node) = N_Case_Expression then
+ declare
+ Alt : Node_Id := First (Alternatives (Orig_Node));
+ Expr : Node_Id;
+
+ begin
+ while Present (Alt) loop
+ Expr := Expression (Alt);
+
+ if not Is_Tag_Indeterminate (Original_Node (Expr)) then
+ return False;
+ end if;
+
+ Next (Alt);
+ end loop;
+
+ return True;
+ end;
+
else
return False;
end if;
@@ -3243,6 +3291,7 @@ package body Sem_Disp is
elsif Nkind (Actual) = N_Explicit_Dereference
and then Nkind (Original_Node (Prefix (Actual))) = N_Function_Call
then
+ pragma Assert (Is_Expanded_Dispatching_Call (Actual));
return;
-- When expansion is suppressed, an unexpanded call to 'Input can occur,
diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb
index e44994a..29b7766 100644
--- a/gcc/ada/sem_res.adb
+++ b/gcc/ada/sem_res.adb
@@ -7270,7 +7270,9 @@ package body Sem_Res is
if Restriction_Check_Required (No_Relative_Delay)
and then Is_RTE (Nam, RE_Set_Handler)
- and then Is_RTE (Etype (Next_Actual (First_Actual (N))), RE_Time_Span)
+ and then
+ Is_RTE
+ (Base_Type (Etype (Next_Actual (First_Actual (N)))), RE_Time_Span)
then
Check_Restriction (No_Relative_Delay, N);
end if;
diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb
index 74de26a..b2b4fed 100644
--- a/gcc/ada/sem_util.adb
+++ b/gcc/ada/sem_util.adb
@@ -35,6 +35,7 @@ with Exp_Ch11; use Exp_Ch11;
with Exp_Util; use Exp_Util;
with Fname; use Fname;
with Freeze; use Freeze;
+with Ghost; use Ghost;
with Itypes; use Itypes;
with Lib; use Lib;
with Lib.Xref; use Lib.Xref;
@@ -1923,6 +1924,10 @@ package body Sem_Util is
-- Build_Elaboration_Entity --
------------------------------
+ -- WARNING: This routine manages Ghost regions. Return statements must be
+ -- replaced by gotos which jump to the end of the routine and restore the
+ -- Ghost mode.
+
procedure Build_Elaboration_Entity (N : Node_Id; Spec_Id : Entity_Id) is
Loc : constant Source_Ptr := Sloc (N);
Decl : Node_Id;
@@ -1956,6 +1961,12 @@ package body Sem_Util is
end if;
end Set_Package_Name;
+ -- Local variables
+
+ Saved_GM : constant Ghost_Mode_Type := Ghost_Mode;
+ Saved_IGR : constant Node_Id := Ignored_Ghost_Region;
+ -- Save the Ghost-related attributes to restore on exit
+
-- Start of processing for Build_Elaboration_Entity
begin
@@ -2003,6 +2014,11 @@ package body Sem_Util is
return;
end if;
+ -- Elaboration entity is never a ghost object, regardless of the context
+ -- in which this routine is called.
+
+ Install_Ghost_Region (None, N);
+
-- Here we need the elaboration entity
-- Construct name of elaboration entity as xxx_E, where xxx is the unit
@@ -2043,6 +2059,8 @@ package body Sem_Util is
Set_Has_Qualified_Name (Elab_Ent);
Set_Has_Fully_Qualified_Name (Elab_Ent);
+
+ Restore_Ghost_Region (Saved_GM, Saved_IGR);
end Build_Elaboration_Entity;
--------------------------------
@@ -3688,6 +3706,7 @@ package body Sem_Util is
Aspect_Aggregate,
Aspect_Max_Entry_Queue_Length
-- , Aspect_No_Controlled_Parts
+ -- , Aspect_No_Task_Parts
);
-- Note that none of these 8 aspects can be specified (for a type)
@@ -10043,16 +10062,19 @@ package body Sem_Util is
and then not Has_Unknown_Discriminants (Utyp)
and then not (Ekind (Utyp) = E_String_Literal_Subtype)
then
- -- Nothing to do if in spec expression (why not???)
+ -- If the type has no discriminants, there is no subtype to build,
+ -- even if the underlying type is discriminated.
- if In_Spec_Expression then
+ if Is_Private_Type (Typ) and then not Has_Discriminants (Typ) then
return Typ;
- elsif Is_Private_Type (Typ) and then not Has_Discriminants (Typ) then
-
- -- If the type has no discriminants, there is no subtype to
- -- build, even if the underlying type is discriminated.
+ -- If we are performing preanalysis on a conjured-up copy of a name
+ -- (see calls to Preanalyze_Range in sem_ch5.adb) then we don't want
+ -- to freeze Atyp, now or ever. In this case, the tree we eventually
+ -- pass to the back end should contain no references to Atyp (and a
+ -- freeze node would contain such a reference).
+ elsif not (Expander_Active or GNATprove_Mode) then
return Typ;
-- Else build the actual subtype
@@ -10068,42 +10090,21 @@ package body Sem_Util is
Atyp := Defining_Identifier (Decl);
- -- If Build_Actual_Subtype generated a new declaration then use it
-
- if Atyp /= Typ then
-
- -- The actual subtype is an Itype, so analyze the declaration,
- -- but do not attach it to the tree, to get the type defined.
-
- Set_Parent (Decl, N);
- Set_Is_Itype (Atyp);
- Analyze (Decl, Suppress => All_Checks);
- Set_Associated_Node_For_Itype (Atyp, N);
- if Expander_Active then
- Set_Has_Delayed_Freeze (Atyp, False);
-
- -- We need to freeze the actual subtype immediately. This is
- -- needed because otherwise this Itype will not get frozen
- -- at all; it is always safe to freeze on creation because
- -- any associated types must be frozen at this point.
+ -- The actual subtype is an Itype, so analyze the declaration
+ -- after attaching it to the tree, to get the type defined.
- -- On the other hand, if we are performing preanalysis on
- -- a conjured-up copy of a name (see calls to
- -- Preanalyze_Range in sem_ch5.adb) then we don't want
- -- to freeze Atyp, now or ever. In this case, the tree
- -- we eventually pass to the back end should contain no
- -- references to Atyp (and a freeze node would contain
- -- such a reference). That's why Expander_Active is tested.
+ Set_Parent (Decl, N);
+ Set_Is_Itype (Atyp);
+ Analyze (Decl, Suppress => All_Checks);
+ Set_Associated_Node_For_Itype (Atyp, N);
- Freeze_Itype (Atyp, N);
- end if;
- return Atyp;
-
- -- Otherwise we did not build a declaration, so return original
+ -- We need to freeze the actual subtype immediately. This is
+ -- needed because otherwise this Itype will not get frozen
+ -- at all; it is always safe to freeze on creation because
+ -- any associated types must be frozen at this point.
- else
- return Typ;
- end if;
+ Freeze_Itype (Atyp, N);
+ return Atyp;
end if;
-- For all remaining cases, the actual subtype is the same as
@@ -15017,6 +15018,7 @@ package body Sem_Util is
| Aspect_Iterator_Element
| Aspect_Max_Entry_Queue_Length
| Aspect_No_Controlled_Parts
+ | Aspect_No_Task_Parts
=>
return;
end case;
@@ -16276,8 +16278,9 @@ package body Sem_Util is
Names_Match (Assign_Indexed_1, Assign_Indexed_2);
end;
- -- Checking for this aspect is performed elsewhere during freezing
- when Aspect_No_Controlled_Parts =>
+ -- Checking for these aspects is performed elsewhere during freezing
+ when Aspect_No_Controlled_Parts
+ | Aspect_No_Task_Parts =>
return True;
-- scalar-valued aspects; compare (static) values.
@@ -21373,6 +21376,18 @@ package body Sem_Util is
return False;
end Is_Unchecked_Conversion_Instance;
+ ---------------------------------
+ -- Is_Unchecked_Union_Equality --
+ ---------------------------------
+
+ function Is_Unchecked_Union_Equality (Id : Entity_Id) return Boolean is
+ begin
+ return Ekind (Id) = E_Function
+ and then Present (First_Formal (Id))
+ and then Is_Unchecked_Union (Etype (First_Formal (Id)))
+ and then Id = TSS (Etype (First_Formal (Id)), TSS_Composite_Equality);
+ end Is_Unchecked_Union_Equality;
+
-------------------------------
-- Is_Universal_Numeric_Type --
-------------------------------
@@ -26955,6 +26970,10 @@ package body Sem_Util is
if Has_Relaxed_Finalization (From_Typ) then
Set_Has_Relaxed_Finalization (Typ);
end if;
+
+ if Deriv and then Has_Destructor (From_Typ) then
+ Set_Has_Destructor (Typ);
+ end if;
end Propagate_Controlled_Flags;
------------------------------
diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads
index efeafda..4554f24 100644
--- a/gcc/ada/sem_util.ads
+++ b/gcc/ada/sem_util.ads
@@ -1578,7 +1578,7 @@ package Sem_Util is
-- underlying type).
function Has_Suffix (E : Entity_Id; Suffix : Character) return Boolean;
- -- Returns true if the last character of E is Suffix. Used in Assertions.
+ -- Returns true if the last character of E is Suffix.
function Has_Tagged_Component (Typ : Entity_Id) return Boolean;
-- Returns True if Typ is a composite type (array or record) that is either
@@ -2131,7 +2131,7 @@ package Sem_Util is
-- object as per RM C.6(8).
function Is_Inherited_Operation (E : Entity_Id) return Boolean;
- -- E is a subprogram. Return True is E is an implicit operation inherited
+ -- E is a subprogram. Return True if E is an implicit operation inherited
-- by a derived type declaration.
function Is_Inlinable_Expression_Function (Subp : Entity_Id) return Boolean;
@@ -2196,7 +2196,7 @@ package Sem_Util is
-- the encapsulated expression is nontrivial.
function Is_Null_Extension
- (T : Entity_Id; Ignore_Privacy : Boolean := False) return Boolean;
+ (T : Entity_Id; Ignore_Privacy : Boolean := False) return Boolean;
-- Given a tagged type, returns True if argument is a type extension
-- that introduces no new components (discriminant or nondiscriminant).
-- Ignore_Privacy should be True for use in implementing dynamic semantics.
@@ -2449,6 +2449,10 @@ package Sem_Util is
-- Determine whether an arbitrary entity denotes an instance of function
-- Ada.Unchecked_Conversion.
+ function Is_Unchecked_Union_Equality (Id : Entity_Id) return Boolean;
+ -- Determine whether an arbitrary entity denotes the predefined equality
+ -- function of an Unchecked_Union type (see Build_Variant_Record_Equality).
+
function Is_Unconstrained_Or_Tagged_Item (Item : Entity_Id) return Boolean;
-- Subsidiary to Collect_Subprogram_Inputs_Outputs and the analysis of
-- pragma Depends. Determine whether the type of dependency item Item is
@@ -2973,11 +2977,11 @@ package Sem_Util is
Comp : Boolean := False;
Deriv : Boolean := False);
-- Set Disable_Controlled, Finalize_Storage_Only, Has_Controlled_Component,
- -- Has_Relaxed_Finalization, and Is_Controlled_Active on Typ when the flags
- -- are set on From_Typ. If Comp is True, From_Typ is assumed to be the type
- -- of a component of Typ while, if Deriv is True, From_Typ is assumed to be
- -- the parent type of Typ. This procedure can only set flags for Typ, and
- -- never clear them.
+ -- Has_Destructor, Has_Relaxed_Finalization, and Is_Controlled_Active on
+ -- Typ when the flags are set on From_Typ. If Comp is True, From_Typ is
+ -- assumed to be the type of a component of Typ while, if Deriv is True,
+ -- From_Typ is assumed to be the parent type of Typ. This procedure can
+ -- only set flags for Typ, and never clear them.
procedure Propagate_DIC_Attributes
(Typ : Entity_Id;
diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads
index c63a97d..3d11d5c 100644
--- a/gcc/ada/sinfo.ads
+++ b/gcc/ada/sinfo.ads
@@ -402,16 +402,17 @@ package Sinfo is
-- Has_Secondary_Private_View set in generic units
-- "plus fields for expression"
- -- Paren_Count number of parentheses levels
- -- Etype type of the expression
- -- Is_Overloaded >1 type interpretation exists
- -- Is_Static_Expression set for static expression
- -- Raises_Constraint_Error evaluation raises CE
- -- Must_Not_Freeze set if must not freeze
- -- Do_Range_Check set if a range check needed
- -- Has_Dynamic_Length_Check set if length check inserted
- -- Assignment_OK set if modification is OK
- -- Is_Controlling_Actual set for controlling argument
+ -- Paren_Count number of parentheses levels
+ -- Etype type of the expression
+ -- Is_Overloaded >1 type interpretation exists
+ -- Is_Static_Expression set for static expression
+ -- Raises_Constraint_Error evaluation raises CE
+ -- Must_Not_Freeze set if must not freeze
+ -- Do_Range_Check set if a range check needed
+ -- Has_Dynamic_Length_Check set if length check inserted
+ -- Assignment_OK set if modification is OK
+ -- Is_Controlling_Actual set for controlling argument
+ -- Is_Expanded_Dispatching_Call set for expanded dispatching calls
-- Note: see under (EXPRESSION) for further details on the use of
-- the Paren_Count field to record the number of parentheses levels.
@@ -1664,6 +1665,10 @@ package Sinfo is
-- actuals to support a build-in-place style of call have been added to
-- the call.
+ -- Is_Expanded_Dispatching_Call
+ -- This flag is set in N_Block_Statement, and expression nodes to
+ -- indicate that it is an expanded dispatching call.
+
-- Is_Expanded_Prefixed_Call
-- This flag is set in N_Function_Call and N_Procedure_Call_Statement
-- nodes to indicate that it is an expanded prefixed call.
@@ -2321,6 +2326,13 @@ package Sinfo is
-- statement applies to. Finally, if Analyze_Continue_Statement detects
-- an error, this field is set to Empty.
+ -- Tag_Propagated
+ -- This flag is set in N_Identifier, N_Explicit_Dereference, and N_Type_
+ -- Conversion nodes that are the LHS of an assignment statement. Used to
+ -- remember that the RHS of the assignment has tag indeterminate function
+ -- calls and the tag has been propagated to the calls (as part of the
+ -- bottom-up analysis of the RHS of the assignment statement).
+
-- Target_Type
-- Used in an N_Validate_Unchecked_Conversion node to point to the target
-- type entity for the unchecked conversion instantiation which gigi must
@@ -2507,6 +2519,7 @@ package Sinfo is
-- Has_Private_View (set in generic units)
-- Has_Secondary_Private_View (set in generic units)
-- Redundant_Use
+ -- Tag_Propagated
-- Atomic_Sync_Required
-- plus fields for expression
@@ -3820,6 +3833,7 @@ package Sinfo is
-- Prefix
-- Actual_Designated_Subtype
-- Has_Dereference_Action
+ -- Tag_Propagated
-- Atomic_Sync_Required
-- plus fields for expression
@@ -4755,6 +4769,7 @@ package Sinfo is
-- Conversion_OK
-- Do_Overflow_Check
-- Rounded_Result
+ -- Tag_Propagated
-- plus fields for expression
-- Note: if a range check is required, then the Do_Range_Check flag
@@ -5196,6 +5211,7 @@ package Sinfo is
-- Has_Created_Identifier
-- Is_Abort_Block
-- Is_Asynchronous_Call_Block
+ -- Is_Expanded_Dispatching_Call
-- Is_Initialization_Block
-- Is_Task_Allocation_Block
-- Is_Task_Master
diff --git a/gcc/ada/snames.ads-tmpl b/gcc/ada/snames.ads-tmpl
index f26515e..272e10b 100644
--- a/gcc/ada/snames.ads-tmpl
+++ b/gcc/ada/snames.ads-tmpl
@@ -151,6 +151,7 @@ package Snames is
Name_Default_Value : constant Name_Id := N + $;
Name_Default_Component_Value : constant Name_Id := N + $;
Name_Designated_Storage_Model : constant Name_Id := N + $;
+ Name_Destructor : constant Name_Id := N + $;
Name_Dimension : constant Name_Id := N + $;
Name_Dimension_System : constant Name_Id := N + $;
Name_Disable_Controlled : constant Name_Id := N + $;
diff --git a/gcc/ada/styleg.adb b/gcc/ada/styleg.adb
index 7b7f252..20945fb 100644
--- a/gcc/ada/styleg.adb
+++ b/gcc/ada/styleg.adb
@@ -499,7 +499,8 @@ package body Styleg is
if Is_Box_Comment
or else Style_Check_Comments_Spacing = 1
then
- Error_Space_Required (Scan_Ptr + 2);
+ Error_Msg -- CODEFIX
+ ("(style) space required?c?", Scan_Ptr + 2);
else
Error_Msg -- CODEFIX
("(style) two spaces required?c?", Scan_Ptr + 2);
@@ -526,7 +527,8 @@ package body Styleg is
-- box comment.
elsif not Is_Box_Comment then
- Error_Space_Required (Scan_Ptr + 3);
+ Error_Msg -- CODEFIX
+ ("(style) space required?c?", Scan_Ptr + 3);
end if;
end if;
end Check_Comment;
diff --git a/gcc/ada/sysdep.c b/gcc/ada/sysdep.c
index 3dc76f9..afbb362 100644
--- a/gcc/ada/sysdep.c
+++ b/gcc/ada/sysdep.c
@@ -40,6 +40,12 @@
- either they are defined as ENOENT (vx7r2);
- or the corresponding system includes are not provided (Helix Cert). */
+#if __has_include ("strings.h")
+/* On VxWorks6, FD_ZERO uses bzero, and index is also declared in strings.h,
+ but since it's not a standard header, don't require it. */
+#include "strings.h"
+#endif
+
#if __has_include ("dosFsLib.h")
/* On helix-cert, this include is only provided for RTPs. */
#include "dosFsLib.h"
diff --git a/gcc/ada/tbuild.adb b/gcc/ada/tbuild.adb
index b89c408..52fdbfc 100644
--- a/gcc/ada/tbuild.adb
+++ b/gcc/ada/tbuild.adb
@@ -926,11 +926,11 @@ package body Tbuild is
-- conversion of an unchecked conversion. Extra unchecked conversions
-- make the .dg output less readable. We can't do this in cases
-- involving bitfields, because the sizes might not match. The
- -- "not Is_Scalar_Type" checks avoid such cases.
+ -- Is_Composite_Type checks avoid such cases.
elsif Nkind (Expr) = N_Unchecked_Type_Conversion
- and then not Is_Scalar_Type (Etype (Expr))
- and then not Is_Scalar_Type (Typ)
+ and then Is_Composite_Type (Etype (Expr))
+ and then Is_Composite_Type (Typ)
then
Set_Subtype_Mark (Expr, New_Occurrence_Of (Typ, Loc));
Result := Relocate_Node (Expr);
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog
index a34fa13..8e5d38e 100644
--- a/gcc/analyzer/ChangeLog
+++ b/gcc/analyzer/ChangeLog
@@ -1,3 +1,110 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * program-point.cc: Make diagnostics::context::m_source_printing
+ private.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * pending-diagnostic.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * program-point.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * program-point.cc: : Update for diagnostic_context becoming
+ diagnostics::context, and for diagnostic_source_print_policy
+ becoming diagnostics::source_print_policy.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * ana-state-to-diagnostic-state.cc: Update for move of
+ diagnostics output formats into namespace "diagnostics" as
+ "sinks".
+ * bounds-checking.cc: Likewise.
+ * call-details.cc: Likewise.
+ * checker-event.cc: Likewise.
+ * checker-event.h: Likewise.
+ * diagnostic-manager.cc: Likewise.
+ * diagnostic-manager.h: Likewise.
+ * infinite-loop.cc: Likewise.
+ * infinite-recursion.cc: Likewise.
+ * pending-diagnostic.h: Likewise.
+ * region-model.cc: Likewise.
+ * sm-taint.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * access-diagram.cc: Update for changes to diagnostic paths:
+ "diagnostic-path.h" moving to "diagnostics/paths.h",
+ "diagnostic-event-id.h" moving to "diagnostics/event-id.h",
+ diagnostic_event_id_t to diagnostics::paths::event_id_t,
+ diagnostic_path to diagnostics::paths::path, and
+ diagnostic_event to diagnostics::paths::event.
+ * access-diagram.h: Likewise.
+ * analyzer.cc: Likewise.
+ * bounds-checking.cc: Likewise.
+ * call-info.cc: Likewise.
+ * checker-event.cc: Likewise.
+ * checker-event.h: Likewise.
+ * checker-path.cc: Likewise.
+ * checker-path.h: Likewise.
+ * common.h: Likewise.
+ * diagnostic-manager.cc: Likewise.
+ * pending-diagnostic.cc: Likewise.
+ * pending-diagnostic.h: Likewise.
+ * program-point.cc: Likewise.
+ * program-state.cc: Likewise.
+ * region-model.cc: Likewise.
+ * sm-fd.cc: Likewise.
+ * sm-file.cc: Likewise.
+ * sm-malloc.cc: Likewise.
+ * sm-pattern-test.cc: Likewise.
+ * sm-sensitive.cc: Likewise.
+ * sm-signal.cc: Likewise.
+ * sm-taint.cc: Likewise.
+ * varargs.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * bounds-checking.cc: Update #include for move of
+ "diagnostic-diagram.h" to "diagnostics/diagram.h". Update for
+ move of diagnostic_diagram to diagnostics::diagram.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic-manager.cc: Update for move of diagnostic_metadata to
+ diagnostics::metadata.
+ * kf.cc: Likewise.
+ * pending-diagnostic.h: Likewise; also, update #include for move
+ of "diagnostic-metadata.h" to "diagnostics/metadata.h".
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * checker-event.h (checker_event::get_logical_location): Update
+ for conversion of logical_location to
+ diagnostics::logical_locations::key.
+ (checker_event::m_logical_loc): Likewise.
+ * diagnostic-manager.cc
+ (diagnostic_manager::get_logical_location_manager): Likewise.
+ * diagnostic-manager.h
+ (diagnostic_manager::get_logical_location_manager): Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * ana-state-to-diagnostic-state.cc: Update #include for move of
+ "diagnostic-state-graphs.h" to "diagnostics/state-graphs.h".
+ * ana-state-to-diagnostic-state.h: Likewise.
+ * checker-event.cc: Likewise.
+ * checker-event.h: Update #include for move of
+ "diagnostic-digraphs.h" to "diagnostics/digraphs.h".
+ * program-state.cc: : Update #include for move of
+ "diagnostic-state-graphs.h" to "diagnostics/state-graphs.h".
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * region-model-asm.cc (region_model::on_asm_stmt): Pass null
+ pointer to parse_{input,output}_constraint().
+
2025-07-11 David Malcolm <dmalcolm@redhat.com>
* ana-state-to-diagnostic-state.cc: Reimplement, replacing
diff --git a/gcc/analyzer/access-diagram.cc b/gcc/analyzer/access-diagram.cc
index 90b396c..166be08 100644
--- a/gcc/analyzer/access-diagram.cc
+++ b/gcc/analyzer/access-diagram.cc
@@ -1300,7 +1300,7 @@ class valid_region_spatial_item : public spatial_item
{
public:
valid_region_spatial_item (const access_operation &op,
- diagnostic_event_id_t region_creation_event_id,
+ diagnostics::paths::event_id_t region_creation_event_id,
const theme &theme)
: m_op (op),
m_region_creation_event_id (region_creation_event_id),
@@ -1523,7 +1523,7 @@ public:
private:
const access_operation &m_op;
- diagnostic_event_id_t m_region_creation_event_id;
+ diagnostics::paths::event_id_t m_region_creation_event_id;
mutable const boundaries *m_boundaries;
const svalue *m_existing_sval;
std::unique_ptr<spatial_item> m_existing_sval_spatial_item;
@@ -2012,7 +2012,7 @@ class access_diagram_impl : public vbox_widget
{
public:
access_diagram_impl (const access_operation &op,
- diagnostic_event_id_t region_creation_event_id,
+ diagnostics::paths::event_id_t region_creation_event_id,
style_manager &sm,
const theme &theme,
logger *logger)
@@ -2564,7 +2564,7 @@ private:
}
const access_operation &m_op;
- diagnostic_event_id_t m_region_creation_event_id;
+ diagnostics::paths::event_id_t m_region_creation_event_id;
style_manager &m_sm;
const theme &m_theme;
logger *m_logger;
@@ -2662,7 +2662,7 @@ direction_widget::paint_to_canvas (canvas &canvas)
an access_diagram_impl. */
access_diagram::access_diagram (const access_operation &op,
- diagnostic_event_id_t region_creation_event_id,
+ diagnostics::paths::event_id_t region_creation_event_id,
style_manager &sm,
const theme &theme,
logger *logger)
diff --git a/gcc/analyzer/access-diagram.h b/gcc/analyzer/access-diagram.h
index e31dd28..d558f53 100644
--- a/gcc/analyzer/access-diagram.h
+++ b/gcc/analyzer/access-diagram.h
@@ -152,7 +152,7 @@ class access_diagram : public text_art::wrapper_widget
{
public:
access_diagram (const access_operation &op,
- diagnostic_event_id_t region_creation_event_id,
+ diagnostics::paths::event_id_t region_creation_event_id,
text_art::style_manager &sm,
const text_art::theme &theme,
logger *logger);
diff --git a/gcc/analyzer/ana-state-to-diagnostic-state.cc b/gcc/analyzer/ana-state-to-diagnostic-state.cc
index 2701259..996538c 100644
--- a/gcc/analyzer/ana-state-to-diagnostic-state.cc
+++ b/gcc/analyzer/ana-state-to-diagnostic-state.cc
@@ -23,8 +23,8 @@ along with GCC; see the file COPYING3. If not see
#define INCLUDE_SET
#include "analyzer/common.h"
-#include "diagnostic-state-graphs.h"
-#include "diagnostic-format-sarif.h"
+#include "diagnostics/state-graphs.h"
+#include "diagnostics/sarif-sink.h"
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
diff --git a/gcc/analyzer/ana-state-to-diagnostic-state.h b/gcc/analyzer/ana-state-to-diagnostic-state.h
index 186e19d..3a5ccc1 100644
--- a/gcc/analyzer/ana-state-to-diagnostic-state.h
+++ b/gcc/analyzer/ana-state-to-diagnostic-state.h
@@ -21,7 +21,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_ANA_STATE_TO_DIAGNOSTIC_STATE_H
#define GCC_ANALYZER_ANA_STATE_TO_DIAGNOSTIC_STATE_H
-#include "diagnostic-state-graphs.h"
+#include "diagnostics/state-graphs.h"
#include "tree-logical-location.h"
namespace ana {
diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
index 938ad6d..9f6f7b4 100644
--- a/gcc/analyzer/analyzer.cc
+++ b/gcc/analyzer/analyzer.cc
@@ -21,7 +21,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/common.h"
#include "tree-pretty-print.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "tree-dfa.h"
#include "intl.h"
@@ -232,7 +232,7 @@ tree_to_json (tree node)
for unknown). */
std::unique_ptr<json::value>
-diagnostic_event_id_to_json (const diagnostic_event_id_t &event_id)
+diagnostic_event_id_to_json (const diagnostics::paths::event_id_t &event_id)
{
if (event_id.known_p ())
{
diff --git a/gcc/analyzer/bounds-checking.cc b/gcc/analyzer/bounds-checking.cc
index d2e2b34..921ad16 100644
--- a/gcc/analyzer/bounds-checking.cc
+++ b/gcc/analyzer/bounds-checking.cc
@@ -20,8 +20,8 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/common.h"
#include "intl.h"
-#include "diagnostic-diagram.h"
-#include "diagnostic-format-sarif.h"
+#include "diagnostics/diagram.h"
+#include "diagnostics/sarif-sink.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
@@ -51,7 +51,7 @@ public:
}
void prepare_for_emission (checker_path *path,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id) override
+ diagnostics::paths::event_id_t emission_id) override
{
region_creation_event_capacity::prepare_for_emission (path,
pd,
@@ -101,10 +101,11 @@ public:
*this));
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/out_of_bounds/"
props.set_string (PROPERTY_PREFIX "dir",
get_dir () == access_direction::read ? "read" : "write");
@@ -181,7 +182,7 @@ protected:
a problem. Give up if that's happened. */
return;
}
- diagnostic_diagram diagram
+ diagnostics::diagram diagram
(canvas,
/* Alt text. */
_("Diagram visualizing the predicted out-of-bounds access"));
@@ -203,7 +204,7 @@ protected:
const region *m_reg;
tree m_diag_arg;
const svalue *m_sval_hint;
- diagnostic_event_id_t m_region_creation_event_id;
+ diagnostics::paths::event_id_t m_region_creation_event_id;
};
/* Abstract base class for all out-of-bounds warnings where the
@@ -228,11 +229,11 @@ public:
&& m_out_of_bounds_bits == other.m_out_of_bounds_bits);
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const override
{
out_of_bounds::maybe_add_sarif_properties (result_obj);
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/concrete_out_of_bounds/"
props.set (PROPERTY_PREFIX "out_of_bounds_bits",
m_out_of_bounds_bits.to_json ());
@@ -294,11 +295,11 @@ public:
*this));
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
concrete_out_of_bounds::maybe_add_sarif_properties (result_obj);
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/concrete_past_the_end/"
props.set (PROPERTY_PREFIX "bit_bound",
tree_to_json (m_bit_bound));
@@ -966,11 +967,12 @@ public:
&& pending_diagnostic::same_tree_p (m_capacity, other.m_capacity));
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
out_of_bounds::maybe_add_sarif_properties (result_obj);
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/symbolic_past_the_end/"
props.set (PROPERTY_PREFIX "offset", tree_to_json (m_offset));
props.set (PROPERTY_PREFIX "num_bytes", tree_to_json (m_num_bytes));
diff --git a/gcc/analyzer/call-details.cc b/gcc/analyzer/call-details.cc
index cb95843..ede1229 100644
--- a/gcc/analyzer/call-details.cc
+++ b/gcc/analyzer/call-details.cc
@@ -25,7 +25,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-pretty-print.h"
#include "stringpool.h"
#include "attribs.h"
-#include "diagnostic-format-sarif.h"
+#include "diagnostics/sarif-sink.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
@@ -528,10 +528,10 @@ public:
return true;
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/overlapping_buffers/"
props.set (PROPERTY_PREFIX "bytes_range_a",
m_byte_range_a.to_json ());
diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc
index 9a698ef..f431143 100644
--- a/gcc/analyzer/call-info.cc
+++ b/gcc/analyzer/call-info.cc
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfg.h"
#include "digraph.h"
#include "sbitmap.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/supergraph.h"
diff --git a/gcc/analyzer/checker-event.cc b/gcc/analyzer/checker-event.cc
index 8cc5ac2..4eac945 100644
--- a/gcc/analyzer/checker-event.cc
+++ b/gcc/analyzer/checker-event.cc
@@ -1,4 +1,4 @@
-/* Subclasses of diagnostic_event for analyzer diagnostics.
+/* Subclasses of diagnostics::paths::event for analyzer diagnostics.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -27,8 +27,8 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-iterator.h"
#include "inlining-iterator.h"
#include "tree-logical-location.h"
-#include "diagnostic-format-sarif.h"
-#include "diagnostic-state-graphs.h"
+#include "diagnostics/sarif-sink.h"
+#include "diagnostics/state-graphs.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
@@ -101,7 +101,7 @@ event_kind_to_string (enum event_kind ek)
}
}
-/* class checker_event : public diagnostic_event. */
+/* class checker_event : public diagnostics::paths::event. */
/* checker_event's ctor. */
@@ -131,24 +131,24 @@ checker_event::checker_event (enum event_kind kind,
}
}
-/* No-op implementation of diagnostic_event::get_meaning vfunc for
+/* No-op implementation of diagnostics::paths::event::get_meaning vfunc for
checker_event: checker events have no meaning by default. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
checker_event::get_meaning () const
{
- return meaning ();
+ return diagnostics::paths::event::meaning ();
}
-/* Implementation of diagnostic_event::maybe_add_sarif_properties
+/* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
for checker_event. */
void
checker_event::
-maybe_add_sarif_properties (sarif_builder &builder,
- sarif_object &thread_flow_loc_obj) const
+maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
+ diagnostics::sarif_object &thread_flow_loc_obj) const
{
- sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
+ auto &props = thread_flow_loc_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
props.set (PROPERTY_PREFIX "emission_id",
diagnostic_event_id_to_json (m_emission_id));
@@ -215,7 +215,7 @@ checker_event::debug () const
void
checker_event::prepare_for_emission (checker_path *path,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id)
+ diagnostics::paths::event_id_t emission_id)
{
m_path = path;
m_pending_diagnostic = pd;
@@ -252,7 +252,7 @@ checker_event::maybe_make_diagnostic_state_graph (bool debug) const
/* class debug_event : public checker_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
debug_event.
Use the saved string as the event's description. */
@@ -264,7 +264,7 @@ debug_event::print_desc (pretty_printer &pp) const
/* class precanned_custom_event : public custom_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
precanned_custom_event.
Use the saved string as the event's description. */
@@ -287,7 +287,7 @@ statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
{
}
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
statement_event.
Use the statement's dump form as the event's description. */
@@ -383,7 +383,7 @@ function_entry_event::function_entry_event (const program_point &dst_point,
{
}
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
function_entry_event.
Use a string such as "entry to 'foo'" as the event's description. */
@@ -394,10 +394,10 @@ function_entry_event::print_desc (pretty_printer &pp) const
pp_printf (&pp, "entry to %qE", m_effective_fndecl);
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
function entry. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
function_entry_event::get_meaning () const
{
return meaning (verb::enter, noun::function);
@@ -429,7 +429,7 @@ state_change_event::state_change_event (const supernode *node,
{
}
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
state_change_event.
Attempt to generate a nicer human-readable description.
@@ -471,7 +471,7 @@ state_change_event::print_desc (pretty_printer &pp) const
pp_string (&pp, "NULL origin");
/* Get any "meaning" of event. */
- diagnostic_event::meaning meaning = get_meaning ();
+ diagnostics::paths::event::meaning meaning = get_meaning ();
pp_string (&pp, ", meaning: ");
meaning.dump_to_pp (&pp);
pp_string (&pp, ")");
@@ -508,11 +508,11 @@ state_change_event::print_desc (pretty_printer &pp) const
}
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
state change events: delegate to the pending_diagnostic to
get any meaning. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
state_change_event::get_meaning () const
{
if (m_pending_diagnostic)
@@ -530,16 +530,17 @@ state_change_event::get_meaning () const
/* class superedge_event : public checker_event. */
-/* Implementation of diagnostic_event::maybe_add_sarif_properties
+/* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
for superedge_event. */
void
-superedge_event::maybe_add_sarif_properties (sarif_builder &builder,
- sarif_object &thread_flow_loc_obj)
+superedge_event::
+maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
+ diagnostics::sarif_object &thread_flow_loc_obj)
const
{
checker_event::maybe_add_sarif_properties (builder, thread_flow_loc_obj);
- sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
+ auto &props = thread_flow_loc_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
if (m_sedge)
props.set (PROPERTY_PREFIX "superedge", m_sedge->to_json ());
@@ -626,10 +627,10 @@ cfg_edge_event::cfg_edge_event (enum event_kind kind,
gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
CFG edge events. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
cfg_edge_event::get_meaning () const
{
const cfg_superedge& cfg_sedge = get_cfg_superedge ();
@@ -643,7 +644,7 @@ cfg_edge_event::get_meaning () const
/* class start_cfg_edge_event : public cfg_edge_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
start_cfg_edge_event.
If -fanalyzer-verbose-edges, then generate low-level descriptions, such
@@ -844,7 +845,7 @@ call_event::call_event (const exploded_edge &eedge,
m_dest_snode = eedge.m_dest->get_supernode ();
}
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
call_event.
If this call event passes critical state for an sm-based warning,
@@ -876,10 +877,10 @@ call_event::print_desc (pretty_printer &pp) const
get_caller_fndecl ());
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
function call events. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
call_event::get_meaning () const
{
return meaning (verb::call, noun::function);
@@ -928,7 +929,7 @@ return_event::return_event (const exploded_edge &eedge,
m_dest_snode = eedge.m_dest->get_supernode ();
}
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
return_event.
If this return event returns critical state for an sm-based warning,
@@ -960,10 +961,10 @@ return_event::print_desc (pretty_printer &pp) const
m_src_snode->m_fun->decl);
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
function return events. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
return_event::get_meaning () const
{
return meaning (verb::return_, noun::function);
@@ -987,10 +988,10 @@ start_consolidated_cfg_edges_event::print_desc (pretty_printer &pp) const
m_edge_sense ? "true" : "false");
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
start_consolidated_cfg_edges_event. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
start_consolidated_cfg_edges_event::get_meaning () const
{
return meaning (verb::branch,
@@ -1008,10 +1009,10 @@ inlined_call_event::print_desc (pretty_printer &pp) const
m_apparent_caller_fndecl);
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
reconstructed inlined function calls. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
inlined_call_event::get_meaning () const
{
return meaning (verb::call, noun::function);
@@ -1019,7 +1020,7 @@ inlined_call_event::get_meaning () const
/* class setjmp_event : public checker_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
setjmp_event. */
void
@@ -1038,7 +1039,7 @@ setjmp_event::print_desc (pretty_printer &pp) const
void
setjmp_event::prepare_for_emission (checker_path *path,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id)
+ diagnostics::paths::event_id_t emission_id)
{
checker_event::prepare_for_emission (path, pd, emission_id);
path->record_setjmp_event (m_enode, emission_id);
@@ -1077,7 +1078,7 @@ rewind_event::rewind_event (const exploded_edge *eedge,
/* class rewind_from_longjmp_event : public rewind_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
rewind_from_longjmp_event. */
void
@@ -1101,7 +1102,7 @@ rewind_from_longjmp_event::print_desc (pretty_printer &pp) const
/* class rewind_to_setjmp_event : public rewind_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
rewind_to_setjmp_event. */
void
@@ -1150,7 +1151,7 @@ rewind_to_setjmp_event::print_desc (pretty_printer &pp) const
void
rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id)
+ diagnostics::paths::event_id_t emission_id)
{
checker_event::prepare_for_emission (path, pd, emission_id);
path->get_setjmp_event (m_rewind_info->get_enode_origin (),
@@ -1203,7 +1204,7 @@ unwind_event::print_desc (pretty_printer &pp) const
/* class warning_event : public checker_event. */
-/* Implementation of diagnostic_event::print_desc vfunc for
+/* Implementation of diagnostics::paths::event::print_desc vfunc for
warning_event.
If the pending diagnostic implements describe_final_event, use it,
@@ -1248,10 +1249,10 @@ warning_event::print_desc (pretty_printer &pp) const
pp_string (&pp, "here");
}
-/* Implementation of diagnostic_event::get_meaning vfunc for
+/* Implementation of diagnostics::paths::event::get_meaning vfunc for
warning_event. */
-diagnostic_event::meaning
+diagnostics::paths::event::meaning
warning_event::get_meaning () const
{
return meaning (verb::danger, noun::unknown);
diff --git a/gcc/analyzer/checker-event.h b/gcc/analyzer/checker-event.h
index cf24e77..909e388 100644
--- a/gcc/analyzer/checker-event.h
+++ b/gcc/analyzer/checker-event.h
@@ -1,4 +1,4 @@
-/* Subclasses of diagnostic_event for analyzer diagnostics.
+/* Subclasses of diagnostics::paths::event for analyzer diagnostics.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-logical-location.h"
#include "analyzer/program-state.h"
#include "analyzer/event-loc-info.h"
-#include "diagnostic-digraphs.h"
+#include "diagnostics/digraphs.h"
namespace ana {
@@ -62,7 +62,7 @@ extern const char *event_kind_to_string (enum event_kind ek);
The class hierarchy looks like this (using indentation to show
inheritance, and with event_kinds shown for the concrete subclasses):
- diagnostic_event
+ diagnostics::paths::event
checker_event
debug_event (event_kind::debug)
custom_event (event_kind::custom)
@@ -91,30 +91,32 @@ extern const char *event_kind_to_string (enum event_kind ek);
unwind_event (event_kind::unwind)
warning_event (event_kind::warning). */
-/* Abstract subclass of diagnostic_event; the base class for use in
- checker_path (the analyzer's diagnostic_path subclass). */
+/* Abstract subclass of diagnostics::paths::event; the base class for use in
+ checker_path (the analyzer's diagnostics::paths::path subclass). */
-class checker_event : public diagnostic_event
+class checker_event : public diagnostics::paths::event
{
public:
- /* Implementation of diagnostic_event. */
+ /* Implementation of diagnostics::paths::event. */
location_t get_location () const final override { return m_loc; }
int get_stack_depth () const final override { return m_effective_depth; }
- logical_location get_logical_location () const final override
+ diagnostics::logical_locations::key
+ get_logical_location () const final override
{
return m_logical_loc;
}
meaning get_meaning () const override;
bool connect_to_next_event_p () const override { return false; }
- diagnostic_thread_id_t get_thread_id () const final override
+ diagnostics::paths::thread_id_t get_thread_id () const final override
{
return 0;
}
void
- maybe_add_sarif_properties (sarif_builder &,
- sarif_object &thread_flow_loc_obj) const override;
+ maybe_add_sarif_properties (diagnostics::sarif_builder &,
+ diagnostics::sarif_object &thread_flow_loc_obj)
+ const override;
/* Additional functionality. */
enum event_kind get_kind () const { return m_kind; }
@@ -124,7 +126,7 @@ public:
virtual void prepare_for_emission (checker_path *,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id);
+ diagnostics::paths::event_id_t emission_id);
virtual bool is_call_p () const { return false; }
virtual bool is_function_entry_p () const { return false; }
virtual bool is_return_p () const { return false; }
@@ -136,7 +138,7 @@ public:
get_program_state () const { return nullptr; }
/* For use with %@. */
- const diagnostic_event_id_t *get_id_ptr () const
+ const diagnostics::paths::event_id_t *get_id_ptr () const
{
return &m_emission_id;
}
@@ -160,8 +162,8 @@ protected:
int m_original_depth;
int m_effective_depth;
pending_diagnostic *m_pending_diagnostic;
- diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
- logical_location m_logical_loc;
+ diagnostics::paths::event_id_t m_emission_id; // only set once all pruning has occurred
+ diagnostics::logical_locations::key m_logical_loc;
};
/* A concrete event subclass for a purely textual event, for use in
@@ -422,8 +424,9 @@ public:
class superedge_event : public checker_event
{
public:
- void maybe_add_sarif_properties (sarif_builder &,
- sarif_object &thread_flow_loc_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_builder &,
+ diagnostics::sarif_object &thread_flow_loc_obj)
const override;
/* Mark this edge event as being either an interprocedural call or
@@ -665,7 +668,7 @@ public:
void prepare_for_emission (checker_path *path,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id) final override;
+ diagnostics::paths::event_id_t emission_id) final override;
private:
const exploded_node *m_enode;
@@ -731,10 +734,10 @@ public:
void prepare_for_emission (checker_path *path,
pending_diagnostic *pd,
- diagnostic_event_id_t emission_id) final override;
+ diagnostics::paths::event_id_t emission_id) final override;
private:
- diagnostic_event_id_t m_original_setjmp_event_id;
+ diagnostics::paths::event_id_t m_original_setjmp_event_id;
};
/* An abstract subclass for throwing/rethrowing an exception. */
diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc
index 45593e0..646d72c 100644
--- a/gcc/analyzer/checker-path.cc
+++ b/gcc/analyzer/checker-path.cc
@@ -1,4 +1,4 @@
-/* Subclass of diagnostic_path for analyzer diagnostics.
+/* Subclass of diagnostics::paths::path for analyzer diagnostics.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h
index 3c174bf..490d21b 100644
--- a/gcc/analyzer/checker-path.h
+++ b/gcc/analyzer/checker-path.h
@@ -1,4 +1,4 @@
-/* Subclass of diagnostic_path for analyzer diagnostics.
+/* Subclass of diagnostics::paths::path for analyzer diagnostics.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -26,28 +26,29 @@ along with GCC; see the file COPYING3. If not see
namespace ana {
-/* Subclass of diagnostic_path for analyzer diagnostics. */
+/* Subclass of diagnostic path for analyzer diagnostics. */
-class checker_path : public diagnostic_path
+class checker_path : public diagnostics::paths::path
{
public:
- checker_path (const logical_location_manager &logical_loc_mgr,
+ checker_path (const diagnostics::logical_locations::manager &logical_loc_mgr,
const extrinsic_state &ext_state,
logger *logger)
- : diagnostic_path (logical_loc_mgr),
+ : diagnostics::paths::path (logical_loc_mgr),
m_ext_state (ext_state),
m_thread ("main"),
m_logger (logger)
{}
- /* Implementation of diagnostic_path vfuncs. */
+ /* Implementation of diagnostics::paths::path vfuncs. */
unsigned num_events () const final override
{
return m_events.length ();
}
- const diagnostic_event & get_event (int idx) const final override
+ const diagnostics::paths::event &
+ get_event (int idx) const final override
{
return *m_events[idx];
}
@@ -55,8 +56,8 @@ public:
{
return 1;
}
- const diagnostic_thread &
- get_thread (diagnostic_thread_id_t) const final override
+ const diagnostics::paths::thread &
+ get_thread (diagnostics::paths::thread_id_t) const final override
{
return m_thread;
}
@@ -115,21 +116,22 @@ public:
checker_event *e;
int i;
FOR_EACH_VEC_ELT (m_events, i, e)
- e->prepare_for_emission (this, pd, diagnostic_event_id_t (i));
+ e->prepare_for_emission (this, pd, diagnostics::paths::event_id_t (i));
}
void fixup_locations (pending_diagnostic *pd);
void record_setjmp_event (const exploded_node *enode,
- diagnostic_event_id_t setjmp_emission_id)
+ diagnostics::paths::event_id_t setjmp_emission_id)
{
m_setjmp_event_ids.put (enode, setjmp_emission_id);
}
bool get_setjmp_event (const exploded_node *enode,
- diagnostic_event_id_t *out_emission_id)
+ diagnostics::paths::event_id_t *out_emission_id)
{
- if (diagnostic_event_id_t *emission_id = m_setjmp_event_ids.get (enode))
+ if (diagnostics::paths::event_id_t *emission_id
+ = m_setjmp_event_ids.get (enode))
{
*out_emission_id = *emission_id;
return true;
@@ -154,7 +156,7 @@ private:
/* During prepare_for_emission (and after), the setjmp_event for each
exploded_node *, so that rewind events can refer to them in their
descriptions. */
- hash_map <const exploded_node *, diagnostic_event_id_t> m_setjmp_event_ids;
+ hash_map <const exploded_node *, diagnostics::paths::event_id_t> m_setjmp_event_ids;
logger *m_logger;
};
diff --git a/gcc/analyzer/common.h b/gcc/analyzer/common.h
index 148bfdd..ac3048c 100644
--- a/gcc/analyzer/common.h
+++ b/gcc/analyzer/common.h
@@ -34,7 +34,7 @@ along with GCC; see the file COPYING3. If not see
#include "options.h"
#include "bitmap.h"
#include "diagnostic-core.h"
-#include "diagnostic-path.h"
+#include "diagnostics/paths.h"
#include "rich-location.h"
#include "function.h"
#include "json.h"
@@ -443,7 +443,7 @@ extern std::unique_ptr<json::value>
tree_to_json (tree node);
extern std::unique_ptr<json::value>
-diagnostic_event_id_to_json (const diagnostic_event_id_t &);
+diagnostic_event_id_to_json (const diagnostics::paths::event_id_t &);
extern std::unique_ptr<json::value>
bit_offset_to_json (const bit_offset_t &offset);
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index c083b8c..88f72d1 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -29,7 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "cgraph.h"
#include "digraph.h"
#include "gcc-rich-location.h"
-#include "diagnostic-format-sarif.h"
+#include "diagnostics/sarif-sink.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
@@ -1017,9 +1017,10 @@ saved_diagnostic::emit_any_notes () const
This extra data is intended for use when debugging the analyzer. */
void
-saved_diagnostic::maybe_add_sarif_properties (sarif_object &result_obj) const
+saved_diagnostic::
+maybe_add_sarif_properties (diagnostics::sarif_object &result_obj) const
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/saved_diagnostic/"
if (m_sm)
props.set_string (PROPERTY_PREFIX "sm", m_sm->get_name ());
@@ -1044,7 +1045,7 @@ saved_diagnostic::maybe_add_sarif_properties (sarif_object &result_obj) const
auto duplicates_arr = std::make_unique<json::array> ();
for (auto iter : m_duplicates)
{
- auto sd_obj = std::make_unique<sarif_object> ();
+ auto sd_obj = std::make_unique<diagnostics::sarif_object> ();
iter->maybe_add_sarif_properties (*sd_obj);
duplicates_arr->append (std::move (sd_obj));
}
@@ -1541,12 +1542,12 @@ diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
best_candidates.emit_best (this, eg);
}
-/* Custom subclass of diagnostic_metadata which, for SARIF output,
+/* Custom subclass of diagnostics::metadata which, for SARIF output,
populates the property bag of the diagnostic's "result" object
with information from the saved_diagnostic and the
pending_diagnostic. */
-class pending_diagnostic_metadata : public diagnostic_metadata
+class pending_diagnostic_metadata : public diagnostics::metadata
{
public:
pending_diagnostic_metadata (const saved_diagnostic &sd)
@@ -1555,7 +1556,8 @@ public:
}
void
- maybe_add_sarif_properties (sarif_object &result_obj) const override
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
+ const override
{
m_sd.maybe_add_sarif_properties (result_obj);
}
@@ -1583,7 +1585,7 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
/* Precompute all enodes from which the diagnostic is reachable. */
path_builder pb (eg, *epath, sd.get_feasibility_problem (), sd);
- /* This is the diagnostic_path subclass that will be built for
+ /* This is the diagnostics::paths::path subclass that will be built for
the diagnostic. */
checker_path emission_path (get_logical_location_manager (),
eg.get_ext_state (),
@@ -1663,7 +1665,7 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
}
}
-const logical_location_manager &
+const diagnostics::logical_locations::manager &
diagnostic_manager::get_logical_location_manager () const
{
gcc_assert (global_dc);
diff --git a/gcc/analyzer/diagnostic-manager.h b/gcc/analyzer/diagnostic-manager.h
index aa0bd79..d9cf109 100644
--- a/gcc/analyzer/diagnostic-manager.h
+++ b/gcc/analyzer/diagnostic-manager.h
@@ -67,7 +67,8 @@ public:
void emit_any_notes () const;
- void maybe_add_sarif_properties (sarif_object &result_obj) const;
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj) const;
//private:
const state_machine *m_sm;
@@ -191,7 +192,7 @@ public:
}
private:
- const logical_location_manager &
+ const diagnostics::logical_locations::manager &
get_logical_location_manager () const;
void build_emission_path (const path_builder &pb,
diff --git a/gcc/analyzer/infinite-loop.cc b/gcc/analyzer/infinite-loop.cc
index ec0b079..a53807c 100644
--- a/gcc/analyzer/infinite-loop.cc
+++ b/gcc/analyzer/infinite-loop.cc
@@ -25,7 +25,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-pretty-print.h"
#include "cgraph.h"
#include "digraph.h"
-#include "diagnostic-format-sarif.h"
+#include "diagnostics/sarif-sink.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
@@ -307,10 +307,11 @@ public:
}
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/infinite_loop_diagnostic/"
props.set (PROPERTY_PREFIX "inf_loop", m_inf_loop->to_json ());
#undef PROPERTY_PREFIX
diff --git a/gcc/analyzer/infinite-recursion.cc b/gcc/analyzer/infinite-recursion.cc
index b80b94a..960b487 100644
--- a/gcc/analyzer/infinite-recursion.cc
+++ b/gcc/analyzer/infinite-recursion.cc
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-pretty-print.h"
#include "cgraph.h"
#include "digraph.h"
+#include "diagnostics/sarif-sink.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
@@ -40,7 +41,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/exploded-graph.h"
#include "analyzer/checker-path.h"
#include "analyzer/feasible-graph.h"
-#include "diagnostic-format-sarif.h"
/* A subclass of pending_diagnostic for complaining about suspected
infinite recursion. */
@@ -223,10 +223,11 @@ public:
return false;
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/infinite_recursion_diagnostic/"
props.set_integer (PROPERTY_PREFIX "prev_entry_enode",
m_prev_entry_enode->m_index);
diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc
index fe25520..2a7c357 100644
--- a/gcc/analyzer/kf.cc
+++ b/gcc/analyzer/kf.cc
@@ -783,7 +783,7 @@ public:
/* SEI CERT C Coding Standard: "POS34-C. Do not call putenv() with a
pointer to an automatic variable as the argument". */
- diagnostic_metadata::precanned_rule
+ diagnostics::metadata::precanned_rule
rule ("POS34-C", "https://wiki.sei.cmu.edu/confluence/x/6NYxBQ");
ctxt.add_rule (rule);
diff --git a/gcc/analyzer/pending-diagnostic.cc b/gcc/analyzer/pending-diagnostic.cc
index 5e95edd..cc2d795 100644
--- a/gcc/analyzer/pending-diagnostic.cc
+++ b/gcc/analyzer/pending-diagnostic.cc
@@ -20,7 +20,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/common.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "cpplib.h"
#include "digraph.h"
#include "ordered-hash-map.h"
@@ -92,7 +92,7 @@ diagnostic_emission_context::warn (const char *gmsgid, ...)
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
- const bool result = emit_diagnostic_valist_meta (DK_WARNING,
+ const bool result = emit_diagnostic_valist_meta (diagnostics::kind::warning,
&m_rich_loc, &m_metadata,
pd.get_controlling_option (),
gmsgid, &ap);
@@ -110,7 +110,7 @@ diagnostic_emission_context::inform (const char *gmsgid, ...)
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
- emit_diagnostic_valist_meta (DK_NOTE,
+ emit_diagnostic_valist_meta (diagnostics::kind::note,
&m_rich_loc, &m_metadata,
pd.get_controlling_option (),
gmsgid, &ap);
diff --git a/gcc/analyzer/pending-diagnostic.h b/gcc/analyzer/pending-diagnostic.h
index 469513c..b5d90a2 100644
--- a/gcc/analyzer/pending-diagnostic.h
+++ b/gcc/analyzer/pending-diagnostic.h
@@ -21,8 +21,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_ANALYZER_PENDING_DIAGNOSTIC_H
#define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
-#include "diagnostic-metadata.h"
-#include "diagnostic-path.h"
+#include "diagnostics/metadata.h"
#include "analyzer/sm.h"
namespace ana {
@@ -44,7 +43,7 @@ struct interesting_t
};
/* Various bundles of information used for generating more precise
- messages for events within a diagnostic_path, for passing to the
+ messages for events within a diagnostic path, for passing to the
various "describe_*" vfuncs of pending_diagnostic. See those
for more information. */
@@ -58,7 +57,7 @@ struct state_change
tree origin,
state_machine::state_t old_state,
state_machine::state_t new_state,
- diagnostic_event_id_t event_id,
+ diagnostics::paths::event_id_t event_id,
const state_change_event &event)
: m_expr (expr), m_origin (origin),
m_old_state (old_state), m_new_state (new_state),
@@ -71,7 +70,7 @@ struct state_change
tree m_origin;
state_machine::state_t m_old_state;
state_machine::state_t m_new_state;
- diagnostic_event_id_t m_event_id;
+ diagnostics::paths::event_id_t m_event_id;
const state_change_event &m_event;
};
@@ -131,14 +130,14 @@ struct final_event
pending_diagnostic::emit vfunc.
The rich_location will have already been populated with a
- diagnostic_path. */
+ diagnostics::paths::path. */
class diagnostic_emission_context
{
public:
diagnostic_emission_context (const saved_diagnostic &sd,
rich_location &rich_loc,
- diagnostic_metadata &metadata,
+ diagnostics::metadata &metadata,
logger *logger)
: m_sd (sd),
m_rich_loc (rich_loc),
@@ -156,7 +155,7 @@ public:
logger *get_logger () const { return m_logger; }
void add_cwe (int cwe) { m_metadata.add_cwe (cwe); }
- void add_rule (const diagnostic_metadata::rule &r)
+ void add_rule (const diagnostics::metadata::rule &r)
{
m_metadata.add_rule (r);
}
@@ -164,7 +163,7 @@ public:
private:
const saved_diagnostic &m_sd;
rich_location &m_rich_loc;
- diagnostic_metadata &m_metadata;
+ diagnostics::metadata &m_metadata;
logger *m_logger;
};
@@ -182,7 +181,7 @@ private:
As well as emitting a diagnostic, the class has various "precision of
wording" virtual functions, for generating descriptions for events
- within a diagnostic_path. These are optional, but implementing these
+ within a diagnostic path. These are optional, but implementing these
allows for more precise wordings than the more generic
implementation. */
@@ -238,7 +237,7 @@ class pending_diagnostic
virtual location_t fixup_location (location_t loc, bool primary) const;
/* Precision-of-wording vfunc for describing a critical state change
- within the diagnostic_path.
+ within the diagnostic path.
For example, a double-free diagnostic might use the descriptions:
- "first 'free' happens here"
@@ -260,13 +259,13 @@ class pending_diagnostic
return false;
}
- /* Vfunc for implementing diagnostic_event::get_meaning for
+ /* Vfunc for implementing event::get_meaning for
state_change_event. */
- virtual diagnostic_event::meaning
+ virtual diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &) const
{
/* Default no-op implementation. */
- return diagnostic_event::meaning ();
+ return diagnostics::paths::event::meaning ();
}
/* Precision-of-wording vfunc for describing an interprocedural call
@@ -285,7 +284,7 @@ class pending_diagnostic
}
/* Precision-of-wording vfunc for describing an interprocedural return
- within the diagnostic_path that carries critial state for the
+ within the diagnostic path that carries critial state for the
diagnostic, from callee back to caller.
For example, a deref-of-unchecked-malloc diagnostic might use:
@@ -301,7 +300,7 @@ class pending_diagnostic
}
/* Precision-of-wording vfunc for describing the final event within a
- diagnostic_path.
+ diagnostic path.
For example a double-free diagnostic might use:
- "second 'free' here; first 'free' was at (3)"
@@ -402,7 +401,8 @@ class pending_diagnostic
the opportunity to add diagnostic-specific properties to the SARIF
"result" object for the diagnostic.
This is intended for use when debugging a diagnostic. */
- virtual void maybe_add_sarif_properties (sarif_object &/*result_obj*/) const
+ virtual void
+ maybe_add_sarif_properties (diagnostics::sarif_object &/*result_obj*/) const
{
/* Default no-op implementation. */
}
diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc
index 1f82559..9baa007 100644
--- a/gcc/analyzer/program-point.cc
+++ b/gcc/analyzer/program-point.cc
@@ -20,7 +20,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/common.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "gcc-rich-location.h"
#include "gimple-pretty-print.h"
#include "sbitmap.h"
@@ -234,17 +234,18 @@ function_point::before_supernode (const supernode *supernode,
return function_point (supernode, from_edge, 0, PK_BEFORE_SUPERNODE);
}
-/* A subclass of diagnostic_context for use by
+/* A subclass of diagnostics::context for use by
program_point::print_source_line. */
-class debug_diagnostic_context : public diagnostic_context
+class debug_diagnostic_context : public diagnostics::context
{
public:
debug_diagnostic_context ()
{
diagnostic_initialize (this, 0);
- m_source_printing.show_line_numbers_p = true;
- m_source_printing.enabled = true;
+ auto &source_printing_opts = get_source_printing_options ();
+ source_printing_opts.show_line_numbers_p = true;
+ source_printing_opts.enabled = true;
}
~debug_diagnostic_context ()
{
@@ -263,9 +264,9 @@ function_point::print_source_line (pretty_printer *pp) const
// TODO: monospace font
debug_diagnostic_context tmp_dc;
gcc_rich_location richloc (stmt->location);
- diagnostic_source_print_policy source_policy (tmp_dc);
+ diagnostics::source_print_policy source_policy (tmp_dc);
gcc_assert (pp);
- source_policy.print (*pp, richloc, DK_ERROR, nullptr);
+ source_policy.print (*pp, richloc, diagnostics::kind::error, nullptr);
pp_string (pp, pp_formatted_text (tmp_dc.get_reference_printer ()));
}
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index 85cbe75..e16a50f 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -27,8 +27,8 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-iterator.h"
#include "cgraph.h"
#include "digraph.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-state-graphs.h"
+#include "diagnostics/event-id.h"
+#include "diagnostics/state-graphs.h"
#include "graphviz.h"
#include "text-art/tree-widget.h"
diff --git a/gcc/analyzer/region-model-asm.cc b/gcc/analyzer/region-model-asm.cc
index d280ae2..fe70490 100644
--- a/gcc/analyzer/region-model-asm.cc
+++ b/gcc/analyzer/region-model-asm.cc
@@ -171,7 +171,8 @@ region_model::on_asm_stmt (const gasm *stmt, region_model_context *ctxt)
no point in going further. */
constraint = constraints[i];
if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
- &allows_mem, &allows_reg, &is_inout))
+ &allows_mem, &allows_reg, &is_inout,
+ nullptr))
{
if (logger)
logger->log ("error parsing constraint for output %i: %qs",
@@ -204,8 +205,8 @@ region_model::on_asm_stmt (const gasm *stmt, region_model_context *ctxt)
const char *constraint = constraints[i + noutputs];
bool allows_reg, allows_mem;
if (! parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
- constraints.address (),
- &allows_mem, &allows_reg))
+ constraints.address (), &allows_mem,
+ &allows_reg, nullptr))
{
if (logger)
logger->log ("error parsing constraint for input %i: %qs",
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 6df3842..618d96b 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -26,7 +26,7 @@ along with GCC; see the file COPYING3. If not see
#include "cgraph.h"
#include "cfg.h"
#include "sbitmap.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "stor-layout.h"
#include "stringpool.h"
#include "attribs.h"
@@ -40,7 +40,7 @@ along with GCC; see the file COPYING3. If not see
#include "is-a.h"
#include "gcc-rich-location.h"
#include "gcc-urlifier.h"
-#include "diagnostic-format-sarif.h"
+#include "diagnostics/sarif-sink.h"
#include "tree-pretty-print.h"
#include "fold-const.h"
#include "selftest-tree.h"
@@ -907,9 +907,10 @@ public:
}
void
- maybe_add_sarif_properties (sarif_object &result_obj) const final override
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
+ const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/poisoned_value_diagnostic/"
props.set (PROPERTY_PREFIX "expr", tree_to_json (m_expr));
props.set_string (PROPERTY_PREFIX "kind", poison_kind_to_str (m_pkind));
@@ -3835,10 +3836,11 @@ public:
interest->add_region_creation (m_rhs);
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/dubious_allocation_size/"
props.set (PROPERTY_PREFIX "lhs", m_lhs->to_json ());
props.set (PROPERTY_PREFIX "rhs", m_rhs->to_json ());
@@ -7595,9 +7597,10 @@ public:
}
void
- maybe_add_sarif_properties (sarif_object &result_obj) const final override
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
+ const final override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/-Wanalyzer-exposure-through-uninit-copy/"
props.set (PROPERTY_PREFIX "src_region", m_src_region->to_json ());
props.set (PROPERTY_PREFIX "dest_region", m_dest_region->to_json ());
diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc
index 370d7a0..b8ae0a1 100644
--- a/gcc/analyzer/sm-fd.cc
+++ b/gcc/analyzer/sm-fd.cc
@@ -20,7 +20,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/common.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "stringpool.h"
#include "attribs.h"
@@ -392,21 +392,22 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (
const evdesc::state_change &change) const final override
{
+ using event = diagnostics::paths::event;
if (change.m_old_state == m_sm.get_start_state ()
&& (m_sm.is_unchecked_fd_p (change.m_new_state)
|| change.m_new_state == m_sm.m_new_datagram_socket
|| change.m_new_state == m_sm.m_new_stream_socket
|| change.m_new_state == m_sm.m_new_unknown_socket))
- return diagnostic_event::meaning (diagnostic_event::verb::acquire,
- diagnostic_event::noun::resource);
+ return event::meaning (event::verb::acquire,
+ event::noun::resource);
if (change.m_new_state == m_sm.m_closed)
- return diagnostic_event::meaning (diagnostic_event::verb::release,
- diagnostic_event::noun::resource);
- return diagnostic_event::meaning ();
+ return event::meaning (event::verb::release,
+ event::noun::resource);
+ return event::meaning ();
}
protected:
@@ -561,7 +562,7 @@ public:
}
private:
- diagnostic_event_id_t m_open_event;
+ diagnostics::paths::event_id_t m_open_event;
std::unique_ptr<program_state> m_final_state;
};
@@ -705,7 +706,7 @@ public:
}
private:
- diagnostic_event_id_t m_first_close_event;
+ diagnostics::paths::event_id_t m_first_close_event;
};
class fd_use_after_close : public fd_param_diagnostic
@@ -784,7 +785,7 @@ public:
}
private:
- diagnostic_event_id_t m_first_close_event;
+ diagnostics::paths::event_id_t m_first_close_event;
};
class fd_use_without_check : public fd_param_diagnostic
@@ -854,7 +855,7 @@ public:
}
private:
- diagnostic_event_id_t m_first_open_event;
+ diagnostics::paths::event_id_t m_first_open_event;
};
/* Concrete pending_diagnostic subclass for -Wanalyzer-fd-phase-mismatch. */
diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc
index 4b1fc77..c852c02 100644
--- a/gcc/analyzer/sm-file.cc
+++ b/gcc/analyzer/sm-file.cc
@@ -20,7 +20,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/common.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "selftest.h"
#include "analyzer/analyzer-logging.h"
@@ -155,18 +155,20 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
+ using event = diagnostics::paths::event;
+
if (change.m_old_state == m_sm.get_start_state ()
&& change.m_new_state == m_sm.m_unchecked)
- return diagnostic_event::meaning (diagnostic_event::verb::acquire,
- diagnostic_event::noun::resource);
+ return event::meaning (event::verb::acquire,
+ event::noun::resource);
if (change.m_new_state == m_sm.m_closed)
- return diagnostic_event::meaning (diagnostic_event::verb::release,
- diagnostic_event::noun::resource);
- return diagnostic_event::meaning ();
+ return event::meaning (event::verb::release,
+ event::noun::resource);
+ return event::meaning ();
}
protected:
@@ -225,7 +227,7 @@ public:
}
private:
- diagnostic_event_id_t m_first_fclose_event;
+ diagnostics::paths::event_id_t m_first_fclose_event;
};
class file_leak : public file_diagnostic
@@ -303,7 +305,7 @@ public:
}
private:
- diagnostic_event_id_t m_fopen_event;
+ diagnostics::paths::event_id_t m_fopen_event;
std::unique_ptr<program_state> m_final_state;
};
diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
index 2a218d0..a6b1421 100644
--- a/gcc/analyzer/sm-malloc.cc
+++ b/gcc/analyzer/sm-malloc.cc
@@ -20,7 +20,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/common.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "stringpool.h"
#include "attribs.h"
#include "xml-printer.h"
@@ -814,18 +814,18 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
if (change.m_old_state == m_sm.get_start_state ()
&& unchecked_p (change.m_new_state))
- return diagnostic_event::meaning (diagnostic_event::verb::acquire,
- diagnostic_event::noun::memory);
+ return diagnostics::paths::event::meaning (diagnostics::paths::event::verb::acquire,
+ diagnostics::paths::event::noun::memory);
if (freed_p (change.m_new_state))
- return diagnostic_event::meaning (diagnostic_event::verb::release,
- diagnostic_event::noun::memory);
- return diagnostic_event::meaning ();
+ return diagnostics::paths::event::meaning (diagnostics::paths::event::verb::release,
+ diagnostics::paths::event::noun::memory);
+ return diagnostics::paths::event::meaning ();
}
protected:
@@ -918,7 +918,7 @@ public:
}
private:
- diagnostic_event_id_t m_alloc_event;
+ diagnostics::paths::event_id_t m_alloc_event;
const deallocator_set *m_expected_deallocators;
const deallocator *m_actual_dealloc;
};
@@ -988,7 +988,7 @@ public:
}
private:
- diagnostic_event_id_t m_first_free_event;
+ diagnostics::paths::event_id_t m_first_free_event;
const char *m_funcname;
};
@@ -1031,7 +1031,7 @@ public:
}
protected:
- diagnostic_event_id_t m_origin_of_unchecked_event;
+ diagnostics::paths::event_id_t m_origin_of_unchecked_event;
};
/* Concrete subclass for describing dereference of a possible NULL
@@ -1419,7 +1419,7 @@ public:
}
private:
- diagnostic_event_id_t m_free_event;
+ diagnostics::paths::event_id_t m_free_event;
const deallocator *m_deallocator;
};
@@ -1500,7 +1500,7 @@ public:
}
private:
- diagnostic_event_id_t m_alloc_event;
+ diagnostics::paths::event_id_t m_alloc_event;
std::unique_ptr<program_state> m_final_state;
};
@@ -1768,7 +1768,7 @@ private:
return result;
}
- diagnostic_event_id_t m_first_deref_event;
+ diagnostics::paths::event_id_t m_first_deref_event;
const exploded_node *m_deref_enode;
tree m_deref_expr;
const exploded_node *m_check_enode;
diff --git a/gcc/analyzer/sm-pattern-test.cc b/gcc/analyzer/sm-pattern-test.cc
index 02b32ac..12449a1 100644
--- a/gcc/analyzer/sm-pattern-test.cc
+++ b/gcc/analyzer/sm-pattern-test.cc
@@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/common.h"
#include "tree-pretty-print.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
diff --git a/gcc/analyzer/sm-sensitive.cc b/gcc/analyzer/sm-sensitive.cc
index f8fcded..4611b10e 100644
--- a/gcc/analyzer/sm-sensitive.cc
+++ b/gcc/analyzer/sm-sensitive.cc
@@ -21,7 +21,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/common.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
@@ -106,14 +106,15 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
+ using event = diagnostics::paths::event;
+
if (change.m_new_state == m_sm.m_sensitive)
- return diagnostic_event::meaning (diagnostic_event::verb::acquire,
- diagnostic_event::noun::sensitive);
- return diagnostic_event::meaning ();
+ return event::meaning (event::verb::acquire, event::noun::sensitive);
+ return event::meaning ();
}
bool
describe_call_with_state (pretty_printer &pp,
@@ -162,7 +163,7 @@ public:
private:
const sensitive_state_machine &m_sm;
tree m_arg;
- diagnostic_event_id_t m_first_sensitive_event;
+ diagnostics::paths::event_id_t m_first_sensitive_event;
};
/* sensitive_state_machine's ctor. */
diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc
index 5a4b384..35ecde1 100644
--- a/gcc/analyzer/sm-signal.cc
+++ b/gcc/analyzer/sm-signal.cc
@@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/common.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "sbitmap.h"
#include "ordered-hash-map.h"
#include "selftest.h"
diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc
index 5c8cc7e..f2a94e8 100644
--- a/gcc/analyzer/sm-taint.cc
+++ b/gcc/analyzer/sm-taint.cc
@@ -30,7 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "fold-const.h"
-#include "diagnostic-format-sarif.h"
+#include "diagnostics/sarif-sink.h"
#include "gcc-urlifier.h"
#include "analyzer/analyzer-logging.h"
@@ -209,20 +209,22 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
+ using event = diagnostics::paths::event;
if (change.m_new_state == m_sm.m_tainted)
- return diagnostic_event::meaning (diagnostic_event::verb::acquire,
- diagnostic_event::noun::taint);
- return diagnostic_event::meaning ();
+ return event::meaning (event::verb::acquire,
+ event::noun::taint);
+ return event::meaning ();
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const override
{
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/taint_diagnostic/"
props.set (PROPERTY_PREFIX "arg", tree_to_json (m_arg));
props.set_string (PROPERTY_PREFIX "has_bounds",
@@ -495,11 +497,12 @@ public:
}
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
taint_diagnostic::maybe_add_sarif_properties (result_obj);
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/tainted_offset/"
props.set (PROPERTY_PREFIX "offset", m_offset->to_json ());
#undef PROPERTY_PREFIX
@@ -864,11 +867,12 @@ public:
}
}
- void maybe_add_sarif_properties (sarif_object &result_obj)
+ void
+ maybe_add_sarif_properties (diagnostics::sarif_object &result_obj)
const final override
{
taint_diagnostic::maybe_add_sarif_properties (result_obj);
- sarif_property_bag &props = result_obj.get_or_create_properties ();
+ auto &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/tainted_allocation_size/"
props.set (PROPERTY_PREFIX "size_in_bytes", m_size_in_bytes->to_json ());
#undef PROPERTY_PREFIX
diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc
index 4947271..1fdfd34 100644
--- a/gcc/analyzer/varargs.cc
+++ b/gcc/analyzer/varargs.cc
@@ -334,17 +334,17 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
if (change.m_new_state == m_sm.m_started)
- return diagnostic_event::meaning (diagnostic_event::verb::acquire,
- diagnostic_event::noun::resource);
+ return diagnostics::paths::event::meaning (diagnostics::paths::event::verb::acquire,
+ diagnostics::paths::event::noun::resource);
if (change.m_new_state == m_sm.m_ended)
- return diagnostic_event::meaning (diagnostic_event::verb::release,
- diagnostic_event::noun::resource);
- return diagnostic_event::meaning ();
+ return diagnostics::paths::event::meaning (diagnostics::paths::event::verb::release,
+ diagnostics::paths::event::noun::resource);
+ return diagnostics::paths::event::meaning ();
}
protected:
@@ -452,7 +452,7 @@ public:
}
private:
- diagnostic_event_id_t m_va_end_event;
+ diagnostics::paths::event_id_t m_va_end_event;
const char *m_usage_fnname;
};
@@ -539,7 +539,7 @@ public:
}
private:
- diagnostic_event_id_t m_start_event;
+ diagnostics::paths::event_id_t m_start_event;
const char *m_start_event_fnname;
std::unique_ptr<program_state> m_final_state;
};
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index fb40698..a754525 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,86 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.cc: Make diagnostics::context::m_source_printing
+ private.
+ * c-format.cc: Likewise.
+ * c-opts.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.cc: Update usage of "diagnostic_info" to explicitly
+ refer to "diagnostics::diagnostic_info".
+ * c-opts.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-format.cc: Update for file_cache and char_span moving from
+ input.h to diagnostics/file-cache.h and into the "diagnostics::"
+ namespace.
+ * c-indentation.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.cc (c_family_tests): Add include of
+ "diagnostics/diagnostics-selftests.h". Replace
+ c_diagnostic_cc_tests with
+ diagnostics::selftest::context_cc_tests.
+ * c-common.h: Drop c_diagnostic_cc_tests decl.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * c-format.cc: Likewise.
+ * c-lex.cc: Likewise.
+ * c-opts.cc: Likewise.
+ * c-pragma.cc: Likewise.
+ * c-warn.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.cc: Update for renaming of diagnostic_option_id to
+ diagnostics::option_id.
+ * c-common.h: Likewise.
+ * c-cppbuiltin.cc: Likewise.
+ * known-headers.cc: Likewise.
+ * known-headers.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.cc: Update comment for renaming of edit_context.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-format.cc (test_type_mismatch_range_labels): Update for
+ move of selftest::test_diagnostic_context to
+ diagnostics::selftest::test_context.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-format.cc: Update for move of selftest-diagnostic.h to
+ diagnostics/selftest-context.h.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.h: Update for diagnostic_context becoming
+ diagnostics::context.
+ * c-opts.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-opts.cc (c_diagnostic_text_finalizer): Add "m_" prefix to
+ fields of diagnostic_info.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-opts.cc: Update for move of "diagnostic-macro-unwinding.h"
+ to "diagnostics/macro-unwinding.h".
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-opts.cc: Update for move of diagnostics output formats into
+ namespace "diagnostics" as "sinks".
+
2025-07-16 Kwok Cheung Yeung <kcyeung@baylibre.com>
* c-omp.cc (c_finish_omp_depobj): Use OMP_ITERATOR_DECL_P.
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 362dc50..e7dd460 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print-markup.h"
#include "gcc-rich-location.h"
#include "gcc-urlifier.h"
+#include "diagnostics/diagnostics-selftests.h"
cpp_reader *parse_in; /* Declared in c-pragma.h. */
@@ -7025,7 +7026,7 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token_type,
/* Return the gcc option code associated with the reason for a cpp
message, or 0 if none. */
-static diagnostic_option_id
+static diagnostics::option_id
c_option_controlling_cpp_diagnostic (enum cpp_warning_reason reason)
{
const struct cpp_reason_option_codes_t *entry;
@@ -7067,8 +7068,8 @@ c_cpp_diagnostic (cpp_reader *pfile ATTRIBUTE_UNUSED,
rich_location *richloc,
const char *msg, va_list *ap)
{
- diagnostic_info diagnostic;
- diagnostic_t dlevel;
+ diagnostics::diagnostic_info diagnostic;
+ enum diagnostics::kind dlevel;
bool save_warn_system_headers = global_dc->m_warn_system_headers;
bool ret;
@@ -7082,24 +7083,24 @@ c_cpp_diagnostic (cpp_reader *pfile ATTRIBUTE_UNUSED,
case CPP_DL_WARNING:
if (flag_no_output)
return false;
- dlevel = DK_WARNING;
+ dlevel = diagnostics::kind::warning;
break;
case CPP_DL_PEDWARN:
if (flag_no_output && !flag_pedantic_errors)
return false;
- dlevel = DK_PEDWARN;
+ dlevel = diagnostics::kind::pedwarn;
break;
case CPP_DL_ERROR:
- dlevel = DK_ERROR;
+ dlevel = diagnostics::kind::error;
break;
case CPP_DL_ICE:
- dlevel = DK_ICE;
+ dlevel = diagnostics::kind::ice;
break;
case CPP_DL_NOTE:
- dlevel = DK_NOTE;
+ dlevel = diagnostics::kind::note;
break;
case CPP_DL_FATAL:
- dlevel = DK_FATAL;
+ dlevel = diagnostics::kind::fatal;
break;
default:
gcc_unreachable ();
@@ -9963,8 +9964,11 @@ c_family_tests (void)
c_indentation_cc_tests ();
c_pretty_print_cc_tests ();
c_spellcheck_cc_tests ();
- c_diagnostic_cc_tests ();
c_opt_problem_cc_tests ();
+
+ /* According to https://gcc.gnu.org/pipermail/gcc/2021-November/237703.html
+ this has some language-specific assumptions, so we run it here. */
+ diagnostics::selftest::context_cc_tests ();
}
} // namespace selftest
@@ -10046,7 +10050,7 @@ try_to_locate_new_include_insertion_point (const char *file, location_t loc)
return UNKNOWN_LOCATION;
/* The "start_location" is column 0, meaning "the whole line".
- rich_location and edit_context can't cope with this, so use
+ rich_location and diagnostics::changes can't cope with this, so use
column 1 instead. */
location_t col_0 = ord_map_for_insertion->start_location;
return linemap_position_for_loc_and_offset (line_table, col_0, 1);
@@ -10110,7 +10114,7 @@ maybe_add_include_fixit (rich_location *richloc, const char *header,
richloc->add_fixit_insert_before (include_insert_loc, text);
free (text);
- if (override_location && global_dc->m_source_printing.enabled)
+ if (override_location && global_dc->get_source_printing_options ().enabled)
{
/* Replace the primary location with that of the insertion point for the
fix-it hint.
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 675708d..7c7e21d 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -979,7 +979,7 @@ extern tree build_va_arg (location_t, tree, tree);
extern const unsigned int c_family_lang_mask;
extern unsigned int c_common_option_lang_mask (void);
-extern void c_common_diagnostics_set_defaults (diagnostic_context *);
+extern void c_common_diagnostics_set_defaults (diagnostics::context *);
extern bool c_common_complain_wrong_lang_p (const struct cl_option *);
extern void c_common_init_options_struct (struct gcc_options *);
extern void c_common_init_options (unsigned int, struct cl_decoded_option *);
@@ -1265,7 +1265,7 @@ extern void c_stddef_cpp_builtins (void);
extern void fe_file_change (const line_map_ordinary *);
extern void c_parse_error (const char *, enum cpp_ttype, tree, unsigned char,
rich_location *richloc);
-extern diagnostic_option_id get_option_for_builtin_define (const char *macro_name);
+extern diagnostics::option_id get_option_for_builtin_define (const char *macro_name);
/* In c-ppoutput.cc */
extern void init_pp_output (FILE *);
@@ -1729,7 +1729,6 @@ extern tree braced_lists_to_strings (tree, tree);
namespace selftest {
/* Declarations for specific families of tests within c-family,
by source file, in alphabetical order. */
- extern void c_diagnostic_cc_tests (void);
extern void c_format_cc_tests (void);
extern void c_indentation_cc_tests (void);
extern void c_opt_problem_cc_tests (void);
diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc
index 2f86b1f..4aea902 100644
--- a/gcc/c-family/c-cppbuiltin.cc
+++ b/gcc/c-family/c-cppbuiltin.cc
@@ -1681,7 +1681,7 @@ c_cpp_builtins (cpp_reader *pfile)
/* Given NAME, return the command-line option that would make it be
a builtin define, or 0 if unrecognized. */
-diagnostic_option_id
+diagnostics::option_id
get_option_for_builtin_define (const char *name)
{
if (!strcmp (name, "_OPENACC"))
diff --git a/gcc/c-family/c-format.cc b/gcc/c-family/c-format.cc
index 80430e9..bf144d0 100644
--- a/gcc/c-family/c-format.cc
+++ b/gcc/c-family/c-format.cc
@@ -32,7 +32,8 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "substring-locations.h"
#include "selftest.h"
-#include "selftest-diagnostic.h"
+#include "diagnostics/selftest-context.h"
+#include "diagnostics/file-cache.h"
#include "builtins.h"
#include "attribs.h"
#include "c-family/c-type-mismatch.h"
@@ -4634,7 +4635,7 @@ get_corrected_substring (const substring_loc &fmt_loc,
if (caret.column > finish.column)
return NULL;
- char_span line
+ diagnostics::char_span line
= global_dc->get_file_cache ().get_source_line (start.file, start.line);
if (!line)
return NULL;
@@ -4646,7 +4647,8 @@ get_corrected_substring (const substring_loc &fmt_loc,
specification, up to the (but not including) the length modifier.
In the above example, this would be "%-+*.*". */
int length_up_to_type = caret.column - start.column;
- char_span prefix_span = line.subspan (start.column - 1, length_up_to_type);
+ diagnostics::char_span prefix_span
+ = line.subspan (start.column - 1, length_up_to_type);
char *prefix = prefix_span.xstrdup ();
/* Now attempt to generate a suggestion for the rest of the specification
@@ -5584,10 +5586,12 @@ test_type_mismatch_range_labels ()
gcc_rich_location richloc (fmt, &fmt_label, nullptr);
richloc.add_range (param, SHOW_RANGE_WITHOUT_CARET, &param_label);
- test_diagnostic_context dc;
+ diagnostics::selftest::test_context dc;
diagnostic_show_locus (&dc,
- dc.m_source_printing,
- &richloc, DK_ERROR, dc.get_reference_printer ());
+ dc.get_source_printing_options (),
+ &richloc,
+ diagnostics::kind::error,
+ dc.get_reference_printer ());
if (c_dialect_cxx ())
/* "char*", without a space. */
ASSERT_STREQ (" printf (\"msg: %i\\n\", msg);\n"
diff --git a/gcc/c-family/c-indentation.cc b/gcc/c-family/c-indentation.cc
index 2e8261d..bb214fc 100644
--- a/gcc/c-family/c-indentation.cc
+++ b/gcc/c-family/c-indentation.cc
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see
#include "c-indentation.h"
#include "selftest.h"
#include "diagnostic.h"
+#include "diagnostics/file-cache.h"
/* Round up VIS_COLUMN to nearest tab stop. */
@@ -45,13 +46,13 @@ next_tab_stop (unsigned int vis_column, unsigned int tab_width)
on the line (up to or before EXPLOC). */
static bool
-get_visual_column (file_cache &fc,
+get_visual_column (diagnostics::file_cache &fc,
expanded_location exploc,
unsigned int *out,
unsigned int *first_nws,
unsigned int tab_width)
{
- char_span line = fc.get_source_line (exploc.file, exploc.line);
+ diagnostics::char_span line = fc.get_source_line (exploc.file, exploc.line);
if (!line)
return false;
if ((size_t)exploc.column > line.length ())
@@ -88,14 +89,14 @@ get_visual_column (file_cache &fc,
Otherwise, return false, leaving *FIRST_NWS untouched. */
static bool
-get_first_nws_vis_column (file_cache &fc,
+get_first_nws_vis_column (diagnostics::file_cache &fc,
const char *file, int line_num,
unsigned int *first_nws,
unsigned int tab_width)
{
gcc_assert (first_nws);
- char_span line = fc.get_source_line (file, line_num);
+ diagnostics::char_span line = fc.get_source_line (file, line_num);
if (!line)
return false;
unsigned int vis_column = 0;
@@ -160,7 +161,7 @@ get_first_nws_vis_column (file_cache &fc,
Return true if such an unindent/outdent is detected. */
static bool
-detect_intervening_unindent (file_cache &fc,
+detect_intervening_unindent (diagnostics::file_cache &fc,
const char *file,
int body_line,
int next_stmt_line,
@@ -335,7 +336,7 @@ should_warn_for_misleading_indentation (const token_indent_info &guard_tinfo,
if (next_stmt_exploc.file != body_exploc.file)
return false;
- file_cache &fc = global_dc->get_file_cache ();
+ diagnostics::file_cache &fc = global_dc->get_file_cache ();
/* If NEXT_STMT_LOC and BODY_LOC are on the same line, consider
the location of the guard.
@@ -691,7 +692,7 @@ test_next_tab_stop ()
static void
assert_get_visual_column_succeeds (const location &loc,
- file_cache &fc,
+ diagnostics::file_cache &fc,
const char *file, int line, int column,
const unsigned int tab_width,
unsigned int expected_visual_column,
@@ -735,7 +736,7 @@ assert_get_visual_column_succeeds (const location &loc,
static void
assert_get_visual_column_fails (const location &loc,
- file_cache &fc,
+ diagnostics::file_cache &fc,
const char *file, int line, int column,
const unsigned int tab_width)
{
@@ -783,7 +784,7 @@ test_get_visual_column ()
"\t line 2\n");
line_table_test ltt;
temp_source_file tmp (SELFTEST_LOCATION, ".txt", content);
- file_cache fc;
+ diagnostics::file_cache fc;
const unsigned int tab_width = 8;
const char *file = tmp.get_filename ();
diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc
index fef6ae6..b45d722 100644
--- a/gcc/c-family/c-lex.cc
+++ b/gcc/c-family/c-lex.cc
@@ -1176,7 +1176,7 @@ interpret_integer (const cpp_token *token, unsigned int flags,
&& (flags & CPP_N_WIDTH) != CPP_N_LARGE)
emit_diagnostic
((c_dialect_cxx () ? cxx_dialect == cxx98 : !flag_isoc99)
- ? DK_PEDWARN : DK_WARNING,
+ ? diagnostics::kind::pedwarn : diagnostics::kind::warning,
input_location, OPT_Wlong_long,
(flags & CPP_N_UNSIGNED)
? "integer constant is too large for %<unsigned long%> type"
diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc
index 795f5a3..c652e82 100644
--- a/gcc/c-family/c-opts.cc
+++ b/gcc/c-family/c-opts.cc
@@ -32,7 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "flags.h"
#include "toplev.h"
#include "langhooks.h"
-#include "diagnostic-macro-unwinding.h" /* for virt_loc_aware_diagnostic_finalizer */
+#include "diagnostics/macro-unwinding.h" /* for virt_loc_aware_diagnostic_finalizer */
#include "intl.h"
#include "cppdefault.h"
#include "incpath.h"
@@ -43,7 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "dumpfile.h"
#include "file-prefix-map.h" /* add_*_prefix_map() */
#include "context.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/text-sink.h"
#ifndef DOLLARS_IN_IDENTIFIERS
# define DOLLARS_IN_IDENTIFIERS true
@@ -169,9 +169,9 @@ c_common_option_lang_mask (void)
/* Diagnostic finalizer for C/C++/Objective-C/Objective-C++. */
static void
-c_diagnostic_text_finalizer (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic,
- diagnostic_t)
+c_diagnostic_text_finalizer (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic,
+ enum diagnostics::kind)
{
pretty_printer *const pp = text_output.get_printer ();
char *saved_prefix = pp_take_prefix (pp);
@@ -179,19 +179,19 @@ c_diagnostic_text_finalizer (diagnostic_text_output_format &text_output,
pp_newline (pp);
diagnostic_show_locus (&text_output.get_context (),
text_output.get_source_printing_options (),
- diagnostic->richloc, diagnostic->kind, pp);
+ diagnostic->m_richloc, diagnostic->m_kind, pp);
/* By default print macro expansion contexts in the diagnostic
finalizer -- for tokens resulting from macro expansion. */
- virt_loc_aware_diagnostic_finalizer (text_output, diagnostic);
+ diagnostics::virt_loc_aware_text_finalizer (text_output, diagnostic);
pp_set_prefix (pp, saved_prefix);
pp_flush (pp);
}
/* Common default settings for diagnostics. */
void
-c_common_diagnostics_set_defaults (diagnostic_context *context)
+c_common_diagnostics_set_defaults (diagnostics::context *context)
{
- diagnostic_text_finalizer (context) = c_diagnostic_text_finalizer;
+ diagnostics::text_finalizer (context) = c_diagnostic_text_finalizer;
context->set_permissive_option (OPT_fpermissive);
}
@@ -278,7 +278,7 @@ c_common_init_options (unsigned int decoded_options_count,
if (c_dialect_cxx ())
set_std_cxx17 (/*ISO*/false);
- global_dc->m_source_printing.colorize_source_p = true;
+ global_dc->get_source_printing_options ().colorize_source_p = true;
}
/* Handle switch SCODE with argument ARG. VALUE is true, unless no-
diff --git a/gcc/c-family/c-pragma.cc b/gcc/c-family/c-pragma.cc
index 137b83bf..8a1218b 100644
--- a/gcc/c-family/c-pragma.cc
+++ b/gcc/c-family/c-pragma.cc
@@ -781,7 +781,7 @@ public:
PK_IGNORED_ATTRIBUTES,
PK_DIAGNOSTIC,
} pd_kind;
- diagnostic_t diagnostic_kind;
+ enum diagnostics::kind diagnostic_kind;
const char *kind_str;
const char *option_str;
bool own_option_str;
@@ -792,7 +792,7 @@ public:
valid = false;
loc_kind = loc_option = UNKNOWN_LOCATION;
pd_kind = PK_INVALID;
- diagnostic_kind = DK_UNSPECIFIED;
+ diagnostic_kind = diagnostics::kind::unspecified;
kind_str = option_str = nullptr;
own_option_str = false;
}
@@ -808,7 +808,7 @@ public:
kind_str = kind_string;
pd_kind = PK_INVALID;
- diagnostic_kind = DK_UNSPECIFIED;
+ diagnostic_kind = diagnostics::kind::unspecified;
if (strcmp (kind_str, "push") == 0)
pd_kind = PK_PUSH;
else if (strcmp (kind_str, "pop") == 0)
@@ -818,17 +818,17 @@ public:
else if (strcmp (kind_str, "error") == 0)
{
pd_kind = PK_DIAGNOSTIC;
- diagnostic_kind = DK_ERROR;
+ diagnostic_kind = diagnostics::kind::error;
}
else if (strcmp (kind_str, "warning") == 0)
{
pd_kind = PK_DIAGNOSTIC;
- diagnostic_kind = DK_WARNING;
+ diagnostic_kind = diagnostics::kind::warning;
}
else if (strcmp (kind_str, "ignored") == 0)
{
pd_kind = PK_DIAGNOSTIC;
- diagnostic_kind = DK_IGNORED;
+ diagnostic_kind = diagnostics::kind::ignored;
}
}
@@ -1016,7 +1016,8 @@ handle_pragma_diagnostic_impl ()
what we used to do here before and changing it breaks e.g.
PR69543 and PR69558. */
control_warning_option (option_index, (int) data.diagnostic_kind,
- arg, data.diagnostic_kind != DK_IGNORED,
+ arg,
+ data.diagnostic_kind != diagnostics::kind::ignored,
input_location, lang_mask, &handlers,
&global_options, &global_options_set,
global_dc);
diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index d547b08..09517d2 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3835,7 +3835,7 @@ do_warn_array_compare (location_t location, tree_code code, tree op0, tree op1)
op1 = TREE_OPERAND (op1, 0);
auto_diagnostic_group d;
- diagnostic_t kind = DK_WARNING;
+ enum diagnostics::kind kind = diagnostics::kind::warning;
const char *msg;
if (c_dialect_cxx () && cxx_dialect >= cxx20)
{
@@ -3843,7 +3843,7 @@ do_warn_array_compare (location_t location, tree_code code, tree op0, tree op1)
if (cxx_dialect >= cxx26)
{
msg = G_("comparison between two arrays is not allowed in C++26");
- kind = DK_PERMERROR;
+ kind = diagnostics::kind::permerror;
}
else
msg = G_("comparison between two arrays is deprecated in C++20");
diff --git a/gcc/c-family/known-headers.cc b/gcc/c-family/known-headers.cc
index 7e0fa95..e3c0113 100644
--- a/gcc/c-family/known-headers.cc
+++ b/gcc/c-family/known-headers.cc
@@ -329,9 +329,10 @@ suggest_missing_header::~suggest_missing_header ()
/* suggest_missing_option's ctor. */
-suggest_missing_option::suggest_missing_option (location_t loc,
- const char *macro_name,
- diagnostic_option_id option_id)
+suggest_missing_option::
+suggest_missing_option (location_t loc,
+ const char *macro_name,
+ diagnostics::option_id option_id)
: deferred_diagnostic (loc), m_name_str (macro_name), m_option_id (option_id)
{
gcc_assert (macro_name);
diff --git a/gcc/c-family/known-headers.h b/gcc/c-family/known-headers.h
index b1da757f..3ffe5f3 100644
--- a/gcc/c-family/known-headers.h
+++ b/gcc/c-family/known-headers.h
@@ -48,12 +48,12 @@ class suggest_missing_option : public deferred_diagnostic
{
public:
suggest_missing_option (location_t loc, const char *name,
- diagnostic_option_id option_id);
+ diagnostics::option_id option_id);
~suggest_missing_option ();
private:
const char *m_name_str;
- diagnostic_option_id m_option_id;
+ diagnostics::option_id m_option_id;
};
#endif /* GCC_KNOWN_HEADERS_H */
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 01edb4c..c41584c 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,38 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-errors.cc: Update usage of "diagnostic_info" to explicitly
+ refer to "diagnostics::diagnostic_info".
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-errors.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * c-parser.cc: Likewise.
+ * c-typeck.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-decl.cc: Update for renaming of diagnostic_option_id to
+ diagnostics::option_id.
+ * c-errors.cc: Likewise.
+ * c-tree.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-objc-common.cc: Update for diagnostic_context becoming
+ diagnostics::context.
+ * c-tree.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * c-errors.cc: Update to add "m_" prefix to fields of
+ diagnostic_info throughout.
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * c-typeck.cc (build_asm_expr): Pass null pointer to
+ parse_{input,output}_constraint().
+
2025-07-16 Kwok Cheung Yeung <kcyeung@baylibre.com>
* c-typeck.cc (handle_omp_array_sections): Use OMP_ITERATOR_DECL_P.
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index acbe2b88..4bef438 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -4556,7 +4556,7 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
/* Next, look for exact matches for builtin defines that would have been
defined if the user had passed a command-line option (e.g. -fopenmp
for "_OPENMP"). */
- diagnostic_option_id option_id
+ diagnostics::option_id option_id
= get_option_for_builtin_define (IDENTIFIER_POINTER (name));
if (option_id.m_idx > 0)
return name_hint
diff --git a/gcc/c/c-errors.cc b/gcc/c/c-errors.cc
index 4682dca..e2c74fe 100644
--- a/gcc/c/c-errors.cc
+++ b/gcc/c/c-errors.cc
@@ -33,10 +33,10 @@ along with GCC; see the file COPYING3. If not see
bool
pedwarn_c23 (location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
bool warned = false;
rich_location richloc (line_table, location);
@@ -48,8 +48,9 @@ pedwarn_c23 (location_t location,
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
(pedantic && !flag_isoc2y)
- ? DK_PEDWARN : DK_WARNING);
- diagnostic.option_id = OPT_Wc23_c2y_compat;
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning);
+ diagnostic.m_option_id = OPT_Wc23_c2y_compat;
warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
}
/* -Wno-c23-c2y-compat suppresses even the pedwarns. */
@@ -58,8 +59,9 @@ pedwarn_c23 (location_t location,
/* For -pedantic outside C2Y, issue a pedwarn. */
else if (pedantic && !flag_isoc2y)
{
- diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
- diagnostic.option_id = option_id;
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
+ diagnostics::kind::pedwarn);
+ diagnostic.m_option_id = option_id;
warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
}
va_end (ap);
@@ -77,10 +79,10 @@ pedwarn_c23 (location_t location,
bool
pedwarn_c11 (location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
bool warned = false;
rich_location richloc (line_table, location);
@@ -93,11 +95,12 @@ pedwarn_c11 (location_t location,
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
(pedantic && !flag_isoc23)
- ? DK_PEDWARN : DK_WARNING);
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning);
if (option_id == OPT_Wpedantic)
- diagnostic.option_id = OPT_Wc11_c23_compat;
+ diagnostic.m_option_id = OPT_Wc11_c23_compat;
else
- diagnostic.option_id = option_id;
+ diagnostic.m_option_id = option_id;
warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
}
/* -Wno-c11-c23-compat suppresses even the pedwarns. */
@@ -106,8 +109,9 @@ pedwarn_c11 (location_t location,
/* For -pedantic outside C23, issue a pedwarn. */
else if (pedantic && !flag_isoc23)
{
- diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
- diagnostic.option_id = option_id;
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
+ diagnostics::kind::pedwarn);
+ diagnostic.m_option_id = option_id;
warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
}
va_end (ap);
@@ -122,10 +126,10 @@ pedwarn_c11 (location_t location,
bool
pedwarn_c99 (location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
bool warned = false;
rich_location richloc (line_table, location);
@@ -137,8 +141,9 @@ pedwarn_c99 (location_t location,
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
(pedantic && !flag_isoc11)
- ? DK_PEDWARN : DK_WARNING);
- diagnostic.option_id = OPT_Wc99_c11_compat;
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning);
+ diagnostic.m_option_id = OPT_Wc99_c11_compat;
warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
}
/* -Wno-c99-c11-compat suppresses even the pedwarns. */
@@ -147,8 +152,9 @@ pedwarn_c99 (location_t location,
/* For -pedantic outside C11, issue a pedwarn. */
else if (pedantic && !flag_isoc11)
{
- diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
- diagnostic.option_id = option_id;
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
+ diagnostics::kind::pedwarn);
+ diagnostic.m_option_id = option_id;
warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
}
va_end (ap);
@@ -164,10 +170,10 @@ pedwarn_c99 (location_t location,
bool
pedwarn_c90 (location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
bool warned = false;
rich_location richloc (line_table, location);
@@ -183,8 +189,9 @@ pedwarn_c90 (location_t location,
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
(pedantic && !flag_isoc99)
- ? DK_PEDWARN : DK_WARNING);
- diagnostic.option_id = option_id;
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning);
+ diagnostic.m_option_id = option_id;
diagnostic_report_diagnostic (global_dc, &diagnostic);
warned = true;
goto out;
@@ -196,8 +203,9 @@ pedwarn_c90 (location_t location,
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
(pedantic && !flag_isoc99)
- ? DK_PEDWARN : DK_WARNING);
- diagnostic.option_id = OPT_Wc90_c99_compat;
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning);
+ diagnostic.m_option_id = OPT_Wc90_c99_compat;
diagnostic_report_diagnostic (global_dc, &diagnostic);
}
/* -Wno-c90-c99-compat suppresses the pedwarns. */
@@ -206,8 +214,9 @@ pedwarn_c90 (location_t location,
/* For -pedantic outside C99, issue a pedwarn. */
else if (pedantic && !flag_isoc99)
{
- diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_PEDWARN);
- diagnostic.option_id = option_id;
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
+ diagnostics::kind::pedwarn);
+ diagnostic.m_option_id = option_id;
diagnostic_report_diagnostic (global_dc, &diagnostic);
warned = true;
}
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index d574bc7..5c50983 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -414,7 +414,7 @@ has_c_linkage (const_tree decl ATTRIBUTE_UNUSED)
}
void
-c_initialize_diagnostics (diagnostic_context *context)
+c_initialize_diagnostics (diagnostics::context *context)
{
context->set_pretty_printer (std::make_unique<c_pretty_printer> ());
c_common_diagnostics_set_defaults (context);
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 5119841..4a13fc0 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -29162,11 +29162,14 @@ c_parser_omp_error (c_parser *parser, enum pragma_context context)
if (msg == NULL)
msg = _("<message unknown at compile time>");
}
+ const enum diagnostics::kind diag_kind = (severity_fatal
+ ? diagnostics::kind::error
+ : diagnostics::kind::warning);
if (msg)
- emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+ emit_diagnostic (diag_kind, loc, 0,
"%<pragma omp error%> encountered: %s", msg);
else
- emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+ emit_diagnostic (diag_kind, loc, 0,
"%<pragma omp error%> encountered");
return false;
}
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 364f51d..bb0b113 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -757,7 +757,7 @@ extern tree c_finish_bc_name (location_t, tree, bool);
extern bool c_objc_common_init (void);
extern bool c_missing_noreturn_ok_p (tree);
extern bool c_warn_unused_global_decl (const_tree);
-extern void c_initialize_diagnostics (diagnostic_context *);
+extern void c_initialize_diagnostics (diagnostics::context *);
extern bool c_var_mod_p (tree x, tree fn);
extern alias_set_type c_get_alias_set (tree);
extern int c_type_dwarf_attribute (const_tree, int);
@@ -960,13 +960,13 @@ extern void c_bind (location_t, tree, bool);
extern bool tag_exists_p (enum tree_code, tree);
/* In c-errors.cc */
-extern bool pedwarn_c90 (location_t, diagnostic_option_id, const char *, ...)
+extern bool pedwarn_c90 (location_t, diagnostics::option_id, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
-extern bool pedwarn_c99 (location_t, diagnostic_option_id, const char *, ...)
+extern bool pedwarn_c99 (location_t, diagnostics::option_id, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
-extern bool pedwarn_c11 (location_t, diagnostic_option_id, const char *, ...)
+extern bool pedwarn_c11 (location_t, diagnostics::option_id, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
-extern bool pedwarn_c23 (location_t, diagnostic_option_id, const char *, ...)
+extern bool pedwarn_c23 (location_t, diagnostics::option_id, const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern void add_note_about_new_keyword (location_t loc,
tree keyword_id);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index f161bd9..ed6e56e 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -6433,14 +6433,16 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp,
else
{
int qual = ENCODE_QUAL_ADDR_SPACE (as_common);
- diagnostic_t kind = DK_PERMERROR;
+ enum diagnostics::kind kind = diagnostics::kind::permerror;
if (!flag_isoc99)
/* This downgrade to a warning ensures that -std=gnu89
-pedantic-errors does not flag these mismatches between
- builtins as errors (as DK_PERMERROR would). ISO C99
- and later do not have implicit function declarations,
+ builtins as errors (as diagnostics::kind::permerror would)
+ ISO C99 and later do not have implicit function declarations,
so the mismatch cannot occur naturally there. */
- kind = bltin1 && bltin2 ? DK_WARNING : DK_PEDWARN;
+ kind = (bltin1 && bltin2
+ ? diagnostics::kind::warning
+ : diagnostics::kind::pedwarn);
if (emit_diagnostic (kind, colon_loc, OPT_Wincompatible_pointer_types,
"pointer type mismatch "
"in conditional expression"))
@@ -7598,7 +7600,8 @@ error_init (location_t loc, const char *gmsgid, ...)
/* The gmsgid may be a format string with %< and %>. */
va_list ap;
va_start (ap, gmsgid);
- bool warned = emit_diagnostic_valist (DK_ERROR, loc, -1, gmsgid, &ap);
+ bool warned = emit_diagnostic_valist (diagnostics::kind::error,
+ loc, -1, gmsgid, &ap);
va_end (ap);
ofwhat = print_spelling ((char *) alloca (spelling_length () + 1));
@@ -7610,7 +7613,7 @@ error_init (location_t loc, const char *gmsgid, ...)
static bool ATTRIBUTE_GCC_DIAG (3,0)
pedwarn_permerror_init (location_t loc, int opt, const char *gmsgid,
- va_list *ap, diagnostic_t kind)
+ va_list *ap, enum diagnostics::kind kind)
{
/* Use the location where a macro was expanded rather than where
it was defined to make sure macros defined in system headers
@@ -7637,7 +7640,8 @@ pedwarn_init (location_t loc, int opt, const char *gmsgid, ...)
{
va_list ap;
va_start (ap, gmsgid);
- bool warned = pedwarn_permerror_init (loc, opt, gmsgid, &ap, DK_PEDWARN);
+ bool warned = pedwarn_permerror_init (loc, opt, gmsgid, &ap,
+ diagnostics::kind::pedwarn);
va_end (ap);
return warned;
}
@@ -7649,7 +7653,8 @@ permerror_init (location_t loc, int opt, const char *gmsgid, ...)
{
va_list ap;
va_start (ap, gmsgid);
- bool warned = pedwarn_permerror_init (loc, opt, gmsgid, &ap, DK_PERMERROR);
+ bool warned = pedwarn_permerror_init (loc, opt, gmsgid, &ap,
+ diagnostics::kind::permerror);
va_end (ap);
return warned;
}
@@ -12646,7 +12651,8 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
oconstraints[i] = constraint;
if (parse_output_constraint (&constraint, i, ninputs, noutputs,
- &allows_mem, &allows_reg, &is_inout))
+ &allows_mem, &allows_reg, &is_inout,
+ nullptr))
{
/* If the operand is going to end up in memory,
mark it addressable. */
@@ -12707,7 +12713,8 @@ build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
input = TREE_VALUE (tail);
if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
- oconstraints, &allows_mem, &allows_reg))
+ oconstraints, &allows_mem, &allows_reg,
+ nullptr))
{
/* If the operand is going to end up in memory,
mark it addressable. */
@@ -12889,7 +12896,9 @@ c_finish_return (location_t loc, tree retval, tree origtype, bool musttail_p)
&& valtype != NULL_TREE && TREE_CODE (valtype) != VOID_TYPE)
{
no_warning = true;
- if (emit_diagnostic (flag_isoc99 ? DK_PERMERROR : DK_WARNING,
+ if (emit_diagnostic (flag_isoc99
+ ? diagnostics::kind::permerror
+ : diagnostics::kind::warning,
loc, OPT_Wreturn_mismatch,
"%<return%> with no value,"
" in function returning non-void"))
diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc
index 8a55f4f..8950294 100644
--- a/gcc/cfgexpand.cc
+++ b/gcc/cfgexpand.cc
@@ -3275,44 +3275,6 @@ expand_asm_loc (tree string, int vol, location_t locus)
emit_insn (body);
}
-/* Return the number of times character C occurs in string S. */
-static int
-n_occurrences (int c, const char *s)
-{
- int n = 0;
- while (*s)
- n += (*s++ == c);
- return n;
-}
-
-/* A subroutine of expand_asm_operands. Check that all operands have
- the same number of alternatives. Return true if so. */
-
-static bool
-check_operand_nalternatives (const vec<const char *> &constraints)
-{
- unsigned len = constraints.length();
- if (len > 0)
- {
- int nalternatives = n_occurrences (',', constraints[0]);
-
- if (nalternatives + 1 > MAX_RECOG_ALTERNATIVES)
- {
- error ("too many alternatives in %<asm%>");
- return false;
- }
-
- for (unsigned i = 1; i < len; ++i)
- if (n_occurrences (',', constraints[i]) != nalternatives)
- {
- error ("operand constraints for %<asm%> differ "
- "in number of alternatives");
- return false;
- }
- }
- return true;
-}
-
/* Check for overlap between registers marked in CLOBBERED_REGS and
anything inappropriate in T. Emit error and return the register
variable definition for error, NULL_TREE for ok. */
@@ -3478,10 +3440,6 @@ expand_asm_stmt (gasm *stmt)
= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
}
- /* ??? Diagnose during gimplification? */
- if (! check_operand_nalternatives (constraints))
- return;
-
/* Count the number of meaningful clobbered registers, ignoring what
we would ignore later. */
auto_vec<rtx> clobber_rvec;
@@ -3555,7 +3513,8 @@ expand_asm_stmt (gasm *stmt)
no point in going further. */
constraint = constraints[i];
if (!parse_output_constraint (&constraint, i, ninputs, noutputs,
- &allows_mem, &allows_reg, &is_inout))
+ &allows_mem, &allows_reg, &is_inout,
+ nullptr))
return;
/* If the output is a hard register, verify it doesn't conflict with
@@ -3633,8 +3592,8 @@ expand_asm_stmt (gasm *stmt)
constraint = constraints[i + noutputs];
if (! parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
- constraints.address (),
- &allows_mem, &allows_reg))
+ constraints.address (), &allows_mem,
+ &allows_reg, nullptr))
return;
if (! allows_reg && allows_mem)
@@ -3664,7 +3623,7 @@ expand_asm_stmt (gasm *stmt)
ok = parse_output_constraint (&constraints[i], i, ninputs,
noutputs, &allows_mem, &allows_reg,
- &is_inout);
+ &is_inout, nullptr);
gcc_assert (ok);
/* If an output operand is not a decl or indirect ref and our constraint
@@ -3769,7 +3728,7 @@ expand_asm_stmt (gasm *stmt)
constraint = constraints[i + noutputs];
ok = parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
constraints.address (),
- &allows_mem, &allows_reg);
+ &allows_mem, &allows_reg, nullptr);
gcc_assert (ok);
/* EXPAND_INITIALIZER will not generate code for valid initializer
diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
index 8e8d855..9f4af63 100644
--- a/gcc/cgraphunit.cc
+++ b/gcc/cgraphunit.cc
@@ -2400,9 +2400,10 @@ symbol_table::compile (void)
if (node->alias
&& lookup_attribute ("weakref", DECL_ATTRIBUTES (node->decl)))
{
- IDENTIFIER_TRANSPARENT_ALIAS
- (DECL_ASSEMBLER_NAME (node->decl)) = 1;
- TREE_CHAIN (DECL_ASSEMBLER_NAME (node->decl))
+ tree id = DECL_ASSEMBLER_NAME (node->decl);
+ gcc_assert (!IDENTIFIER_INTERNAL_P (id));
+ IDENTIFIER_TRANSPARENT_ALIAS (id) = 1;
+ TREE_CHAIN (id)
= (node->alias_target ? node->alias_target
: DECL_ASSEMBLER_NAME (node->get_alias_target ()->decl));
}
diff --git a/gcc/cobol/ChangeLog b/gcc/cobol/ChangeLog
index f594331..b286f5d 100644
--- a/gcc/cobol/ChangeLog
+++ b/gcc/cobol/ChangeLog
@@ -1,3 +1,168 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * util.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * util.cc: Update for renaming of diagnostic_option_id to
+ diagnostics::option_id.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * util.cc: Remove redundant #includes
+
+2025-07-24 Robert Dubner <rdubner@symas.com>
+
+ PR cobol/119231
+ * gcobolspec.cc: (lang_specific_driver): Pass OPT_static through.
+ Handle -static and -static-libgcobol properly.
+
+2025-07-23 Robert Dubner <rdubner@symas.com>
+
+ * genapi.cc (leave_procedure): Adjust location_t for PERFORM.
+ (parser_perform_times): Likewise.
+ (internal_perform_through_times): Likewise.
+ (perform_outofline_before_until): Likewise.
+ (perform_outofline_after_until): Likewise.
+ (perform_outofline_testafter_varying): Likewise.
+ (perform_outofline_before_varying): Likewise.
+
+2025-07-21 Robert Dubner <rdubner@symas.com>
+ James K. Lowden <jklowden@cobolworx.com>
+
+ PR cobol/120402
+ * Make-lang.in: Elminate commented-out scripting.
+ * cbldiag.h (_CBLDIAG_H): Change #if 0 to #if GCOBOL_GETENV
+ (warn_msg): Add printf attributes.
+ (location_dump): Add debugging message.
+ * cdf.y: Improved linemap tracking.
+ * genapi.cc (treeplet_fill_source): const attribute for formal parameter.
+ (insert_nop): Created to consolidate var_decl_nop writes.
+ (build_main_that_calls_something): Move generation to the end of executable.
+ (level_88_helper): Formatting.
+ (parser_call_targets_dump): Formatting.
+ (function_pointer_from_name): const attribute for formal parameter.
+ (parser_initialize_programs): const attribute for formal parameter.
+ (parser_statement_begin): Improved linemap handling.
+ (section_label): Improved linemap handling.
+ (paragraph_label): Improved linemap handling.
+ (pseudo_return_pop): Improved linemap handling.
+ (leave_procedure): Formatting.
+ (parser_enter_section): Improved linemap handling.
+ (parser_enter_paragraph): Improved linemap handling.
+ (parser_perform): Formatting.
+ (parser_leave_file): Move creation of main() to this routine.
+ (parser_enter_program): Move creation of main from here to leave_file.
+ (parser_accept): Formatting. const attribute for formal parameter.
+ (parser_accept_command_line): const attribute for formal parameter.
+ (parser_accept_command_line_count): const attribute for formal parameter.
+ (parser_accept_envar): Likewise.
+ (parser_set_envar): Likewise.
+ (parser_display): Likewise.
+ (get_exhibit_name): Implement EXHIBIT verb.
+ (parser_exhibit): Likewise.
+ (parser_sleep): const attribute for formal parameter.
+ (parser_division): Improved linemap handling.
+ (parser_classify): const attribute for formal parameter.
+ (create_iline_address_pairs): Improved linemap handling.
+ (parser_perform_start): Likewise.
+ (perform_inline_until): Likewise.
+ (perform_inline_testbefore_varying): Likewise.
+ (parser_perform_until): Likewise.
+ (parser_perform_inline_times): Likewise.
+ (parser_intrinsic_subst): const attribute for formal parameter.
+ (parser_file_merge): Formatting.
+ (create_and_call): Improved linemap handling.
+ (mh_identical): const attribute for formal parameter.
+ (mh_numeric_display): const attribute for formal parameter.
+ (mh_little_endian): Likewise.
+ (mh_source_is_group): Likewise.
+ (psa_FldLiteralA): Formatting.
+ * genapi.h (parser_accept): const attribute for formal parameter.
+ (parser_accept_envar): Likewise.
+ (parser_set_envar): Likewise.
+ (parser_accept_command_line): Likewise.
+ (parser_accept_command_line_count): Likewise.
+ (parser_add): Likewise.
+ (parser_classify): Likewise.
+ (parser_sleep): Likewise.
+ (parser_exhibit): Likewise.
+ (parser_display): Likewise.
+ (parser_initialize_programs): Likewise.
+ (parser_intrinsic_subst): Likewise.
+ * gengen.cc (gg_assign): Improved linemap handling.
+ (gg_add_field_to_structure): Likewise.
+ (gg_define_from_declaration): Likewise.
+ (gg_build_relational_expression): Likewise.
+ (gg_goto_label_decl): Likewise.
+ (gg_goto): Likewise.
+ (gg_printf): Likewise.
+ (gg_fprintf): Likewise.
+ (gg_memset): Likewise.
+ (gg_memchr): Likewise.
+ (gg_memcpy): Likewise.
+ (gg_memmove): Likewise.
+ (gg_strcpy): Likewise.
+ (gg_strcmp): Likewise.
+ (gg_strncmp): Likewise.
+ (gg_return): Likewise.
+ (chain_parameter_to_function): Likewise.
+ (gg_define_function): Likewise.
+ (gg_get_function_decl): Likewise.
+ (gg_call_expr): Likewise.
+ (gg_call): Likewise.
+ (gg_call_expr_list): Likewise.
+ (gg_exit): Likewise.
+ (gg_abort): Likewise.
+ (gg_strlen): Likewise.
+ (gg_strdup): Likewise.
+ (gg_malloc): Likewise.
+ (gg_realloc): Likewise.
+ (gg_free): Likewise.
+ (gg_set_current_line_number): Likewise.
+ (gg_get_current_line_number): Likewise.
+ (gg_insert_into_assembler): Likewise.
+ (token_location_override): Likewise.
+ (gg_token_location): Likewise.
+ * gengen.h (location_from_lineno): Likewise.
+ (gg_set_current_line_number): Likewise.
+ (gg_get_current_line_number): Likewise.
+ (gg_token_location): Likewise.
+ (current_token_location): Likewise.
+ (current_location_minus_one): Likewise.
+ (current_location_minus_one_clear): Likewise.
+ (token_location_override): Likewise.
+ * genmath.cc (fast_divide): const attribute for formal parameter.
+ * genutil.cc (get_and_check_refstart_and_reflen): Likewise.
+ (get_data_offset): Likewise.
+ (refer_refmod_length): Likewise.
+ (refer_offset): Likewise.
+ (refer_size): Likewise.
+ (refer_size_dest): Likewise.
+ (refer_size_source): Likewise.
+ (qualified_data_location): Likewise.
+ * genutil.h (refer_offset): Likewise.
+ (refer_size_source): Likewise.
+ (refer_size_dest): Likewise.
+ (qualified_data_location): Likewise.
+ * parse.y: EVALUATE token; Implement EXHIBIT verb;
+ Improved linemap handling.
+ * parse_ante.h (input_file_status_notify): Improved linemap handling.
+ (location_set): Likewise.
+ * scan.l: PICTURE string validation.
+ * scan_ante.h (class picture_t): PICTURE string validation.
+ (validate_picture): Likewise.
+ * symbols.cc (symbol_currency): Revised default currency handling.
+ * symbols.h (symbol_currency): Likewise.
+ * util.cc (location_from_lineno): Improved linemap handling.
+ (current_token_location): Improved linemap handling.
+ (current_location_minus_one): Improved linemap handling.
+ (current_location_minus_one_clear): Improved linemap handling.
+ (gcc_location_set_impl): Improved linemap handling.
+ (warn_msg): Improved linemap handling.
+ * util.h (cobol_lineno): Improved linemap handling.
+
2025-07-15 Jakub Jelinek <jakub@redhat.com>
Jason Merrill <jason@redhat.com>
diff --git a/gcc/cobol/Make-lang.in b/gcc/cobol/Make-lang.in
index 22de3b1..0e2a773 100644
--- a/gcc/cobol/Make-lang.in
+++ b/gcc/cobol/Make-lang.in
@@ -385,12 +385,3 @@ selftest-cobol:
lang_checks += check-cobol
-###
-### Note that the process environment variable CXXFLAGS_FOR_COBOL is applied to
-### gcc/cobol compilations. This is not a configuration-level variable.
-###
-##
-##cobol/%.o: cobol/%.cc
-## @echo $(COMPILE) $(CXXFLAGS_FOR_COBOL) $<
-## $(COMPILE) $(CXXFLAGS_FOR_COBOL) $<
-## $(POSTCOMPILE)
diff --git a/gcc/cobol/cbldiag.h b/gcc/cobol/cbldiag.h
index 49dc44b..39f1369 100644
--- a/gcc/cobol/cbldiag.h
+++ b/gcc/cobol/cbldiag.h
@@ -33,7 +33,7 @@
#else
#define _CBLDIAG_H
-#if 0
+#if GCOBOL_GETENV
#define gcobol_getenv(x) getenv(x)
#else
#define gcobol_getenv(x) ((char *)nullptr)
@@ -78,10 +78,15 @@ struct YDFLTYPE
#endif
+// Diagnostic format specifiers are documented in gcc/pretty-print.cc
// an error at a location, called from the parser for semantic errors
void error_msg( const YYLTYPE& loc, const char gmsgid[], ... )
ATTRIBUTE_GCOBOL_DIAG(2, 3);
+bool
+warn_msg( const YYLTYPE& loc, const char gmsgid[], ... )
+ ATTRIBUTE_GCOBOL_DIAG(2, 3);
+
// an error that uses token_location, not yylloc
void error_msg_direct( const char gmsgid[], ... )
ATTRIBUTE_GCOBOL_DIAG(1, 2);
@@ -116,11 +121,14 @@ template <typename LOC>
static void
location_dump( const char func[], int line, const char tag[], const LOC& loc) {
extern int yy_flex_debug; // cppcheck-suppress shadowVariable
- if( yy_flex_debug && gcobol_getenv("update_location") ) {
- fprintf(stderr, "%s:%d: %s location (%d,%d) to (%d,%d)\n",
- func, line, tag,
- loc.first_line, loc.first_column, loc.last_line, loc.last_column);
- gcc_location_dump();
+ if( yy_flex_debug ) {
+ const char *detail = gcobol_getenv("update_location");
+ if( detail ) {
+ fprintf(stderr, "%s:%d: %s location (%d,%d) to (%d,%d)\n",
+ func, line, tag,
+ loc.first_line, loc.first_column, loc.last_line, loc.last_column);
+ if( *detail == '2' ) gcc_location_dump();
+ }
}
}
#endif // defined(yy_flex_debug)
diff --git a/gcc/cobol/cdf.y b/gcc/cobol/cdf.y
index 840eb50..53fea5d 100644
--- a/gcc/cobol/cdf.y
+++ b/gcc/cobol/cdf.y
@@ -95,7 +95,7 @@ void input_file_status_notify();
} \
location_dump("cdf.c", __LINE__, "current", (Current)); \
input_file_status_notify(); \
- gcc_location_set( location_set(Current) ); \
+ location_set(Current); \
} while (0)
%}
diff --git a/gcc/cobol/gcobolspec.cc b/gcc/cobol/gcobolspec.cc
index 038aaec..1f1b463 100644
--- a/gcc/cobol/gcobolspec.cc
+++ b/gcc/cobol/gcobolspec.cc
@@ -470,7 +470,10 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
//// break;
////#endif
case OPT_static:
+#if defined (HAVE_LD_STATIC_DYNAMIC)
+ append_arg(decoded_options[i]);
static_in_general = true;
+#endif
break;
default:
@@ -498,17 +501,23 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
need_libgcobol = false;
}
+ if( static_in_general )
+ {
+ // These two options interfere with each other.
+ static_libgcobol = false;
+ }
+
if( need_libgcobol )
{
add_arg_lib(COBOL_LIBRARY, static_libgcobol);
}
if( need_libdl )
{
- add_arg_lib(DL_LIBRARY, static_in_general);
+ add_arg_lib(DL_LIBRARY, false);
}
if( need_libstdc )
{
- add_arg_lib(STDCPP_LIBRARY, static_in_general);
+ add_arg_lib(STDCPP_LIBRARY, false);
}
if( prior_main )
diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index a293912..666802e 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -118,7 +118,7 @@ typedef struct TREEPLET
static
void
-treeplet_fill_source(TREEPLET &treeplet, cbl_refer_t &refer)
+treeplet_fill_source(TREEPLET &treeplet, const cbl_refer_t &refer)
{
treeplet.pfield = gg_get_address_of(refer.field->var_decl_node);
treeplet.offset = refer_offset(refer);
@@ -233,6 +233,13 @@ trace1_init()
}
}
+static
+void
+insert_nop(int n)
+ {
+ gg_assign(var_decl_nop, build_int_cst_type(INT, n));
+ }
+
static void
create_cblc_string_variable(const char *var_name, const char *var_contents)
{
@@ -270,8 +277,6 @@ build_main_that_calls_something(const char *something)
SHOW_PARSE_END
}
- gg_set_current_line_number(DEFAULT_LINE_NUMBER);
-
tree function_decl = gg_define_function( INT,
"main",
"main",
@@ -325,7 +330,6 @@ build_main_that_calls_something(const char *something)
argc,
argv,
NULL_TREE)));
- strncpy(ach_cobol_entry_point, psz, sizeof(ach_cobol_entry_point)-1);
free(psz);
gg_finalize_function();
}
@@ -369,7 +373,7 @@ level_88_helper(size_t parent_capacity,
gcc_assert(retval);
char *builder = static_cast<char *>(xmalloc(parent_capacity + 64));
gcc_assert(builder);
-
+
size_t nbuild = 0;
cbl_figconst_t figconst = cbl_figconst_of( elem.name());
@@ -788,7 +792,7 @@ parser_call_targets_dump()
}
fprintf(stderr, " ]\n");
}
-#endif
+#endif
}
size_t
@@ -816,8 +820,8 @@ parser_call_target_update( size_t caller,
}
static tree
-function_pointer_from_name(cbl_refer_t &name,
- tree function_return_type)
+function_pointer_from_name(const cbl_refer_t &name,
+ tree function_return_type)
{
Analyze();
@@ -893,7 +897,8 @@ function_pointer_from_name(cbl_refer_t &name,
}
void
-parser_initialize_programs(size_t nprogs, struct cbl_refer_t *progs)
+parser_initialize_programs( size_t nprogs,
+ const struct cbl_refer_t *progs)
{
Analyze();
SHOW_PARSE
@@ -1178,14 +1183,6 @@ parser_statement_begin( const cbl_name_t statement_name,
exception_processing = file_ops.find(statement_name) != file_ops.end();
}
- if( gg_get_current_line_number() == DEFAULT_LINE_NUMBER )
- {
- // This code is intended to prevert GDB anomalies when the first line of a
- // program is a PERFORM <proc> ... TEST AFTER ... UNTIL ...
- gg_set_current_line_number(CURRENT_LINE_NUMBER-1);
- gg_assign(var_decl_nop, build_int_cst_type(INT, 106));
- }
-
// At this point, if any exception is enabled, we store the location stuff.
// Each file I-O routine calls store_location_stuff explicitly, because
// those exceptions can't be defeated.
@@ -1195,8 +1192,6 @@ parser_statement_begin( const cbl_name_t statement_name,
store_location_stuff(statement_name);
}
- gg_set_current_line_number(CURRENT_LINE_NUMBER);
-
if( exception_processing )
{
set_exception_environment(ecs, dcls);
@@ -2666,8 +2661,6 @@ section_label(struct cbl_proc_t *procedure)
// With nested programs, you can have multiple program/section pairs with the
// the same names; we use a deconflictor to avoid collisions
- gg_set_current_line_number(CURRENT_LINE_NUMBER);
-
size_t deconflictor = symbol_label_id(procedure->label);
cbl_label_t *label = procedure->label;
@@ -2692,7 +2685,7 @@ section_label(struct cbl_proc_t *procedure)
}
assembler_label(psz2);
free(psz2);
- gg_assign(var_decl_nop, build_int_cst_type(INT, 108));
+ insert_nop(108);
}
static void
@@ -2707,8 +2700,6 @@ paragraph_label(struct cbl_proc_t *procedure)
// are not referenced by the program. We provide a deconflictor to
// separate such labels.
- gg_set_current_line_number(CURRENT_LINE_NUMBER);
-
cbl_label_t *paragraph = procedure->label;
cbl_label_t *section = nullptr;
@@ -2730,6 +2721,9 @@ paragraph_label(struct cbl_proc_t *procedure)
section_name ? section_name: "(null)" ,
current_function->our_unmangled_name ? current_function->our_unmangled_name: "" ,
(fmt_size_t)deconflictor );
+
+ // (0) is wrong, so back up one
+
gg_insert_into_assembler(psz1);
SHOW_PARSE
@@ -2746,7 +2740,25 @@ paragraph_label(struct cbl_proc_t *procedure)
combined_name(procedure->label));
assembler_label(psz2);
free(psz2);
- gg_assign(var_decl_nop, build_int_cst_type(INT, 109));
+
+ // We are inserting a NOP after having created a label for the procedure.
+ // This means that when using GDC_COBOL to step into a procedure, the
+ // execution will stop there and show "123 para-name." at the stopped point.
+ //
+ // Note that because there is no user-specified executable code at that point
+ // the user can't set a working breakpoint with "break 123". But because
+ // GDB will pick up the psz2 text and set a breakpoint there (which is the
+ // location of the NOP) "break para-name" will actually stop and show line
+ // 123.
+ //
+ // This really only makes sense when you look at the assembly language. Keep
+ // in mind as you read it that issuing a "break 123" causes GDB to set a
+ // breakpoint at the first executable machine language code following the
+ // first ".loc 123" directive.
+ //
+ // Yes, trying to understand this causes headaches for many people who read
+ // this. Take an aspirin.
+ insert_nop(109);
}
static void
@@ -2790,6 +2802,7 @@ pseudo_return_pop(cbl_proc_t *procedure)
NULL_TREE);
}
+ token_location_override(current_location_minus_one());
IF( var_decl_exit_address, eq_op, procedure->exit.addr )
{
TRACE1
@@ -2799,11 +2812,13 @@ pseudo_return_pop(cbl_proc_t *procedure)
// The top of the stack is us!
// Pick up the return address from the pseudo_return stack:
+ token_location_override(current_location_minus_one());
gg_assign(current_function->void_star_temp,
gg_call_expr( VOID_P,
"__gg__pseudo_return_pop",
NULL_TREE));
// And do the return:
+ token_location_override(current_location_minus_one());
gg_goto(current_function->void_star_temp);
}
ELSE
@@ -2837,11 +2852,13 @@ leave_procedure(struct cbl_proc_t *procedure, bool /*section*/)
// procedure->bottom.label);
// Procedure can be null, for example at the beginning of a
// new program, or after somebody else has cleared it out.
+
gg_append_statement(procedure->exit.label);
char *psz;
psz = xasprintf("_procret." HOST_SIZE_T_PRINT_DEC ":",
(fmt_size_t)symbol_label_id(procedure->label));
+ token_location_override(current_location_minus_one());
gg_insert_into_assembler(psz);
free(psz);
pseudo_return_pop(procedure);
@@ -3012,6 +3029,8 @@ parser_enter_section(cbl_label_t *label)
{
SHOW_PARSE_HEADER
SHOW_PARSE_LABEL(" ", label)
+ SHOW_PARSE_INDENT
+ linemap_dump_location( line_table, current_token_location(), stderr );
SHOW_PARSE_END
}
@@ -3019,8 +3038,7 @@ parser_enter_section(cbl_label_t *label)
// This NOP is needed to give GDB a line number for the entry point of
// paragraphs
- gg_set_current_line_number(CURRENT_LINE_NUMBER);
- gg_assign(var_decl_nop, build_int_cst_type(INT, 101));
+ insert_nop(101);
struct cbl_proc_t *procedure = find_procedure(label);
gg_append_statement(procedure->top.label);
@@ -3047,6 +3065,8 @@ parser_enter_paragraph(cbl_label_t *label)
{
SHOW_PARSE_HEADER
SHOW_PARSE_LABEL(" ", label)
+ SHOW_PARSE_INDENT
+ linemap_dump_location( line_table, current_token_location(), stderr );
SHOW_PARSE_END
}
@@ -3272,7 +3292,7 @@ parser_perform(cbl_label_t *label, bool suppress_nexting)
SHOW_PARSE_TEXT(ach)
if( label )
{
- sprintf(ach,
+ sprintf(ach,
" label->proc is %p",
static_cast<void*>(label->structs.proc));
}
@@ -3426,6 +3446,7 @@ parser_perform_times( cbl_label_t *proc_1, cbl_refer_t count )
sprintf(ach,
"_procretb." HOST_SIZE_T_PRINT_DEC ":",
(fmt_size_t)our_pseudo_label);
+ token_location_override(current_location_minus_one());
gg_insert_into_assembler(ach);
}
@@ -3579,6 +3600,7 @@ internal_perform_through_times( cbl_label_t *proc_1,
sprintf(ach,
"_procretb." HOST_SIZE_T_PRINT_DEC ":",
(fmt_size_t)our_pseudo_label);
+ token_location_override(current_location_minus_one());
gg_insert_into_assembler( ach );
}
@@ -3770,6 +3792,22 @@ parser_leave_file()
{
// We are leaving the top-level file, which means this compilation is
// done, done, done.
+
+ // There is, however, one thing left to do. If the command line says
+ // that this module needs a main entry point, then this is where
+ // we create a main() function. We build it at the end, so that all of
+ // the .loc directives associated with it appear at the end of the
+ // source code. We used to create the main() entry point at the beginning,
+ // but that created confusion for GDB when trying to debug the generated
+ // executable.
+ if( main_entry_point )
+ {
+ next_program_is_main = false;
+ build_main_that_calls_something(main_entry_point);
+ free(main_entry_point);
+ main_entry_point = NULL;
+ }
+
gg_leaving_the_source_code_file();
}
}
@@ -3879,17 +3917,8 @@ parser_enter_program( const char *funcname_,
// The first thing we have to do is mangle this name. This is safe even
// though the end result will be mangled again, because the mangler doesn't
// change a mangled name.
-
- char *mangled_name;
-
- if( current_call_convention() == cbl_call_cobol_e )
- {
- mangled_name = cobol_name_mangler(funcname_);
- }
- else
- {
- mangled_name = xstrdup(funcname_);
- }
+
+ char *mangled_name = cobol_name_mangler(funcname_);
size_t parent_index = current_program_index();
char *funcname;
@@ -3917,28 +3946,25 @@ parser_enter_program( const char *funcname_,
if( !is_function && !parent_index )
{
- // This is a top_level program, and not a function
+ // This is a top_level program-id, and not a function
if( next_program_is_main )
{
+ // This is the first top-level program-id.
next_program_is_main = false;
- if(main_entry_point)
- {
- build_main_that_calls_something(main_entry_point);
- free(main_entry_point);
- main_entry_point = NULL;
- }
- else
+ if( !main_entry_point )
{
- build_main_that_calls_something(funcname);
+ // Because no explicit main_entry_point was specified, this program-id,
+ // the first in the file, becomes the target of the main() function
+ // that will be created at parser_leave_file time.
+ main_entry_point = xstrdup(funcname);
+
+ char *psz = cobol_name_mangler(main_entry_point);
+ strncpy(ach_cobol_entry_point, psz, sizeof(ach_cobol_entry_point)-1);
+ free(psz);
}
}
}
- // Call this after build_main_that_calls_something, because it manipulates
- // the current line number to DEFAULT_LINE_NUMBER. We have to manipulate it
- // back afterward.
- gg_set_current_line_number(CURRENT_LINE_NUMBER);
-
if( strcmp(funcname_, "main") == 0 && this_module_has_main )
{
// setting 'retval' to 1 let's the caller know that we are being told
@@ -4361,7 +4387,7 @@ psa_FldBlob(struct cbl_field_t *var )
}
void
-parser_accept(struct cbl_refer_t tgt,
+parser_accept(const struct cbl_refer_t &tgt,
special_name_t special_e,
cbl_label_t *error,
cbl_label_t *not_error )
@@ -4464,7 +4490,7 @@ parser_accept(struct cbl_refer_t tgt,
case ARG_VALUE_e:
// We are fetching the variable whose index was established by a prior
- // DISPLAY UPON ARGUMENT-NUMBER. After the fetch, the value will be
+ // DISPLAY UPON ARGUMENT-NUMBER. After the fetch, the value will be
// incremented by one.
function_to_call = "__gg__accept_arg_value";
break;
@@ -4600,8 +4626,8 @@ parser_accept_exception_end( cbl_label_t *accept_label )
}
void
-parser_accept_command_line( cbl_refer_t tgt,
- cbl_refer_t source,
+parser_accept_command_line( const cbl_refer_t &tgt,
+ const cbl_refer_t &source,
cbl_label_t *error,
cbl_label_t *not_error )
{
@@ -4743,7 +4769,7 @@ parser_accept_command_line( cbl_refer_t tgt,
}
void
-parser_accept_command_line_count( cbl_refer_t tgt )
+parser_accept_command_line_count( const cbl_refer_t &tgt )
{
Analyze();
SHOW_PARSE
@@ -4765,10 +4791,10 @@ parser_accept_command_line_count( cbl_refer_t tgt )
}
void
-parser_accept_envar(struct cbl_refer_t tgt,
- struct cbl_refer_t envar,
- cbl_label_t *error,
- cbl_label_t *not_error )
+parser_accept_envar(const struct cbl_refer_t &tgt,
+ const struct cbl_refer_t &envar,
+ cbl_label_t *error,
+ cbl_label_t *not_error )
{
Analyze();
@@ -4851,7 +4877,8 @@ parser_accept_envar(struct cbl_refer_t tgt,
}
void
-parser_set_envar( struct cbl_refer_t name, struct cbl_refer_t value )
+parser_set_envar( const struct cbl_refer_t &name,
+ const struct cbl_refer_t &value )
{
Analyze();
SHOW_PARSE
@@ -5392,9 +5419,9 @@ parser_display_field(cbl_field_t *field)
void
parser_display( const struct cbl_special_name_t *upon,
- std::vector<cbl_refer_t> refs,
- bool advance,
- const cbl_label_t *not_error,
+ const std::vector<cbl_refer_t> &refs,
+ bool advance,
+ const cbl_label_t *not_error,
const cbl_label_t *error )
{
const size_t n = refs.size();
@@ -5569,6 +5596,106 @@ parser_display( const struct cbl_special_name_t *upon,
cursor_at_sol = advance;
}
+static
+bool // Returns false for literals; true for named variables
+get_exhibit_name(tree file_descriptor, const cbl_refer_t &arg)
+ {
+ bool retval;
+ if( is_literal(arg.field) )
+ {
+ // If something is a literal, we just display the literal value
+ parser_display_internal(file_descriptor,
+ arg,
+ DISPLAY_NO_ADVANCE);
+ retval = false;
+ }
+ else
+ {
+ // It's not a literal, so we show its name, and the names or literal
+ // values) of any qualifier subscripts or refmods
+ gg_write( file_descriptor,
+ gg_string_literal(arg.field->name),
+ build_int_cst_type(SIZE_T, strlen(arg.field->name)) );
+
+ if( arg.subscripts.size() )
+ {
+ // This refer has subscripts:
+ gg_write( file_descriptor,
+ gg_string_literal("("),
+ integer_one_node );
+ for(size_t i=0; i<arg.subscripts.size(); i++)
+ {
+ if( i > 0 )
+ {
+ gg_write( file_descriptor,
+ gg_string_literal(","),
+ integer_one_node );
+ }
+ get_exhibit_name(file_descriptor, arg.subscripts[i]);
+ }
+ gg_write( file_descriptor,
+ gg_string_literal(")"),
+ integer_one_node );
+ }
+ if( arg.refmod.from || arg.refmod.len )
+ {
+ gg_write( file_descriptor,
+ gg_string_literal("("),
+ integer_one_node );
+ if( arg.refmod.from )
+ {
+ get_exhibit_name(file_descriptor, *(arg.refmod.from));
+ }
+ gg_write( file_descriptor,
+ gg_string_literal(":"),
+ integer_one_node );
+ if( arg.refmod.len )
+ {
+ get_exhibit_name(file_descriptor, *(arg.refmod.len));
+ }
+ gg_write( file_descriptor,
+ gg_string_literal(")"),
+ integer_one_node );
+ }
+ retval = true;
+ }
+ return retval;
+ }
+
+void
+parser_exhibit( bool /*changed*/, bool /*named*/,
+ const std::vector<cbl_refer_t> &args )
+ {
+ tree file_descriptor = gg_define_int();
+ gg_assign(file_descriptor, integer_one_node); // stdout is file descriptor 1.
+
+ for(size_t i=0; i<args.size(); i++)
+ {
+ CHECK_FIELD(args[i].field);
+ if(i > 0)
+ {
+ // When there more than one argument, the second through Nth get a space
+ // in front of them.
+ gg_write( file_descriptor,
+ gg_string_literal(" "),
+ integer_one_node);
+ }
+ if( get_exhibit_name(file_descriptor, args[i]) )
+ {
+ gg_write( file_descriptor,
+ gg_string_literal("="),
+ integer_one_node);
+ parser_display_internal(file_descriptor,
+ args[i],
+ DISPLAY_NO_ADVANCE);
+ }
+ }
+ gg_write( file_descriptor,
+ gg_string_literal("\n"),
+ integer_one_node);
+ cursor_at_sol = true;
+ }
+
static tree
get_literalN_value(cbl_field_t *var)
{
@@ -6344,7 +6471,7 @@ is_valuable( cbl_field_type_t type ) {
return false;
}
-void parser_sleep(cbl_refer_t seconds)
+void parser_sleep(const cbl_refer_t &seconds)
{
if( seconds.field )
{
@@ -6364,7 +6491,7 @@ void parser_sleep(cbl_refer_t seconds)
// This is a naked place-holding CONTINUE. Generate some do-nothing
// code that will stick some .LOC information into the assembly language,
// so that GDB-COBOL can display the CONTINUE statement.
- gg_assign(var_decl_nop, build_int_cst_type(INT, 103));
+ insert_nop(103);
}
}
@@ -6935,8 +7062,6 @@ parser_division(cbl_division_t division,
SHOW_PARSE_END
}
- gg_set_current_line_number(CURRENT_LINE_NUMBER);
-
if( division == data_div_e )
{
Analyze();
@@ -7394,6 +7519,11 @@ parser_division(cbl_division_t division,
ENDIF
}
ENDIF
+ // The first token_location that the parser establishes is caused by the
+ // parser scanning all of the lines in the source code. This messes up the
+ // logic for backing up one line, which is needed to correctly step through
+ // COBOL code with GDB-COBOL. So, we clear it here.
+ current_location_minus_one_clear();
}
}
@@ -8002,7 +8132,7 @@ parser_setop( struct cbl_field_t *tgt,
void
parser_classify( cbl_field_t *tgt,
- cbl_refer_t candidate,
+ const cbl_refer_t &candidate,
enum classify_t type )
{
Analyze();
@@ -8099,14 +8229,6 @@ create_iline_address_pairs(struct cbl_perform_tgt_t *tgt)
gg_create_goto_pair(&tgt->addresses.setup.go_to,
&tgt->addresses.setup.label);
-
- // Even in -O0 compilations, the compiler does some elementary optimizations
- // around JMP instructions. We have the SETUP code for in-line performats
- // in an island at the end of the loop code. With this intervention, NEXTing
- // through the code shows you the final statement of the loop before the
- // loop actually starts.
-
- tgt->addresses.line_number_of_setup_code = gg_get_current_line_number();
}
void
@@ -8169,7 +8291,7 @@ parser_perform_start( struct cbl_perform_tgt_t *tgt )
// Give GDB-COBOL something to chew on when NEXTing. This instruction will
// get the line number of the PERFORM N TIMES code.
gg_append_statement(tgt->addresses.top.label);
- gg_assign(var_decl_nop, build_int_cst_type(INT, 104));
+ insert_nop(104);
}
void
@@ -8321,6 +8443,7 @@ perform_outofline_before_until(struct cbl_perform_tgt_t *tgt,
sprintf(ach,
"_procretb." HOST_SIZE_T_PRINT_DEC ":",
(fmt_size_t)our_pseudo_label);
+ token_location_override(current_location_minus_one());
gg_insert_into_assembler( ach );
}
@@ -8384,6 +8507,7 @@ perform_outofline_after_until(struct cbl_perform_tgt_t *tgt,
sprintf(ach,
"_procretb." HOST_SIZE_T_PRINT_DEC ":",
(fmt_size_t)our_pseudo_label);
+ token_location_override(current_location_minus_one());
gg_insert_into_assembler( ach );
}
@@ -8504,6 +8628,7 @@ perform_outofline_testafter_varying(struct cbl_perform_tgt_t *tgt,
sprintf(ach,
"_procretb." HOST_SIZE_T_PRINT_DEC ":",
(fmt_size_t)our_pseudo_label);
+ token_location_override(current_location_minus_one());
gg_insert_into_assembler( ach );
}
@@ -8647,6 +8772,7 @@ perform_outofline_before_varying( struct cbl_perform_tgt_t *tgt,
sprintf(ach,
"_procretb." HOST_SIZE_T_PRINT_DEC ":",
(fmt_size_t)our_pseudo_label);
+ token_location_override(current_location_minus_one());
gg_insert_into_assembler( ach );
}
@@ -8726,8 +8852,6 @@ perform_inline_until( struct cbl_perform_tgt_t *tgt,
GOTO TOP
EXIT:
*/
- gg_set_current_line_number(cobol_location().last_line);
-
gg_append_statement(tgt->addresses.test.label);
// Go to where the conditional is recalculated....
@@ -8842,8 +8966,6 @@ perform_inline_testbefore_varying( struct cbl_perform_tgt_t *tgt,
parser_move(varys[i].varying, varys[i].from);
}
- gg_set_current_line_number(cobol_location().last_line);
-
// Lay down the testing cycle:
for(size_t i=0; i<N; i++)
{
@@ -9165,9 +9287,6 @@ parser_perform_until( struct cbl_perform_tgt_t *tgt,
SHOW_PARSE_END
}
- gg_set_current_line_number(cobol_location().last_line);
- gg_assign(var_decl_nop, build_int_cst_type(INT, 105));
-
if( tgt->from()->type != LblLoop )
{
perform_outofline( tgt, test_before, N, varys);
@@ -9234,10 +9353,6 @@ parser_perform_inline_times(struct cbl_perform_tgt_t *tgt,
gg_append_statement( tgt->addresses.testA.label );
gg_append_statement( tgt->addresses.test.label );
- // AT this point, we want to set the line_number to the location of the
- // END-PERFORM statement.
- gg_set_current_line_number(cobol_location().last_line);
-
gg_decrement(counter);
// Do the test:
IF( counter, gt_op, gg_cast(LONG, integer_zero_node) )
@@ -9268,8 +9383,6 @@ parser_perform_inline_times(struct cbl_perform_tgt_t *tgt,
SHOW_PARSE_END
}
- int stash = gg_get_current_line_number();
- gg_set_current_line_number(tgt->addresses.line_number_of_setup_code);
gg_append_statement( tgt->addresses.setup.label );
// Get the count:
@@ -9300,8 +9413,6 @@ parser_perform_inline_times(struct cbl_perform_tgt_t *tgt,
gg_append_statement( tgt->addresses.exit.go_to );
ENDIF
- gg_set_current_line_number(stash);
-
SHOW_PARSE
{
SHOW_PARSE_INDENT
@@ -10740,7 +10851,7 @@ parser_intrinsic_numval_c( cbl_field_t *f,
void
parser_intrinsic_subst( cbl_field_t *f,
- cbl_refer_t& ref1,
+ const cbl_refer_t& ref1,
size_t argc,
cbl_substitute_t * argv )
{
@@ -12317,7 +12428,7 @@ parser_file_merge( cbl_file_t *workfile,
const cbl_enabled_exceptions_t&
enabled_exceptions( cdf_enabled_exceptions() );
-
+
for(size_t i=0; i<ninputs; i++)
{
if( process_this_exception(ec_sort_merge_file_open_e) )
@@ -13016,7 +13127,7 @@ create_and_call(size_t narg,
// Fetch the FUNCTION_DECL for that FUNCTION_TYPE
tree function_decl = gg_build_fn_decl(funcname, fndecl_type);
set_call_convention(function_decl, current_call_convention());
-
+
// Take the address of the function decl:
tree address_of_function = gg_get_address_of(function_decl);
@@ -13028,7 +13139,7 @@ create_and_call(size_t narg,
parser_call_target( funcname, assigment );
// Create the call_expr from that address
- call_expr = build_call_array_loc( location_from_lineno(),
+ call_expr = build_call_array_loc( gg_token_location(),
returned_value_type,
address_of_function,
narg,
@@ -14140,9 +14251,9 @@ conditional_abs(tree source, const cbl_field_t *field)
}
static bool
-mh_identical(cbl_refer_t &destref,
- const cbl_refer_t &sourceref,
- const TREEPLET &tsource)
+mh_identical(const cbl_refer_t &destref,
+ const cbl_refer_t &sourceref,
+ const TREEPLET &tsource)
{
// Check to see if the two variables are identical types, thus allowing
// for a simple byte-for-byte copy of the data areas:
@@ -14733,10 +14844,10 @@ picky_memcpy(tree &dest_p, const tree &source_p, size_t length)
}
static bool
-mh_numeric_display( cbl_refer_t &destref,
- const cbl_refer_t &sourceref,
- const TREEPLET &tsource,
- tree size_error)
+mh_numeric_display( const cbl_refer_t &destref,
+ const cbl_refer_t &sourceref,
+ const TREEPLET &tsource,
+ tree size_error)
{
bool moved = false;
@@ -15222,11 +15333,11 @@ mh_numeric_display( cbl_refer_t &destref,
}
static bool
-mh_little_endian( cbl_refer_t &destref,
- const cbl_refer_t &sourceref,
- const TREEPLET &tsource,
- bool check_for_error,
- tree size_error)
+mh_little_endian( const cbl_refer_t &destref,
+ const cbl_refer_t &sourceref,
+ const TREEPLET &tsource,
+ bool check_for_error,
+ tree size_error)
{
bool moved = false;
@@ -15294,9 +15405,9 @@ mh_little_endian( cbl_refer_t &destref,
}
static bool
-mh_source_is_group( cbl_refer_t &destref,
- const cbl_refer_t &sourceref,
- const TREEPLET &tsrc)
+mh_source_is_group( const cbl_refer_t &destref,
+ const cbl_refer_t &sourceref,
+ const TREEPLET &tsrc)
{
bool retval = false;
if( sourceref.field->type == FldGroup && !(destref.field->attr & rjust_e) )
@@ -16640,7 +16751,7 @@ psa_FldLiteralA(struct cbl_field_t *field )
vs_file_static);
}
else
-#endif
+#endif
{
// We have not seen that string before
static int nvar = 0;
diff --git a/gcc/cobol/genapi.h b/gcc/cobol/genapi.h
index c2219a7..b41b906 100644
--- a/gcc/cobol/genapi.h
+++ b/gcc/cobol/genapi.h
@@ -52,20 +52,26 @@ void parser_division( cbl_division_t division,
void parser_enter_program(const char *funcname, bool is_function, int *retval);
void parser_leave_program();
-void parser_accept( cbl_refer_t refer, special_name_t special_e,
- cbl_label_t *error, cbl_label_t *not_error );
+void parser_accept( const cbl_refer_t &refer,
+ special_name_t special_e,
+ cbl_label_t *error,
+ cbl_label_t *not_error );
void parser_accept_exception( cbl_label_t *name );
void parser_accept_exception_end( cbl_label_t *name );
void parser_accept_under_discussion(struct cbl_refer_t tgt, special_name_t special,
cbl_label_t *error, cbl_label_t *not_error );
-void parser_accept_envar( cbl_refer_t refer, cbl_refer_t envar,
- cbl_label_t *error, cbl_label_t *not_error );
-void parser_set_envar( cbl_refer_t envar, cbl_refer_t refer );
-
-void parser_accept_command_line( cbl_refer_t tgt, cbl_refer_t src,
- cbl_label_t *error, cbl_label_t *not_error );
-void parser_accept_command_line_count( cbl_refer_t tgt );
+void parser_accept_envar( const cbl_refer_t &refer,
+ const cbl_refer_t &envar,
+ cbl_label_t *error,
+ cbl_label_t *not_error );
+void parser_set_envar( const cbl_refer_t &envar, const cbl_refer_t &refer );
+
+void parser_accept_command_line(const cbl_refer_t &tgt,
+ const cbl_refer_t &src,
+ cbl_label_t *error,
+ cbl_label_t *not_error );
+void parser_accept_command_line_count( const cbl_refer_t &tgt );
void parser_accept_date_yymmdd( cbl_field_t *tgt );
void parser_accept_date_yyyymmdd( cbl_field_t *tgt );
@@ -89,8 +95,7 @@ parser_add( size_t nC, cbl_num_result_t *C,
size_t nA, cbl_refer_t *A,
cbl_arith_format_t format,
cbl_label_t *error,
- cbl_label_t *not_error,
- void *compute_error = NULL); // This has to be cast to a tree pointer to int
+ cbl_label_t *not_error, void *compute_error = NULL); // This has to be cast to a tree pointer to int
void parser_arith_error( cbl_label_t *name );
void parser_arith_error_end( cbl_label_t *name );
@@ -177,7 +182,8 @@ parser_bitwise_op(struct cbl_field_t *tgt,
void
parser_classify( struct cbl_field_t *tgt,
- struct cbl_refer_t srca, enum classify_t type );
+ const struct cbl_refer_t &srca,
+ enum classify_t type );
void
parser_op( struct cbl_refer_t cref,
@@ -256,7 +262,7 @@ parser_program_hierarchy( const struct cbl_prog_hier_t& hier );
void
parser_end_program(const char *name=NULL);
-void parser_sleep(cbl_refer_t seconds);
+void parser_sleep(const cbl_refer_t &seconds);
void parser_exit( const cbl_refer_t& refer, ec_type_t = ec_none_e );
void parser_exit_section(void);
@@ -265,9 +271,12 @@ void parser_exit_perform( struct cbl_perform_tgt_t *tgt, bool cycle );
void parser_exit_program(void); // exits back to COBOL only, else continue
void
+parser_exhibit( bool changed, bool named,
+ const std::vector<cbl_refer_t> &args );
+void
parser_display( const struct cbl_special_name_t *upon,
- std::vector<cbl_refer_t> args,
- bool advance = DISPLAY_ADVANCE,
+ const std::vector<cbl_refer_t> &args,
+ bool advance = DISPLAY_ADVANCE,
const cbl_label_t *not_error = nullptr,
const cbl_label_t *compute_error = nullptr );
@@ -305,7 +314,7 @@ void
parser_initialize(const cbl_refer_t& refer, bool like_parser_symbol_add=false);
void
-parser_initialize_programs(size_t nprog, struct cbl_refer_t *progs);
+parser_initialize_programs(size_t nprog, const struct cbl_refer_t *progs);
void
parser_label_label( struct cbl_label_t *label );
@@ -452,7 +461,7 @@ parser_intrinsic_numval_c( cbl_field_t *f,
void
parser_intrinsic_subst( cbl_field_t *f,
- cbl_refer_t& ref1,
+ const cbl_refer_t& ref1,
size_t argc,
cbl_substitute_t * argv );
diff --git a/gcc/cobol/gengen.cc b/gcc/cobol/gengen.cc
index 7395350..3ad3344 100644
--- a/gcc/cobol/gengen.cc
+++ b/gcc/cobol/gengen.cc
@@ -107,8 +107,6 @@
// Don't like it? Cry me a river.
static const int ARG_LIMIT = 512;
-static int sv_current_line_number;
-
// These are globally useful constants
tree char_nodes[256];
@@ -452,7 +450,7 @@ gg_assign(tree dest, const tree source)
if( okay )
{
- stmt = build2_loc(location_from_lineno(),
+ stmt = build2_loc(gg_token_location(),
MODIFY_EXPR,
TREE_TYPE(dest),
dest,
@@ -616,7 +614,7 @@ gg_add_field_to_structure(const tree type_of_field, const char *name_of_field, t
tree id_of_field = get_identifier (name_of_field);
// Create the new field:
- tree new_field_decl = build_decl( location_from_lineno(),
+ tree new_field_decl = build_decl( gg_token_location(),
FIELD_DECL,
id_of_field,
type_of_field);
@@ -1043,7 +1041,7 @@ gg_define_from_declaration(tree var_decl)
{
// Having made sure the chain of variable declarations is nicely started,
// it's time to actually define the storage with a decl_expression:
- tree stmt = build1_loc (location_from_lineno(),
+ tree stmt = build1_loc (gg_token_location(),
DECL_EXPR,
TREE_TYPE(var_decl),
var_decl);
@@ -1774,7 +1772,7 @@ gg_build_relational_expression(tree operand_a,
compare = LE_EXPR;
break;
}
- tree relational_expression = build2_loc(location_from_lineno(),
+ tree relational_expression = build2_loc(gg_token_location(),
compare,
boolean_type_node,
operand_a,
@@ -1891,7 +1889,7 @@ gg_create_goto_pair(tree *goto_expr,
void
gg_goto_label_decl(tree label_decl)
{
- tree goto_expr = build1_loc( location_from_lineno(),
+ tree goto_expr = build1_loc( gg_token_location(),
GOTO_EXPR,
void_type_node,
label_decl);
@@ -1938,7 +1936,7 @@ gg_create_goto_pair(tree *goto_expr, tree *label_expr, const char *name)
void
gg_goto(tree var_decl_pointer)
{
- tree go_to = build1_loc(location_from_lineno(),
+ tree go_to = build1_loc(gg_token_location(),
GOTO_EXPR,
void_type_node,
var_decl_pointer);
@@ -2186,7 +2184,7 @@ gg_printf(const char *format_string, ...)
function = gg_get_function_address(INT, "__gg__fprintf_stderr");
}
- tree stmt = build_call_array_loc (location_from_lineno(),
+ tree stmt = build_call_array_loc (gg_token_location(),
INT,
function,
nargs,
@@ -2233,7 +2231,7 @@ gg_fprintf(tree fd, int nargs, const char *format_string, ...)
function = gg_get_function_address(INT, "sprintf");
}
- tree stmt = build_call_array_loc (location_from_lineno(),
+ tree stmt = build_call_array_loc (gg_token_location(),
INT,
function,
argc,
@@ -2280,7 +2278,7 @@ void
gg_memset(tree dest, const tree value, tree size)
{
tree the_call =
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_MEMSET),
3,
dest,
@@ -2294,7 +2292,7 @@ gg_memchr(tree buf, tree ch, tree length)
{
tree the_call = fold_convert(
pvoid_type_node,
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_MEMCHR),
3,
buf,
@@ -2309,7 +2307,7 @@ void
gg_memcpy(tree dest, const tree src, tree size)
{
tree the_call = build_call_expr_loc(
- location_from_lineno(),
+ gg_token_location(),
builtin_decl_explicit (BUILT_IN_MEMCPY),
3,
dest,
@@ -2324,7 +2322,7 @@ void
gg_memmove(tree dest, const tree src, tree size)
{
tree the_call = build_call_expr_loc(
- location_from_lineno(),
+ gg_token_location(),
builtin_decl_explicit (BUILT_IN_MEMMOVE),
3,
dest,
@@ -2357,7 +2355,7 @@ void
gg_strcpy(tree dest, tree src)
{
tree the_call =
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_STRCPY),
2,
dest,
@@ -2370,7 +2368,7 @@ gg_strcmp(tree A, tree B)
{
tree the_call = fold_convert(
integer_type_node,
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_STRCMP),
2,
A,
@@ -2402,7 +2400,7 @@ gg_strncmp(tree char_star_A, tree char_star_B, tree size_t_N)
{
tree the_call = fold_convert(
integer_type_node,
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_STRNCMP),
3,
char_star_A,
@@ -2433,7 +2431,7 @@ gg_return(tree operand)
{
// When there is no operand, or if the function result is void, then
// we just generate a return_expr.
- stmt = build1_loc(location_from_lineno(), RETURN_EXPR, void_type_node, NULL_TREE);
+ stmt = build1_loc(gg_token_location(), RETURN_EXPR, void_type_node, NULL_TREE);
}
else
{
@@ -2443,7 +2441,7 @@ gg_return(tree operand)
function_type,
DECL_RESULT(current_function->function_decl),
gg_cast(function_type, operand));
- stmt = build1_loc(location_from_lineno(), RETURN_EXPR, void_type_node, modify);
+ stmt = build1_loc(gg_token_location(), RETURN_EXPR, void_type_node, modify);
}
gg_append_statement(stmt);
}
@@ -2451,7 +2449,7 @@ gg_return(tree operand)
void
chain_parameter_to_function(tree function_decl, const tree param_type, const char *name)
{
- tree parm = build_decl (location_from_lineno(),
+ tree parm = build_decl (gg_token_location(),
PARM_DECL,
get_identifier (name),
param_type);
@@ -2686,7 +2684,7 @@ gg_define_function( tree return_type,
}
// Establish the RESULT_DECL for the function:
- tree resdecl = build_decl (location_from_lineno(), RESULT_DECL, NULL_TREE, return_type);
+ tree resdecl = build_decl (gg_token_location(), RESULT_DECL, NULL_TREE, return_type);
DECL_CONTEXT (resdecl) = function_decl;
DECL_RESULT (function_decl) = resdecl;
@@ -2818,7 +2816,7 @@ gg_get_function_decl(tree return_type, const char *funcname, ...)
}
// Establish the RESULT_DECL for the function:
- tree resdecl = build_decl (location_from_lineno(), RESULT_DECL, NULL_TREE, return_type);
+ tree resdecl = build_decl (gg_token_location(), RESULT_DECL, NULL_TREE, return_type);
DECL_CONTEXT (resdecl) = function_decl;
DECL_RESULT (function_decl) = resdecl;
@@ -3076,7 +3074,7 @@ gg_call_expr(tree return_type, const char *function_name, ...)
tree the_func_addr = build1(ADDR_EXPR,
build_pointer_type (TREE_TYPE(function_decl)),
function_decl);
- tree the_call = build_call_array_loc(location_from_lineno(),
+ tree the_call = build_call_array_loc(gg_token_location(),
return_type,
the_func_addr,
nargs,
@@ -3132,7 +3130,7 @@ gg_call(tree return_type, const char *function_name, ...)
tree the_func_addr = build1(ADDR_EXPR,
build_pointer_type (TREE_TYPE(function_decl)),
function_decl);
- tree the_call = build_call_array_loc(location_from_lineno(),
+ tree the_call = build_call_array_loc(gg_token_location(),
return_type,
the_func_addr,
nargs,
@@ -3157,7 +3155,7 @@ gg_call_expr_list(tree return_type, tree function_pointer, int param_count, tree
// Avoid that with something like
// gg_assign( dest, gg_call_expr_list(...) );
- tree the_call = build_call_array_loc(location_from_lineno(),
+ tree the_call = build_call_array_loc(gg_token_location(),
return_type,
function_pointer,
param_count,
@@ -3192,7 +3190,7 @@ void
gg_exit(tree exit_code)
{
tree the_call =
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_EXIT),
1,
exit_code);
@@ -3203,7 +3201,7 @@ void
gg_abort()
{
tree the_call =
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_ABORT),
0);
gg_append_statement(the_call);
@@ -3214,7 +3212,7 @@ gg_strlen(tree psz)
{
tree the_call = fold_convert(
size_type_node,
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_STRLEN),
1,
psz));
@@ -3226,7 +3224,7 @@ gg_strdup(tree psz)
{
tree the_call = fold_convert(
build_pointer_type(char_type_node),
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_STRDUP),
1,
psz));
@@ -3240,7 +3238,7 @@ gg_malloc(tree size)
{
tree the_call = fold_convert(
pvoid_type_node,
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_MALLOC),
1,
size));
@@ -3252,7 +3250,7 @@ gg_realloc(tree base, tree size)
{
tree the_call = fold_convert(
pvoid_type_node,
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_REALLOC),
2,
base,
@@ -3276,7 +3274,7 @@ void
gg_free(tree pointer)
{
tree the_call =
- build_call_expr_loc(location_from_lineno(),
+ build_call_expr_loc(gg_token_location(),
builtin_decl_explicit (BUILT_IN_FREE),
1,
pointer);
@@ -3377,18 +3375,6 @@ gg_string_literal(const char *string)
return build_string_literal(strlen(string)+1, string);
}
-void
-gg_set_current_line_number(int line_number)
- {
- sv_current_line_number = line_number;
- }
-
-int
-gg_get_current_line_number()
- {
- return sv_current_line_number;
- }
-
tree
gg_trans_unit_var_decl(const char *var_name)
{
@@ -3410,7 +3396,7 @@ gg_insert_into_assembler(const char ach[])
if( !optimize )
{
// Create the required generic tag
- tree asm_expr = build5_loc( location_from_lineno(),
+ tree asm_expr = build5_loc( gg_token_location(),
ASM_EXPR,
VOID,
build_string(strlen(ach), ach),
@@ -3447,5 +3433,28 @@ gg_insert_into_assemblerf(const char *format, ...)
gg_insert_into_assembler(ach);
}
}
+#pragma GCC diagnostic pop
+
+static location_t sv_token_location_override = 0;
-#pragma GCC diagnostic pop \ No newline at end of file
+void
+token_location_override(location_t loc)
+ {
+ sv_token_location_override = loc;
+ }
+
+location_t
+gg_token_location()
+ {
+ location_t retval;
+ if( sv_token_location_override )
+ {
+ retval = sv_token_location_override;
+ sv_token_location_override = 0;
+ }
+ else
+ {
+ retval = current_token_location();
+ }
+ return retval;
+ }
diff --git a/gcc/cobol/gengen.h b/gcc/cobol/gengen.h
index 06b28e06..96e69dd 100644
--- a/gcc/cobol/gengen.h
+++ b/gcc/cobol/gengen.h
@@ -525,11 +525,11 @@ extern tree gg_indirect(tree pointer, tree byte_offset = NULL_TREE);
extern tree gg_string_literal(const char *string);
#define CURRENT_LINE_NUMBER (cobol_location().first_line)
-extern location_t location_from_lineno();
-
-// When set to true, use UNKNOWN_LOCATION instead of CURRENT_LINE_NUMBER
-extern void gg_set_current_line_number(int line_number);
-extern int gg_get_current_line_number();
+extern location_t gg_token_location();
+extern location_t current_token_location();
+extern location_t current_location_minus_one();
+extern void current_location_minus_one_clear();
+extern void token_location_override(location_t loc);
extern tree gg_trans_unit_var_decl(const char *var_name);
diff --git a/gcc/cobol/genmath.cc b/gcc/cobol/genmath.cc
index e74aebd..e7eb971 100644
--- a/gcc/cobol/genmath.cc
+++ b/gcc/cobol/genmath.cc
@@ -610,7 +610,7 @@ static bool
fast_divide(size_t nC, cbl_num_result_t *C,
size_t nA, cbl_refer_t *A,
size_t nB, cbl_refer_t *B,
- cbl_refer_t remainder)
+ const cbl_refer_t &remainder)
{
bool retval = false;
if( all_results_binary(nC, C) )
diff --git a/gcc/cobol/genutil.cc b/gcc/cobol/genutil.cc
index 20b47ab..7895ea8 100644
--- a/gcc/cobol/genutil.cc
+++ b/gcc/cobol/genutil.cc
@@ -305,7 +305,7 @@ static
void
get_and_check_refstart_and_reflen( tree refstart,// LONG returned value
tree reflen, // LONG returned value
- cbl_refer_t &refer)
+ const cbl_refer_t &refer)
{
const cbl_enabled_exceptions_t&
enabled_exceptions( cdf_enabled_exceptions() );
@@ -542,8 +542,8 @@ get_depending_on_value(tree retval, const cbl_refer_t &refer)
static
tree
-get_data_offset(cbl_refer_t &refer,
- int *pflags = NULL)
+get_data_offset(const cbl_refer_t &refer,
+ int *pflags = NULL)
{
Analyze();
// This routine returns a tree which is the size_t offset to the data in the
@@ -1974,7 +1974,7 @@ refer_is_clean(const cbl_refer_t &refer)
*/
static
tree // size_t
-refer_refmod_length(cbl_refer_t &refer)
+refer_refmod_length(const cbl_refer_t &refer)
{
Analyze();
REFER("refstart and reflen");
@@ -2017,8 +2017,8 @@ refer_fill_depends(const cbl_refer_t &refer)
}
tree // size_t
-refer_offset(cbl_refer_t &refer,
- int *pflags)
+refer_offset(const cbl_refer_t &refer,
+ int *pflags)
{
// This routine calculates the effect of a refer offset on the
// refer.field->data location. When there are subscripts, the data location
@@ -2045,7 +2045,7 @@ refer_offset(cbl_refer_t &refer,
static
tree // size_t
-refer_size(cbl_refer_t &refer, refer_type_t refer_type)
+refer_size(const cbl_refer_t &refer, refer_type_t refer_type)
{
Analyze();
static tree retval = gg_define_variable(SIZE_T, "..rs_retval", vs_file_static);
@@ -2086,13 +2086,13 @@ refer_size(cbl_refer_t &refer, refer_type_t refer_type)
}
tree // size_t
-refer_size_dest(cbl_refer_t &refer)
+refer_size_dest(const cbl_refer_t &refer)
{
return refer_size(refer, refer_dest);
}
tree // size_t
-refer_size_source(cbl_refer_t &refer)
+refer_size_source(const cbl_refer_t &refer)
{
/* There are oddities involved with refer_size_source and refer_size_dest.
See the comments in refer_has_depends for some explanation. There are
@@ -2129,7 +2129,7 @@ refer_size_source(cbl_refer_t &refer)
}
tree
-qualified_data_location(cbl_refer_t &refer)
+qualified_data_location(const cbl_refer_t &refer)
{
return gg_add(member(refer.field->var_decl_node, "data"),
refer_offset(refer));
diff --git a/gcc/cobol/genutil.h b/gcc/cobol/genutil.h
index 20783e1..f12124e 100644
--- a/gcc/cobol/genutil.h
+++ b/gcc/cobol/genutil.h
@@ -140,12 +140,12 @@ char *get_literal_string(cbl_field_t *field);
bool refer_is_clean(const cbl_refer_t &refer);
-tree refer_offset(cbl_refer_t &refer,
+tree refer_offset(const cbl_refer_t &refer,
int *pflags=NULL);
-tree refer_size_source(cbl_refer_t &refer);
-tree refer_size_dest(cbl_refer_t &refer);
+tree refer_size_source(const cbl_refer_t &refer);
+tree refer_size_dest(const cbl_refer_t &refer);
-tree qualified_data_location(cbl_refer_t &refer);
+tree qualified_data_location(const cbl_refer_t &refer);
void build_array_of_treeplets( int ngroup,
size_t N,
diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y
index 7bcbf74..59cc64d 100644
--- a/gcc/cobol/parse.y
+++ b/gcc/cobol/parse.y
@@ -801,6 +801,7 @@
%type <boolean> io_invalid read_eof write_eop
global is_global anycase backward
end_display
+ exh_changed exh_named
%type <number> mistake globally first_last
%type <io_mode> io_mode
@@ -1012,7 +1013,9 @@
%right IF THEN ELSE
SENTENCE
ACCEPT ADD ALTER CALL CANCEL CLOSE COMPUTE CONTINUE
- DELETE DISPLAY DIVIDE EVALUATE END EOP EXIT FILLER_kw
+ DELETE DISPLAY DIVIDE
+ EVALUATE END EOP EXIT
+ FILLER_kw
GOBACK GOTO
INITIALIZE INSPECT
MERGE MOVE MULTIPLY OPEN OVERFLOW_kw PARAGRAPH PERFORM
@@ -5052,6 +5055,7 @@ statement: error {
| divide { $$ = DIVIDE; }
| entry { $$ = ENTRY; }
| evaluate { $$ = EVALUATE; }
+ | exhibit_stmt { $$ = EXHIBIT; }
| exit { $$ = EXIT; }
| free { $$ = FREE; }
| go_to { $$ = GOTO; }
@@ -5687,6 +5691,20 @@ disp_upon: device_name {
}
;
+exhibit_stmt: EXHIBIT exh_changed exh_named vargs {
+ statement_begin(@1, EXHIBIT);
+ std::vector<cbl_refer_t> args( $vargs->args.begin(),
+ $vargs->args.end() );
+ parser_exhibit( $exh_changed, $exh_named, args );
+ }
+ ;
+exh_changed: %empty { $$ = false; }
+ | CHANGED { $$ = true; }
+ ;
+exh_named: %empty { $$ = false; }
+ | NAMED { $$ = true; }
+ ;
+
divide: divide_impl end_divide { ast_divide($1); }
| divide_cond end_divide { ast_divide($1); }
;
@@ -7636,6 +7654,7 @@ perform_cond: UNTIL { parser_perform_conditional( &perform_current()->tgt); }
perform_inline: perform_start statements END_PERFORM
{
location_set(@END_PERFORM);
+ parser_sleep(*cbl_refer_t::empty());
$$ = perform_current();
if( $perform_start == LOCATION ) {
error_msg(@1, "LOCATION not valid with PERFORM Format 2");
@@ -7644,6 +7663,7 @@ perform_inline: perform_start statements END_PERFORM
| perform_start END_PERFORM
{
location_set(@END_PERFORM);
+ parser_sleep(*cbl_refer_t::empty());
$$ = perform_current();
if( $perform_start == LOCATION ) {
error_msg(@1, "LOCATION not valid with PERFORM Format 2");
@@ -11788,7 +11808,7 @@ label_add( const YYLTYPE& loc,
name, cbl_label_of(p)->name, cbl_label_of(p)->line);
}
}
- struct cbl_label_t label = { type, parent, loc.last_line };
+ struct cbl_label_t label = { type, parent, loc.first_line };
if( !namcpy(loc, label.name, name) ) return NULL;
auto p = symbol_label_add(PROGRAM, &label);
diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h
index fa06e6c..03cb0a0 100644
--- a/gcc/cobol/parse_ante.h
+++ b/gcc/cobol/parse_ante.h
@@ -103,7 +103,7 @@ void input_file_status_notify();
} \
location_dump("parse.c", __LINE__, "current", (Current)); \
input_file_status_notify(); \
- gcc_location_set( location_set(Current) ); \
+ location_set(Current); \
} while (0)
int yylex(void);
@@ -3493,18 +3493,18 @@ goodnight_gracie() {
// false after USE statement, to enter Declarative with EC intact.
static bool statement_cleanup = true;
+static YYLTYPE current_location;
static void statement_epilog( int token );
const char * keyword_str( int token );
-static YYLTYPE current_location;
-
const YYLTYPE& cobol_location() { return current_location; }
-static inline YYLTYPE
+static inline void
location_set( const YYLTYPE& loc ) {
- return current_location = loc;
+ current_location = loc;
+ gcc_location_set(loc);
}
static void statement_begin( const YYLTYPE& loc, int token );
diff --git a/gcc/cobol/scan.l b/gcc/cobol/scan.l
index 8b5dc25..2da38d8 100644
--- a/gcc/cobol/scan.l
+++ b/gcc/cobol/scan.l
@@ -89,6 +89,7 @@ EOL \r?\n
BLANK_EOL [[:blank:]]*{EOL}
BLANK_OEOL [[:blank:]]*{EOL}?
+PICTURE [^[:space:]]+
DOTSEP [.]+[[:space:]]
DOTEOL [[:blank:]]*[.]{BLANK_EOL}
@@ -176,7 +177,7 @@ SIZE_ERROR (ON[[[:space:]]+)?SIZE[[:space:]]+ERROR
VARTYPE NUMERIC|ALPHABETIC|ALPHABETIC_LOWER|ALPHABETIC_UPPER|DBCS|KANJI
NAMTYP {NAME}|{VARTYPE}
-NL [[:blank:]]*\r?\n[[:blank:]]*
+NL [[:blank:]]*{EOL}[[:blank:]]*
PUSH_FILE \f?[#]FILE{SPC}PUSH{SPC}[^\f]+\f
POP_FILE \f?[#]FILE{SPC}POP\f
@@ -965,7 +966,9 @@ USE({SPC}FOR)? { return USE; }
return NUMSTR;
}
- PIC(TURE)?({SPC}IS)?[[:space:]]{BLANK_OEOL} {
+ PIC(TURE)?({SPC}IS)?{SPC}{PICTURE} {
+ auto pos = validate_picture();
+ myless(pos);
yy_push_state(picture); return PIC; }
ANY { return ANY; }
@@ -1147,7 +1150,7 @@ USE({SPC}FOR)? { return USE; }
yy_push_state(hex_state); }
N?X{nonseq} { dbgmsg("invalid hexadecimal value: %s", yytext);
return NO_CONDITION; }
- [[:blank:]]*\r?\n {}
+ [[:blank:]]*{EOL} {}
WORKING-STORAGE{SPC}SECTION { return WORKING_STORAGE_SECT; }
LOCAL-STORAGE{SPC}SECTION { return LOCAL_STORAGE_SECT; }
@@ -1217,7 +1220,7 @@ USE({SPC}FOR)? { return USE; }
{NP}V?/[,.]? { yylval.number = ndigit(yyleng); return picset(PIC_P); }
{N9}*V/{N9}* { yylval.number = ndigit(yyleng - 1); return picset(NINEV); }
{N9}/{N9}*[,.]? { yylval.number = ndigit(yyleng); return picset(NINES); }
- P+/[,.]?\r?\n { yylval.number = yyleng; return picset(PIC_P); }
+ P+/[,.]?{EOL} { yylval.number = yyleng; return picset(PIC_P); }
1{1,31}/({COUNT}|[(]{NAME}[)]) {
yy_push_state(picture_count);
@@ -1316,7 +1319,7 @@ USE({SPC}FOR)? { return USE; }
[""]{SPC}[&]{SPC}[""''] {
if( yytext[yyleng - 1] == '\'' ) BEGIN(quoted1);
}
- [""]-{OSPC}(\r?\n{OSPC})+[""] /* continue ... */
+ [""]-{OSPC}({EOL}{OSPC})+[""] /* continue ... */
[""] {
char *s = xstrdup(tmpstring? tmpstring : "\0");
yylval.literal.set_data(strlen(s), s);
@@ -1333,7 +1336,7 @@ USE({SPC}FOR)? { return USE; }
['']{SPC}[&]{SPC}[""''] {
if( yytext[yyleng - 1] == '"' ) BEGIN(quoted2);
}
- ['']-{OSPC}(\r?\n{OSPC})+[''] /* continue ... */
+ ['']-{OSPC}({EOL}{OSPC})+[''] /* continue ... */
[''] {
char *s = xstrdup(tmpstring? tmpstring : "\0");
yylval.literal.set_data(strlen(s), s);
@@ -2040,7 +2043,7 @@ BASIS { yy_push_state(basis); return BASIS; }
return symbol_file(PROGRAM, yytext)? FILENAME : NAME;
}
[[:blank:]]+
- \r?\n { yy_pop_state(); }
+ {EOL} { yy_pop_state(); }
}
<raising>{
@@ -2169,7 +2172,7 @@ BASIS { yy_push_state(basis); return BASIS; }
<*>{DOTSEP} { return '.'; }
<*>[().=*/+&-] { return *yytext; }
<*>[[:blank:]]+
-<*>\r?\n
+<*>{EOL}
<*>{
{COMMA}
diff --git a/gcc/cobol/scan_ante.h b/gcc/cobol/scan_ante.h
index 6128a3f..19ceb2b 100644
--- a/gcc/cobol/scan_ante.h
+++ b/gcc/cobol/scan_ante.h
@@ -694,6 +694,387 @@ picset( int token ) {
return token;
}
+/**
+## Script and data to produce picture_t::followers.
+## Based on ISO Table 10.
+#! /usr/bin/awk -f
+
+BEGIN {
+ str = "B0/ , . + +- +- CR/DB cs cs Z* Z* + + cs cs 9 AX S V P P 1 N E"
+ split(str, cols)
+}
+
+$1 ~ /CR|DB|cs/ { next }
+
+0 && !nlines++ {
+ for( i=0; i < length(cols); i++ ) {
+ print i, cols[i], "'" $i "'"
+ }
+}
+
+$field == "x" {
+ if( ! nout++ ) {
+ printf "%2d: %5s: \"", field, cols[field - 1]
+ }
+
+ gsub(/^ +| +$/, "", $1)
+ printf "%s", $1
+}
+
+END {
+ if( ! nout++ ) {
+ printf "%2d: %5s: \"", field, cols[field - 1]
+ }
+ print "\""
+}
+
+B x x x - x - - x - x x x x x x x x - x - x - x
+0 x x x - x - - x - x x x x x x x x - x - x - x
+/ x x x - x - - x - x x x x x x x x - x - x - x
+, x x x - x - - x - x x x x x x x - - x - x
+. x x - - x - - x - x - x - x - x
++ - - - - - - - - - - - - - - - - - - - - - - - x
++
+–
++ x x x - - - - x x x x - - x x x - - x x x
+CR x x x - - - - x x x x - - x x x - - x x x
+DB x x x - - - - x x x x - - x x x - - x x x
+cs - - - - x
+cs x x x - x - - - - x x - - - - x - - x x x
+
+Z x x - - x - - x - x
+* x x - - x - - x - x
+Z x x x - x - - x - x x - - - - - - - x - x
+* x x x - x - - x - x x - - - - - - - x - x
++ x x - - - - - x - - - x
+– x x - - - - - x - - - x
++ x x x - - - - x - - - x x - - - - - x
+– x x x - - - - x - - - x x - - - - - x
+cs x x - - x - - - - - - - - x
+cs x x x - x - - - - - - - - x x - - - x
+
+9 x x x x x - - x - x - x - x - x x x x - x - - x
+A x - - - - - - - - - - - - - - x x
+X x - - - - - - - - - - - - - - x x
+S
+V x x - - x - - x - x - x - x - x - x - x
+P x x - - x - - x - x - x - x - x - x - x
+P - - - - x - - x - - - - - - - - - x x - x
+1 - - - - - - - - - - - - - - - - - - - - - x
+N x - - - - - - - - - - - - - - - - - - - - - x
+E x x x - x - - - - - - - - - - x
+**/
+
+class picture_t {
+ static const char dot = '.', comma = ',';
+
+ typedef std::vector<std::string> followings_t;
+ static const std::map <char, followings_t> followers;
+
+ const char * const begin;
+ const char *p, *pend;
+ size_t pos;
+ struct exclusions_t { // Nonzero if set, > 1 is false.
+ // crdb means CR/DB or +/-.
+ // pluses means 2 or more consecutive '+'.
+ // minuses means 2 or more consecutive '-'.
+ // "21) The symbol 'Z' and the symbol '*' are mutually exclusive "
+ // stars means '*' or Z.
+ unsigned short int crdb, currency, dot, pluses, minuses, stars, zzz;
+ exclusions_t()
+ : crdb(0), currency(0), dot(0), pluses(0), minuses(0), stars(0)
+ {}
+ } exclusions;
+ YYLTYPE loc;
+
+ bool is_crdb() const { // input must be uppercase for CR/DB
+ if( p[0] == 'C' || p[0] == 'D' ) {
+ char input[3] = { p[0], p[1] };
+ return ( 0 == strcmp(input, "CR") || 0 == strcmp(input, "DB") );
+ }
+ return false;
+ }
+
+ const char * match_paren( const char *paren ) const {
+ gcc_assert(paren[0] == '('); // start with opening paren
+ paren = std::find_if( paren, pend,
+ []( char ch ) {
+ return ch == '(' || ch == ')';
+ } );
+ if( *paren == '(' ) return nullptr; // no nesting
+ if( paren == pend ) return nullptr;
+ return ++paren;
+ }
+
+ const char * next_not( char ch ) const {
+ return std::find_if( p, pend,
+ [ch = TOUPPER(ch)]( char next ) {
+ return ch != next;
+ } );
+ }
+
+ const char * valid_next( const char *p, const std::string& valid ) const {
+ if( p == pend || p + 1 == pend ) return pend;
+ if( p[1] == '(' ) {
+ return match_paren(++p);
+ }
+ auto pv = std::find(valid.begin(), valid.end(), TOUPPER(p[1]));
+ return pv != valid.end()? ++p : nullptr;
+ }
+ const char * valid_next( const char *p,
+ bool first = true, char ch = '\0' ) const {
+ if( p == pend || p + 1 == pend ) return pend;
+ if( p[0] == '(' ) {
+ if( (p = match_paren(p)) == nullptr ) return nullptr;
+ }
+ if( p[0] == '(' ) return nullptr; // consecutive parentheses
+
+ int index = first? 0 : 1;
+ if( !ch ) ch = *p; // use current character unless overridden
+ auto valid = followers.find(TOUPPER(ch));
+ if( valid == followers.end() ) {
+ YYLTYPE loc(yylloc);
+ loc.first_column += int(p - begin);
+ error_msg( loc, "PICTURE: strange character %qc, giving up", ch );
+ return nullptr;
+ }
+ return valid_next(p, valid->second[index]);
+ }
+
+ const char * start() { // start modifies exclusions, but not p
+ auto pnext = p;
+
+ switch(TOUPPER(p[0])) {
+ case comma: case dot:
+ // use decimal_is_comma()
+ // 4: .: "B0/,+Z*+-9E"
+ exclusions.dot++;
+ pnext = valid_next(p, "B0/,+Z*+-9E");
+ break;
+ case '+': case '-':
+ // 6: +-: "B0/,.Z*Z*9VPPE"
+ exclusions.crdb++;
+ pnext = next_not(p[0]);
+ if( p + 1 < pnext ) {
+ exclusions.pluses++;
+ }
+ pnext = valid_next(--pnext, "B0/,.Z*Z*9VPPE");
+ break;
+ case 'Z': case '*':
+ exclusions.stars++;
+ pnext = next_not(p[0]);
+ break;
+ case 'S':
+ // 19: S: "9VP"
+ pnext = valid_next(p, "9VP");
+ break;
+ }
+
+ /*
+ * "For fixed editing sign control, the currency symbol, when used, shall
+ * be either the leftmost symbol in character-string-1, optionally preceded
+ * by one of the symbols '+' or '-' "
+ */
+ if( pnext ) {
+ if( p == pnext || p[0] == '+' || p[0] == '-' ) {
+ if( symbol_currency(*pnext) ) {
+ exclusions.currency++;
+ pnext = next_not(*pnext);
+ pnext = valid_next(--pnext, true, '$');
+ }
+ }
+ }
+
+ return pnext;
+ }
+
+ const char * next() { // modify state; do not modify position
+ auto pnext = p;
+ auto loc(picture_t::loc);
+ loc.first_column += int(p - begin);
+
+ if( is_crdb() ) {
+ if( exclusions.crdb++ ) {
+ error_msg( loc, "PICTURE: CR/DB and %c/%c may appear only once", '+', '-' );
+ return nullptr;
+ }
+ if( p + 2 != pend ) {
+ error_msg( loc, "PICTURE: CR/DB must appear at the end" );
+ return nullptr;
+ }
+ return pend;
+ }
+
+ if( symbol_currency(p[0]) ) {
+ if( false && exclusions.currency++ ) { // not enforced
+ error_msg( loc, "PICTURE: CURRENCY SYMBOL sequence may appear at most once" );
+ return nullptr;
+ }
+ return valid_next(p, ! exclusions.dot, '$');
+ }
+
+ switch(TOUPPER(p[0])) {
+ case '(':
+ return match_paren(p);
+ break;
+ case 'B': case '0': case '/':
+ pnext = valid_next(p);
+ break;
+ case comma:
+ if( decimal_is_comma() ) {
+ if( exclusions.dot++ ) {
+ error_msg( loc, "PICTURE: %qc: may appear at most once", p[0] );
+ return nullptr;
+ }
+ pnext = valid_next(p, true, dot);
+ } else {
+ pnext = valid_next(p);
+ }
+ break;
+ case dot:
+ if( p + 1 == pend ) {
+ pnext = pend;
+ } else {
+ if( decimal_is_comma() ) {
+ pnext = valid_next(p, true, comma );
+ } else {
+ if( exclusions.dot++ ) {
+ error_msg( loc, "PICTURE: %qc: may appear at most once", p[0] );
+ return nullptr;
+ }
+ pnext = valid_next(p);
+ }
+ }
+ break;
+
+ case '+': case '-':
+ // 7 is trailing sign; 13 & 14 are numeric. Leading sign handled by start().
+ if( p + 1 == pend ) {
+ if( exclusions.crdb++ ) {
+ error_msg( loc, "PICTURE: %c/%c may appear at most once as a sign", '+', '-' );
+ return nullptr;
+ }
+ pnext = pend;
+ } else {
+ pnext = next_not(p[0]);
+ if( p + 1 < pnext ) {
+ if( false && exclusions.pluses++ ) { // not enforced
+ error_msg( loc, "PICTURE: %qc: sequence may appear at most once", p[0] );
+ return nullptr;
+ }
+ }
+ pnext = valid_next(pnext, ! exclusions.dot);
+ }
+ break;
+
+ case 'Z': case '*':
+ if( false && exclusions.stars++ ) { // not enforced
+ error_msg( loc, "PICTURE: %qc: sequence may appear at most once", p[0] );
+ return nullptr;
+ }
+ if( (pnext = next_not(p[0])) == nullptr ) return pnext;
+ pnext = valid_next(pnext, ! exclusions.dot);
+ break;
+ case 'P':
+ pnext = valid_next(pnext, ! exclusions.dot);
+ break;
+ case '9':
+ case 'A': case 'X':
+ case 'V':
+ case '1':
+ case 'N':
+ pnext = valid_next(p);
+ break;
+ case 'E':
+ pnext = valid_next(p, "+9");
+ if( pnext && *pnext == '+' ) {
+ pnext = valid_next(p, "9");
+ }
+ break;
+ default:
+ error_msg( loc, "PICTURE: %qc: invalid character", p[0] );
+ return nullptr;
+ }
+ return pnext;
+ }
+
+ public:
+ picture_t( const char *p, int len )
+ : begin(p)
+ , p(p), pend(p + len)
+ , loc(yylloc)
+ {
+ assert(TOUPPER(*p) == 'P'); // as in PICTURE (or PICTURE IS)
+ // move p to start of picture string
+ while( (p = std::find_if(p, pend, fisspace)) != pend ) {
+ this->p = p = std::find_if(p, pend,
+ []( char ch ) { return ! fisspace(ch); } );
+ }
+ assert(this->p != pend);
+ pos = this->p - begin;
+ }
+
+ bool is_valid() {
+ if( !p ) return false;
+ if( (p = start()) == nullptr ) {
+ return false;
+ }
+
+ while( p && p < pend) {
+ p = next();
+ }
+ return p == pend;
+ }
+
+ int starts_at() const { return pos; }
+};
+
+/*
+ * The Followers map gives 1 or 2 lists of valid characters following a
+ * character, the one in the key. If there are two lists, the correct one is
+ * determined by the caller based on the state of the picture string, i.e.,
+ * what has been seen before.
+ */
+const std::map <char, picture_t::followings_t> picture_t::followers {
+ /* B0/ */ { 'B', {"B0/,.Z*+-9AXVPNE" } },
+ /* B0/ */ { '0', {"B0/,.Z*+-9AXVPNE" } },
+ /* B0/ */ { '/', {"B0/,.Z*+-9AXVPNE" } },
+ /* , */ { ',', {"B0/,.Z*+-9VPE"} },
+ /* . */ { '.', {"B0/,Z*+-9E"} },
+ /* + { '+', "9" }, */
+ /* +- */ { '+', {"B0/,.Z*9VPE", "" } },
+ /* +- */ { '-', {"B0/,.Z*9VPE", "" } },
+ /* CR/DB { 'C', "" }, */
+ /* cs { 'c', "B0/,.Z*+-9VP" }, */
+ /* cs { 'c', "+" }, */
+ /* Z* */ { 'Z', {"B0/,.+Z*9VP", "B0/,+Z*"} },
+ /* Z* */ { '*', {"B0/,.+Z*9VP", "B0/,+Z*"} },
+ /* + */ { '+', {"B0/,.+-9VP", "B0/,+-"} },
+ /* cs */ { '$', {"B0/,.+9VP", "B0/,+"} },
+ /* 9 */ { '9', {"B0/,.+9AXVPE"} },
+ /* AX */ { 'A', {"B0/9AX"} },
+ /* AX */ { 'X', {"B0/9AX"} },
+ /* S */ { 'S', {"9VP"} },
+ /* V */ { 'V', {"B0/,+Z*+-9P"} },
+ /* P */ { 'P', {"+VP", "B0/,+Z*9P"} },
+ /* 1 */ { '1', {"1"} },
+ /* N */ { 'N', {"B0/N"} },
+ /* E */ { 'E', {"+9"} },
+};
+
+/*
+ * Although picture_t::is_valid return a bool, it's not used. The validation
+ * routines emit messages where the error is detected. The entire string is
+ * subsequently parsed by the parser, which might otherwise accept an invalid
+ * string, but will usually emit a message of its own.
+ */
+static int
+validate_picture() {
+ picture_t picture(yytext, yyleng);
+ picture.is_valid();
+ return picture.starts_at();
+}
+
static inline bool
is_integer_token( int *pvalue = NULL ) {
int v, n = 0;
diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc
index aaaa6f3..7d6a955 100644
--- a/gcc/cobol/symbols.cc
+++ b/gcc/cobol/symbols.cc
@@ -4249,6 +4249,11 @@ symbol_currency( char sign ) {
if( currencies.size() == 0 ) {
currencies['$'] = "$";
}
+ if( sign == '\0' ) { // default
+ auto result = currencies.begin();
+ gcc_assert(result != currencies.end());
+ return result->second;
+ }
auto result = currencies.find(sign);
return result == currencies.end()? NULL : result->second;
}
diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h
index c3de0aa..c8ae32f 100644
--- a/gcc/cobol/symbols.h
+++ b/gcc/cobol/symbols.h
@@ -2613,7 +2613,7 @@ symbol_field_same_as( cbl_field_t *tgt, const cbl_field_t *src );
size_t symbol_file_same_record_area( std::list<cbl_file_t*>& files );
bool symbol_currency_add( const char symbol[], const char sign[] = NULL );
-const char * symbol_currency( char symbol );
+const char * symbol_currency( char symbol = '\0' );
const char * symbol_type_str( enum symbol_type_t type );
const char * cbl_field_type_str( enum cbl_field_type_t type );
diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc
index 6439f23..2a7bf2b 100644
--- a/gcc/cobol/util.cc
+++ b/gcc/cobol/util.cc
@@ -47,15 +47,7 @@
#include <intl.h>
#include <backtrace.h>
#include <diagnostic.h>
-#include <diagnostic-color.h>
-#include <diagnostic-url.h>
-#include <diagnostic-metadata.h>
-#include <diagnostic-path.h>
-#include <edit-context.h>
-#include <selftest.h>
-#include <selftest-diagnostic.h>
#include <opts.h>
-
#include "util.h"
#include "cbldiag.h"
@@ -2078,16 +2070,45 @@ cobol_filename_restore() {
linemap_add(line_table, LC_LEAVE, sysp, NULL, 0);
}
-static location_t token_location;
+static int first_line_minus_1 = 0;
+static location_t token_location_minus_1 = 0;
+static location_t token_location = 0;
-location_t location_from_lineno() { return token_location; }
+location_t current_token_location() { return token_location; }
+location_t current_location_minus_one() { return token_location_minus_1; }
+void current_location_minus_one_clear()
+ {
+ first_line_minus_1 = 0;
+ }
template <typename LOC>
static void
gcc_location_set_impl( const LOC& loc ) {
// Set the position to the first line & column in the location.
+ if( getenv("KILROY") )
+ {
+ fprintf(stderr, "********** KILROY %d\n", loc.first_line);
+ }
+
+ static location_t loc_m_1 = 0;
+
token_location = linemap_line_start( line_table, loc.first_line, 80 );
token_location = linemap_position_for_column( line_table, loc.first_column);
+
+ if( loc.first_line > first_line_minus_1 )
+ {
+ // In order for GDB-COBOL to be able to step through COBOL code properly,
+ // it is sometimes necessary for the code at the beginning of a COBOL
+ // line to be using the location_t of the previous line. This is true, for
+ // example, when laying down the infrastructure code between the last
+ // statement of a paragraph and the code created at the beginning of the
+ // following paragragh. This code assumes that token_location values of
+ // interest are monotonic, and stores that prior value.
+ first_line_minus_1 = loc.first_line;
+ token_location_minus_1 = loc_m_1;
+ loc_m_1 = token_location;
+ }
+
location_dump(__func__, __LINE__, "parser", loc);
}
@@ -2128,7 +2149,7 @@ verify_format( const char gmsgid[] ) {
}
#endif
-static const diagnostic_option_id option_zero;
+static const diagnostics::option_id option_zero;
size_t parse_error_inc();
void gcc_location_dump() {
@@ -2147,7 +2168,8 @@ ydferror( const char gmsgid[], ... ) {
va_start (ap, gmsgid);
rich_location richloc (line_table, token_location);
/*bool ret =*/ global_dc->diagnostic_impl (&richloc, nullptr, option_zero,
- gmsgid, &ap, DK_ERROR);
+ gmsgid, &ap,
+ diagnostics::kind::error);
va_end (ap);
}
@@ -2202,7 +2224,8 @@ class temp_loc_t {
va_start (ap, gmsgid); \
rich_location richloc (line_table, token_location); \
bool ret = global_dc->diagnostic_impl (&richloc, nullptr, option_zero, \
- gmsgid, &ap, DK_ERROR); \
+ gmsgid, &ap, \
+ diagnostics::kind::error); \
va_end (ap); \
global_dc->end_group();
@@ -2218,13 +2241,29 @@ void error_msg( const YDFLTYPE& loc, const char gmsgid[], ... ) {
ERROR_MSG_BODY
}
+bool
+warn_msg( const YYLTYPE& loc, const char gmsgid[], ... ) {
+ temp_loc_t looker(loc);
+ verify_format(gmsgid);
+ auto_diagnostic_group d;
+ va_list ap;
+ va_start (ap, gmsgid);
+ rich_location richloc (line_table, token_location);
+ auto ret = emit_diagnostic_valist( diagnostics::kind::warning,
+ token_location,
+ option_zero, gmsgid, &ap );
+ va_end (ap);
+ return ret;
+}
+
void error_msg_direct( const char gmsgid[], ... ) {
verify_format(gmsgid);
parse_error_inc();
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
- /*auto ret = */emit_diagnostic_valist( DK_ERROR, token_location,
+ /*auto ret = */emit_diagnostic_valist( diagnostics::kind::error,
+ token_location,
option_zero, gmsgid, &ap );
va_end (ap);
}
@@ -2242,7 +2281,7 @@ yyerror( const char gmsgid[], ... ) {
nullptr,
option_zero,
gmsgid,
- &ap, DK_ERROR);
+ &ap, diagnostics::kind::error);
va_end (ap);
global_dc->end_group();
}
@@ -2253,7 +2292,7 @@ yywarn( const char gmsgid[], ... ) {
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
- auto ret = emit_diagnostic_valist( DK_WARNING, token_location,
+ auto ret = emit_diagnostic_valist( diagnostics::kind::warning, token_location,
option_zero, gmsgid, &ap );
va_end (ap);
return ret;
@@ -2451,7 +2490,8 @@ cbl_internal_error(const char *gmsgid, ...) {
auto_diagnostic_group d;
va_list ap;
va_start(ap, gmsgid);
- emit_diagnostic_valist( DK_ICE, token_location, option_zero, gmsgid, &ap );
+ emit_diagnostic_valist( diagnostics::kind::ice,
+ token_location, option_zero, gmsgid, &ap );
va_end(ap);
abort(); // This unnecessary statement is needed so that [[noreturn]]
// // doesn't cause a warning.
@@ -2463,7 +2503,8 @@ cbl_unimplementedw(const char *gmsgid, ...) {
auto_diagnostic_group d;
va_list ap;
va_start(ap, gmsgid);
- emit_diagnostic_valist( DK_SORRY, token_location, option_zero, gmsgid, &ap );
+ emit_diagnostic_valist( diagnostics::kind::sorry,
+ token_location, option_zero, gmsgid, &ap );
va_end(ap);
}
@@ -2473,7 +2514,8 @@ cbl_unimplemented(const char *gmsgid, ...) {
auto_diagnostic_group d;
va_list ap;
va_start(ap, gmsgid);
- emit_diagnostic_valist( DK_SORRY, token_location, option_zero, gmsgid, &ap );
+ emit_diagnostic_valist( diagnostics::kind::sorry,
+ token_location, option_zero, gmsgid, &ap );
va_end(ap);
}
@@ -2484,7 +2526,8 @@ cbl_unimplemented_at( const YYLTYPE& loc, const char *gmsgid, ... ) {
auto_diagnostic_group d;
va_list ap;
va_start(ap, gmsgid);
- emit_diagnostic_valist( DK_SORRY, token_location, option_zero, gmsgid, &ap );
+ emit_diagnostic_valist( diagnostics::kind::sorry,
+ token_location, option_zero, gmsgid, &ap );
va_end(ap);
}
@@ -2501,7 +2544,8 @@ cbl_err(const char *fmt, ...) {
verify_format(gmsgid);
va_list ap;
va_start(ap, fmt);
- emit_diagnostic_valist( DK_FATAL, token_location, option_zero, gmsgid, &ap );
+ emit_diagnostic_valist( diagnostics::kind::fatal,
+ token_location, option_zero, gmsgid, &ap );
va_end(ap);
}
#pragma GCC diagnostic pop
@@ -2512,7 +2556,8 @@ cbl_errx(const char *gmsgid, ...) {
auto_diagnostic_group d;
va_list ap;
va_start(ap, gmsgid);
- emit_diagnostic_valist( DK_FATAL, token_location, option_zero, gmsgid, &ap );
+ emit_diagnostic_valist( diagnostics::kind::fatal,
+ token_location, option_zero, gmsgid, &ap );
va_end(ap);
}
diff --git a/gcc/cobol/util.h b/gcc/cobol/util.h
index 00ab6a7..d478ea2 100644
--- a/gcc/cobol/util.h
+++ b/gcc/cobol/util.h
@@ -49,7 +49,7 @@ void cobol_set_pp_option(int opt);
void cobol_filename_restore();
const char * cobol_lineno( int );
-int cobol_lineno();
+int cobol_lineno(void);
unsigned long gb4( size_t input );
diff --git a/gcc/common.opt b/gcc/common.opt
index d68d7d8..70659fa 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -1447,7 +1447,7 @@ Driver Common Joined RejectNegative Var(flag_diagnostics_show_color) Enum(diagno
; Required for these enum values.
SourceInclude
-diagnostic-color.h
+diagnostics/color.h
Enum
Name(diagnostic_color_rule) Type(int)
@@ -1471,7 +1471,7 @@ Driver Common Joined RejectNegative Var(flag_diagnostics_show_urls) Enum(diagnos
; Required for these enum values.
SourceInclude
-diagnostic-url.h
+diagnostics/url.h
Enum
Name(diagnostic_url_rule) Type(int)
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 8ed1113..0d8dbc4 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -3504,10 +3504,9 @@ sparc*-*-solaris2*)
sparc64-*-* | sparcv9-*-*)
tm_file="sparc/default64.h ${tm_file}"
;;
- *)
- test x$with_cpu != x || with_cpu=v9
- ;;
esac
+ # Match Studio 12.6 cc.
+ with_cpu=${with_cpu:-ultrasparc3}
tmake_file="${tmake_file} sparc/t-sparc sparc/t-sol2"
;;
sparc-wrs-vxworks)
diff --git a/gcc/config/aarch64/aarch64-cost-tables.h b/gcc/config/aarch64/aarch64-cost-tables.h
index c49ff7f..e7926eb 100644
--- a/gcc/config/aarch64/aarch64-cost-tables.h
+++ b/gcc/config/aarch64/aarch64-cost-tables.h
@@ -125,9 +125,9 @@ const struct cpu_cost_table qdf24xx_extra_costs =
{
COSTS_N_INSNS (1), /* alu. */
COSTS_N_INSNS (4), /* mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -233,9 +233,9 @@ const struct cpu_cost_table thunderx_extra_costs =
{
COSTS_N_INSNS (1), /* Alu. */
COSTS_N_INSNS (4), /* mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -340,9 +340,9 @@ const struct cpu_cost_table thunderx2t99_extra_costs =
{
COSTS_N_INSNS (1), /* Alu. */
COSTS_N_INSNS (4), /* Mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -447,9 +447,9 @@ const struct cpu_cost_table thunderx3t110_extra_costs =
{
COSTS_N_INSNS (1), /* Alu. */
COSTS_N_INSNS (4), /* Mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -555,9 +555,9 @@ const struct cpu_cost_table tsv110_extra_costs =
{
COSTS_N_INSNS (1), /* alu. */
COSTS_N_INSNS (4), /* mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -662,9 +662,9 @@ const struct cpu_cost_table a64fx_extra_costs =
{
COSTS_N_INSNS (1), /* alu. */
COSTS_N_INSNS (4), /* mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -769,9 +769,9 @@ const struct cpu_cost_table ampere1_extra_costs =
{
COSTS_N_INSNS (3), /* alu. */
COSTS_N_INSNS (3), /* mult. */
- COSTS_N_INSNS (2), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (1), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -876,9 +876,9 @@ const struct cpu_cost_table ampere1a_extra_costs =
{
COSTS_N_INSNS (3), /* alu. */
COSTS_N_INSNS (3), /* mult. */
- COSTS_N_INSNS (2), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (1), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -983,9 +983,9 @@ const struct cpu_cost_table ampere1b_extra_costs =
{
COSTS_N_INSNS (1), /* alu. */
COSTS_N_INSNS (2), /* mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (1), /* dup. */
- COSTS_N_INSNS (1) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (0), /* dup. */
+ COSTS_N_INSNS (0) /* extract. */
}
};
diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index 270cb2f..8b75c3d 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -1190,13 +1190,16 @@
[(set_attr "type" "neon_ins<q>, neon_from_gp<q>, neon_load1_one_lane<q>")]
)
+;; Inserting from the zero register into a vector lane is treated as an
+;; expensive GP->FP move on all CPUs. Avoid it when optimizing for speed.
(define_insn "aarch64_simd_vec_set_zero<mode>"
[(set (match_operand:VALL_F16 0 "register_operand" "=w")
(vec_merge:VALL_F16
(match_operand:VALL_F16 1 "register_operand" "0")
(match_operand:VALL_F16 3 "aarch64_simd_imm_zero" "")
(match_operand:SI 2 "immediate_operand" "i")))]
- "TARGET_SIMD && aarch64_exact_log2_inverse (<nunits>, operands[2]) >= 0"
+ "TARGET_SIMD && aarch64_exact_log2_inverse (<nunits>, operands[2]) >= 0
+ && optimize_function_for_size_p (cfun)"
{
int elt = ENDIAN_LANE_N (<nunits>,
aarch64_exact_log2_inverse (<nunits>,
diff --git a/gcc/config/aarch64/aarch64-sve.md b/gcc/config/aarch64/aarch64-sve.md
index 10aecf1..b252eef 100644
--- a/gcc/config/aarch64/aarch64-sve.md
+++ b/gcc/config/aarch64/aarch64-sve.md
@@ -3752,9 +3752,9 @@
;; Unpredicated floating-point unary operations.
(define_insn "@aarch64_sve_<optab><mode>"
- [(set (match_operand:SVE_FULL_F 0 "register_operand" "=w")
- (unspec:SVE_FULL_F
- [(match_operand:SVE_FULL_F 1 "register_operand" "w")]
+ [(set (match_operand:SVE_F 0 "register_operand" "=w")
+ (unspec:SVE_F
+ [(match_operand:SVE_F 1 "register_operand" "w")]
SVE_FP_UNARY))]
"TARGET_SVE"
"<sve_fp_op>\t%0.<Vetype>, %1.<Vetype>"
@@ -3762,25 +3762,41 @@
;; Unpredicated floating-point unary operations.
(define_expand "<optab><mode>2"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
[(match_dup 2)
- (const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F 1 "register_operand")]
+ (match_dup 3)
+ (match_operand:SVE_F 1 "register_operand")]
SVE_COND_FP_UNARY_OPTAB))]
"TARGET_SVE"
{
+ operands[2] = aarch64_sve_fp_pred (<MODE>mode, &operands[3]);
+ }
+)
+
+;; FABS and FNEG are non-trapping, so we can always expand with a <VPRED>
+;; predicate. It doesn't matter whether the padding bits of a partial
+;; vector mode are active or inactive.
+(define_expand "<optab><mode>2"
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
+ [(match_dup 2)
+ (const_int SVE_RELAXED_GP)
+ (match_operand:SVE_F 1 "register_operand")]
+ SVE_COND_FP_UNARY_BITWISE))]
+ "TARGET_SVE"
+ {
operands[2] = aarch64_ptrue_reg (<VPRED>mode);
}
)
;; Predicated floating-point unary operations.
(define_insn "@aarch64_pred_<optab><mode>"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
- [(match_operand:<VPRED> 1 "register_operand")
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
+ [(match_operand:<VPRED> 1 "aarch64_predicate_operand")
(match_operand:SI 3 "aarch64_sve_gp_strictness")
- (match_operand:SVE_FULL_F 2 "register_operand")]
+ (match_operand:SVE_F 2 "register_operand")]
SVE_COND_FP_UNARY))]
"TARGET_SVE"
{@ [ cons: =0 , 1 , 2 ; attrs: movprfx ]
@@ -3806,13 +3822,13 @@
;; Predicated floating-point unary arithmetic, merging with the first input.
(define_insn_and_rewrite "*cond_<optab><mode>_2_relaxed"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
[(match_operand:<VPRED> 1 "register_operand")
- (unspec:SVE_FULL_F
+ (unspec:SVE_F
[(match_operand 3)
(const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F 2 "register_operand")]
+ (match_operand:SVE_F 2 "register_operand")]
SVE_COND_FP_UNARY)
(match_dup 2)]
UNSPEC_SEL))]
@@ -3854,15 +3870,15 @@
;; as earlyclobber helps to make the instruction more regular to the
;; register allocator.
(define_insn_and_rewrite "*cond_<optab><mode>_any_relaxed"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
[(match_operand:<VPRED> 1 "register_operand")
- (unspec:SVE_FULL_F
+ (unspec:SVE_F
[(match_operand 4)
(const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F 2 "register_operand")]
+ (match_operand:SVE_F 2 "register_operand")]
SVE_COND_FP_UNARY)
- (match_operand:SVE_FULL_F 3 "aarch64_simd_reg_or_zero")]
+ (match_operand:SVE_F 3 "aarch64_simd_reg_or_zero")]
UNSPEC_SEL))]
"TARGET_SVE && !rtx_equal_p (operands[2], operands[3])"
{@ [ cons: =0 , 1 , 2 , 3 ; attrs: movprfx ]
@@ -5495,27 +5511,25 @@
;; Split a predicated instruction whose predicate is unused into an
;; unpredicated instruction.
(define_split
- [(set (match_operand:SVE_FULL_F_B16B16 0 "register_operand")
- (unspec:SVE_FULL_F_B16B16
+ [(set (match_operand:SVE_F_B16B16 0 "register_operand")
+ (unspec:SVE_F_B16B16
[(match_operand:<VPRED> 1 "register_operand")
- (match_operand:SI 4 "aarch64_sve_gp_strictness")
- (match_operand:SVE_FULL_F_B16B16 2 "register_operand")
- (match_operand:SVE_FULL_F_B16B16 3 "register_operand")]
+ (const_int SVE_RELAXED_GP)
+ (match_operand:SVE_F_B16B16 2 "register_operand")
+ (match_operand:SVE_F_B16B16 3 "register_operand")]
<SVE_COND_FP>))]
- "TARGET_SVE
- && reload_completed
- && INTVAL (operands[4]) == SVE_RELAXED_GP"
+ "TARGET_SVE && reload_completed"
[(set (match_dup 0)
- (SVE_UNPRED_FP_BINARY:SVE_FULL_F_B16B16 (match_dup 2) (match_dup 3)))]
+ (SVE_UNPRED_FP_BINARY:SVE_F_B16B16 (match_dup 2) (match_dup 3)))]
)
;; Unpredicated floating-point binary operations (post-RA only).
;; These are generated by the split above.
(define_insn "*post_ra_<sve_fp_op><mode>3"
- [(set (match_operand:SVE_FULL_F_B16B16 0 "register_operand" "=w")
- (SVE_UNPRED_FP_BINARY:SVE_FULL_F_B16B16
- (match_operand:SVE_FULL_F_B16B16 1 "register_operand" "w")
- (match_operand:SVE_FULL_F_B16B16 2 "register_operand" "w")))]
+ [(set (match_operand:SVE_F_B16B16 0 "register_operand" "=w")
+ (SVE_UNPRED_FP_BINARY:SVE_F_B16B16
+ (match_operand:SVE_F_B16B16 1 "register_operand" "w")
+ (match_operand:SVE_F_B16B16 2 "register_operand" "w")))]
"TARGET_SVE && reload_completed"
"<b><sve_fp_op>\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>")
@@ -5547,10 +5561,10 @@
;; Unpredicated floating-point binary operations.
(define_insn "@aarch64_sve_<optab><mode>"
- [(set (match_operand:SVE_FULL_F 0 "register_operand" "=w")
- (unspec:SVE_FULL_F
- [(match_operand:SVE_FULL_F 1 "register_operand" "w")
- (match_operand:SVE_FULL_F 2 "register_operand" "w")]
+ [(set (match_operand:SVE_F 0 "register_operand" "=w")
+ (unspec:SVE_F
+ [(match_operand:SVE_F 1 "register_operand" "w")
+ (match_operand:SVE_F 2 "register_operand" "w")]
SVE_FP_BINARY))]
"TARGET_SVE"
"<sve_fp_op>\t%0.<Vetype>, %1.<Vetype>, %2.<Vetype>"
@@ -5559,27 +5573,27 @@
;; Unpredicated floating-point binary operations that need to be predicated
;; for SVE.
(define_expand "<optab><mode>3"
- [(set (match_operand:SVE_FULL_F_B16B16 0 "register_operand")
- (unspec:SVE_FULL_F_B16B16
+ [(set (match_operand:SVE_F_B16B16 0 "register_operand")
+ (unspec:SVE_F_B16B16
[(match_dup 3)
- (const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F_B16B16 1 "<sve_pred_fp_rhs1_operand>")
- (match_operand:SVE_FULL_F_B16B16 2 "<sve_pred_fp_rhs2_operand>")]
+ (match_dup 4)
+ (match_operand:SVE_F_B16B16 1 "<sve_pred_fp_rhs1_operand>")
+ (match_operand:SVE_F_B16B16 2 "<sve_pred_fp_rhs2_operand>")]
SVE_COND_FP_BINARY_OPTAB))]
"TARGET_SVE && (<supports_bf16> || !<is_bf16>)"
{
- operands[3] = aarch64_ptrue_reg (<VPRED>mode);
+ operands[3] = aarch64_sve_fp_pred (<MODE>mode, &operands[4]);
}
)
;; Predicated floating-point binary operations that have no immediate forms.
(define_insn "@aarch64_pred_<optab><mode>"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
- [(match_operand:<VPRED> 1 "register_operand")
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
+ [(match_operand:<VPRED> 1 "aarch64_predicate_operand")
(match_operand:SI 4 "aarch64_sve_gp_strictness")
- (match_operand:SVE_FULL_F 2 "register_operand")
- (match_operand:SVE_FULL_F 3 "register_operand")]
+ (match_operand:SVE_F 2 "register_operand")
+ (match_operand:SVE_F 3 "register_operand")]
SVE_COND_FP_BINARY_REG))]
"TARGET_SVE"
{@ [ cons: =0 , 1 , 2 , 3 ; attrs: movprfx ]
@@ -5607,14 +5621,14 @@
;; Predicated floating-point operations, merging with the first input.
(define_insn_and_rewrite "*cond_<optab><mode>_2_relaxed"
- [(set (match_operand:SVE_FULL_F_B16B16 0 "register_operand")
- (unspec:SVE_FULL_F_B16B16
+ [(set (match_operand:SVE_F_B16B16 0 "register_operand")
+ (unspec:SVE_F_B16B16
[(match_operand:<VPRED> 1 "register_operand")
- (unspec:SVE_FULL_F_B16B16
+ (unspec:SVE_F_B16B16
[(match_operand 4)
(const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F_B16B16 2 "register_operand")
- (match_operand:SVE_FULL_F_B16B16 3 "register_operand")]
+ (match_operand:SVE_F_B16B16 2 "register_operand")
+ (match_operand:SVE_F_B16B16 3 "register_operand")]
SVE_COND_FP_BINARY)
(match_dup 2)]
UNSPEC_SEL))]
@@ -5650,14 +5664,14 @@
;; Same for operations that take a 1-bit constant.
(define_insn_and_rewrite "*cond_<optab><mode>_2_const_relaxed"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
[(match_operand:<VPRED> 1 "register_operand")
- (unspec:SVE_FULL_F
+ (unspec:SVE_F
[(match_operand 4)
(const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F 2 "register_operand")
- (match_operand:SVE_FULL_F 3 "<sve_pred_fp_rhs2_immediate>")]
+ (match_operand:SVE_F 2 "register_operand")
+ (match_operand:SVE_F 3 "<sve_pred_fp_rhs2_immediate>")]
SVE_COND_FP_BINARY_I1)
(match_dup 2)]
UNSPEC_SEL))]
@@ -5693,14 +5707,14 @@
;; Predicated floating-point operations, merging with the second input.
(define_insn_and_rewrite "*cond_<optab><mode>_3_relaxed"
- [(set (match_operand:SVE_FULL_F_B16B16 0 "register_operand")
- (unspec:SVE_FULL_F_B16B16
+ [(set (match_operand:SVE_F_B16B16 0 "register_operand")
+ (unspec:SVE_F_B16B16
[(match_operand:<VPRED> 1 "register_operand")
- (unspec:SVE_FULL_F_B16B16
+ (unspec:SVE_F_B16B16
[(match_operand 4)
(const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F_B16B16 2 "register_operand")
- (match_operand:SVE_FULL_F_B16B16 3 "register_operand")]
+ (match_operand:SVE_F_B16B16 2 "register_operand")
+ (match_operand:SVE_F_B16B16 3 "register_operand")]
SVE_COND_FP_BINARY)
(match_dup 3)]
UNSPEC_SEL))]
@@ -5736,16 +5750,16 @@
;; Predicated floating-point operations, merging with an independent value.
(define_insn_and_rewrite "*cond_<optab><mode>_any_relaxed"
- [(set (match_operand:SVE_FULL_F_B16B16 0 "register_operand")
- (unspec:SVE_FULL_F_B16B16
+ [(set (match_operand:SVE_F_B16B16 0 "register_operand")
+ (unspec:SVE_F_B16B16
[(match_operand:<VPRED> 1 "register_operand")
- (unspec:SVE_FULL_F_B16B16
+ (unspec:SVE_F_B16B16
[(match_operand 5)
(const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F_B16B16 2 "register_operand")
- (match_operand:SVE_FULL_F_B16B16 3 "register_operand")]
+ (match_operand:SVE_F_B16B16 2 "register_operand")
+ (match_operand:SVE_F_B16B16 3 "register_operand")]
SVE_COND_FP_BINARY)
- (match_operand:SVE_FULL_F_B16B16 4 "aarch64_simd_reg_or_zero")]
+ (match_operand:SVE_F_B16B16 4 "aarch64_simd_reg_or_zero")]
UNSPEC_SEL))]
"TARGET_SVE
&& (<supports_bf16> || !<is_bf16>)
@@ -5818,16 +5832,16 @@
;; Same for operations that take a 1-bit constant.
(define_insn_and_rewrite "*cond_<optab><mode>_any_const_relaxed"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
[(match_operand:<VPRED> 1 "register_operand")
- (unspec:SVE_FULL_F
+ (unspec:SVE_F
[(match_operand 5)
(const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F 2 "register_operand")
- (match_operand:SVE_FULL_F 3 "<sve_pred_fp_rhs2_immediate>")]
+ (match_operand:SVE_F 2 "register_operand")
+ (match_operand:SVE_F 3 "<sve_pred_fp_rhs2_immediate>")]
SVE_COND_FP_BINARY_I1)
- (match_operand:SVE_FULL_F 4 "aarch64_simd_reg_or_zero")]
+ (match_operand:SVE_F 4 "aarch64_simd_reg_or_zero")]
UNSPEC_SEL))]
"TARGET_SVE && !rtx_equal_p (operands[2], operands[4])"
{@ [ cons: =0 , 1 , 2 , 4 ]
@@ -5892,12 +5906,12 @@
;; Predicated floating-point addition.
(define_insn "@aarch64_pred_<optab><mode>"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
- [(match_operand:<VPRED> 1 "register_operand")
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
+ [(match_operand:<VPRED> 1 "aarch64_predicate_operand")
(match_operand:SI 4 "aarch64_sve_gp_strictness")
- (match_operand:SVE_FULL_F 2 "register_operand")
- (match_operand:SVE_FULL_F 3 "aarch64_sve_float_arith_with_sub_operand")]
+ (match_operand:SVE_F 2 "register_operand")
+ (match_operand:SVE_F 3 "aarch64_sve_float_arith_with_sub_operand")]
SVE_COND_FP_ADD))]
"TARGET_SVE"
{@ [ cons: =0 , 1 , %2 , 3 , 4 ; attrs: movprfx ]
@@ -5914,14 +5928,14 @@
;; Predicated floating-point addition of a constant, merging with the
;; first input.
(define_insn_and_rewrite "*cond_add<mode>_2_const_relaxed"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
[(match_operand:<VPRED> 1 "register_operand")
- (unspec:SVE_FULL_F
+ (unspec:SVE_F
[(match_operand 4)
(const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F 2 "register_operand")
- (match_operand:SVE_FULL_F 3 "aarch64_sve_float_arith_with_sub_immediate")]
+ (match_operand:SVE_F 2 "register_operand")
+ (match_operand:SVE_F 3 "aarch64_sve_float_arith_with_sub_immediate")]
UNSPEC_COND_FADD)
(match_dup 2)]
UNSPEC_SEL))]
@@ -5962,16 +5976,16 @@
;; Predicated floating-point addition of a constant, merging with an
;; independent value.
(define_insn_and_rewrite "*cond_add<mode>_any_const_relaxed"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
[(match_operand:<VPRED> 1 "register_operand")
- (unspec:SVE_FULL_F
+ (unspec:SVE_F
[(match_operand 5)
(const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F 2 "register_operand")
- (match_operand:SVE_FULL_F 3 "aarch64_sve_float_arith_with_sub_immediate")]
+ (match_operand:SVE_F 2 "register_operand")
+ (match_operand:SVE_F 3 "aarch64_sve_float_arith_with_sub_immediate")]
UNSPEC_COND_FADD)
- (match_operand:SVE_FULL_F 4 "aarch64_simd_reg_or_zero")]
+ (match_operand:SVE_F 4 "aarch64_simd_reg_or_zero")]
UNSPEC_SEL))]
"TARGET_SVE && !rtx_equal_p (operands[2], operands[4])"
{@ [ cons: =0 , 1 , 2 , 3 , 4 ]
@@ -6208,12 +6222,12 @@
;; Predicated floating-point subtraction.
(define_insn "@aarch64_pred_<optab><mode>"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
- [(match_operand:<VPRED> 1 "register_operand")
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
+ [(match_operand:<VPRED> 1 "aarch64_predicate_operand")
(match_operand:SI 4 "aarch64_sve_gp_strictness")
- (match_operand:SVE_FULL_F 2 "aarch64_sve_float_arith_operand")
- (match_operand:SVE_FULL_F 3 "register_operand")]
+ (match_operand:SVE_F 2 "aarch64_sve_float_arith_operand")
+ (match_operand:SVE_F 3 "register_operand")]
SVE_COND_FP_SUB))]
"TARGET_SVE"
{@ [ cons: =0 , 1 , 2 , 3 , 4 ; attrs: movprfx ]
@@ -6229,14 +6243,14 @@
;; Predicated floating-point subtraction from a constant, merging with the
;; second input.
(define_insn_and_rewrite "*cond_sub<mode>_3_const_relaxed"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
[(match_operand:<VPRED> 1 "register_operand")
- (unspec:SVE_FULL_F
+ (unspec:SVE_F
[(match_operand 4)
(const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F 2 "aarch64_sve_float_arith_immediate")
- (match_operand:SVE_FULL_F 3 "register_operand")]
+ (match_operand:SVE_F 2 "aarch64_sve_float_arith_immediate")
+ (match_operand:SVE_F 3 "register_operand")]
UNSPEC_COND_FSUB)
(match_dup 3)]
UNSPEC_SEL))]
@@ -6273,16 +6287,16 @@
;; Predicated floating-point subtraction from a constant, merging with an
;; independent value.
(define_insn_and_rewrite "*cond_sub<mode>_const_relaxed"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
[(match_operand:<VPRED> 1 "register_operand")
- (unspec:SVE_FULL_F
+ (unspec:SVE_F
[(match_operand 5)
(const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F 2 "aarch64_sve_float_arith_immediate")
- (match_operand:SVE_FULL_F 3 "register_operand")]
+ (match_operand:SVE_F 2 "aarch64_sve_float_arith_immediate")
+ (match_operand:SVE_F 3 "register_operand")]
UNSPEC_COND_FSUB)
- (match_operand:SVE_FULL_F 4 "aarch64_simd_reg_or_zero")]
+ (match_operand:SVE_F 4 "aarch64_simd_reg_or_zero")]
UNSPEC_SEL))]
"TARGET_SVE && !rtx_equal_p (operands[3], operands[4])"
{@ [ cons: =0 , 1 , 3 , 4 ]
@@ -6631,12 +6645,12 @@
;; Predicated floating-point multiplication.
(define_insn "@aarch64_pred_<optab><mode>"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
- [(match_operand:<VPRED> 1 "register_operand")
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
+ [(match_operand:<VPRED> 1 "aarch64_predicate_operand")
(match_operand:SI 4 "aarch64_sve_gp_strictness")
- (match_operand:SVE_FULL_F 2 "register_operand")
- (match_operand:SVE_FULL_F 3 "aarch64_sve_float_mul_operand")]
+ (match_operand:SVE_F 2 "register_operand")
+ (match_operand:SVE_F 3 "aarch64_sve_float_mul_operand")]
SVE_COND_FP_MUL))]
"TARGET_SVE"
{@ [ cons: =0 , 1 , %2 , 3 , 4 ; attrs: movprfx ]
@@ -6671,12 +6685,12 @@
;; -------------------------------------------------------------------------
(define_expand "div<mode>3"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
[(match_dup 3)
- (const_int SVE_RELAXED_GP)
- (match_operand:SVE_FULL_F 1 "nonmemory_operand")
- (match_operand:SVE_FULL_F 2 "register_operand")]
+ (match_dup 4)
+ (match_operand:SVE_F 1 "nonmemory_operand")
+ (match_operand:SVE_F 2 "register_operand")]
UNSPEC_COND_FDIV))]
"TARGET_SVE"
{
@@ -6684,23 +6698,23 @@
DONE;
operands[1] = force_reg (<MODE>mode, operands[1]);
- operands[3] = aarch64_ptrue_reg (<VPRED>mode);
+ operands[3] = aarch64_sve_fp_pred (<MODE>mode, &operands[4]);
}
)
(define_expand "@aarch64_frecpe<mode>"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
- [(match_operand:SVE_FULL_F 1 "register_operand")]
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
+ [(match_operand:SVE_F 1 "register_operand")]
UNSPEC_FRECPE))]
"TARGET_SVE"
)
(define_expand "@aarch64_frecps<mode>"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
- [(match_operand:SVE_FULL_F 1 "register_operand")
- (match_operand:SVE_FULL_F 2 "register_operand")]
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
+ [(match_operand:SVE_F 1 "register_operand")
+ (match_operand:SVE_F 2 "register_operand")]
UNSPEC_FRECPS))]
"TARGET_SVE"
)
@@ -6865,12 +6879,12 @@
;; Predicated floating-point maximum/minimum.
(define_insn "@aarch64_pred_<optab><mode>"
- [(set (match_operand:SVE_FULL_F 0 "register_operand")
- (unspec:SVE_FULL_F
- [(match_operand:<VPRED> 1 "register_operand")
+ [(set (match_operand:SVE_F 0 "register_operand")
+ (unspec:SVE_F
+ [(match_operand:<VPRED> 1 "aarch64_predicate_operand")
(match_operand:SI 4 "aarch64_sve_gp_strictness")
- (match_operand:SVE_FULL_F 2 "register_operand")
- (match_operand:SVE_FULL_F 3 "aarch64_sve_float_maxmin_operand")]
+ (match_operand:SVE_F 2 "register_operand")
+ (match_operand:SVE_F 3 "aarch64_sve_float_maxmin_operand")]
SVE_COND_FP_MAXMIN))]
"TARGET_SVE"
{@ [ cons: =0 , 1 , %2 , 3 ; attrs: movprfx ]
@@ -9653,6 +9667,31 @@
}
)
+;; As above, for pairs that are used by the auto-vectorizer only.
+(define_insn_and_rewrite "*cond_<optab>_nontrunc<SVE_PARTIAL_F:mode><SVE_HSDI:mode>_relaxed"
+ [(set (match_operand:SVE_HSDI 0 "register_operand")
+ (unspec:SVE_HSDI
+ [(match_operand:<SVE_HSDI:VPRED> 1 "register_operand")
+ (unspec:SVE_HSDI
+ [(match_operand 4)
+ (const_int SVE_RELAXED_GP)
+ (match_operand:SVE_PARTIAL_F 2 "register_operand")]
+ SVE_COND_FCVTI)
+ (match_operand:SVE_HSDI 3 "aarch64_simd_reg_or_zero")]
+ UNSPEC_SEL))]
+ "TARGET_SVE
+ && (~(<SVE_HSDI:self_mask> | <SVE_HSDI:narrower_mask>) & <SVE_PARTIAL_F:self_mask>) == 0"
+ {@ [ cons: =0 , 1 , 2 , 3 ; attrs: movprfx ]
+ [ &w , Upl , w , 0 ; * ] fcvtz<su>\t%0.<SVE_HSDI:Vetype>, %1/m, %2.<SVE_PARTIAL_F:Vetype>
+ [ &w , Upl , w , Dz ; yes ] movprfx\t%0.<SVE_HSDI:Vetype>, %1/z, %2.<SVE_HSDI:Vetype>\;fcvtz<su>\t%0.<SVE_HSDI:Vetype>, %1/m, %2.<SVE_PARTIAL_F:Vetype>
+ [ ?&w , Upl , w , w ; yes ] movprfx\t%0, %3\;fcvtz<su>\t%0.<SVE_HSDI:Vetype>, %1/m, %2.<SVE_PARTIAL_F:Vetype>
+ }
+ "&& !rtx_equal_p (operands[1], operands[4])"
+ {
+ operands[4] = copy_rtx (operands[1]);
+ }
+)
+
(define_insn "*cond_<optab>_nontrunc<SVE_FULL_F:mode><SVE_FULL_HSDI:mode>_strict"
[(set (match_operand:SVE_FULL_HSDI 0 "register_operand")
(unspec:SVE_FULL_HSDI
@@ -9706,6 +9745,29 @@
}
)
+(define_insn_and_rewrite "*cond_<optab>_trunc<VNx2DF_ONLY:mode><VNx2SI_ONLY:mode>_relaxed"
+ [(set (match_operand:VNx2SI_ONLY 0 "register_operand")
+ (unspec:VNx2SI_ONLY
+ [(match_operand:VNx2BI 1 "register_operand")
+ (unspec:VNx2SI_ONLY
+ [(match_operand 4)
+ (const_int SVE_RELAXED_GP)
+ (match_operand:VNx2DF_ONLY 2 "register_operand")]
+ SVE_COND_FCVTI)
+ (match_operand:VNx2SI_ONLY 3 "aarch64_simd_reg_or_zero")]
+ UNSPEC_SEL))]
+ "TARGET_SVE"
+ {@ [ cons: =0 , 1 , 2 , 3 ; attrs: movprfx ]
+ [ &w , Upl , w , 0 ; * ] fcvtz<su>\t%0.<VNx2SI_ONLY:Vetype>, %1/m, %2.<VNx2DF_ONLY:Vetype>
+ [ &w , Upl , w , Dz ; yes ] movprfx\t%0.<VNx2DF_ONLY:Vetype>, %1/z, %2.<VNx2DF_ONLY:Vetype>\;fcvtz<su>\t%0.<VNx2SI_ONLY:Vetype>, %1/m, %2.<VNx2DF_ONLY:Vetype>
+ [ ?&w , Upl , w , w ; yes ] movprfx\t%0, %3\;fcvtz<su>\t%0.<VNx2SI_ONLY:Vetype>, %1/m, %2.<VNx2DF_ONLY:Vetype>
+ }
+ "&& !rtx_equal_p (operands[1], operands[4])"
+ {
+ operands[4] = copy_rtx (operands[1]);
+ }
+)
+
;; -------------------------------------------------------------------------
;; ---- [INT<-FP] Packs
;; -------------------------------------------------------------------------
@@ -9857,6 +9919,31 @@
}
)
+;; As above, for pairs that are used by the auto-vectorizer only.
+(define_insn_and_rewrite "*cond_<optab>_nonextend<SVE_HSDI:mode><SVE_PARTIAL_F:mode>_relaxed"
+ [(set (match_operand:SVE_PARTIAL_F 0 "register_operand")
+ (unspec:SVE_PARTIAL_F
+ [(match_operand:<SVE_HSDI:VPRED> 1 "register_operand")
+ (unspec:SVE_PARTIAL_F
+ [(match_operand 4)
+ (const_int SVE_RELAXED_GP)
+ (match_operand:SVE_HSDI 2 "register_operand")]
+ SVE_COND_ICVTF)
+ (match_operand:SVE_PARTIAL_F 3 "aarch64_simd_reg_or_zero")]
+ UNSPEC_SEL))]
+ "TARGET_SVE
+ && (~(<SVE_HSDI:self_mask> | <SVE_HSDI:narrower_mask>) & <SVE_PARTIAL_F:self_mask>) == 0"
+ {@ [ cons: =0 , 1 , 2 , 3 ; attrs: movprfx ]
+ [ &w , Upl , w , 0 ; * ] <su>cvtf\t%0.<SVE_PARTIAL_F:Vetype>, %1/m, %2.<SVE_HSDI:Vetype>
+ [ &w , Upl , w , Dz ; yes ] movprfx\t%0.<SVE_HSDI:Vetype>, %1/z, %2.<SVE_HSDI:Vetype>\;<su>cvtf\t%0.<SVE_PARTIAL_F:Vetype>, %1/m, %2.<SVE_HSDI:Vetype>
+ [ ?&w , Upl , w , w ; yes ] movprfx\t%0, %3\;<su>cvtf\t%0.<SVE_PARTIAL_F:Vetype>, %1/m, %2.<SVE_HSDI:Vetype>
+ }
+ "&& !rtx_equal_p (operands[1], operands[4])"
+ {
+ operands[4] = copy_rtx (operands[1]);
+ }
+)
+
(define_insn "*cond_<optab>_nonextend<SVE_FULL_HSDI:mode><SVE_FULL_F:mode>_strict"
[(set (match_operand:SVE_FULL_F 0 "register_operand")
(unspec:SVE_FULL_F
@@ -10066,6 +10153,30 @@
}
)
+;; As above, for pairs that are used by the auto-vectorizer only.
+(define_insn_and_rewrite "*cond_<optab>_trunc<SVE_SDF:mode><SVE_PARTIAL_HSF:mode>"
+ [(set (match_operand:SVE_PARTIAL_HSF 0 "register_operand")
+ (unspec:SVE_PARTIAL_HSF
+ [(match_operand:<SVE_SDF:VPRED> 1 "register_operand")
+ (unspec:SVE_PARTIAL_HSF
+ [(match_operand 4)
+ (const_int SVE_RELAXED_GP)
+ (match_operand:SVE_SDF 2 "register_operand")]
+ SVE_COND_FCVT)
+ (match_operand:SVE_PARTIAL_HSF 3 "aarch64_simd_reg_or_zero")]
+ UNSPEC_SEL))]
+ "TARGET_SVE && (~<SVE_SDF:narrower_mask> & <SVE_PARTIAL_HSF:self_mask>) == 0"
+ {@ [ cons: =0 , 1 , 2 , 3 ; attrs: movprfx ]
+ [ w , Upl , w , 0 ; * ] fcvt\t%0.<SVE_PARTIAL_HSF:Vetype>, %1/m, %2.<SVE_SDF:Vetype>
+ [ ?&w , Upl , w , Dz ; yes ] movprfx\t%0.<SVE_SDF:Vetype>, %1/z, %2.<SVE_SDF:Vetype>\;fcvt\t%0.<SVE_PARTIAL_HSF:Vetype>, %1/m, %2.<SVE_SDF:Vetype>
+ [ ?&w , Upl , w , w ; yes ] movprfx\t%0, %3\;fcvt\t%0.<SVE_PARTIAL_HSF:Vetype>, %1/m, %2.<SVE_SDF:Vetype>
+ }
+ "&& !rtx_equal_p (operands[1], operands[4])"
+ {
+ operands[4] = copy_rtx (operands[1]);
+ }
+)
+
;; -------------------------------------------------------------------------
;; ---- [FP<-FP] Packs (bfloat16)
;; -------------------------------------------------------------------------
@@ -10259,6 +10370,30 @@
}
)
+;; As above, for pairs that are used by the auto-vectorizer only.
+(define_insn_and_rewrite "*cond_<optab>_nontrunc<SVE_PARTIAL_HSF:mode><SVE_SDF:mode>_relaxed"
+ [(set (match_operand:SVE_SDF 0 "register_operand")
+ (unspec:SVE_SDF
+ [(match_operand:<SVE_SDF:VPRED> 1 "register_operand")
+ (unspec:SVE_SDF
+ [(match_operand 4)
+ (const_int SVE_RELAXED_GP)
+ (match_operand:SVE_PARTIAL_HSF 2 "register_operand")]
+ SVE_COND_FCVT)
+ (match_operand:SVE_SDF 3 "aarch64_simd_reg_or_zero")]
+ UNSPEC_SEL))]
+ "TARGET_SVE && (~<SVE_SDF:narrower_mask> & <SVE_PARTIAL_HSF:self_mask>) == 0"
+ {@ [ cons: =0 , 1 , 2 , 3 ; attrs: movprfx ]
+ [ w , Upl , w , 0 ; * ] fcvt\t%0.<SVE_SDF:Vetype>, %1/m, %2.<SVE_PARTIAL_HSF:Vetype>
+ [ ?&w , Upl , w , Dz ; yes ] movprfx\t%0.<SVE_SDF:Vetype>, %1/z, %2.<SVE_SDF:Vetype>\;fcvt\t%0.<SVE_SDF:Vetype>, %1/m, %2.<SVE_PARTIAL_HSF:Vetype>
+ [ ?&w , Upl , w , w ; yes ] movprfx\t%0, %3\;fcvt\t%0.<SVE_SDF:Vetype>, %1/m, %2.<SVE_PARTIAL_HSF:Vetype>
+ }
+ "&& !rtx_equal_p (operands[1], operands[4])"
+ {
+ operands[4] = copy_rtx (operands[1]);
+ }
+)
+
;; -------------------------------------------------------------------------
;; ---- [PRED<-PRED] Packs
;; -------------------------------------------------------------------------
diff --git a/gcc/config/aarch64/aarch64-sve2.md b/gcc/config/aarch64/aarch64-sve2.md
index 8c03e28..31bdd85 100644
--- a/gcc/config/aarch64/aarch64-sve2.md
+++ b/gcc/config/aarch64/aarch64-sve2.md
@@ -1346,12 +1346,12 @@
;; Predicated B16B16 binary operations.
(define_insn "@aarch64_pred_<optab><mode>"
- [(set (match_operand:VNx8BF_ONLY 0 "register_operand")
- (unspec:VNx8BF_ONLY
- [(match_operand:<VPRED> 1 "register_operand")
+ [(set (match_operand:SVE_BF 0 "register_operand")
+ (unspec:SVE_BF
+ [(match_operand:<VPRED> 1 "aarch64_predicate_operand")
(match_operand:SI 4 "aarch64_sve_gp_strictness")
- (match_operand:VNx8BF_ONLY 2 "register_operand")
- (match_operand:VNx8BF_ONLY 3 "register_operand")]
+ (match_operand:SVE_BF 2 "register_operand")
+ (match_operand:SVE_BF 3 "register_operand")]
SVE_COND_FP_BINARY_OPTAB))]
"TARGET_SSVE_B16B16 && <supports_bf16>"
{@ [ cons: =0 , 1 , 2 , 3 ; attrs: movprfx , is_rev ]
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 0485f69..4d9d83d 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -356,7 +356,8 @@ static int aarch64_address_cost (rtx, machine_mode, addr_space_t, bool);
static bool aarch64_builtin_support_vector_misalignment (machine_mode mode,
const_tree type,
int misalignment,
- bool is_packed);
+ bool is_packed,
+ bool is_gather_scatter);
static machine_mode aarch64_simd_container_mode (scalar_mode, poly_int64);
static bool aarch64_print_address_internal (FILE*, machine_mode, rtx,
aarch64_addr_query_type);
@@ -15854,11 +15855,14 @@ cost_plus:
break;
case CONST_VECTOR:
{
- /* Load using MOVI/MVNI. */
- if (aarch64_simd_valid_mov_imm (x))
- *cost = extra_cost->vect.movi;
- else /* Load using constant pool. */
- *cost = extra_cost->ldst.load;
+ if (speed)
+ {
+ /* Load using MOVI/MVNI. */
+ if (aarch64_simd_valid_mov_imm (x))
+ *cost += extra_cost->vect.movi;
+ else /* Load using constant pool. */
+ *cost += extra_cost->ldst.load;
+ }
break;
}
case VEC_CONCAT:
@@ -15867,7 +15871,8 @@ cost_plus:
break;
case VEC_DUPLICATE:
/* Load using a DUP. */
- *cost = extra_cost->vect.dup;
+ if (speed)
+ *cost += extra_cost->vect.dup;
return false;
case VEC_SELECT:
{
@@ -15875,13 +15880,16 @@ cost_plus:
*cost = rtx_cost (op0, GET_MODE (op0), VEC_SELECT, 0, speed);
/* cost subreg of 0 as free, otherwise as DUP */
- rtx op1 = XEXP (x, 1);
- if (vec_series_lowpart_p (mode, GET_MODE (op1), op1))
- ;
- else if (vec_series_highpart_p (mode, GET_MODE (op1), op1))
- *cost = extra_cost->vect.dup;
- else
- *cost = extra_cost->vect.extract;
+ if (speed)
+ {
+ rtx op1 = XEXP (x, 1);
+ if (vec_series_lowpart_p (mode, GET_MODE (op1), op1))
+ ;
+ else if (vec_series_highpart_p (mode, GET_MODE (op1), op1))
+ *cost += extra_cost->vect.dup;
+ else
+ *cost += extra_cost->vect.extract;
+ }
return true;
}
default:
@@ -17969,6 +17977,7 @@ aarch64_vector_costs::add_stmt_cost (int count, vect_cost_for_stmt kind,
/* Check if we've seen an SVE gather/scatter operation and which size. */
if (kind == scalar_load
+ && vectype
&& aarch64_sve_mode_p (TYPE_MODE (vectype))
&& vect_mem_access_type (stmt_info, node) == VMAT_GATHER_SCATTER)
{
@@ -19958,8 +19967,9 @@ aarch64_process_one_target_attr (char *arg_str)
if (valid)
{
set_option (&global_options, NULL, p_attr->opt_num, value,
- NULL, DK_UNSPECIFIED, input_location,
- global_dc);
+ NULL,
+ static_cast<int> (diagnostics::kind::unspecified),
+ input_location, global_dc);
}
else
{
@@ -24406,10 +24416,14 @@ aarch64_simd_vector_alignment_reachable (const_tree type, bool is_packed)
static bool
aarch64_builtin_support_vector_misalignment (machine_mode mode,
const_tree type, int misalignment,
- bool is_packed)
+ bool is_packed,
+ bool is_gather_scatter)
{
if (TARGET_SIMD && STRICT_ALIGNMENT)
{
+ if (is_gather_scatter)
+ return true;
+
/* Return if movmisalign pattern is not supported for this mode. */
if (optab_handler (movmisalign_optab, mode) == CODE_FOR_nothing)
return false;
@@ -24419,7 +24433,8 @@ aarch64_builtin_support_vector_misalignment (machine_mode mode,
return false;
}
return default_builtin_support_vector_misalignment (mode, type, misalignment,
- is_packed);
+ is_packed,
+ is_gather_scatter);
}
/* If VALS is a vector constant that can be loaded into a register
diff --git a/gcc/config/aarch64/cortex-a57-fma-steering.cc b/gcc/config/aarch64/cortex-a57-fma-steering.cc
index fd6da66..f7675be 100644
--- a/gcc/config/aarch64/cortex-a57-fma-steering.cc
+++ b/gcc/config/aarch64/cortex-a57-fma-steering.cc
@@ -948,6 +948,11 @@ func_fma_steering::analyze ()
/* Search the chain where this instruction is (one of) the root. */
dest_op_info = insn_rr[INSN_UID (insn)].op_info;
+
+ /* Register rename could fail. */
+ if (!dest_op_info)
+ continue;
+
dest_regno = REGNO (SET_DEST (PATTERN (insn)));
for (i = 0; i < dest_op_info->n_chains; i++)
{
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index c59fcd6..8533912 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -463,6 +463,7 @@
(define_mode_iterator VNx8SI_ONLY [VNx8SI])
(define_mode_iterator VNx8SF_ONLY [VNx8SF])
(define_mode_iterator VNx8DI_ONLY [VNx8DI])
+(define_mode_iterator VNx2SI_ONLY [VNx2SI])
(define_mode_iterator VNx4SI_ONLY [VNx4SI])
(define_mode_iterator VNx4SF_ONLY [VNx4SF])
(define_mode_iterator VNx2DI_ONLY [VNx2DI])
@@ -3366,6 +3367,10 @@
(define_int_iterator SVE_INT_UNARY [UNSPEC_REVB
UNSPEC_REVH UNSPEC_REVW])
+;; This iterator is currently only used for estimation instructions,
+;; which are never generated automatically when -ftrapping-math is true.
+;; The iterator is therefore applied unconditionally to partial FP modes.
+;; This might need to be revisited if new operations are added in future.
(define_int_iterator SVE_FP_UNARY [UNSPEC_FRECPE UNSPEC_RSQRTE])
(define_int_iterator SVE_FP_UNARY_INT [(UNSPEC_FEXPA "TARGET_NON_STREAMING")])
@@ -3378,6 +3383,10 @@
(define_int_iterator SVE_INT_BINARY_MULTI [UNSPEC_SQDMULH
UNSPEC_SRSHL UNSPEC_URSHL])
+;; This iterator is currently only used for estimation instructions,
+;; which are never generated automatically when -ftrapping-math is true.
+;; The iterator is therefore applied unconditionally to partial FP modes.
+;; This might need to be revisited if new operations are added in future.
(define_int_iterator SVE_FP_BINARY [UNSPEC_FRECPS UNSPEC_RSQRTS])
(define_int_iterator SVE_FP_BINARY_INT [UNSPEC_FTSMUL UNSPEC_FTSSEL])
@@ -3429,9 +3438,10 @@
UNSPEC_FMINQV
UNSPEC_FMINNMQV])
-(define_int_iterator SVE_COND_FP_UNARY [UNSPEC_COND_FABS
- UNSPEC_COND_FNEG
- UNSPEC_COND_FRECPX
+(define_int_iterator SVE_COND_FP_UNARY_BITWISE [UNSPEC_COND_FABS
+ UNSPEC_COND_FNEG])
+
+(define_int_iterator SVE_COND_FP_UNARY [UNSPEC_COND_FRECPX
UNSPEC_COND_FRINTA
UNSPEC_COND_FRINTI
UNSPEC_COND_FRINTM
@@ -3439,13 +3449,12 @@
UNSPEC_COND_FRINTP
UNSPEC_COND_FRINTX
UNSPEC_COND_FRINTZ
- UNSPEC_COND_FSQRT])
+ UNSPEC_COND_FSQRT
+ SVE_COND_FP_UNARY_BITWISE])
;; Same as SVE_COND_FP_UNARY, but without codes that have a dedicated
;; <optab><mode>2 expander.
-(define_int_iterator SVE_COND_FP_UNARY_OPTAB [UNSPEC_COND_FABS
- UNSPEC_COND_FNEG
- UNSPEC_COND_FRECPX
+(define_int_iterator SVE_COND_FP_UNARY_OPTAB [UNSPEC_COND_FRECPX
UNSPEC_COND_FRINTA
UNSPEC_COND_FRINTI
UNSPEC_COND_FRINTM
diff --git a/gcc/config/arm/aarch-cost-tables.h b/gcc/config/arm/aarch-cost-tables.h
index c7a14b3..0600e59 100644
--- a/gcc/config/arm/aarch-cost-tables.h
+++ b/gcc/config/arm/aarch-cost-tables.h
@@ -123,9 +123,9 @@ const struct cpu_cost_table generic_extra_costs =
{
COSTS_N_INSNS (1), /* alu. */
COSTS_N_INSNS (4), /* mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -230,9 +230,9 @@ const struct cpu_cost_table cortexa53_extra_costs =
{
COSTS_N_INSNS (1), /* alu. */
COSTS_N_INSNS (4), /* mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -337,9 +337,9 @@ const struct cpu_cost_table cortexa57_extra_costs =
{
COSTS_N_INSNS (1), /* alu. */
COSTS_N_INSNS (4), /* mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -444,9 +444,9 @@ const struct cpu_cost_table cortexa76_extra_costs =
{
COSTS_N_INSNS (1), /* alu. */
COSTS_N_INSNS (4), /* mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -551,9 +551,9 @@ const struct cpu_cost_table exynosm1_extra_costs =
{
COSTS_N_INSNS (0), /* alu. */
COSTS_N_INSNS (4), /* mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
@@ -658,9 +658,9 @@ const struct cpu_cost_table xgene1_extra_costs =
{
COSTS_N_INSNS (2), /* alu. */
COSTS_N_INSNS (8), /* mult. */
- COSTS_N_INSNS (1), /* movi. */
- COSTS_N_INSNS (2), /* dup. */
- COSTS_N_INSNS (2) /* extract. */
+ COSTS_N_INSNS (0), /* movi. */
+ COSTS_N_INSNS (1), /* dup. */
+ COSTS_N_INSNS (1) /* extract. */
}
};
diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
index bde06f3..29b45ae 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -289,7 +289,8 @@ static bool arm_vector_alignment_reachable (const_tree type, bool is_packed);
static bool arm_builtin_support_vector_misalignment (machine_mode mode,
const_tree type,
int misalignment,
- bool is_packed);
+ bool is_packed,
+ bool is_gather_scatter);
static void arm_conditional_register_usage (void);
static enum flt_eval_method arm_excess_precision (enum excess_precision_type);
static reg_class_t arm_preferred_rename_class (reg_class_t rclass);
@@ -30661,12 +30662,16 @@ arm_vector_alignment_reachable (const_tree type, bool is_packed)
static bool
arm_builtin_support_vector_misalignment (machine_mode mode,
const_tree type, int misalignment,
- bool is_packed)
+ bool is_packed,
+ bool is_gather_scatter)
{
if (TARGET_NEON && !BYTES_BIG_ENDIAN && unaligned_access)
{
HOST_WIDE_INT align = TYPE_ALIGN_UNIT (type);
+ if (is_gather_scatter)
+ return true;
+
if (is_packed)
return align == 1;
@@ -30683,7 +30688,8 @@ arm_builtin_support_vector_misalignment (machine_mode mode,
}
return default_builtin_support_vector_misalignment (mode, type, misalignment,
- is_packed);
+ is_packed,
+ is_gather_scatter);
}
static void
diff --git a/gcc/config/avr/avr-passes.cc b/gcc/config/avr/avr-passes.cc
index 284f49d..6a88a27 100644
--- a/gcc/config/avr/avr-passes.cc
+++ b/gcc/config/avr/avr-passes.cc
@@ -4120,9 +4120,8 @@ avr_optimize_casesi (rtx_insn *insns[5], rtx *xop)
JUMP_LABEL (cbranch) = xop[4];
++LABEL_NUSES (xop[4]);
- rtx_insn *seq1 = get_insns ();
rtx_insn *last1 = get_last_insn ();
- end_sequence ();
+ rtx_insn *seq1 = end_sequence ();
emit_insn_after (seq1, insns[2]);
@@ -4141,9 +4140,8 @@ avr_optimize_casesi (rtx_insn *insns[5], rtx *xop)
emit_insn (pat_4);
- rtx_insn *seq2 = get_insns ();
rtx_insn *last2 = get_last_insn ();
- end_sequence ();
+ rtx_insn *seq2 = end_sequence ();
emit_insn_after (seq2, insns[3]);
diff --git a/gcc/config/cris/cris.cc b/gcc/config/cris/cris.cc
index a34c9e9..4acdd1d 100644
--- a/gcc/config/cris/cris.cc
+++ b/gcc/config/cris/cris.cc
@@ -3711,9 +3711,11 @@ cris_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &inputs,
/* Determine if the source using MOF. If it is, automatically
clobbering MOF would cause it to have impossible constraints. */
- /* Look for a use of the MOF constraint letter: h. */
+ /* Look for a use of the MOF constraint letter h or a hard register
+ constraint. */
for (unsigned i = 0, n = constraints.length(); i < n; ++i)
- if (strchr (constraints[i], 'h') != NULL)
+ if (strchr (constraints[i], 'h') != NULL
+ || strstr (constraints[i], "{mof}") != NULL)
return NULL;
/* Look for an output or an input that touches MOF. */
diff --git a/gcc/config/epiphany/epiphany.cc b/gcc/config/epiphany/epiphany.cc
index 16626f8..f53a643 100644
--- a/gcc/config/epiphany/epiphany.cc
+++ b/gcc/config/epiphany/epiphany.cc
@@ -2816,12 +2816,16 @@ epiphany_vector_alignment_reachable (const_tree type, bool is_packed)
static bool
epiphany_support_vector_misalignment (machine_mode mode, const_tree type,
- int misalignment, bool is_packed)
+ int misalignment, bool is_packed,
+ bool is_gather_scatter)
{
+ if (is_gather_scatter)
+ return true;
if (GET_MODE_SIZE (mode) == 8 && misalignment % 4 == 0)
return true;
return default_builtin_support_vector_misalignment (mode, type, misalignment,
- is_packed);
+ is_packed,
+ is_gather_scatter);
}
/* STRUCTURE_SIZE_BOUNDARY seems a bit crude in how it enlarges small
diff --git a/gcc/config/gcn/gcn-opts.h b/gcc/config/gcn/gcn-opts.h
index 0bfc786..fe68678 100644
--- a/gcc/config/gcn/gcn-opts.h
+++ b/gcc/config/gcn/gcn-opts.h
@@ -82,8 +82,13 @@ enum hsaco_attr_type
#define TARGET_DPP_FULL !TARGET_RDNA2_PLUS
#define TARGET_DPP16 TARGET_RDNA2_PLUS
#define TARGET_DPP8 TARGET_RDNA2_PLUS
+/* Device requires no manually inserted wait states; that's the
+ case for RDNA 2, 3 and 3.5 (but not for RNDA 4). */
+#define TARGET_NO_MANUAL_NOPS TARGET_RDNA2_PLUS
/* Device requires CDNA1-style manually inserted wait states for AVGPRs. */
#define TARGET_AVGPR_CDNA1_NOPS TARGET_CDNA1
+/* Device requires CDNA3-style manually inserted wait states. */
+#define TARGET_CDNA3_NOPS TARGET_CDNA3
/* Whether to use the 'globally coherent' (glc) or the 'scope' (sc0) flag
for non-scalar memory operations. The string starts on purpose with a space.
Note: for scalar memory operations (i.e. 's_...'), 'glc' is still used.
diff --git a/gcc/config/gcn/gcn-valu.md b/gcc/config/gcn/gcn-valu.md
index 7c4dde1..0994329 100644
--- a/gcc/config/gcn/gcn-valu.md
+++ b/gcc/config/gcn/gcn-valu.md
@@ -811,7 +811,7 @@
[(set_attr "type" "vop3a")
(set_attr "length" "8")
(set_attr "exec" "none")
- (set_attr "laneselect" "yes")])
+ (set_attr "laneselect" "write")])
; FIXME: 64bit operations really should be splitters, but I am not sure how
; to represent vertical subregs.
@@ -828,7 +828,7 @@
[(set_attr "type" "vmult")
(set_attr "length" "16")
(set_attr "exec" "none")
- (set_attr "laneselect" "yes")])
+ (set_attr "laneselect" "write")])
(define_expand "vec_set<mode>"
[(set (match_operand:V_MOV 0 "register_operand")
@@ -854,7 +854,7 @@
[(set_attr "type" "vop3a")
(set_attr "length" "8")
(set_attr "exec" "none")
- (set_attr "laneselect" "yes")])
+ (set_attr "laneselect" "write")])
(define_insn "*vec_set<mode>_1"
[(set (match_operand:V_2REG 0 "register_operand" "=v")
@@ -871,7 +871,7 @@
[(set_attr "type" "vmult")
(set_attr "length" "16")
(set_attr "exec" "none")
- (set_attr "laneselect" "yes")])
+ (set_attr "laneselect" "write")])
(define_insn "vec_duplicate<mode><exec>"
[(set (match_operand:V_1REG 0 "register_operand" "=v")
@@ -910,7 +910,7 @@
[(set_attr "type" "vop3a")
(set_attr "length" "8")
(set_attr "exec" "none")
- (set_attr "laneselect" "yes")])
+ (set_attr "laneselect" "read")])
(define_insn "vec_extract<mode><scalar_mode>"
[(set (match_operand:<SCALAR_MODE> 0 "register_operand" "=&Sg")
@@ -922,7 +922,7 @@
[(set_attr "type" "vmult")
(set_attr "length" "16")
(set_attr "exec" "none")
- (set_attr "laneselect" "yes")])
+ (set_attr "laneselect" "read")])
(define_insn "vec_extract<mode><scalar_mode>"
[(set (match_operand:<SCALAR_MODE> 0 "register_operand" "=&Sg")
@@ -934,7 +934,7 @@
[(set_attr "type" "vmult")
(set_attr "length" "32")
(set_attr "exec" "none")
- (set_attr "laneselect" "yes")])
+ (set_attr "laneselect" "read")])
(define_insn "vec_extract<V_1REG:mode><V_1REG_ALT:mode>_nop"
[(set (match_operand:V_1REG_ALT 0 "register_operand" "=v,v")
@@ -1133,6 +1133,23 @@
DONE;
})
+(define_expand "gather_load<mode><vndi>"
+ [(match_operand:V_MOV 0 "register_operand")
+ (match_operand:DI 1 "register_operand")
+ (match_operand:<VnDI> 2 "register_operand")
+ (match_operand 3 "immediate_operand")
+ (match_operand:SI 4 "gcn_alu_operand")]
+ ""
+ {
+ rtx addr = gcn_expand_scaled_offsets (DEFAULT_ADDR_SPACE, operands[1],
+ operands[2], operands[4],
+ INTVAL (operands[3]), NULL);
+
+ emit_insn (gen_gather<mode>_insn_1offset (operands[0], addr, const0_rtx,
+ const0_rtx, const0_rtx));
+ DONE;
+ })
+
; Allow any address expression
(define_expand "gather<mode>_expr<exec>"
[(set (match_operand:V_MOV 0 "register_operand")
@@ -1175,6 +1192,7 @@
return buf;
}
[(set_attr "type" "flat")
+ (set_attr "flatmemaccess" "load")
(set_attr "length" "12")
(set_attr "cdna" "*,cdna2,*,cdna2")
(set_attr "xnack" "off,off,on,on")])
@@ -1233,6 +1251,7 @@
return buf;
}
[(set_attr "type" "flat")
+ (set_attr "flatmemaccess" "load")
(set_attr "length" "12")
(set_attr "cdna" "*,cdna2,*,cdna2")
(set_attr "xnack" "off,off,on,on")])
@@ -1259,6 +1278,23 @@
DONE;
})
+(define_expand "scatter_store<mode><vndi>"
+ [(match_operand:DI 0 "register_operand")
+ (match_operand:<VnDI> 1 "register_operand")
+ (match_operand 2 "immediate_operand")
+ (match_operand:SI 3 "gcn_alu_operand")
+ (match_operand:V_MOV 4 "register_operand")]
+ ""
+ {
+ rtx addr = gcn_expand_scaled_offsets (DEFAULT_ADDR_SPACE, operands[0],
+ operands[1], operands[3],
+ INTVAL (operands[2]), NULL);
+
+ emit_insn (gen_scatter<mode>_insn_1offset (addr, const0_rtx, operands[4],
+ const0_rtx, const0_rtx));
+ DONE;
+ })
+
; Allow any address expression
(define_expand "scatter<mode>_expr<exec_scatter>"
[(set (mem:BLK (scratch))
@@ -1301,6 +1337,7 @@
return buf;
}
[(set_attr "type" "flat")
+ (set_attr "flatmemaccess" "store")
(set_attr "length" "12")
(set_attr "cdna" "*,cdna2")])
@@ -1356,6 +1393,7 @@
return buf;
}
[(set_attr "type" "flat")
+ (set_attr "flatmemaccess" "store")
(set_attr "length" "12")
(set_attr "cdna" "*,cdna2")])
@@ -1645,6 +1683,39 @@
[(set_attr "type" "vmult")
(set_attr "length" "8")])
+(define_insn_and_split "add<mode>3_dup"
+ [(set (match_operand:V_DI 0 "register_operand" "= v")
+ (plus:V_DI
+ (vec_duplicate:V_DI
+ (match_operand:DI 1 "register_operand" "SvB"))
+ (match_operand:V_DI 2 "gcn_alu_operand" "vDb")))
+ (clobber (reg:DI VCC_REG))
+ (clobber (match_scratch:<VnSI> 3 "=&v"))]
+ ""
+ "#"
+ "gcn_can_split_p (<MODE>mode, operands[0])
+ && gcn_can_split_p (<MODE>mode, operands[1])
+ && gcn_can_split_p (<MODE>mode, operands[2])"
+ [(const_int 0)]
+ {
+ rtx vcc = gen_rtx_REG (DImode, VCC_REG);
+ emit_insn (gen_add<vnsi>3_vcc_dup
+ (gcn_operand_part (<MODE>mode, operands[0], 0),
+ gcn_operand_part (DImode, operands[1], 0),
+ gcn_operand_part (<MODE>mode, operands[2], 0),
+ vcc));
+ emit_insn (gen_vec_duplicate<vnsi> (operands[3],
+ gcn_operand_part (DImode, operands[1], 1)));
+ emit_insn (gen_addc<vnsi>3
+ (gcn_operand_part (<MODE>mode, operands[0], 1),
+ operands[3],
+ gcn_operand_part (<MODE>mode, operands[2], 1),
+ vcc, vcc));
+ DONE;
+ }
+ [(set_attr "type" "vmult")
+ (set_attr "length" "8")])
+
(define_insn_and_split "add<mode>3_exec"
[(set (match_operand:V_DI 0 "register_operand" "= v")
(vec_merge:V_DI
@@ -1682,6 +1753,49 @@
[(set_attr "type" "vmult")
(set_attr "length" "8")])
+(define_insn_and_split "add<mode>3_dup_exec"
+ [(set (match_operand:V_DI 0 "register_operand" "= v")
+ (vec_merge:V_DI
+ (plus:V_DI
+ (vec_duplicate:V_DI
+ (match_operand:DI 1 "register_operand" "SvB"))
+ (match_operand:V_DI 2 "gcn_alu_operand" "vDb"))
+ (match_operand:V_DI 3 "gcn_register_or_unspec_operand" " U0")
+ (match_operand:DI 4 "gcn_exec_reg_operand" " e")))
+ (clobber (reg:DI VCC_REG))
+ (clobber (match_scratch:<VnSI> 5 "=&v"))]
+ ""
+ "#"
+ "gcn_can_split_p (<MODE>mode, operands[0])
+ && gcn_can_split_p (<MODE>mode, operands[1])
+ && gcn_can_split_p (<MODE>mode, operands[2])
+ && gcn_can_split_p (<MODE>mode, operands[4])"
+ [(const_int 0)]
+ {
+ rtx vcc = gen_rtx_REG (DImode, VCC_REG);
+ emit_insn (gen_add<vnsi>3_vcc_dup_exec
+ (gcn_operand_part (<MODE>mode, operands[0], 0),
+ gcn_operand_part (DImode, operands[1], 0),
+ gcn_operand_part (<MODE>mode, operands[2], 0),
+ vcc,
+ gcn_operand_part (<MODE>mode, operands[3], 0),
+ operands[4]));
+ emit_insn (gen_vec_duplicate<vnsi>_exec (operands[5],
+ gcn_operand_part (DImode, operands[1], 1),
+ gcn_gen_undef (<VnSI>mode),
+ operands[4]));
+ emit_insn (gen_addc<vnsi>3_exec
+ (gcn_operand_part (<MODE>mode, operands[0], 1),
+ operands[5],
+ gcn_operand_part (<MODE>mode, operands[2], 1),
+ vcc, vcc,
+ gcn_operand_part (<MODE>mode, operands[3], 1),
+ operands[4]));
+ DONE;
+ }
+ [(set_attr "type" "vmult")
+ (set_attr "length" "8")])
+
(define_insn_and_split "sub<mode>3"
[(set (match_operand:V_DI 0 "register_operand" "= v, v")
(minus:V_DI
@@ -2187,6 +2301,22 @@
[(set_attr "type" "vop3a")
(set_attr "length" "8")])
+(define_insn "<su>mul<mode>3_highpart_dup<exec>"
+ [(set (match_operand:V_SI 0 "register_operand" "= v")
+ (truncate:V_SI
+ (lshiftrt:<VnDI>
+ (mult:<VnDI>
+ (any_extend:<VnDI>
+ (vec_duplicate:V_SI
+ (match_operand:SI 1 "gcn_alu_operand" "SvA")))
+ (any_extend:<VnDI>
+ (match_operand:V_SI 2 "gcn_alu_operand" " vA")))
+ (const_int 32))))]
+ ""
+ "v_mul_hi<sgnsuffix>0\t%0, %2, %1"
+ [(set_attr "type" "vop3a")
+ (set_attr "length" "8")])
+
(define_insn "mul<mode>3<exec>"
[(set (match_operand:V_INT_1REG 0 "register_operand" "= v")
(mult:V_INT_1REG
@@ -2198,11 +2328,11 @@
(set_attr "length" "8")])
(define_insn "mul<mode>3_dup<exec>"
- [(set (match_operand:V_INT_1REG 0 "register_operand" "= v")
+ [(set (match_operand:V_INT_1REG 0 "register_operand" "= v")
(mult:V_INT_1REG
- (match_operand:V_INT_1REG 1 "gcn_alu_operand" "%vSvA")
(vec_duplicate:V_INT_1REG
- (match_operand:<SCALAR_MODE> 2 "gcn_alu_operand" " SvA"))))]
+ (match_operand:<SCALAR_MODE> 1 "gcn_alu_operand" "SvA"))
+ (match_operand:V_INT_1REG 2 "gcn_alu_operand" " vA")))]
""
"v_mul_lo_u32\t%0, %1, %2"
[(set_attr "type" "vop3a")
@@ -2238,6 +2368,37 @@
DONE;
})
+(define_insn_and_split "mul<mode>3_dup"
+ [(set (match_operand:V_DI 0 "register_operand" "=&v")
+ (mult:V_DI
+ (vec_duplicate:V_DI
+ (match_operand:DI 1 "gcn_alu_operand" " Sv"))
+ (match_operand:V_DI 2 "gcn_alu_operand" "vDA")))
+ (clobber (match_scratch:<VnSI> 3 "=&v"))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ rtx out_lo = gcn_operand_part (<MODE>mode, operands[0], 0);
+ rtx out_hi = gcn_operand_part (<MODE>mode, operands[0], 1);
+ rtx left_lo = gcn_operand_part (DImode, operands[1], 0);
+ rtx left_hi = gcn_operand_part (DImode, operands[1], 1);
+ rtx right_lo = gcn_operand_part (<MODE>mode, operands[2], 0);
+ rtx right_hi = gcn_operand_part (<MODE>mode, operands[2], 1);
+ rtx tmp = operands[3];
+
+ emit_insn (gen_mul<vnsi>3_dup (out_lo, left_lo, right_lo));
+ emit_insn (gen_umul<vnsi>3_highpart_dup (out_hi, left_lo, right_lo));
+ emit_insn (gen_mul<vnsi>3_dup (tmp, left_hi, right_lo));
+ emit_insn (gen_add<vnsi>3 (out_hi, out_hi, tmp));
+ emit_insn (gen_mul<vnsi>3_dup (tmp, left_lo, right_hi));
+ emit_insn (gen_add<vnsi>3 (out_hi, out_hi, tmp));
+ emit_insn (gen_mul<vnsi>3_dup (tmp, left_hi, right_hi));
+ emit_insn (gen_add<vnsi>3 (out_hi, out_hi, tmp));
+ DONE;
+ })
+
(define_insn_and_split "mul<mode>3_exec"
[(set (match_operand:V_DI 0 "register_operand" "=&v")
(vec_merge:V_DI
@@ -2286,6 +2447,56 @@
DONE;
})
+(define_insn_and_split "mul<mode>3_dup_exec"
+ [(set (match_operand:V_DI 0 "register_operand" "=&v")
+ (vec_merge:V_DI
+ (mult:V_DI
+ (vec_duplicate:V_DI
+ (match_operand:DI 1 "gcn_alu_operand" " Sv"))
+ (match_operand:V_DI 2 "gcn_alu_operand" "vDA"))
+ (match_operand:V_DI 3 "gcn_register_or_unspec_operand" " U0")
+ (match_operand:DI 4 "gcn_exec_reg_operand" " e")))
+ (clobber (match_scratch:<VnSI> 5 "=&v"))]
+ ""
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ {
+ rtx out_lo = gcn_operand_part (<MODE>mode, operands[0], 0);
+ rtx out_hi = gcn_operand_part (<MODE>mode, operands[0], 1);
+ rtx left_lo = gcn_operand_part (DImode, operands[1], 0);
+ rtx left_hi = gcn_operand_part (DImode, operands[1], 1);
+ rtx right_lo = gcn_operand_part (<MODE>mode, operands[2], 0);
+ rtx right_hi = gcn_operand_part (<MODE>mode, operands[2], 1);
+ rtx exec = operands[4];
+ rtx tmp = operands[5];
+
+ rtx old_lo, old_hi;
+ if (GET_CODE (operands[3]) == UNSPEC)
+ {
+ old_lo = old_hi = gcn_gen_undef (<VnSI>mode);
+ }
+ else
+ {
+ old_lo = gcn_operand_part (<MODE>mode, operands[3], 0);
+ old_hi = gcn_operand_part (<MODE>mode, operands[3], 1);
+ }
+
+ rtx undef = gcn_gen_undef (<VnSI>mode);
+
+ emit_insn (gen_mul<vnsi>3_dup_exec (out_lo, left_lo, right_lo, old_lo,
+ exec));
+ emit_insn (gen_umul<vnsi>3_highpart_dup_exec (out_hi, left_lo, right_lo,
+ old_hi, exec));
+ emit_insn (gen_mul<vnsi>3_dup_exec (tmp, left_hi, right_lo, undef, exec));
+ emit_insn (gen_add<vnsi>3_exec (out_hi, out_hi, tmp, out_hi, exec));
+ emit_insn (gen_mul<vnsi>3_dup_exec (tmp, left_lo, right_hi, undef, exec));
+ emit_insn (gen_add<vnsi>3_exec (out_hi, out_hi, tmp, out_hi, exec));
+ emit_insn (gen_mul<vnsi>3_dup_exec (tmp, left_hi, right_hi, undef, exec));
+ emit_insn (gen_add<vnsi>3_exec (out_hi, out_hi, tmp, out_hi, exec));
+ DONE;
+ })
+
(define_insn_and_split "mul<mode>3_zext"
[(set (match_operand:V_DI 0 "register_operand" "=&v")
(mult:V_DI
@@ -3053,7 +3264,8 @@
"flag_unsafe_math_optimizations"
"v_sqrt%i0\t%0, %1"
[(set_attr "type" "vop1")
- (set_attr "length" "8")])
+ (set_attr "length" "8")
+ (set_attr "transop" "yes")])
(define_insn "sqrt<mode>2"
[(set (match_operand:FP 0 "register_operand" "= v")
@@ -3062,7 +3274,8 @@
"flag_unsafe_math_optimizations"
"v_sqrt%i0\t%0, %1"
[(set_attr "type" "vop1")
- (set_attr "length" "8")])
+ (set_attr "length" "8")
+ (set_attr "transop" "yes")])
; These FP unops have f64, f32 and f16 versions.
(define_int_iterator MATH_UNOP_1OR2REG
@@ -3352,7 +3565,8 @@
""
"v_rcp%i0\t%0, %1"
[(set_attr "type" "vop1")
- (set_attr "length" "8")])
+ (set_attr "length" "8")
+ (set_attr "transop" "yes")])
;; v_div_scale takes a numerator (op2) and denominator (op1) and returns the
;; one that matches op3 adjusted for best results in reciprocal division.
@@ -4049,6 +4263,32 @@
DONE;
})
+(define_expand "mask_gather_load<mode><vndi>"
+ [(set:V_MOV (match_operand:V_MOV 0 "register_operand")
+ (unspec:V_MOV
+ [(match_operand:DI 1 "register_operand")
+ (match_operand:<VnDI> 2 "register_operand")
+ (match_operand 3 "immediate_operand")
+ (match_operand:SI 4 "gcn_alu_operand")
+ (match_operand:DI 5 "")
+ (match_operand:V_MOV 6 "maskload_else_operand")]
+ UNSPEC_GATHER))]
+ ""
+ {
+ rtx exec = force_reg (DImode, operands[5]);
+
+ rtx addr = gcn_expand_scaled_offsets (DEFAULT_ADDR_SPACE, operands[1],
+ operands[2], operands[4],
+ INTVAL (operands[3]), exec);
+
+ emit_insn (gen_gather<mode>_insn_1offset_exec (operands[0], addr,
+ const0_rtx, const0_rtx,
+ const0_rtx,
+ gcn_gen_undef (<MODE>mode),
+ exec));
+ DONE;
+ })
+
(define_expand "mask_scatter_store<mode><vnsi>"
[(match_operand:DI 0 "register_operand")
(match_operand:<VnSI> 1 "register_operand")
@@ -4077,6 +4317,27 @@
DONE;
})
+(define_expand "mask_scatter_store<mode><vndi>"
+ [(match_operand:DI 0 "register_operand")
+ (match_operand:<VnDI> 1 "register_operand")
+ (match_operand 2 "immediate_operand")
+ (match_operand:SI 3 "gcn_alu_operand")
+ (match_operand:V_MOV 4 "register_operand")
+ (match_operand:DI 5 "")]
+ ""
+ {
+ rtx exec = force_reg (DImode, operands[5]);
+
+ rtx addr = gcn_expand_scaled_offsets (DEFAULT_ADDR_SPACE, operands[0],
+ operands[1], operands[3],
+ INTVAL (operands[2]), exec);
+
+ emit_insn (gen_scatter<mode>_insn_1offset_exec (addr, const0_rtx,
+ operands[4], const0_rtx,
+ const0_rtx, exec));
+ DONE;
+ })
+
(define_code_iterator cond_op [plus minus mult])
(define_expand "cond_<expander><mode>"
@@ -4397,7 +4658,7 @@
rtx tmp = gen_reg_rtx (<MODE>mode);
rtx v1 = gen_rtx_REG (<MODE>mode, VGPR_REGNO (1));
- emit_insn (gen_mul<mode>3_dup (tmp, v1, operands[2]));
+ emit_insn (gen_mul<mode>3_dup (tmp, operands[2], v1));
emit_insn (gen_add<mode>3_dup (operands[0], tmp, operands[1]));
DONE;
})
diff --git a/gcc/config/gcn/gcn.cc b/gcc/config/gcn/gcn.cc
index 0ce5a29..8959118 100644
--- a/gcc/config/gcn/gcn.cc
+++ b/gcc/config/gcn/gcn.cc
@@ -1275,13 +1275,13 @@ gen_##PREFIX##vN##SUFFIX (PARAMS) \
}
#define GEN_VNM_NOEXEC(PREFIX, SUFFIX, PARAMS, ARGS) \
-GEN_VN_NOEXEC (PREFIX, qi##SUFFIX, A(PARAMS), A(ARGS)) \
-GEN_VN_NOEXEC (PREFIX, hi##SUFFIX, A(PARAMS), A(ARGS)) \
-GEN_VN_NOEXEC (PREFIX, hf##SUFFIX, A(PARAMS), A(ARGS)) \
+USE_QHF (GEN_VN_NOEXEC (PREFIX, qi##SUFFIX, A(PARAMS), A(ARGS))) \
+USE_QHF (GEN_VN_NOEXEC (PREFIX, hi##SUFFIX, A(PARAMS), A(ARGS))) \
+USE_QHF (GEN_VN_NOEXEC (PREFIX, hf##SUFFIX, A(PARAMS), A(ARGS))) \
GEN_VN_NOEXEC (PREFIX, si##SUFFIX, A(PARAMS), A(ARGS)) \
-GEN_VN_NOEXEC (PREFIX, sf##SUFFIX, A(PARAMS), A(ARGS)) \
+USE_QHF (GEN_VN_NOEXEC (PREFIX, sf##SUFFIX, A(PARAMS), A(ARGS))) \
GEN_VN_NOEXEC (PREFIX, di##SUFFIX, A(PARAMS), A(ARGS)) \
-GEN_VN_NOEXEC (PREFIX, df##SUFFIX, A(PARAMS), A(ARGS)) \
+USE_QHF (GEN_VN_NOEXEC (PREFIX, df##SUFFIX, A(PARAMS), A(ARGS))) \
static rtx \
gen_##PREFIX##vNm##SUFFIX (PARAMS) \
{ \
@@ -1289,13 +1289,13 @@ gen_##PREFIX##vNm##SUFFIX (PARAMS) \
\
switch (mode) \
{ \
- case E_QImode: return gen_##PREFIX##vNqi##SUFFIX (ARGS); \
- case E_HImode: return gen_##PREFIX##vNhi##SUFFIX (ARGS); \
- case E_HFmode: return gen_##PREFIX##vNhf##SUFFIX (ARGS); \
+ USE_QHF (case E_QImode: return gen_##PREFIX##vNqi##SUFFIX (ARGS);) \
+ USE_QHF (case E_HImode: return gen_##PREFIX##vNhi##SUFFIX (ARGS);) \
+ USE_QHF (case E_HFmode: return gen_##PREFIX##vNhf##SUFFIX (ARGS);) \
case E_SImode: return gen_##PREFIX##vNsi##SUFFIX (ARGS); \
- case E_SFmode: return gen_##PREFIX##vNsf##SUFFIX (ARGS); \
+ USE_QHF (case E_SFmode: return gen_##PREFIX##vNsf##SUFFIX (ARGS);) \
case E_DImode: return gen_##PREFIX##vNdi##SUFFIX (ARGS); \
- case E_DFmode: return gen_##PREFIX##vNdf##SUFFIX (ARGS); \
+ USE_QHF (case E_DFmode: return gen_##PREFIX##vNdf##SUFFIX (ARGS);) \
default: \
break; \
} \
@@ -1340,13 +1340,13 @@ gen_##PREFIX##vN##SUFFIX (PARAMS, rtx merge_src=NULL, rtx exec=NULL) \
}
#define GEN_VNM(PREFIX, SUFFIX, PARAMS, ARGS) \
-GEN_VN (PREFIX, qi##SUFFIX, A(PARAMS), A(ARGS)) \
-GEN_VN (PREFIX, hi##SUFFIX, A(PARAMS), A(ARGS)) \
-GEN_VN (PREFIX, hf##SUFFIX, A(PARAMS), A(ARGS)) \
+USE_QHF (GEN_VN (PREFIX, qi##SUFFIX, A(PARAMS), A(ARGS))) \
+USE_QHF (GEN_VN (PREFIX, hi##SUFFIX, A(PARAMS), A(ARGS))) \
+USE_QHF (GEN_VN (PREFIX, hf##SUFFIX, A(PARAMS), A(ARGS))) \
GEN_VN (PREFIX, si##SUFFIX, A(PARAMS), A(ARGS)) \
-GEN_VN (PREFIX, sf##SUFFIX, A(PARAMS), A(ARGS)) \
+USE_QHF (GEN_VN (PREFIX, sf##SUFFIX, A(PARAMS), A(ARGS))) \
GEN_VN (PREFIX, di##SUFFIX, A(PARAMS), A(ARGS)) \
-GEN_VN (PREFIX, df##SUFFIX, A(PARAMS), A(ARGS)) \
+USE_QHF (GEN_VN (PREFIX, df##SUFFIX, A(PARAMS), A(ARGS))) \
USE_TI (GEN_VN (PREFIX, ti##SUFFIX, A(PARAMS), A(ARGS))) \
static rtx \
gen_##PREFIX##vNm##SUFFIX (PARAMS, rtx merge_src=NULL, rtx exec=NULL) \
@@ -1355,15 +1355,22 @@ gen_##PREFIX##vNm##SUFFIX (PARAMS, rtx merge_src=NULL, rtx exec=NULL) \
\
switch (mode) \
{ \
- case E_QImode: return gen_##PREFIX##vNqi##SUFFIX (ARGS, merge_src, exec); \
- case E_HImode: return gen_##PREFIX##vNhi##SUFFIX (ARGS, merge_src, exec); \
- case E_HFmode: return gen_##PREFIX##vNhf##SUFFIX (ARGS, merge_src, exec); \
- case E_SImode: return gen_##PREFIX##vNsi##SUFFIX (ARGS, merge_src, exec); \
- case E_SFmode: return gen_##PREFIX##vNsf##SUFFIX (ARGS, merge_src, exec); \
- case E_DImode: return gen_##PREFIX##vNdi##SUFFIX (ARGS, merge_src, exec); \
- case E_DFmode: return gen_##PREFIX##vNdf##SUFFIX (ARGS, merge_src, exec); \
- case E_TImode: \
- USE_TI (return gen_##PREFIX##vNti##SUFFIX (ARGS, merge_src, exec);) \
+ USE_QHF (case E_QImode: \
+ return gen_##PREFIX##vNqi##SUFFIX (ARGS, merge_src, exec);) \
+ USE_QHF (case E_HImode: \
+ return gen_##PREFIX##vNhi##SUFFIX (ARGS, merge_src, exec);) \
+ USE_QHF (case E_HFmode: \
+ return gen_##PREFIX##vNhf##SUFFIX (ARGS, merge_src, exec);) \
+ case E_SImode: \
+ return gen_##PREFIX##vNsi##SUFFIX (ARGS, merge_src, exec); \
+ USE_QHF (case E_SFmode: \
+ return gen_##PREFIX##vNsf##SUFFIX (ARGS, merge_src, exec);) \
+ case E_DImode: \
+ return gen_##PREFIX##vNdi##SUFFIX (ARGS, merge_src, exec); \
+ USE_QHF (case E_DFmode: \
+ return gen_##PREFIX##vNdf##SUFFIX (ARGS, merge_src, exec);) \
+ USE_TI (case E_TImode: \
+ return gen_##PREFIX##vNti##SUFFIX (ARGS, merge_src, exec);) \
default: \
break; \
} \
@@ -1372,7 +1379,8 @@ gen_##PREFIX##vNm##SUFFIX (PARAMS, rtx merge_src=NULL, rtx exec=NULL) \
return NULL_RTX; \
}
-/* These have TImode support. */
+/* These support everything. */
+#define USE_QHF(ARGS) ARGS
#define USE_TI(ARGS) ARGS
GEN_VNM (mov,, A(rtx dest, rtx src), A(dest, src))
GEN_VNM (vec_duplicate,, A(rtx dest, rtx src), A(dest, src))
@@ -1382,6 +1390,7 @@ GEN_VNM (vec_duplicate,, A(rtx dest, rtx src), A(dest, src))
#define USE_TI(ARGS)
GEN_VNM (add,3, A(rtx dest, rtx src1, rtx src2), A(dest, src1, src2))
GEN_VN (add,si3_dup, A(rtx dest, rtx src1, rtx src2), A(dest, src1, src2))
+GEN_VN (add,di3_dup, A(rtx dest, rtx src1, rtx src2), A(dest, src1, src2))
GEN_VN (add,si3_vcc_dup, A(rtx dest, rtx src1, rtx src2, rtx vcc),
A(dest, src1, src2, vcc))
GEN_VN (add,di3_sext_dup2, A(rtx dest, rtx src1, rtx src2), A(dest, src1, src2))
@@ -1393,15 +1402,20 @@ GEN_VN (add,di3_vcc_zext_dup2, A(rtx dest, rtx src1, rtx src2, rtx vcc),
GEN_VN (addc,si3, A(rtx dest, rtx src1, rtx src2, rtx vccout, rtx vccin),
A(dest, src1, src2, vccout, vccin))
GEN_VN (and,si3, A(rtx dest, rtx src1, rtx src2), A(dest, src1, src2))
-GEN_VN (ashl,si3, A(rtx dest, rtx src, rtx shift), A(dest, src, shift))
GEN_VNM_NOEXEC (ds_bpermute,, A(rtx dest, rtx addr, rtx src, rtx exec),
A(dest, addr, src, exec))
GEN_VNM (gather,_expr, A(rtx dest, rtx addr, rtx as, rtx vol),
A(dest, addr, as, vol))
-GEN_VN (mul,si3_dup, A(rtx dest, rtx src1, rtx src2), A(dest, src1, src2))
GEN_VN (sub,si3, A(rtx dest, rtx src1, rtx src2), A(dest, src1, src2))
GEN_VN_NOEXEC (vec_series,si, A(rtx dest, rtx x, rtx c), A(dest, x, c))
+/* These do not have QI, HI, or any FP support. */
+#undef USE_QHF
+#define USE_QHF(ARGS)
+GEN_VNM (ashl,3, A(rtx dest, rtx src, rtx shift), A(dest, src, shift))
+GEN_VNM (mul,3_dup, A(rtx dest, rtx src1, rtx src2), A(dest, src1, src2))
+
+#undef USE_QHF
#undef USE_TI
#undef GEN_VNM
#undef GEN_VN
@@ -1995,8 +2009,8 @@ gcn_expand_vector_init (rtx op0, rtx vec)
rtx addr = gen_reg_rtx (addrmode);
int unit_size = GET_MODE_SIZE (GET_MODE_INNER (GET_MODE (op0)));
- emit_insn (gen_mulvNsi3_dup (ramp, gen_rtx_REG (offsetmode, VGPR_REGNO (1)),
- GEN_INT (unit_size)));
+ emit_insn (gen_mulvNsi3_dup (ramp, GEN_INT (unit_size),
+ gen_rtx_REG (offsetmode, VGPR_REGNO (1))));
bool simple_repeat = true;
@@ -2293,36 +2307,46 @@ gcn_expand_scalar_to_vector_address (machine_mode mode, rtx exec, rtx mem,
Return values.
ADDR_SPACE_FLAT - return VnDImode vector of absolute addresses.
- ADDR_SPACE_GLOBAL - return VnSImode vector of offsets. */
+ ADDR_SPACE_GLOBAL - return VnSImode vector of offsets.
+ 64-bit offsets - return VnDImode vector of absolute addresses. */
rtx
gcn_expand_scaled_offsets (addr_space_t as, rtx base, rtx offsets, rtx scale,
bool unsigned_p, rtx exec)
{
int vf = GET_MODE_NUNITS (GET_MODE (offsets));
- rtx tmpsi = gen_reg_rtx (VnMODE (vf, SImode));
- rtx tmpdi = gen_reg_rtx (VnMODE (vf, DImode));
+ rtx scaled_offsets = gen_reg_rtx (GET_MODE (offsets));
+ rtx abs_addr = gen_reg_rtx (VnMODE (vf, DImode));
+ bool use_di = GET_MODE_INNER (GET_MODE (scaled_offsets)) == DImode;
if (CONST_INT_P (scale)
&& INTVAL (scale) > 0
&& exact_log2 (INTVAL (scale)) >= 0)
- emit_insn (gen_ashlvNsi3 (tmpsi, offsets,
- GEN_INT (exact_log2 (INTVAL (scale))),
- NULL, exec));
+ emit_insn (gen_ashlvNm3 (scaled_offsets, offsets,
+ GEN_INT (exact_log2 (INTVAL (scale))),
+ NULL, exec));
else
- emit_insn (gen_mulvNsi3_dup (tmpsi, offsets, scale, NULL, exec));
+ emit_insn (gen_mulvNm3_dup (scaled_offsets, scale, offsets, NULL, exec));
+ /* No instructions support DImode offsets. */
+ if (use_di)
+ {
+ emit_insn (gen_addvNdi3_dup (abs_addr, base, scaled_offsets, NULL, exec));
+ return abs_addr;
+ }
/* "Global" instructions do not support negative register offsets. */
- if (as == ADDR_SPACE_FLAT || !unsigned_p)
+ else if (as == ADDR_SPACE_FLAT || !unsigned_p)
{
if (unsigned_p)
- emit_insn (gen_addvNdi3_zext_dup2 (tmpdi, tmpsi, base, NULL, exec));
+ emit_insn (gen_addvNdi3_zext_dup2 (abs_addr, scaled_offsets, base,
+ NULL, exec));
else
- emit_insn (gen_addvNdi3_sext_dup2 (tmpdi, tmpsi, base, NULL, exec));
- return tmpdi;
+ emit_insn (gen_addvNdi3_sext_dup2 (abs_addr, scaled_offsets, base,
+ NULL, exec));
+ return abs_addr;
}
else if (as == ADDR_SPACE_GLOBAL)
- return tmpsi;
+ return scaled_offsets;
gcc_unreachable ();
}
@@ -5315,8 +5339,12 @@ gcn_preferred_vector_alignment (const_tree type)
static bool
gcn_vectorize_support_vector_misalignment (machine_mode ARG_UNUSED (mode),
const_tree type, int misalignment,
- bool is_packed)
+ bool is_packed,
+ bool is_gather_scatter)
{
+ if (is_gather_scatter)
+ return true;
+
if (is_packed)
return false;
@@ -5764,6 +5792,42 @@ gcn_libc_has_function (enum function_class fn_class,
/* }}} */
/* {{{ md_reorg pass. */
+/* Identify V_CMPX from the "type" attribute;
+ note: this will also match 'v_cmp %E1 vcc'. */
+
+static bool
+gcn_cmpx_insn_p (attr_type type)
+{
+ switch (type)
+ {
+ case TYPE_VOPC:
+ return true;
+ case TYPE_MUBUF:
+ case TYPE_MTBUF:
+ case TYPE_FLAT:
+ case TYPE_VOP3P_MAI:
+ case TYPE_UNKNOWN:
+ case TYPE_SOP1:
+ case TYPE_SOP2:
+ case TYPE_SOPK:
+ case TYPE_SOPC:
+ case TYPE_SOPP:
+ case TYPE_SMEM:
+ case TYPE_DS:
+ case TYPE_VOP2:
+ case TYPE_VOP1:
+ case TYPE_VOP3A:
+ case TYPE_VOP3B:
+ case TYPE_VOP_SDWA:
+ case TYPE_VOP_DPP:
+ case TYPE_MULT:
+ case TYPE_VMULT:
+ return false;
+ }
+ gcc_unreachable ();
+ return false;
+}
+
/* Identify VMEM instructions from their "type" attribute. */
static bool
@@ -6124,12 +6188,22 @@ gcn_md_reorg (void)
detects the missed cases, and inserts the documented number of NOPs
required for correct execution. */
+ /* RDNA4 (not yet implemented) differs from RNDA 2/3/3.5 and requires some
+ s_nop, see 5.7 and esp. 5.7.2. in its ISA manual.
+ The assert here is a reminder to add those. */
+ STATIC_ASSERT (ISA_CDNA1 - ISA_RDNA3 == 1);
+
+ if (TARGET_NO_MANUAL_NOPS)
+ return;
+
const int max_waits = 5;
struct ilist
{
rtx_insn *insn;
attr_unit unit;
- attr_delayeduse delayeduse;
+ attr_type type;
+ attr_flatmemaccess flatmemaccess;
+ bool delayeduse;
HARD_REG_SET writes;
HARD_REG_SET reads;
int age;
@@ -6150,7 +6224,29 @@ gcn_md_reorg (void)
attr_type itype = get_attr_type (insn);
attr_unit iunit = get_attr_unit (insn);
- attr_delayeduse idelayeduse = get_attr_delayeduse (insn);
+ attr_flatmemaccess iflatmemaccess = get_attr_flatmemaccess (insn);
+ bool delayeduse;
+ if (TARGET_CDNA3_NOPS)
+ switch (iflatmemaccess)
+ {
+ case FLATMEMACCESS_STORE:
+ case FLATMEMACCESS_STOREX34:
+ case FLATMEMACCESS_ATOMIC:
+ case FLATMEMACCESS_CMPSWAPX2:
+ delayeduse = true;
+ break;
+ case FLATMEMACCESS_LOAD:
+ case FLATMEMACCESS_ATOMICWAIT:
+ case FLATMEMACCESS_NO:
+ delayeduse = false;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ else
+ delayeduse = (iflatmemaccess == FLATMEMACCESS_CMPSWAPX2
+ || iflatmemaccess == FLATMEMACCESS_STOREX34);
+
int ivccwait = get_attr_vccwait (insn);
HARD_REG_SET ireads, iwrites;
CLEAR_HARD_REG_SET (ireads);
@@ -6195,16 +6291,26 @@ gcn_md_reorg (void)
&& TEST_HARD_REG_BIT (ireads, VCCZ_REG))))
nops_rqd = 5 - prev_insn->age;
- /* VALU writes SGPR/VCC followed by v_{read,write}lane using
- SGPR/VCC as lane select requires 4 wait states. */
+ /* VALU writes SGPR/VCC followed by
+ - v_{read,write}lane using SGPR/VCC as lane select requires
+ 4 wait states
+ - [CDNA3] VALU reads SGPR as constant requires 1 wait state
+ - [CDNA3] VALU reads SGPR as carry-in requires no wait states */
if ((prev_insn->age + nops_rqd) < 4
&& prev_insn->unit == UNIT_VECTOR
- && get_attr_laneselect (insn) == LANESELECT_YES
+ && get_attr_laneselect (insn) != LANESELECT_NO
&& (hard_reg_set_intersect_p
(depregs, reg_class_contents[(int) SGPR_REGS])
|| hard_reg_set_intersect_p
(depregs, reg_class_contents[(int) VCC_CONDITIONAL_REG])))
nops_rqd = 4 - prev_insn->age;
+ else if (TARGET_CDNA3_NOPS
+ && (prev_insn->age + nops_rqd) < 1
+ && prev_insn->unit == UNIT_VECTOR
+ && iunit == UNIT_VECTOR
+ && hard_reg_set_intersect_p
+ (depregs, reg_class_contents[(int) SGPR_REGS]))
+ nops_rqd = 1 - prev_insn->age;
/* VALU writes VGPR followed by VALU_DPP reading that VGPR
requires 2 wait states. */
@@ -6217,22 +6323,88 @@ gcn_md_reorg (void)
nops_rqd = 2 - prev_insn->age;
}
+ /* VALU writes EXEC followed by VALU DPP op requires 5 nop. */
+ if ((prev_insn->age + nops_rqd) < 5
+ && itype == TYPE_VOP_DPP
+ && prev_insn->unit == UNIT_VECTOR
+ && TEST_HARD_REG_BIT (prev_insn->writes, EXECZ_REG))
+ nops_rqd = 5 - prev_insn->age;
+
/* Store that requires input registers are not overwritten by
- following instruction. */
- if ((prev_insn->age + nops_rqd) < 1
- && prev_insn->delayeduse == DELAYEDUSE_YES
+ following instruction.
+ For CDNA3, only, VALU writes require 2 not 1 nop.
+ CDNA3 additionally requires that 1 or 2 nop for global & scatch
+ store/atomic. */
+ if (TARGET_CDNA3_NOPS
+ && (prev_insn->age + nops_rqd) < 2
+ && prev_insn->delayeduse
+ && iunit == UNIT_VECTOR
+ && ((hard_reg_set_intersect_p
+ (prev_insn->reads, iwrites))))
+ nops_rqd = 2 - prev_insn->age;
+ else if ((prev_insn->age + nops_rqd) < 1
+ && prev_insn->delayeduse
&& ((hard_reg_set_intersect_p
(prev_insn->reads, iwrites))))
nops_rqd = 1 - prev_insn->age;
- /* Instruction that requires VCC is not written too close before
- using it. */
+ /* Instruction (such as v_div_fmas) that requires VCC is not written
+ too close before using it */
if (prev_insn->age < ivccwait
&& (hard_reg_set_intersect_p
(prev_insn->writes,
reg_class_contents[(int)VCC_CONDITIONAL_REG])))
nops_rqd = ivccwait - prev_insn->age;
+ /* CDNA3: v_cmpx followed by
+ - V_readlane, v_readfirstlane, v_writelane requires 4 wait states
+ - VALU reads EXEC as constant requires 2 wait states
+ - other VALU requires no wait state */
+ if (TARGET_CDNA3_NOPS
+ && (prev_insn->age + nops_rqd) < 4
+ && gcn_cmpx_insn_p (prev_insn->type)
+ && get_attr_laneselect (insn) != LANESELECT_NO)
+ nops_rqd = 4 - prev_insn->age;
+ else if (TARGET_CDNA3_NOPS
+ && (prev_insn->age + nops_rqd) < 2
+ && iunit == UNIT_VECTOR
+ && gcn_cmpx_insn_p (prev_insn->type)
+ && TEST_HARD_REG_BIT (ireads, EXECZ_REG))
+ nops_rqd = 2 - prev_insn->age;
+
+ /* CDNA3: VALU writes VGPR followed by v_readlane vsrc0 reads VGPRn
+ requires 1 wait state. */
+ if (TARGET_CDNA3_NOPS
+ && (prev_insn->age + nops_rqd) < 1
+ && prev_insn->unit == UNIT_VECTOR
+ && prev_insn->flatmemaccess != FLATMEMACCESS_LOAD
+ && get_attr_laneselect (insn) == LANESELECT_READ
+ && hard_reg_set_intersect_p
+ (depregs, reg_class_contents[(int) VGPR_REGS]))
+ nops_rqd = 1 - prev_insn->age;
+
+ /* CDNA3: VALU op which uses OPSEL or SDWA with changes the result's
+ bit position followed by VALU op consumes result of that op
+ requires 1 wait state.
+ FIXME: Handle OPSEL, once used. */
+ if (TARGET_CDNA3_NOPS
+ && (prev_insn->age + nops_rqd) < 1
+ && prev_insn->unit == UNIT_VECTOR
+ && prev_insn->type == TYPE_VOP_SDWA
+ && !hard_reg_set_empty_p (depregs))
+ nops_rqd = 1 - prev_insn->age;
+
+ /* CNDA3: VALU Trans Op (such as v_rcp_f64) followed by non-trans VALU
+ op consumes result of that op requires 1 wait state. */
+ if (TARGET_CDNA3_NOPS
+ && (prev_insn->age + nops_rqd) < 1
+ && prev_insn->unit == UNIT_VECTOR
+ && iunit == UNIT_VECTOR
+ && get_attr_transop (prev_insn->insn) == TRANSOP_YES
+ && get_attr_transop (insn) == TRANSOP_NO
+ && !hard_reg_set_empty_p (depregs))
+ nops_rqd = 1 - prev_insn->age;
+
/* CDNA1: write VGPR before v_accvgpr_write reads it. */
if (TARGET_AVGPR_CDNA1_NOPS
&& (prev_insn->age + nops_rqd) < 2
@@ -6288,7 +6460,9 @@ gcn_md_reorg (void)
/* Track the current instruction as a previous instruction. */
back[oldest].insn = insn;
back[oldest].unit = iunit;
- back[oldest].delayeduse = idelayeduse;
+ back[oldest].type = itype;
+ back[oldest].flatmemaccess = iflatmemaccess;
+ back[oldest].delayeduse = delayeduse;
back[oldest].writes = iwrites;
back[oldest].reads = ireads;
back[oldest].age = 0;
diff --git a/gcc/config/gcn/gcn.md b/gcc/config/gcn/gcn.md
index 9193461..fad42e6 100644
--- a/gcc/config/gcn/gcn.md
+++ b/gcc/config/gcn/gcn.md
@@ -312,18 +312,28 @@
; We need to be able to identify v_readlane and v_writelane with
; SGPR lane selection in order to handle "Manually Inserted Wait States".
-(define_attr "laneselect" "yes,no" (const_string "no"))
+(define_attr "laneselect" "write,read,no" (const_string "no"))
-; Identify instructions that require a "Manually Inserted Wait State" if
-; their inputs are overwritten by subsequent instructions.
+; Global or flat memory access using store or load followed by waitcnt
+; and using flat/global atomic access, possibly followed by a waitcnt.
+; 'storex34' denotes FLAT_STORE_X{3,4}.
+; 'cmpswapx2' denotes FLAT_ATOMIC_{F}CMPSWAP_X2
+; Used to handle "Manually Inserted Wait State".
-(define_attr "delayeduse" "yes,no" (const_string "no"))
+(define_attr "flatmemaccess"
+ "store,storex34,load,atomic,atomicwait,cmpswapx2,no"
+ (const_string "no"))
; Identify instructions that require "Manually Inserted Wait State" if
; a previous instruction writes to VCC. The number gives the number of NOPs.
(define_attr "vccwait" "" (const_int 0))
+; Mark trans ops such as v_{exp,rsq,sqrt,sin,cos,log,...}_F{16,32,64}
+; for later conditional s_nop insertion.
+
+(define_attr "transop" "yes,no" (const_string "no"))
+
;; }}}
;; {{{ Iterators useful across the wole machine description
@@ -555,9 +565,11 @@
}
[(set_attr "type" "sop1,vop1,vop3a,sopk,vopc,mult,smem,smem,smem,flat,flat,
flat,flat,flat,flat")
+ (set_attr "flatmemaccess" "*,*,*,*,*,*,*,*,*,load,load,store,load,load,store")
(set_attr "exec" "*,*,none,*,*,*,*,*,*,*,*,*,*,*,*")
(set_attr "length" "4,4,4,4,4,8,12,12,12,12,12,12,12,12,12")
- (set_attr "xnack" "*,*,*,*,*,*,off,on,*,off,on,*,off,on,*")])
+ (set_attr "xnack" "*,*,*,*,*,*,off,on,*,off,on,*,off,on,*")
+ (set_attr "laneselect" "*,*,read,*,*,*,*,*,*,*,*,*,*,*,*")])
; 32bit move pattern
@@ -565,38 +577,38 @@
[(set (match_operand:SISF 0 "nonimmediate_operand")
(match_operand:SISF 1 "gcn_load_operand"))]
""
- {@ [cons: =0, 1; attrs: type, exec, length, cdna, xnack]
- [SD ,SSA ;sop1 ,* ,4 ,* ,* ] s_mov_b32\t%0, %1
- [SD ,J ;sopk ,* ,4 ,* ,* ] s_movk_i32\t%0, %1
- [SD ,B ;sop1 ,* ,8 ,* ,* ] s_mov_b32\t%0, %1
- [SD ,RB ;smem ,* ,12,* ,off] s_buffer_load%s0\t%0, s[0:3], %1\;s_waitcnt\tlgkmcnt(0)
- [&SD ,RB ;smem ,* ,12,* ,on ] ^
- [RB ,Sm ;smem ,* ,12,* ,* ] s_buffer_store%s1\t%1, s[0:3], %0
- [Sm ,RS ;smem ,* ,12,* ,off] s_load_dword\t%0, %A1\;s_waitcnt\tlgkmcnt(0)
- [&Sm ,RS ;smem ,* ,12,* ,on ] ^
- [RS ,Sm ;smem ,* ,12,* ,* ] s_store_dword\t%1, %A0
- [v ,v ;vop1 ,* ,4 ,* ,* ] v_mov_b32\t%0, %1
- [Sg ,v ;vop3a,none,8 ,* ,* ] v_readlane_b32\t%0, %1, 0
- [v ,Sv ;vop3a,none,8 ,* ,* ] v_writelane_b32\t%0, %1, 0
- [v ,^a ;vop3p_mai,*,8,* ,* ] v_accvgpr_read_b32\t%0, %1
- [a ,v ;vop3p_mai,*,8,* ,* ] v_accvgpr_write_b32\t%0, %1
- [a ,a ;vop1 ,* ,4,cdna2,* ] v_accvgpr_mov_b32\t%0, %1
- [v ,RF ;flat ,* ,12,* ,off] flat_load_dword\t%0, %A1%O1%g1\;s_waitcnt\t0
- [&v ,RF ;flat ,* ,12,* ,on ] ^
- [^a ,RF ;flat ,* ,12,cdna2,off] ^
- [&^a ,RF ;flat ,* ,12,cdna2,on ] ^
- [RF ,v ;flat ,* ,12,* ,* ] flat_store_dword\t%A0, %1%O0%g0
- [RF ,a ;flat ,* ,12,cdna2,* ] ^
- [v ,B ;vop1 ,* ,8 ,* ,* ] v_mov_b32\t%0, %1
- [RLRG,v ;ds ,* ,12,* ,* ] ds_write_b32\t%A0, %1%O0\;s_waitcnt\tlgkmcnt(0)
- [v ,RLRG;ds ,* ,12,* ,* ] ds_read_b32\t%0, %A1%O1\;s_waitcnt\tlgkmcnt(0)
- [SD ,Y ;sop1 ,* ,8 ,* ,* ] s_mov_b32\t%0, %1
- [v ,RM ;flat ,* ,12,* ,off] global_load_dword\t%0, %A1%O1%g1\;s_waitcnt\tvmcnt(0)
- [&v ,RM ;flat ,* ,12,* ,on ] ^
- [^a ,RM ;flat ,* ,12,cdna2,off] ^
- [&^a ,RM ;flat ,* ,12,cdna2,on ] ^
- [RM ,v ;flat ,* ,12,* ,* ] global_store_dword\t%A0, %1%O0%g0
- [RM ,a ;flat ,* ,12,cdna2,* ] ^
+ {@ [cons: =0, 1; attrs: type, exec, length, cdna, xnack, laneselect, flatmemaccess]
+ [SD ,SSA ;sop1 ,* ,4 ,* ,* ,* ,* ] s_mov_b32\t%0, %1
+ [SD ,J ;sopk ,* ,4 ,* ,* ,* ,* ] s_movk_i32\t%0, %1
+ [SD ,B ;sop1 ,* ,8 ,* ,* ,* ,* ] s_mov_b32\t%0, %1
+ [SD ,RB ;smem ,* ,12,* ,off,* ,* ] s_buffer_load%s0\t%0, s[0:3], %1\;s_waitcnt\tlgkmcnt(0)
+ [&SD ,RB ;smem ,* ,12,* ,on ,* ,* ] ^
+ [RB ,Sm ;smem ,* ,12,* ,* ,* ,* ] s_buffer_store%s1\t%1, s[0:3], %0
+ [Sm ,RS ;smem ,* ,12,* ,off,* ,* ] s_load_dword\t%0, %A1\;s_waitcnt\tlgkmcnt(0)
+ [&Sm ,RS ;smem ,* ,12,* ,on ,* ,* ] ^
+ [RS ,Sm ;smem ,* ,12,* ,* ,* ,* ] s_store_dword\t%1, %A0
+ [v ,v ;vop1 ,* ,4 ,* ,* ,* ,* ] v_mov_b32\t%0, %1
+ [Sg ,v ;vop3a,none,8 ,* ,* ,read ,* ] v_readlane_b32\t%0, %1, 0
+ [v ,Sv ;vop3a,none,8 ,* ,* ,write,* ] v_writelane_b32\t%0, %1, 0
+ [v ,^a ;vop3p_mai,*,8,* ,* ,* ,* ] v_accvgpr_read_b32\t%0, %1
+ [a ,v ;vop3p_mai,*,8,* ,* ,* ,* ] v_accvgpr_write_b32\t%0, %1
+ [a ,a ;vop1 ,* ,4,cdna2,* ,* ,* ] v_accvgpr_mov_b32\t%0, %1
+ [v ,RF ;flat ,* ,12,* ,off,* ,load ] flat_load_dword\t%0, %A1%O1%g1\;s_waitcnt\t0
+ [&v ,RF ;flat ,* ,12,* ,on ,* ,load ] ^
+ [^a ,RF ;flat ,* ,12,cdna2,off,* ,load ] ^
+ [&^a ,RF ;flat ,* ,12,cdna2,on ,* ,load ] ^
+ [RF ,v ;flat ,* ,12,* ,* ,* ,store] flat_store_dword\t%A0, %1%O0%g0
+ [RF ,a ;flat ,* ,12,cdna2,* ,* ,store] ^
+ [v ,B ;vop1 ,* ,8 ,* ,* ,* ,* ] v_mov_b32\t%0, %1
+ [RLRG,v ;ds ,* ,12,* ,* ,* ,* ] ds_write_b32\t%A0, %1%O0\;s_waitcnt\tlgkmcnt(0)
+ [v ,RLRG;ds ,* ,12,* ,* ,* ,* ] ds_read_b32\t%0, %A1%O1\;s_waitcnt\tlgkmcnt(0)
+ [SD ,Y ;sop1 ,* ,8 ,* ,* ,* ,* ] s_mov_b32\t%0, %1
+ [v ,RM ;flat ,* ,12,* ,off,* ,load ] global_load_dword\t%0, %A1%O1%g1\;s_waitcnt\tvmcnt(0)
+ [&v ,RM ;flat ,* ,12,* ,on ,* ,load ] ^
+ [^a ,RM ;flat ,* ,12,cdna2,off,* ,load ] ^
+ [&^a ,RM ;flat ,* ,12,cdna2,on ,* ,load ] ^
+ [RM ,v ;flat ,* ,12,* ,* ,* ,store] global_store_dword\t%A0, %1%O0%g0
+ [RM ,a ;flat ,* ,12,cdna2,* ,* ,store] ^
})
; 8/16bit move pattern
@@ -606,31 +618,31 @@
[(set (match_operand:QIHI 0 "nonimmediate_operand")
(match_operand:QIHI 1 "gcn_load_operand"))]
"gcn_valid_move_p (<MODE>mode, operands[0], operands[1])"
- {@ [cons: =0, 1; attrs: type, exec, length, cdna, xnack]
- [SD ,SSA ;sop1 ,* ,4 ,* ,* ] s_mov_b32\t%0, %1
- [SD ,J ;sopk ,* ,4 ,* ,* ] s_movk_i32\t%0, %1
- [SD ,B ;sop1 ,* ,8 ,* ,* ] s_mov_b32\t%0, %1
- [v ,v ;vop1 ,* ,4 ,* ,* ] v_mov_b32\t%0, %1
- [Sg ,v ;vop3a,none,4 ,* ,* ] v_readlane_b32\t%0, %1, 0
- [v ,Sv ;vop3a,none,4 ,* ,* ] v_writelane_b32\t%0, %1, 0
- [v ,^a ;vop3p_mai,*,8,* ,* ] v_accvgpr_read_b32\t%0, %1
- [a ,v ;vop3p_mai,*,8,* ,* ] v_accvgpr_write_b32\t%0, %1
- [a ,a ;vop1 ,* ,8,cdna2,* ] v_accvgpr_mov_b32\t%0, %1
- [v ,RF ;flat ,* ,12,* ,off] flat_load%o1\t%0, %A1%O1%g1\;s_waitcnt\t0
- [&v ,RF ;flat ,* ,12,* ,on ] ^
- [^a ,RF ;flat ,* ,12,cdna2,off] ^
- [&^a ,RF ;flat ,* ,12,cdna2,on ] ^
- [RF ,v ;flat ,* ,12,* ,* ] flat_store%s0\t%A0, %1%O0%g0
- [RF ,a ;flat ,* ,12,cdna2,* ] ^
- [v ,B ;vop1 ,* ,8 ,* ,* ] v_mov_b32\t%0, %1
- [RLRG,v ;ds ,* ,12,* ,* ] ds_write%b0\t%A0, %1%O0\;s_waitcnt\tlgkmcnt(0)
- [v ,RLRG;ds ,* ,12,* ,* ] ds_read%u1\t%0, %A1%O1\;s_waitcnt\tlgkmcnt(0)
- [v ,RM ;flat ,* ,12,* ,off] global_load%o1\t%0, %A1%O1%g1\;s_waitcnt\tvmcnt(0)
- [&v ,RM ;flat ,* ,12,* ,on ] ^
- [^a ,RM ;flat ,* ,12,cdna2,off] ^
- [&^a ,RM ;flat ,* ,12,cdna2,on ] ^
- [RM ,v ;flat ,* ,12,* ,* ] global_store%s0\t%A0, %1%O0%g0
- [RM ,a ;flat ,* ,12,cdna2,* ] ^
+ {@ [cons: =0, 1; attrs: type, exec, length, cdna, xnack, laneselect, flatmemaccess]
+ [SD ,SSA ;sop1 ,* ,4 ,* ,* ,* ,* ] s_mov_b32\t%0, %1
+ [SD ,J ;sopk ,* ,4 ,* ,* ,* ,* ] s_movk_i32\t%0, %1
+ [SD ,B ;sop1 ,* ,8 ,* ,* ,* ,* ] s_mov_b32\t%0, %1
+ [v ,v ;vop1 ,* ,4 ,* ,* ,* ,* ] v_mov_b32\t%0, %1
+ [Sg ,v ;vop3a,none,4 ,* ,* ,read ,* ] v_readlane_b32\t%0, %1, 0
+ [v ,Sv ;vop3a,none,4 ,* ,* ,write,* ] v_writelane_b32\t%0, %1, 0
+ [v ,^a ;vop3p_mai,*,8,* ,* ,* ,* ] v_accvgpr_read_b32\t%0, %1
+ [a ,v ;vop3p_mai,*,8,* ,* ,* ,* ] v_accvgpr_write_b32\t%0, %1
+ [a ,a ;vop1 ,* ,8,cdna2,* ,* ,* ] v_accvgpr_mov_b32\t%0, %1
+ [v ,RF ;flat ,* ,12,* ,off,* ,load ] flat_load%o1\t%0, %A1%O1%g1\;s_waitcnt\t0
+ [&v ,RF ;flat ,* ,12,* ,on ,* ,load ] ^
+ [^a ,RF ;flat ,* ,12,cdna2,off,* ,load ] ^
+ [&^a ,RF ;flat ,* ,12,cdna2,on ,* ,load ] ^
+ [RF ,v ;flat ,* ,12,* ,* ,* ,store] flat_store%s0\t%A0, %1%O0%g0
+ [RF ,a ;flat ,* ,12,cdna2,* ,* ,store] ^
+ [v ,B ;vop1 ,* ,8 ,* ,* ,* ,* ] v_mov_b32\t%0, %1
+ [RLRG,v ;ds ,* ,12,* ,* ,* ,* ] ds_write%b0\t%A0, %1%O0\;s_waitcnt\tlgkmcnt(0)
+ [v ,RLRG;ds ,* ,12,* ,* ,* ,* ] ds_read%u1\t%0, %A1%O1\;s_waitcnt\tlgkmcnt(0)
+ [v ,RM ;flat ,* ,12,* ,off,* ,load ] global_load%o1\t%0, %A1%O1%g1\;s_waitcnt\tvmcnt(0)
+ [&v ,RM ;flat ,* ,12,* ,on ,* ,load ] ^
+ [^a ,RM ;flat ,* ,12,cdna2,off,* ,load ] ^
+ [&^a ,RM ;flat ,* ,12,cdna2,on ,* ,load ] ^
+ [RM ,v ;flat ,* ,12,* ,* ,* ,store] global_store%s0\t%A0, %1%O0%g0
+ [RM ,a ;flat ,* ,12,cdna2,* ,* ,store] ^
})
; 64bit move pattern
@@ -639,34 +651,34 @@
[(set (match_operand:DIDF 0 "nonimmediate_operand")
(match_operand:DIDF 1 "general_operand"))]
"GET_CODE(operands[1]) != SYMBOL_REF"
- {@ [cons: =0, 1; attrs: type, length, cdna, xnack]
- [SD ,SSA ;sop1 ,4 ,* ,* ] s_mov_b64\t%0, %1
- [SD ,C ;sop1 ,8 ,* ,* ] ^
- [SD ,DB ;mult ,* ,* ,* ] #
- [RS ,Sm ;smem ,12,* ,* ] s_store_dwordx2\t%1, %A0
- [Sm ,RS ;smem ,12,* ,off] s_load_dwordx2\t%0, %A1\;s_waitcnt\tlgkmcnt(0)
- [&Sm ,RS ;smem ,12,* ,on ] ^
- [v ,v ;vmult,* ,* ,* ] #
- [v ,DB ;vmult,* ,* ,* ] #
- [Sg ,v ;vmult,* ,* ,* ] #
- [v ,Sv ;vmult,* ,* ,* ] #
- [v ,^a ;vmult,* ,* ,* ] #
- [a ,v ;vmult,* ,* ,* ] #
- [a ,a ;vmult,* ,cdna2,* ] #
- [v ,RF ;flat ,12,* ,off] flat_load_dwordx2\t%0, %A1%O1%g1\;s_waitcnt\t0
- [&v ,RF ;flat ,12,* ,on ] ^
- [^a ,RF ;flat ,12,cdna2,off] ^
- [&^a ,RF ;flat ,12,cdna2,on ] ^
- [RF ,v ;flat ,12,* ,* ] flat_store_dwordx2\t%A0, %1%O0%g0
- [RF ,a ;flat ,12,cdna2,* ] ^
- [RLRG,v ;ds ,12,* ,* ] ds_write_b64\t%A0, %1%O0\;s_waitcnt\tlgkmcnt(0)
- [v ,RLRG;ds ,12,* ,* ] ds_read_b64\t%0, %A1%O1\;s_waitcnt\tlgkmcnt(0)
- [v ,RM ;flat ,12,* ,off] global_load_dwordx2\t%0, %A1%O1%g1\;s_waitcnt\tvmcnt(0)
- [&v ,RM ;flat ,12,* ,on ] ^
- [^a ,RM ;flat ,12,cdna2,off] ^
- [&^a ,RM ;flat ,12,cdna2,on ] ^
- [RM ,v ;flat ,12,* ,* ] global_store_dwordx2\t%A0, %1%O0%g0
- [RM ,a ;flat ,12,cdna2,* ] ^
+ {@ [cons: =0, 1; attrs: type, length, cdna, xnack, flatmemaccess]
+ [SD ,SSA ;sop1 ,4 ,* ,* ,* ] s_mov_b64\t%0, %1
+ [SD ,C ;sop1 ,8 ,* ,* ,* ] ^
+ [SD ,DB ;mult ,* ,* ,* ,* ] #
+ [RS ,Sm ;smem ,12,* ,* ,* ] s_store_dwordx2\t%1, %A0
+ [Sm ,RS ;smem ,12,* ,off,* ] s_load_dwordx2\t%0, %A1\;s_waitcnt\tlgkmcnt(0)
+ [&Sm ,RS ;smem ,12,* ,on ,* ] ^
+ [v ,v ;vmult,* ,* ,* ,* ] #
+ [v ,DB ;vmult,* ,* ,* ,* ] #
+ [Sg ,v ;vmult,* ,* ,* ,* ] #
+ [v ,Sv ;vmult,* ,* ,* ,* ] #
+ [v ,^a ;vmult,* ,* ,* ,* ] #
+ [a ,v ;vmult,* ,* ,* ,* ] #
+ [a ,a ;vmult,* ,cdna2,* ,* ] #
+ [v ,RF ;flat ,12,* ,off,load ] flat_load_dwordx2\t%0, %A1%O1%g1\;s_waitcnt\t0
+ [&v ,RF ;flat ,12,* ,on ,load ] ^
+ [^a ,RF ;flat ,12,cdna2,off,load ] ^
+ [&^a ,RF ;flat ,12,cdna2,on ,load ] ^
+ [RF ,v ;flat ,12,* ,* ,store] flat_store_dwordx2\t%A0, %1%O0%g0
+ [RF ,a ;flat ,12,cdna2,* ,store] ^
+ [RLRG,v ;ds ,12,* ,* ,* ] ds_write_b64\t%A0, %1%O0\;s_waitcnt\tlgkmcnt(0)
+ [v ,RLRG;ds ,12,* ,* ,* ] ds_read_b64\t%0, %A1%O1\;s_waitcnt\tlgkmcnt(0)
+ [v ,RM ;flat ,12,* ,off,load ] global_load_dwordx2\t%0, %A1%O1%g1\;s_waitcnt\tvmcnt(0)
+ [&v ,RM ;flat ,12,* ,on ,load ] ^
+ [^a ,RM ;flat ,12,cdna2,off,load ] ^
+ [&^a ,RM ;flat ,12,cdna2,on ,load ] ^
+ [RM ,v ;flat ,12,* ,* ,store] global_store_dwordx2\t%A0, %1%O0%g0
+ [RM ,a ;flat ,12,cdna2,* ,store] ^
}
"reload_completed
&& ((!MEM_P (operands[0]) && !MEM_P (operands[1])
@@ -704,31 +716,31 @@
[(set (match_operand:TI 0 "nonimmediate_operand")
(match_operand:TI 1 "general_operand" ))]
""
- {@ [cons: =0, 1; attrs: type, delayeduse, length, cdna, xnack]
- [SD ,SSB;mult ,* ,* ,* ,* ] #
- [RS ,Sm ;smem ,* ,12,* ,* ] s_store_dwordx4\t%1, %A0
- [Sm ,RS ;smem ,yes,12,* ,off] s_load_dwordx4\t%0, %A1\;s_waitcnt\tlgkmcnt(0)
- [&Sm,RS ;smem ,yes,12,* ,on ] ^
- [RF ,v ;flat ,* ,12,* ,* ] flat_store_dwordx4\t%A0, %1%O0%g0
- [RF ,a ;flat ,* ,12,cdna2,* ] ^
- [v ,RF ;flat ,* ,12,* ,off] flat_load_dwordx4\t%0, %A1%O1%g1\;s_waitcnt\t0
- [&v ,RF ;flat ,* ,12,* ,on ] ^
- [^a ,RF ;flat ,* ,12,cdna2,off] ^
- [&^a,RF ;flat ,* ,12,cdna2,on ] ^
- [v ,v ;vmult,* ,* ,* ,* ] #
- [v ,Sv ;vmult,* ,* ,* ,* ] #
- [SD ,v ;vmult,* ,* ,* ,* ] #
- [RM ,v ;flat ,yes,12,* ,* ] global_store_dwordx4\t%A0, %1%O0%g0
- [RM ,a ;flat ,yes,12,cdna2,* ] ^
- [v ,RM ;flat ,* ,12,* ,off] global_load_dwordx4\t%0, %A1%O1%g1\;s_waitcnt\tvmcnt(0)
- [&v ,RM ;flat ,* ,12,* ,on ] ^
- [^a ,RM ;flat ,* ,12,cdna2,off] ^
- [&^a,RM ;flat ,* ,12,cdna2,on ] ^
- [RL ,v ;ds ,* ,12,* ,* ] ds_write_b128\t%A0, %1%O0\;s_waitcnt\tlgkmcnt(0)
- [v ,RL ;ds ,* ,12,* ,* ] ds_read_b128\t%0, %A1%O1\;s_waitcnt\tlgkmcnt(0)
- [v ,^a ;vmult,* ,* ,* ,* ] #
- [a ,v ;vmult,* ,* ,* ,* ] #
- [a ,a ;vmult,* ,* ,cdna2,* ] #
+ {@ [cons: =0, 1; attrs: type, length, cdna, xnack, flatmemaccess]
+ [SD ,SSB;mult ,* ,* ,* ,* ] #
+ [RS ,Sm ;smem ,12,* ,* ,* ] s_store_dwordx4\t%1, %A0
+ [Sm ,RS ;smem ,12,* ,off,* ] s_load_dwordx4\t%0, %A1\;s_waitcnt\tlgkmcnt(0)
+ [&Sm,RS ;smem ,12,* ,on ,* ] ^
+ [RF ,v ;flat ,12,* ,* ,storex34] flat_store_dwordx4\t%A0, %1%O0%g0
+ [RF ,a ;flat ,12,cdna2,* ,storex34] ^
+ [v ,RF ;flat ,12,* ,off,load ] flat_load_dwordx4\t%0, %A1%O1%g1\;s_waitcnt\t0
+ [&v ,RF ;flat ,12,* ,on ,load ] ^
+ [^a ,RF ;flat ,12,cdna2,off,load ] ^
+ [&^a,RF ;flat ,12,cdna2,on ,load ] ^
+ [v ,v ;vmult,* ,* ,* ,* ] #
+ [v ,Sv ;vmult,* ,* ,* ,* ] #
+ [SD ,v ;vmult,* ,* ,* ,* ] #
+ [RM ,v ;flat ,12,* ,* ,storex34] global_store_dwordx4\t%A0, %1%O0%g0
+ [RM ,a ;flat ,12,cdna2,* ,storex34] ^
+ [v ,RM ;flat ,12,* ,off,load ] global_load_dwordx4\t%0, %A1%O1%g1\;s_waitcnt\tvmcnt(0)
+ [&v ,RM ;flat ,12,* ,on ,load ] ^
+ [^a ,RM ;flat ,12,cdna2,off,load ] ^
+ [&^a,RM ;flat ,12,cdna2,on ,load ] ^
+ [RL ,v ;ds ,12,* ,* ,* ] ds_write_b128\t%A0, %1%O0\;s_waitcnt\tlgkmcnt(0)
+ [v ,RL ;ds ,12,* ,* ,* ] ds_read_b128\t%0, %A1%O1\;s_waitcnt\tlgkmcnt(0)
+ [v ,^a ;vmult,* ,* ,* ,* ] #
+ [a ,v ;vmult,* ,* ,* ,* ] #
+ [a ,a ;vmult,* ,cdna2,* ,* ] #
}
"reload_completed
&& REG_P (operands[0])
@@ -1985,6 +1997,7 @@
flat_atomic_<bare_mnemonic><X>\t%0, %1, %2 %G2\;s_waitcnt\t0
global_atomic_<bare_mnemonic><X>\t%0, %A1, %2%O1 %G2\;s_waitcnt\tvmcnt(0)"
[(set_attr "type" "smem,flat,flat")
+ (set_attr "flatmemaccess" "*,atomicwait,atomicwait")
(set_attr "length" "12")])
; FIXME: These patterns are disabled because the instructions don't
@@ -2006,6 +2019,7 @@
flat_atomic_<bare_mnemonic><X>\t%0, %1\;s_waitcnt\t0
global_atomic_<bare_mnemonic><X>\t%A0, %1%O0\;s_waitcnt\tvmcnt(0)"
[(set_attr "type" "smem,flat,flat")
+ (set_attr "flatmemaccess" "*,atomicwait,atomicwait")
(set_attr "length" "12")])
(define_mode_attr x2 [(SI "DI") (DI "TI")])
@@ -2053,7 +2067,7 @@
global_atomic_cmpswap<X>\t%0, %A1, %2%O1 %G2\;s_waitcnt\tvmcnt(0)"
[(set_attr "type" "smem,flat,flat")
(set_attr "length" "12")
- (set_attr "delayeduse" "*,yes,yes")])
+ (set_attr "flatmemaccess" "*,cmpswapx2,cmpswapx2")])
(define_insn "sync_compare_and_swap<mode>_lds_insn"
[(set (match_operand:SIDI 0 "register_operand" "= v")
@@ -2173,6 +2187,7 @@
gcc_unreachable ();
}
[(set_attr "type" "smem,flat,flat")
+ (set_attr "flatmemaccess" "*,load,load")
(set_attr "length" "28")
(set_attr "rdna" "no,*,*")])
@@ -2257,6 +2272,7 @@
gcc_unreachable ();
}
[(set_attr "type" "smem,flat,flat")
+ (set_attr "flatmemaccess" "*,store,store")
(set_attr "length" "28")
(set_attr "rdna" "no,*,*")])
@@ -2389,6 +2405,7 @@
gcc_unreachable ();
}
[(set_attr "type" "smem,flat,flat")
+ (set_attr "flatmemaccess" "*,atomicwait,atomicwait")
(set_attr "length" "28")
(set_attr "rdna" "no,*,*")])
diff --git a/gcc/config/i386/i386-options.cc b/gcc/config/i386/i386-options.cc
index d244b225..ca6bb83 100644
--- a/gcc/config/i386/i386-options.cc
+++ b/gcc/config/i386/i386-options.cc
@@ -1362,7 +1362,9 @@ ix86_valid_target_attribute_inner_p (tree fndecl, tree args, char *p_strings[],
arg_ok = opt_enum_arg_to_value (opt, p + opt_len, &value, CL_TARGET);
if (arg_ok)
set_option (opts, enum_opts_set, opt, value,
- p + opt_len, DK_UNSPECIFIED, input_location,
+ p + opt_len,
+ static_cast<int> (diagnostics::kind::unspecified),
+ input_location,
global_dc);
else
{
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 49bd393..4682db85 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -24788,6 +24788,12 @@ static void map_egpr_constraints (vec<const char *> &constraints)
buf.safe_push (cur[j + 1]);
j++;
break;
+ case '{':
+ do
+ {
+ buf.safe_push (cur[j]);
+ } while (cur[j++] != '}');
+ break;
default:
buf.safe_push (cur[j]);
break;
diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc
index b00fcc7..493f95e 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -11052,17 +11052,21 @@ static bool
loongarch_builtin_support_vector_misalignment (machine_mode mode,
const_tree type,
int misalignment,
- bool is_packed)
+ bool is_packed,
+ bool is_gather_scatter)
{
if ((ISA_HAS_LSX || ISA_HAS_LASX) && STRICT_ALIGNMENT)
{
+ if (is_gather_scatter)
+ return true;
if (optab_handler (movmisalign_optab, mode) == CODE_FOR_nothing)
return false;
if (misalignment == -1)
return false;
}
return default_builtin_support_vector_misalignment (mode, type, misalignment,
- is_packed);
+ is_packed,
+ is_gather_scatter);
}
/* Return a PARALLEL containing NELTS elements, with element I equal
diff --git a/gcc/config/pru/pru-pragma.cc b/gcc/config/pru/pru-pragma.cc
index c3f3d33..9338780 100644
--- a/gcc/config/pru/pru-pragma.cc
+++ b/gcc/config/pru/pru-pragma.cc
@@ -46,21 +46,24 @@ pru_pragma_ctable_entry (cpp_reader *)
enum cpp_ttype type;
type = pragma_lex (&ctable_index);
- if (type == CPP_NUMBER && tree_fits_uhwi_p (ctable_index))
+ if (type == CPP_NUMBER && tree_fits_shwi_p (ctable_index))
{
type = pragma_lex (&base_addr);
- if (type == CPP_NUMBER && tree_fits_uhwi_p (base_addr))
+ if (type == CPP_NUMBER && tree_fits_shwi_p (base_addr))
{
- unsigned HOST_WIDE_INT i = tree_to_uhwi (ctable_index);
- unsigned HOST_WIDE_INT base = tree_to_uhwi (base_addr);
+ HOST_WIDE_INT i = tree_to_shwi (ctable_index);
+ HOST_WIDE_INT base = sext_hwi (tree_to_shwi (base_addr),
+ POINTER_SIZE);
type = pragma_lex (&base_addr);
if (type != CPP_EOF)
error ("junk at end of %<#pragma CTABLE_ENTRY%>");
- else if (i >= ARRAY_SIZE (pru_ctable))
+ else if (!IN_RANGE (i, 0, ARRAY_SIZE (pru_ctable) - 1))
error ("%<CTABLE_ENTRY%> index %wd is not valid", i);
else if (pru_ctable[i].valid && pru_ctable[i].base != base)
error ("redefinition of %<CTABLE_ENTRY %wd%>", i);
+ else if (!IN_RANGE (base, INT32_MIN, INT32_MAX))
+ error ("%<CTABLE_ENTRY%> base address does not fit in 32-bits");
else
{
if (base & 0xff)
diff --git a/gcc/config/pru/pru-protos.h b/gcc/config/pru/pru-protos.h
index c73fad8..4750f0e 100644
--- a/gcc/config/pru/pru-protos.h
+++ b/gcc/config/pru/pru-protos.h
@@ -23,7 +23,7 @@
struct pru_ctable_entry {
bool valid;
- unsigned HOST_WIDE_INT base;
+ HOST_WIDE_INT base;
};
extern struct pru_ctable_entry pru_ctable[32];
@@ -66,9 +66,9 @@ pru_regno_ok_for_index_p (int regno, bool strict_p)
return pru_regno_ok_for_base_p (regno, strict_p);
}
-extern int pru_get_ctable_exact_base_index (unsigned HOST_WIDE_INT caddr);
-extern int pru_get_ctable_base_index (unsigned HOST_WIDE_INT caddr);
-extern int pru_get_ctable_base_offset (unsigned HOST_WIDE_INT caddr);
+extern int pru_get_ctable_exact_base_index (HOST_WIDE_INT caddr);
+extern int pru_get_ctable_base_index (HOST_WIDE_INT caddr);
+extern int pru_get_ctable_base_offset (HOST_WIDE_INT caddr);
extern int pru_symref2ioregno (rtx op);
diff --git a/gcc/config/pru/pru.cc b/gcc/config/pru/pru.cc
index 47e5f24..322e319 100644
--- a/gcc/config/pru/pru.cc
+++ b/gcc/config/pru/pru.cc
@@ -1428,7 +1428,7 @@ pru_valid_const_ubyte_offset (machine_mode mode, HOST_WIDE_INT offset)
/* Recognize a CTABLE base address. Return CTABLE entry index, or -1 if
base was not found in the pragma-filled pru_ctable. */
int
-pru_get_ctable_exact_base_index (unsigned HOST_WIDE_INT caddr)
+pru_get_ctable_exact_base_index (HOST_WIDE_INT caddr)
{
unsigned int i;
@@ -1444,7 +1444,7 @@ pru_get_ctable_exact_base_index (unsigned HOST_WIDE_INT caddr)
/* Check if the given address can be addressed via CTABLE_BASE + UBYTE_OFFS,
and return the base CTABLE index if possible. */
int
-pru_get_ctable_base_index (unsigned HOST_WIDE_INT caddr)
+pru_get_ctable_base_index (HOST_WIDE_INT caddr)
{
unsigned int i;
@@ -1461,7 +1461,7 @@ pru_get_ctable_base_index (unsigned HOST_WIDE_INT caddr)
/* Return the offset from some CTABLE base for this address. */
int
-pru_get_ctable_base_offset (unsigned HOST_WIDE_INT caddr)
+pru_get_ctable_base_offset (HOST_WIDE_INT caddr)
{
int i;
@@ -2004,7 +2004,7 @@ pru_print_operand_address (FILE *file, machine_mode mode, rtx op)
case CONST_INT:
{
- unsigned HOST_WIDE_INT caddr = INTVAL (op);
+ HOST_WIDE_INT caddr = INTVAL (op);
int base = pru_get_ctable_base_index (caddr);
int offs = pru_get_ctable_base_offset (caddr);
if (base < 0)
diff --git a/gcc/config/riscv/autovec-opt.md b/gcc/config/riscv/autovec-opt.md
index f372f0e..6531996 100644
--- a/gcc/config/riscv/autovec-opt.md
+++ b/gcc/config/riscv/autovec-opt.md
@@ -1714,6 +1714,74 @@
}
[(set_attr "type" "vialu")])
+(define_insn_and_split "*<sat_op_v_vdup>_vx_<mode>"
+ [(set (match_operand:V_VLSI 0 "register_operand")
+ (if_then_else:V_VLSI
+ (unspec:<VM>
+ [(match_operand:<VM> 1 "vector_mask_operand")
+ (match_operand 5 "vector_length_operand")
+ (match_operand 6 "const_int_operand")
+ (match_operand 7 "const_int_operand")
+ (match_operand 8 "const_int_operand")
+ (match_operand 9 "const_int_operand")
+ (reg:SI VL_REGNUM)
+ (reg:SI VTYPE_REGNUM)
+ (reg:SI VXRM_REGNUM)] UNSPEC_VPREDICATE)
+ (unspec:V_VLSI
+ [(match_operand:V_VLSI 3 "register_operand")
+ (vec_duplicate:V_VLSI
+ (match_operand:<VEL> 4 "reg_or_int_operand"))] VSAT_VX_OP_V_VDUP)
+ (unspec:V_VLSI
+ [(match_operand:DI 2 "register_operand")] UNSPEC_VUNDEF)))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ int vxrm_val = INTVAL (operands[9]);
+ riscv_vector::expand_vx_binary_vxrm_vec_vec_dup (operands[0], operands[3],
+ operands[4],
+ <VSAT_VX_OP_V_VDUP>,
+ vxrm_val, <MODE>mode);
+
+ DONE;
+ }
+ [(set_attr "type" "vaalu")])
+
+(define_insn_and_split "*<sat_op_vdup_v>_vx_<mode>"
+ [(set (match_operand:V_VLSI 0 "register_operand")
+ (if_then_else:V_VLSI
+ (unspec:<VM>
+ [(match_operand:<VM> 1 "vector_mask_operand")
+ (match_operand 5 "vector_length_operand")
+ (match_operand 6 "const_int_operand")
+ (match_operand 7 "const_int_operand")
+ (match_operand 8 "const_int_operand")
+ (match_operand 9 "const_int_operand")
+ (reg:SI VL_REGNUM)
+ (reg:SI VTYPE_REGNUM)
+ (reg:SI VXRM_REGNUM)] UNSPEC_VPREDICATE)
+ (unspec:V_VLSI
+ [(vec_duplicate:V_VLSI
+ (match_operand:<VEL> 4 "reg_or_int_operand"))
+ (match_operand:V_VLSI 3 "register_operand")] VSAT_VX_OP_VDUP_V)
+ (unspec:V_VLSI
+ [(match_operand:DI 2 "register_operand")] UNSPEC_VUNDEF)))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ int vxrm_val = INTVAL (operands[9]);
+ riscv_vector::expand_vx_binary_vxrm_vec_dup_vec (operands[0], operands[3],
+ operands[4],
+ <VSAT_VX_OP_VDUP_V>,
+ vxrm_val, <MODE>mode);
+
+ DONE;
+ }
+ [(set_attr "type" "vaalu")])
+
;; =============================================================================
;; Combine vec_duplicate + op.vv to op.vf
;; Include
@@ -1838,8 +1906,58 @@
emit_insn (gen_extend<vsubel><vel>2(tmp, operands[1]));
rtx ops[] = {operands[0], tmp};
- riscv_vector::emit_vlmax_insn (code_for_pred_broadcast (<MODE>mode),
- riscv_vector::UNARY_OP, ops);
+ riscv_vector::expand_broadcast (<MODE>mode, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfwmuladd")]
+)
+
+;; vfwnmacc.vf
+(define_insn_and_split "*vfwnmacc_vf_<mode>"
+ [(set (match_operand:VWEXTF 0 "register_operand")
+ (minus:VWEXTF
+ (mult:VWEXTF
+ (neg:VWEXTF
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand"))))
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand")))
+ (match_operand:VWEXTF 1 "register_operand")))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3]};
+ riscv_vector::emit_vlmax_insn(
+ code_for_pred_widen_mul_neg_scalar(MINUS, <MODE>mode),
+ riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfwmuladd")]
+)
+
+;; vfwnmsac.vf
+(define_insn_and_split "*vfwnmsac_vf_<mode>"
+ [(set (match_operand:VWEXTF 0 "register_operand")
+ (minus:VWEXTF
+ (match_operand:VWEXTF 1 "register_operand")
+ (mult:VWEXTF
+ (float_extend:VWEXTF
+ (match_operand:<V_DOUBLE_TRUNC> 3 "register_operand"))
+ (vec_duplicate:VWEXTF
+ (float_extend:<VEL>
+ (match_operand:<VSUBEL> 2 "register_operand"))))))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3]};
+ riscv_vector::emit_vlmax_insn(
+ code_for_pred_widen_mul_neg_scalar (PLUS, <MODE>mode),
+ riscv_vector::WIDEN_TERNARY_OP_FRM_DYN, ops);
DONE;
}
[(set_attr "type" "vfwmuladd")]
diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index 2e86826..48de5ef 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -1359,9 +1359,7 @@
if (operands[2] == const0_rtx)
{
rtx ops[] = {operands[0], operands[0], operands[1]};
- riscv_vector::emit_nonvlmax_insn (code_for_pred_broadcast (<MODE>mode),
- riscv_vector::SCALAR_MOVE_MERGED_OP_TU,
- ops, CONST1_RTX (Pmode));
+ riscv_vector::expand_set_first_tu (<MODE>mode, ops);
}
else
{
@@ -1385,8 +1383,7 @@
VL we need for the slide. */
rtx tmp = gen_reg_rtx (<MODE>mode);
rtx ops1[] = {tmp, operands[1]};
- emit_nonvlmax_insn (code_for_pred_broadcast (<MODE>mode),
- riscv_vector::UNARY_OP, ops1, length);
+ riscv_vector::expand_broadcast (<MODE>mode, ops1, length);
/* Slide exactly one element up leaving the tail elements
unchanged. */
@@ -2489,7 +2486,8 @@
(sign_extend:VWEXTI
(match_operand:<V_DOUBLE_TRUNC> 1 "register_operand"))
(sign_extend:VWEXTI
- (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand"))))))]
+ (match_operand:<V_DOUBLE_TRUNC> 2 "register_operand")))
+ (const_int 1))))]
"TARGET_VECTOR"
{
insn_code icode = code_for_pred (UNSPEC_VAADD, <V_DOUBLE_TRUNC>mode);
@@ -2522,7 +2520,8 @@
(match_operand:<V_DOUBLE_TRUNC> 1 "register_operand"))
(sign_extend:VWEXTI
(match_operand:<V_DOUBLE_TRUNC> 2 "register_operand")))
- (const_int 1)))))]
+ (const_int 1))
+ (const_int 1))))]
"TARGET_VECTOR"
{
insn_code icode = code_for_pred (UNSPEC_VAADD, <V_DOUBLE_TRUNC>mode);
@@ -2532,6 +2531,19 @@
}
)
+(define_expand "avg<mode>3_ceil"
+ [(match_operand:V_VLSI_D 0 "register_operand")
+ (match_operand:V_VLSI_D 1 "register_operand")
+ (match_operand:V_VLSI_D 2 "register_operand")]
+ "TARGET_VECTOR"
+ {
+ insn_code icode = code_for_pred (UNSPEC_VAADD, <MODE>mode);
+ riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RNU,
+ operands);
+ DONE;
+ }
+)
+
;; csrwi vxrm, 2
;; vaaddu.vv vd, vs2, vs1
(define_expand "uavg<mode>3_floor"
diff --git a/gcc/config/riscv/generic-vector-ooo.md b/gcc/config/riscv/generic-vector-ooo.md
index ab9e57f..773003b 100644
--- a/gcc/config/riscv/generic-vector-ooo.md
+++ b/gcc/config/riscv/generic-vector-ooo.md
@@ -17,6 +17,9 @@
;; <http://www.gnu.org/licenses/>.
;; Vector load/store
+;; The insn reservations include "generic" as we won't have a in-order
+;; generic definition for vector instructions.
+
(define_automaton "vector_ooo")
;; Separate issue queue for vector instructions.
@@ -29,119 +32,141 @@
(define_cpu_unit "vxu_ooo_multicycle" "vector_ooo")
(define_insn_reservation "vec_load" 6
- (eq_attr "type" "vlde,vldm,vlds,vldux,vldox,vldff,vldr")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vlde,vldm,vlds,vldux,vldox,vldff,vldr"))
"vxu_ooo_issue,vxu_ooo_alu")
(define_insn_reservation "vec_store" 6
- (eq_attr "type" "vste,vstm,vsts,vstux,vstox,vstr")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vste,vstm,vsts,vstux,vstox,vstr"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector segment loads/stores.
(define_insn_reservation "vec_loadstore_seg" 10
- (eq_attr "type" "vlsegde,vlsegds,vlsegdux,vlsegdox,vlsegdff,\
- vssegte,vssegts,vssegtux,vssegtox")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vlsegde,vlsegds,vlsegdux,vlsegdox,vlsegdff,\
+ vssegte,vssegts,vssegtux,vssegtox"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Regular vector operations and integer comparisons.
(define_insn_reservation "vec_alu" 3
- (eq_attr "type" "vialu,viwalu,vext,vicalu,vshift,vnshift,viminmax,vicmp,\
- vimov,vsalu,vaalu,vsshift,vnclip,vmov,vfmov,vector,\
- vandn,vbrev,vbrev8,vrev8,vclz,vctz,vrol,vror,vwsll")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vialu,viwalu,vext,vicalu,vshift,vnshift,viminmax,vicmp,\
+ vimov,vsalu,vaalu,vsshift,vnclip,vmov,vfmov,vector,\
+ vandn,vbrev,vbrev8,vrev8,vclz,vctz,vrol,vror,vwsll"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector float comparison, conversion etc.
(define_insn_reservation "vec_fcmp" 3
- (eq_attr "type" "vfrecp,vfminmax,vfcmp,vfsgnj,vfclass,vfcvtitof,\
- vfcvtftoi,vfwcvtitof,vfwcvtftoi,vfwcvtftof,vfncvtitof,\
- vfncvtftoi,vfncvtftof,vfncvtbf16,vfwcvtbf16")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vfrecp,vfminmax,vfcmp,vfsgnj,vfclass,vfcvtitof,\
+ vfcvtftoi,vfwcvtitof,vfwcvtftoi,vfwcvtftof,vfncvtitof,\
+ vfncvtftoi,vfncvtftof,vfncvtbf16,vfwcvtbf16"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector integer multiplication.
(define_insn_reservation "vec_imul" 4
- (eq_attr "type" "vimul,viwmul,vimuladd,viwmuladd,vsmul,vclmul,vclmulh,\
- vghsh,vgmul")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vimul,viwmul,vimuladd,viwmuladd,vsmul,vclmul,vclmulh,\
+ vghsh,vgmul"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector float addition.
(define_insn_reservation "vec_fadd" 4
- (eq_attr "type" "vfalu,vfwalu")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vfalu,vfwalu"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector float multiplication and FMA.
(define_insn_reservation "vec_fmul" 6
- (eq_attr "type" "vfmul,vfwmul,vfmuladd,vfwmuladd,vfwmaccbf16,sf_vqmacc,sf_vfnrclip")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vfmul,vfwmul,vfmuladd,vfwmuladd,vfwmaccbf16,sf_vqmacc,sf_vfnrclip"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector crypto, assumed to be a generic operation for now.
(define_insn_reservation "vec_crypto" 4
- (eq_attr "type" "crypto,vclz,vctz,vcpop")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "crypto,vclz,vctz,vcpop"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector crypto, AES
(define_insn_reservation "vec_crypto_aes" 4
- (eq_attr "type" "vaesef,vaesem,vaesdf,vaesdm,vaeskf1,vaeskf2,vaesz")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vaesef,vaesem,vaesdf,vaesdm,vaeskf1,vaeskf2,vaesz"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector crypto, sha
(define_insn_reservation "vec_crypto_sha" 4
- (eq_attr "type" "vsha2ms,vsha2ch,vsha2cl")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vsha2ms,vsha2ch,vsha2cl"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector crypto, SM3/4
(define_insn_reservation "vec_crypto_sm" 4
- (eq_attr "type" "vsm4k,vsm4r,vsm3me,vsm3c")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vsm4k,vsm4r,vsm3me,vsm3c"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector permute.
(define_insn_reservation "vec_perm" 3
- (eq_attr "type" "vimerge,vfmerge,vslideup,vslidedown,vislide1up,\
- vislide1down,vfslide1up,vfslide1down,vgather,vcompress")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vimerge,vfmerge,vslideup,vslidedown,vislide1up,\
+ vislide1down,vfslide1up,vfslide1down,vgather,vcompress"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector reduction.
(define_insn_reservation "vec_reduction" 8
- (eq_attr "type" "vired,viwred,vfredu,vfwredu")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vired,viwred,vfredu,vfwredu"))
"vxu_ooo_issue,vxu_ooo_multicycle")
;; Vector ordered reduction, assume the latency number is for
;; a 128-bit vector. It is scaled in riscv_sched_adjust_cost
;; for larger vectors.
(define_insn_reservation "vec_ordered_reduction" 10
- (eq_attr "type" "vfredo,vfwredo")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vfredo,vfwredo"))
"vxu_ooo_issue,vxu_ooo_multicycle*3")
;; Vector integer division, assume not pipelined.
(define_insn_reservation "vec_idiv" 16
- (eq_attr "type" "vidiv")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vidiv"))
"vxu_ooo_issue,vxu_ooo_multicycle*3")
;; Vector float divisions and sqrt, assume not pipelined.
(define_insn_reservation "vec_float_divsqrt" 16
- (eq_attr "type" "vfdiv,vfsqrt")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vfdiv,vfsqrt"))
"vxu_ooo_issue,vxu_ooo_multicycle*3")
;; Vector mask operations.
(define_insn_reservation "vec_mask" 2
- (eq_attr "type" "vmalu,vmpop,vmffs,vmsfs,vmiota,vmidx,vimovvx,vimovxv,\
- vfmovvf,vfmovfv")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vmalu,vmpop,vmffs,vmsfs,vmiota,vmidx,vimovvx,vimovxv,\
+ vfmovvf,vfmovfv"))
"vxu_ooo_issue,vxu_ooo_alu")
;; Vector vsetvl.
(define_insn_reservation "vec_vesetvl" 1
- (eq_attr "type" "vsetvl,vsetvl_pre")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "vsetvl,vsetvl_pre"))
"vxu_ooo_issue")
;; Vector rounding mode setters, assume pipeline barrier.
(define_insn_reservation "vec_setrm" 20
- (eq_attr "type" "wrvxrm,wrfrm")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "wrvxrm,wrfrm"))
"vxu_ooo_issue,vxu_ooo_issue*3")
;; Vector read vlen/vlenb.
(define_insn_reservation "vec_readlen" 4
- (eq_attr "type" "rdvlenb,rdvl")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "rdvlenb,rdvl"))
"vxu_ooo_issue,vxu_ooo_issue")
;; Vector sf_vcp.
(define_insn_reservation "vec_sf_vcp" 2
- (eq_attr "type" "sf_vc,sf_vc_se")
+ (and (eq_attr "tune" "generic_ooo,generic")
+ (eq_attr "type" "sf_vc,sf_vc_se"))
"vxu_ooo_issue")
diff --git a/gcc/config/riscv/mips-p8700.md b/gcc/config/riscv/mips-p8700.md
index ae0ea8d..fac9abb 100644
--- a/gcc/config/riscv/mips-p8700.md
+++ b/gcc/config/riscv/mips-p8700.md
@@ -163,5 +163,5 @@
vgather,vcompress,vmov,vector,vandn,vbrev,vbrev8,vrev8,vclz,vctz,vcpop,vrol,vror,vwsll,
vclmul,vclmulh,vghsh,vgmul,vaesef,vaesem,vaesdf,vaesdm,vaeskf1,vaeskf2,vaesz,
vsha2ms,vsha2ch,vsha2cl,vsm4k,vsm4r,vsm3me,vsm3c,vfncvtbf16,vfwcvtbf16,vfwmaccbf16,
- sf_vc,sf_vc_se"))
+ sf_vc,sf_vc_se,ghost"))
"mips_p8700_dummies")
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md
index 1f9a6b5..381f96c 100644
--- a/gcc/config/riscv/predicates.md
+++ b/gcc/config/riscv/predicates.md
@@ -518,6 +518,10 @@
(define_predicate "vector_broadcast_mask_operand"
(ior (match_operand 0 "vector_least_significant_set_mask_operand")
+ (match_operand 0 "vector_all_trues_mask_operand")))
+
+(define_predicate "strided_broadcast_mask_operand"
+ (ior (match_operand 0 "vector_least_significant_set_mask_operand")
(ior (match_operand 0 "register_operand")
(match_operand 0 "vector_all_trues_mask_operand"))))
@@ -619,6 +623,15 @@
(define_predicate "direct_broadcast_operand"
(match_test "riscv_vector::can_be_broadcast_p (op)"))
+;; A strided broadcast is just a fallback pattern that loads from
+;; memory.
+(define_predicate "strided_broadcast_operand"
+ (match_test "riscv_vector::strided_broadcast_p (op)"))
+
+(define_predicate "any_broadcast_operand"
+ (ior (match_operand 0 "direct_broadcast_operand")
+ (match_operand 0 "strided_broadcast_operand")))
+
;; 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-ext.def b/gcc/config/riscv/riscv-ext.def
index 6fc6d38..09f18ad 100644
--- a/gcc/config/riscv/riscv-ext.def
+++ b/gcc/config/riscv/riscv-ext.def
@@ -80,8 +80,8 @@ DEFINE_RISCV_EXT(
/* DEP_EXTS */ ({}),
/* SUPPORTED_VERSIONS */ ({{2, 0}}),
/* FLAG_GROUP */ base,
- /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED,
- /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED,
+ /* BITMASK_GROUP_ID */ 0,
+ /* BITMASK_BIT_POSITION*/ 4,
/* EXTRA_EXTENSION_FLAGS */ 0)
DEFINE_RISCV_EXT(
@@ -190,8 +190,8 @@ DEFINE_RISCV_EXT(
/* DEP_EXTS */ ({"zba", "zbb", "zbs"}),
/* SUPPORTED_VERSIONS */ ({{1, 0}}),
/* FLAG_GROUP */ base,
- /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED,
- /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED,
+ /* BITMASK_GROUP_ID */ 0,
+ /* BITMASK_BIT_POSITION*/ 1,
/* EXTRA_EXTENSION_FLAGS */ EXT_FLAG_MACRO)
DEFINE_RISCV_EXT(
@@ -216,8 +216,8 @@ DEFINE_RISCV_EXT(
/* DEP_EXTS */ ({}),
/* SUPPORTED_VERSIONS */ ({{1, 0}}),
/* FLAG_GROUP */ base,
- /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED,
- /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED,
+ /* BITMASK_GROUP_ID */ 0,
+ /* BITMASK_BIT_POSITION*/ 7,
/* EXTRA_EXTENSION_FLAGS */ 0)
DEFINE_RISCV_EXT(
@@ -398,8 +398,8 @@ DEFINE_RISCV_EXT(
/* DEP_EXTS */ ({}),
/* SUPPORTED_VERSIONS */ ({{2, 0}}),
/* FLAG_GROUP */ zi,
- /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED,
- /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED,
+ /* BITMASK_GROUP_ID */ 1,
+ /* BITMASK_BIT_POSITION*/ 11,
/* EXTRA_EXTENSION_FLAGS */ 0)
DEFINE_RISCV_EXT(
@@ -464,7 +464,7 @@ DEFINE_RISCV_EXT(
/* SUPPORTED_VERSIONS */ ({{1, 0}}),
/* FLAG_GROUP */ zi,
/* BITMASK_GROUP_ID */ 1,
- /* BITMASK_BIT_POSITION*/ 1,
+ /* BITMASK_BIT_POSITION*/ 8,
/* EXTRA_EXTENSION_FLAGS */ 0)
DEFINE_RISCV_EXT(
@@ -476,8 +476,8 @@ DEFINE_RISCV_EXT(
/* DEP_EXTS */ ({}),
/* SUPPORTED_VERSIONS */ ({{1, 0}}),
/* FLAG_GROUP */ zm,
- /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED,
- /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED,
+ /* BITMASK_GROUP_ID */ 1,
+ /* BITMASK_BIT_POSITION*/ 12,
/* EXTRA_EXTENSION_FLAGS */ 0)
DEFINE_RISCV_EXT(
@@ -787,8 +787,8 @@ DEFINE_RISCV_EXT(
/* DEP_EXTS */ ({"zca"}),
/* SUPPORTED_VERSIONS */ ({{1, 0}}),
/* FLAG_GROUP */ zc,
- /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED,
- /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED,
+ /* BITMASK_GROUP_ID */ 1,
+ /* BITMASK_BIT_POSITION*/ 10,
/* EXTRA_EXTENSION_FLAGS */ 0)
DEFINE_RISCV_EXT(
@@ -813,8 +813,8 @@ DEFINE_RISCV_EXT(
/* DEP_EXTS */ ({"zca", "zilsd"}),
/* SUPPORTED_VERSIONS */ ({{1, 0}}),
/* FLAG_GROUP */ zc,
- /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED,
- /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED,
+ /* BITMASK_GROUP_ID */ 1,
+ /* BITMASK_BIT_POSITION*/ 9,
/* EXTRA_EXTENSION_FLAGS */ 0)
DEFINE_RISCV_EXT(
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index a41c4c2..539321f 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -414,8 +414,14 @@ enum insn_flags : unsigned int
/* Means INSN has VXRM operand and the value is VXRM_RNU. */
VXRM_RNU_P = 1 << 20,
+ /* Means INSN has VXRM operand and the value is VXRM_RNE. */
+ VXRM_RNE_P = 1 << 21,
+
/* Means INSN has VXRM operand and the value is VXRM_RDN. */
- VXRM_RDN_P = 1 << 21,
+ VXRM_RDN_P = 1 << 22,
+
+ /* Means INSN has VXRM operand and the value is VXRM_ROD. */
+ VXRM_ROD_P = 1 << 23,
};
enum insn_type : unsigned int
@@ -477,7 +483,9 @@ enum insn_type : unsigned int
BINARY_OP_TUMA = __MASK_OP_TUMA | BINARY_OP_P,
BINARY_OP_FRM_DYN = BINARY_OP | FRM_DYN_P,
BINARY_OP_VXRM_RNU = BINARY_OP | VXRM_RNU_P,
+ BINARY_OP_VXRM_RNE = BINARY_OP | VXRM_RNE_P,
BINARY_OP_VXRM_RDN = BINARY_OP | VXRM_RDN_P,
+ BINARY_OP_VXRM_ROD = BINARY_OP | VXRM_ROD_P,
/* Ternary operator. Always have real merge operand. */
TERNARY_OP = HAS_DEST_P | HAS_MASK_P | USE_ALL_TRUES_MASK_P | HAS_MERGE_P
@@ -672,6 +680,8 @@ void expand_vec_oct_sstrunc (rtx, rtx, machine_mode, machine_mode,
machine_mode);
void expand_vx_binary_vec_dup_vec (rtx, rtx, rtx, rtx_code, machine_mode);
void expand_vx_binary_vec_vec_dup (rtx, rtx, rtx, rtx_code, machine_mode);
+void expand_vx_binary_vxrm_vec_vec_dup (rtx, rtx, rtx, int, int, machine_mode);
+void expand_vx_binary_vxrm_vec_dup_vec (rtx, rtx, rtx, int, int, machine_mode);
#endif
bool sew64_scalar_helper (rtx *, rtx *, rtx, machine_mode,
bool, void (*)(rtx *, rtx), enum avl_type);
@@ -695,6 +705,9 @@ bool expand_block_move (rtx, rtx, rtx, bool);
machine_mode preferred_simd_mode (scalar_mode);
machine_mode get_mask_mode (machine_mode);
void expand_vec_series (rtx, rtx, rtx, rtx = 0);
+void expand_broadcast (machine_mode, rtx *, rtx = 0);
+void expand_set_first (machine_mode, rtx *, rtx = 0);
+void expand_set_first_tu (machine_mode, rtx *, rtx = 0);
void expand_vec_init (rtx, rtx);
void expand_vec_perm (rtx, rtx, rtx, rtx);
void expand_select_vl (rtx *);
@@ -762,6 +775,7 @@ enum vlmul_type get_vlmul (rtx_insn *);
int count_regno_occurrences (rtx_insn *, unsigned int);
bool imm_avl_p (machine_mode);
bool can_be_broadcast_p (rtx);
+bool strided_broadcast_p (rtx);
bool gather_scatter_valid_offset_p (machine_mode);
HOST_WIDE_INT estimated_poly_value (poly_int64, unsigned int);
bool whole_reg_to_reg_move_p (rtx *, machine_mode, int);
diff --git a/gcc/config/riscv/riscv-string.cc b/gcc/config/riscv/riscv-string.cc
index 9080189..61c4a09 100644
--- a/gcc/config/riscv/riscv-string.cc
+++ b/gcc/config/riscv/riscv-string.cc
@@ -1625,16 +1625,14 @@ expand_vec_setmem (rtx dst_in, rtx length_in, rtx fill_value_in)
Otherwise, use a predicated store. */
if (known_eq (GET_MODE_SIZE (info.vmode), INTVAL (info.avl)))
{
- emit_vlmax_insn (code_for_pred_broadcast (info.vmode), UNARY_OP,
- broadcast_ops);
+ riscv_vector::expand_broadcast (info.vmode, broadcast_ops);
emit_move_insn (dst, fill_value);
}
else
{
if (!satisfies_constraint_vl (info.avl))
info.avl = force_reg (Pmode, info.avl);
- emit_nonvlmax_insn (code_for_pred_broadcast (info.vmode),
- riscv_vector::UNARY_OP, broadcast_ops, info.avl);
+ riscv_vector::expand_broadcast (info.vmode, broadcast_ops, info.avl);
machine_mode mask_mode
= riscv_vector::get_vector_mode (BImode, GET_MODE_NUNITS (info.vmode))
.require ();
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index 242ac08..c9c8328 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -351,9 +351,12 @@ public:
add_rounding_mode_operand (FRM_RNE);
else if (m_insn_flags & VXRM_RNU_P)
add_rounding_mode_operand (VXRM_RNU);
+ else if (m_insn_flags & VXRM_RNE_P)
+ add_rounding_mode_operand (VXRM_RNE);
else if (m_insn_flags & VXRM_RDN_P)
add_rounding_mode_operand (VXRM_RDN);
-
+ else if (m_insn_flags & VXRM_ROD_P)
+ add_rounding_mode_operand (VXRM_ROD);
if (insn_data[(int) icode].n_operands != m_opno)
internal_error ("invalid number of operands for insn %s, "
@@ -1190,6 +1193,59 @@ expand_vector_init_trailing_same_elem (rtx target,
return false;
}
+/* Helper function to emit a vmv.vx/vi and float variants.
+ If VL is not given a VLMAX insn will be emitted, otherwise
+ a non-VLMAX insn with length VL.
+ If the value to be broadcast is not suitable for vmv.vx
+ fall back to a vlse with zero stride. This itself has a
+ fallback if the uarch prefers not to use a strided load
+ for broadcast. */
+
+void
+expand_broadcast (machine_mode mode, rtx *ops, rtx vl)
+{
+ rtx elt = ops[1];
+ avl_type type = vl ? NONVLMAX : VLMAX;
+ if (can_be_broadcast_p (elt))
+ emit_avltype_insn (code_for_pred_broadcast (mode), UNARY_OP, ops,
+ type, vl);
+ else
+ emit_avltype_insn (code_for_pred_strided_broadcast (mode),
+ UNARY_OP, ops, type, vl);
+}
+
+/* Similar to expand_broadcast but emits a vmv.s.x/vfmv.s.f instead. */
+
+void
+expand_set_first (machine_mode mode, rtx *ops, rtx vl)
+{
+ rtx elt = ops[1];
+ avl_type type = vl ? NONVLMAX : VLMAX;
+ if (can_be_broadcast_p (elt))
+ emit_avltype_insn (code_for_pred_broadcast (mode),
+ SCALAR_MOVE_OP, ops, type, vl);
+ else
+ emit_avltype_insn (code_for_pred_strided_broadcast (mode),
+ SCALAR_MOVE_OP, ops, type, vl);
+}
+
+/* Similar to expand_set_first but keeping the tail elements
+ unchanged (TU) */
+
+void
+expand_set_first_tu (machine_mode mode, rtx *ops, rtx vl)
+{
+ rtx elt = ops[2];
+ if (!vl)
+ vl = const1_rtx;
+ if (can_be_broadcast_p (elt))
+ emit_nonvlmax_insn (code_for_pred_broadcast (mode),
+ SCALAR_MOVE_MERGED_OP_TU, ops, vl);
+ else
+ emit_nonvlmax_insn (code_for_pred_strided_broadcast (mode),
+ SCALAR_MOVE_MERGED_OP_TU, ops, vl);
+}
+
static void
expand_const_vec_duplicate (rtx target, rtx src, rtx elt)
{
@@ -1226,7 +1282,7 @@ expand_const_vec_duplicate (rtx target, rtx src, rtx elt)
if (lra_in_progress)
{
rtx ops[] = {result, elt};
- emit_vlmax_insn (code_for_pred_broadcast (mode), UNARY_OP, ops);
+ expand_broadcast (mode, ops);
}
else
{
@@ -1278,8 +1334,7 @@ expand_const_vector_duplicate_repeating (rtx target, rvv_builder *builder)
{
dup = gen_reg_rtx (builder->new_mode ());
rtx ops[] = {dup, ele};
- emit_vlmax_insn (code_for_pred_broadcast (builder->new_mode ()),
- UNARY_OP, ops);
+ expand_broadcast (builder->new_mode (), ops);
}
else
dup = expand_vector_broadcast (builder->new_mode (), ele);
@@ -1322,8 +1377,7 @@ expand_const_vector_duplicate_default (rtx target, rvv_builder *builder)
rtx tmp1 = gen_reg_rtx (builder->mode ());
rtx dup_ops[] = {tmp1, builder->elt (0)};
- emit_vlmax_insn (code_for_pred_broadcast (builder->mode ()), UNARY_OP,
- dup_ops);
+ expand_broadcast (builder->mode (), dup_ops);
for (unsigned int i = 1; i < builder->npatterns (); i++)
{
@@ -2136,18 +2190,32 @@ has_vi_variant_p (rtx_code code, rtx x)
}
}
+/* This is a helper for binary ops with DImode scalar operands that are
+ broadcast (like vadd.vx v1, a1).
+ Instead of having similar code for all the expanders this function
+ unifies the handling. For 64-bit targets all we do is choose
+ between the vi variant (if available) and the register variant.
+ For 32-bit targets we either create the sign-extending variant
+ of vop.vx (when the immediate fits 32 bits) or emit a vector
+ broadcast of the 64-bit register/immediate and switch to a
+ vop.vv (replacing the scalar op with the broadcast vector. */
+
bool
sew64_scalar_helper (rtx *operands, rtx *scalar_op, rtx vl,
machine_mode vector_mode, bool has_vi_variant_p,
void (*emit_vector_func) (rtx *, rtx), enum avl_type type)
{
machine_mode scalar_mode = GET_MODE_INNER (vector_mode);
+
+ /* If the scalar broadcast op fits an immediate, use the
+ vop.vi variant if there is one. */
if (has_vi_variant_p)
{
*scalar_op = force_reg (scalar_mode, *scalar_op);
return false;
}
+ /* On a 64-bit target we can always use the vop.vx variant. */
if (TARGET_64BIT)
{
if (!rtx_equal_p (*scalar_op, const0_rtx))
@@ -2155,6 +2223,8 @@ sew64_scalar_helper (rtx *operands, rtx *scalar_op, rtx vl,
return false;
}
+ /* For 32 bit and if there is no vop.vi variant for a 32-bit immediate
+ we need to use the sign-extending (SI -> DI) vop.vx variants. */
if (immediate_operand (*scalar_op, Pmode))
{
if (!rtx_equal_p (*scalar_op, const0_rtx))
@@ -2164,40 +2234,29 @@ sew64_scalar_helper (rtx *operands, rtx *scalar_op, rtx vl,
return false;
}
- bool avoid_strided_broadcast = false;
+ /* Now we're left with a 64-bit immediate or a register.
+ We cannot use a vop.vx variant but must broadcast the value first
+ and switch to a vop.vv variant.
+ Broadcast can either be done via vlse64.v v1, reg, zero
+ or by loading one 64-bit element (vle64.v) and using a
+ broadcast vrgather.vi. This is decided when splitting
+ the strided broadcast insn. */
+ gcc_assert (!TARGET_64BIT
+ && (CONST_INT_P (*scalar_op)
+ || register_operand (*scalar_op, scalar_mode)));
+
if (CONST_INT_P (*scalar_op))
{
if (maybe_gt (GET_MODE_SIZE (scalar_mode), GET_MODE_SIZE (Pmode)))
- {
- if (strided_load_broadcast_p ())
- *scalar_op = force_const_mem (scalar_mode, *scalar_op);
- else
- avoid_strided_broadcast = true;
- }
+ *scalar_op = force_const_mem (scalar_mode, *scalar_op);
else
*scalar_op = force_reg (scalar_mode, *scalar_op);
}
rtx tmp = gen_reg_rtx (vector_mode);
- if (!avoid_strided_broadcast)
- {
- rtx ops[] = {tmp, *scalar_op};
- emit_avltype_insn (code_for_pred_broadcast (vector_mode), UNARY_OP, ops,
- type, vl);
- }
- else
- {
- /* Load scalar as V1DI and broadcast via vrgather.vi. */
- rtx tmp1 = gen_reg_rtx (V1DImode);
- emit_move_insn (tmp1, lowpart_subreg (V1DImode, *scalar_op,
- scalar_mode));
- tmp1 = lowpart_subreg (vector_mode, tmp1, V1DImode);
-
- rtx ops[] = {tmp, tmp1, CONST0_RTX (Pmode)};
- emit_vlmax_insn (code_for_pred_gather_scalar (vector_mode),
- BINARY_OP, ops);
- }
-
+ rtx ops[] = {tmp, *scalar_op};
+ emit_avltype_insn (code_for_pred_strided_broadcast (vector_mode),
+ UNARY_OP, ops, type, vl);
emit_vector_func (operands, tmp);
return true;
@@ -2591,8 +2650,7 @@ expand_vector_init_merge_repeating_sequence (rtx target,
/* Step 1: Broadcast the first pattern. */
rtx ops[] = {target, force_reg (builder.inner_mode (), builder.elt (0))};
- emit_vlmax_insn (code_for_pred_broadcast (builder.mode ()),
- UNARY_OP, ops);
+ expand_broadcast (builder.mode (), ops);
/* Step 2: Merge the rest iteration of pattern. */
for (unsigned int i = 1; i < builder.npatterns (); i++)
{
@@ -2605,8 +2663,7 @@ expand_vector_init_merge_repeating_sequence (rtx target,
if (full_nelts <= builder.inner_bits_size ()) /* vmv.s.x. */
{
rtx ops[] = {dup, merge_mask};
- emit_nonvlmax_insn (code_for_pred_broadcast (GET_MODE (dup)),
- SCALAR_MOVE_OP, ops, CONST1_RTX (Pmode));
+ expand_set_first (GET_MODE (dup), ops);
}
else /* vmv.v.x. */
{
@@ -2614,8 +2671,7 @@ expand_vector_init_merge_repeating_sequence (rtx target,
force_reg (GET_MODE_INNER (mask_int_mode), merge_mask)};
rtx vl = gen_int_mode (CEIL (full_nelts, builder.inner_bits_size ()),
Pmode);
- emit_nonvlmax_insn (code_for_pred_broadcast (mask_int_mode), UNARY_OP,
- ops, vl);
+ expand_broadcast (mask_int_mode, ops, vl);
}
emit_move_insn (mask, gen_lowpart (mask_bit_mode, dup));
@@ -4706,20 +4762,20 @@ expand_reduction (unsigned unspec, unsigned unspec_for_vl0_safe,
rtx m1_tmp = gen_reg_rtx (m1_mode);
rtx scalar_move_ops[] = {m1_tmp, init};
- insn_code icode = code_for_pred_broadcast (m1_mode);
if (need_mask_operand_p (insn_flags))
{
if (need_vl0_safe)
- emit_nonvlmax_insn (icode, SCALAR_MOVE_OP, scalar_move_ops, const1_rtx);
+ expand_set_first (m1_mode, scalar_move_ops, const1_rtx);
else
- emit_nonvlmax_insn (icode, SCALAR_MOVE_OP, scalar_move_ops, vl_op);
+ expand_set_first (m1_mode, scalar_move_ops, vl_op);
}
else
- emit_vlmax_insn (icode, SCALAR_MOVE_OP, scalar_move_ops);
+ expand_set_first (m1_mode, scalar_move_ops);
rtx m1_tmp2 = gen_reg_rtx (m1_mode);
rtx reduc_ops[] = {m1_tmp2, vector_src, m1_tmp};
+ insn_code icode;
if (need_vl0_safe)
icode = code_for_pred (unspec_for_vl0_safe, vmode);
else
@@ -5597,6 +5653,82 @@ expand_vx_binary_vec_dup_vec (rtx op_0, rtx op_1, rtx op_2,
emit_vlmax_insn (icode, riscv_vector::BINARY_OP, ops);
}
+static enum insn_type
+get_insn_type_by_vxrm_val (int vxrm_val)
+{
+ enum insn_type itype;
+
+ switch (vxrm_val)
+ {
+ case VXRM_RNU:
+ itype = BINARY_OP_VXRM_RNU;
+ break;
+ case VXRM_RNE:
+ itype = BINARY_OP_VXRM_RNE;
+ break;
+ case VXRM_RDN:
+ itype = BINARY_OP_VXRM_RDN;
+ break;
+ case VXRM_ROD:
+ itype = BINARY_OP_VXRM_ROD;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ return itype;
+}
+
+/* Expand the binary vx combine with the format like v2 = vop(v1, vec_dup(x))
+ and its' vxrm value. Aka the second op comes from the vec_duplicate,
+ and the first op is the vector reg. */
+
+void
+expand_vx_binary_vxrm_vec_vec_dup (rtx op_0, rtx op_1, rtx op_2, int unspec,
+ int vxrm_val, machine_mode mode)
+{
+ enum insn_code icode;
+ enum insn_type itype = get_insn_type_by_vxrm_val (vxrm_val);
+ rtx ops[] = {op_0, op_1, op_2};
+
+ switch (unspec)
+ {
+ case UNSPEC_VAADD:
+ case UNSPEC_VAADDU:
+ icode = code_for_pred_scalar (unspec, mode);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ emit_vlmax_insn (icode, itype, ops);
+}
+
+/* Expand the binary vx combine with the format like v2 = vop(vec_dup(x), v1)
+ and its' vxrm value. Aka the second op comes from the vec_duplicate,
+ and the first op is the vector reg. */
+
+void
+expand_vx_binary_vxrm_vec_dup_vec (rtx op_0, rtx op_1, rtx op_2, int unspec,
+ int vxrm_val, machine_mode mode)
+{
+ enum insn_code icode;
+ enum insn_type itype = get_insn_type_by_vxrm_val (vxrm_val);
+ rtx ops[] = {op_0, op_1, op_2};
+
+ switch (unspec)
+ {
+ case UNSPEC_VAADD:
+ case UNSPEC_VAADDU:
+ icode = code_for_pred_scalar (unspec, mode);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ emit_vlmax_insn (icode, itype, ops);
+}
+
/* Expand the binary vx combine with the format like v2 = vop(v1, vec_dup(x)).
Aka the second op comes from the vec_duplicate, and the first op is
the vector reg. */
@@ -5808,25 +5940,84 @@ count_regno_occurrences (rtx_insn *rinsn, unsigned int regno)
return count;
}
-/* Return true if the OP can be directly broadcast. */
+/* Return true if the OP can be broadcast with a
+ v[f]mv.v.[xif] instruction. */
+
bool
can_be_broadcast_p (rtx op)
{
machine_mode mode = GET_MODE (op);
- /* We don't allow RA (register allocation) reload generate
- (vec_duplicate:DI reg) in RV32 system wheras we allow
- (vec_duplicate:DI mem) in RV32 system. */
- if (!can_create_pseudo_p () && !FLOAT_MODE_P (mode)
- && maybe_gt (GET_MODE_SIZE (mode), GET_MODE_SIZE (Pmode))
- && !satisfies_constraint_Wdm (op))
+
+ /* Zero always works and we can always put an immediate into a
+ register.
+ What's tricky is that for an immediate we don't know the
+ register's mode it will end up in, i.e. what element size
+ we want to broadcast. So even if the immediate is small it might
+ still end up in a DImode register that we cannot broadcast.
+ vmv.s.x, i.e. a single-element set can handle this, though,
+ because it implicitly sign-extends to SEW. */
+ if (rtx_equal_p (op, CONST0_RTX (mode))
+ || const_int_operand (op, Xmode))
+ return true;
+
+ /* Do not accept DImode broadcasts on !TARGET_64BIT. Those
+ are handled by strided broadcast. */
+ if (INTEGRAL_MODE_P (mode)
+ && maybe_gt (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+ return false;
+
+ /* Non-register operands that can be forced into a register we can
+ handle. These don't need to use strided broadcast. */
+ if (INTEGRAL_MODE_P (mode)
+ && (memory_operand (op, mode) || CONST_POLY_INT_P (op))
+ && can_create_pseudo_p ())
+ return true;
+
+ /* Likewise, do not accept HFmode broadcast if we don't have
+ vfmv.v.f for 16-bit registers available. */
+ if (mode == HFmode && !TARGET_ZVFH)
+ return false;
+
+ /* Same for float, just that we can always handle 64-bit doubles
+ even on !TARGET_64BIT. We have ruled out 16-bit HF already
+ above. */
+ if (FLOAT_MODE_P (mode)
+ && (memory_operand (op, mode) || CONSTANT_P (op))
+ && can_create_pseudo_p ())
+ return true;
+
+ /* After excluding all the cases we cannot handle the register types
+ that remain can always be broadcast. */
+ if (register_operand (op, mode))
+ return true;
+
+ return false;
+}
+
+/* Returns true for all operands that cannot use vmv.vx, vfmv.vf,
+ vmv.s.x, or vfmv.s.f but rather need to go via memory. */
+
+bool
+strided_broadcast_p (rtx op)
+{
+ machine_mode mode = GET_MODE (op);
+ if (!memory_operand (op, mode)
+ && !register_operand (op, mode)
+ && !rtx_equal_p (op, CONST0_RTX (mode))
+ && !const_int_operand (op, mode))
return false;
- if (satisfies_constraint_K (op) || register_operand (op, mode)
- || (strided_load_broadcast_p () && satisfies_constraint_Wdm (op))
- || rtx_equal_p (op, CONST0_RTX (mode)))
+ /* !TARGET64_BIT does not have a vmv.v.x/vmv.s.x for 64-bit
+ DImode elements. */
+ if (INTEGRAL_MODE_P (mode)
+ && maybe_gt (GET_MODE_SIZE (mode), UNITS_PER_WORD))
+ return true;
+
+ /* Zvfhmin does not have a vfmv.v.f/vfmv.s.f. for 16-bit elements. */
+ if (!TARGET_ZVFH && mode == HFmode)
return true;
- return can_create_pseudo_p () && nonmemory_operand (op, mode);
+ return false;
}
void
@@ -5941,7 +6132,10 @@ whole_reg_to_reg_move_p (rtx *ops, machine_mode mode, int avl_type_index)
return false;
}
-/* Return true if we can transform vmv.v.x/vfmv.v.f to vmv.s.x/vfmv.s.f. */
+/* Return true if we can transform vmv.v.x/vfmv.v.f to vmv.s.x/vfmv.s.f.
+ That's the case if we're dealing with a scalar broadcast that
+ has VL = 1. */
+
bool
splat_to_scalar_move_p (rtx *ops)
{
diff --git a/gcc/config/riscv/riscv-vector-builtins-bases.cc b/gcc/config/riscv/riscv-vector-builtins-bases.cc
index bf5172c..7e4d396 100644
--- a/gcc/config/riscv/riscv-vector-builtins-bases.cc
+++ b/gcc/config/riscv/riscv-vector-builtins-bases.cc
@@ -643,7 +643,8 @@ public:
return e.use_exact_insn (code_for_pred_mov (e.vector_mode ()));
case OP_TYPE_x:
case OP_TYPE_f:
- return e.use_exact_insn (code_for_pred_broadcast (e.vector_mode ()));
+ return e.use_scalar_broadcast_insn
+ (code_for_pred_broadcast (e.vector_mode ()));
default:
gcc_unreachable ();
}
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index 8810af0..0db7549 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -4753,7 +4753,10 @@ function_expander::use_ternop_insn (bool vd_accum_p, insn_code icode)
}
/* Implement the call using instruction ICODE, with a 1:1 mapping between
- arguments and input operands. */
+ arguments and input operands.
+ There are operands that cannot be broadcast using v[f]mv. In that case
+ we switch to a strided broadcast. */
+
rtx
function_expander::use_widen_ternop_insn (insn_code icode)
{
@@ -4794,7 +4797,10 @@ function_expander::use_widen_ternop_insn (insn_code icode)
}
/* Implement the call using instruction ICODE, with a 1:1 mapping between
- arguments and input operands. */
+ arguments and input operands.
+ There are operands that cannot be broadcast using v[f]mv. In that case
+ we switch to a strided broadcast. */
+
rtx
function_expander::use_scalar_move_insn (insn_code icode)
{
@@ -4812,6 +4818,37 @@ function_expander::use_scalar_move_insn (insn_code icode)
for (int argno = arg_offset; argno < call_expr_nargs (exp); argno++)
add_input_operand (argno);
+ if (!can_be_broadcast_p (m_ops[3].value))
+ icode = code_for_pred_strided_broadcast (vector_mode ());
+
+ add_input_operand (Pmode, get_tail_policy_for_pred (pred));
+ add_input_operand (Pmode, get_mask_policy_for_pred (pred));
+ add_input_operand (Pmode, get_avl_type_rtx (avl_type::NONVLMAX));
+ return generate_insn (icode);
+}
+
+/* Implement the call using instruction ICODE, with a 1:1 mapping between
+ arguments and input operands. */
+rtx
+function_expander::use_scalar_broadcast_insn (insn_code icode)
+{
+ machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
+
+ /* Record the offset to get the argument. */
+ int arg_offset = 0;
+ add_all_one_mask_operand (mask_mode ());
+
+ if (use_real_merge_p (pred))
+ add_input_operand (arg_offset++);
+ else
+ add_vundef_operand (mode);
+
+ for (int argno = arg_offset; argno < call_expr_nargs (exp); argno++)
+ add_input_operand (argno);
+
+ if (!can_be_broadcast_p (m_ops[3].value))
+ icode = code_for_pred_strided_broadcast (vector_mode ());
+
add_input_operand (Pmode, get_tail_policy_for_pred (pred));
add_input_operand (Pmode, get_mask_policy_for_pred (pred));
add_input_operand (Pmode, get_avl_type_rtx (avl_type::NONVLMAX));
diff --git a/gcc/config/riscv/riscv-vector-builtins.h b/gcc/config/riscv/riscv-vector-builtins.h
index 1f2587a..86d8115 100644
--- a/gcc/config/riscv/riscv-vector-builtins.h
+++ b/gcc/config/riscv/riscv-vector-builtins.h
@@ -497,6 +497,7 @@ public:
rtx use_ternop_insn (bool, insn_code);
rtx use_widen_ternop_insn (insn_code);
rtx use_scalar_move_insn (insn_code);
+ rtx use_scalar_broadcast_insn (insn_code);
rtx generate_insn (insn_code);
/* The function call expression. */
diff --git a/gcc/config/riscv/riscv-vector-costs.cc b/gcc/config/riscv/riscv-vector-costs.cc
index 4d8170d..df924fa 100644
--- a/gcc/config/riscv/riscv-vector-costs.cc
+++ b/gcc/config/riscv/riscv-vector-costs.cc
@@ -178,8 +178,8 @@ get_live_range (hash_map<tree, pair> *live_ranges, tree arg)
STMT 5 (be vectorized) -- point 2
...
*/
-static void
-compute_local_program_points (
+void
+costs::compute_local_program_points (
vec_info *vinfo,
hash_map<basic_block, vec<stmt_point>> &program_points_per_bb)
{
@@ -274,14 +274,14 @@ loop_invariant_op_p (class loop *loop,
/* Return true if the variable should be counted into liveness. */
static bool
-variable_vectorized_p (class loop *loop, stmt_vec_info stmt_info, tree var,
- bool lhs_p)
+variable_vectorized_p (class loop *loop, stmt_vec_info stmt_info,
+ slp_tree node ATTRIBUTE_UNUSED, tree var, bool lhs_p)
{
if (!var)
return false;
gimple *stmt = STMT_VINFO_STMT (stmt_info);
- enum stmt_vec_info_type type
- = STMT_VINFO_TYPE (vect_stmt_to_vectorize (stmt_info));
+ stmt_info = vect_stmt_to_vectorize (stmt_info);
+ enum stmt_vec_info_type type = STMT_VINFO_TYPE (stmt_info);
if (is_gimple_call (stmt) && gimple_call_internal_p (stmt))
{
if (gimple_call_internal_fn (stmt) == IFN_MASK_STORE
@@ -357,8 +357,8 @@ variable_vectorized_p (class loop *loop, stmt_vec_info stmt_info, tree var,
The live range of SSA 1 is [1, 3] in bb 2.
The live range of SSA 2 is [0, 4] in bb 3. */
-static machine_mode
-compute_local_live_ranges (
+machine_mode
+costs::compute_local_live_ranges (
loop_vec_info loop_vinfo,
const hash_map<basic_block, vec<stmt_point>> &program_points_per_bb,
hash_map<basic_block, hash_map<tree, pair>> &live_ranges_per_bb)
@@ -388,8 +388,11 @@ compute_local_live_ranges (
unsigned int point = program_point.point;
gimple *stmt = program_point.stmt;
tree lhs = gimple_get_lhs (stmt);
- if (variable_vectorized_p (loop, program_point.stmt_info, lhs,
- true))
+ slp_tree *node = vinfo_slp_map.get (program_point.stmt_info);
+ if (!node)
+ continue;
+ if (variable_vectorized_p (loop, program_point.stmt_info,
+ *node, lhs, true))
{
biggest_mode = get_biggest_mode (biggest_mode,
TYPE_MODE (TREE_TYPE (lhs)));
@@ -406,8 +409,8 @@ compute_local_live_ranges (
for (i = 0; i < gimple_num_args (stmt); i++)
{
tree var = gimple_arg (stmt, i);
- if (variable_vectorized_p (loop, program_point.stmt_info, var,
- false))
+ if (variable_vectorized_p (loop, program_point.stmt_info,
+ *node, var, false))
{
biggest_mode
= get_biggest_mode (biggest_mode,
@@ -597,11 +600,11 @@ get_store_value (gimple *stmt)
}
/* Return true if additional vector vars needed. */
-static bool
-need_additional_vector_vars_p (stmt_vec_info stmt_info)
+bool
+costs::need_additional_vector_vars_p (stmt_vec_info stmt_info,
+ slp_tree node ATTRIBUTE_UNUSED)
{
- enum stmt_vec_info_type type
- = STMT_VINFO_TYPE (vect_stmt_to_vectorize (stmt_info));
+ enum stmt_vec_info_type type = STMT_VINFO_TYPE (stmt_info);
if (type == load_vec_info_type || type == store_vec_info_type)
{
if (STMT_VINFO_GATHER_SCATTER_P (stmt_info)
@@ -657,8 +660,8 @@ compute_estimated_lmul (loop_vec_info loop_vinfo, machine_mode mode)
Then, after this function, we update SSA 1 live range in bb 2
into [2, 4] since SSA 1 is live out into bb 3. */
-static void
-update_local_live_ranges (
+void
+costs::update_local_live_ranges (
vec_info *vinfo,
hash_map<basic_block, vec<stmt_point>> &program_points_per_bb,
hash_map<basic_block, hash_map<tree, pair>> &live_ranges_per_bb,
@@ -685,8 +688,13 @@ update_local_live_ranges (
{
gphi *phi = psi.phi ();
stmt_vec_info stmt_info = vinfo->lookup_stmt (phi);
- if (STMT_VINFO_TYPE (vect_stmt_to_vectorize (stmt_info))
- == undef_vec_info_type)
+ stmt_info = vect_stmt_to_vectorize (stmt_info);
+ slp_tree *node = vinfo_slp_map.get (stmt_info);
+
+ if (!node)
+ continue;
+
+ if (STMT_VINFO_TYPE (stmt_info) == undef_vec_info_type)
continue;
for (j = 0; j < gimple_phi_num_args (phi); j++)
@@ -761,9 +769,12 @@ update_local_live_ranges (
if (!is_gimple_assign_or_call (gsi_stmt (si)))
continue;
stmt_vec_info stmt_info = vinfo->lookup_stmt (gsi_stmt (si));
- enum stmt_vec_info_type type
- = STMT_VINFO_TYPE (vect_stmt_to_vectorize (stmt_info));
- if (need_additional_vector_vars_p (stmt_info))
+ stmt_info = vect_stmt_to_vectorize (stmt_info);
+ slp_tree *node = vinfo_slp_map.get (stmt_info);
+ if (!node)
+ continue;
+ enum stmt_vec_info_type type = STMT_VINFO_TYPE (stmt_info);
+ if (need_additional_vector_vars_p (stmt_info, *node))
{
/* For non-adjacent load/store STMT, we will potentially
convert it into:
@@ -816,8 +827,8 @@ update_local_live_ranges (
}
/* Compute the maximum live V_REGS. */
-static bool
-has_unexpected_spills_p (loop_vec_info loop_vinfo)
+bool
+costs::has_unexpected_spills_p (loop_vec_info loop_vinfo)
{
/* Compute local program points.
It's a fast and effective computation. */
@@ -899,7 +910,11 @@ costs::analyze_loop_vinfo (loop_vec_info loop_vinfo)
/* Detect whether we're vectorizing for VLA and should apply the unrolling
heuristic described above m_unrolled_vls_niters. */
record_potential_vls_unrolling (loop_vinfo);
+}
+void
+costs::record_lmul_spills (loop_vec_info loop_vinfo)
+{
/* Detect whether the LOOP has unexpected spills. */
record_potential_unexpected_spills (loop_vinfo);
}
@@ -1239,8 +1254,12 @@ costs::add_stmt_cost (int count, vect_cost_for_stmt kind,
int stmt_cost
= targetm.vectorize.builtin_vectorization_cost (kind, vectype, misalign);
+ if (stmt_info && node)
+ vinfo_slp_map.put (stmt_info, node);
+
/* Do one-time initialization based on the vinfo. */
loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (m_vinfo);
+
if (!m_analyzed_vinfo)
{
if (loop_vinfo)
@@ -1326,6 +1345,8 @@ costs::finish_cost (const vector_costs *scalar_costs)
{
if (loop_vec_info loop_vinfo = dyn_cast<loop_vec_info> (m_vinfo))
{
+ record_lmul_spills (loop_vinfo);
+
adjust_vect_cost_per_loop (loop_vinfo);
}
vector_costs::finish_cost (scalar_costs);
diff --git a/gcc/config/riscv/riscv-vector-costs.h b/gcc/config/riscv/riscv-vector-costs.h
index de546a6..b84ceb1 100644
--- a/gcc/config/riscv/riscv-vector-costs.h
+++ b/gcc/config/riscv/riscv-vector-costs.h
@@ -91,7 +91,10 @@ private:
typedef pair_hash <tree_operand_hash, tree_operand_hash> tree_pair_hash;
hash_set <tree_pair_hash> memrefs;
+ hash_map <stmt_vec_info, slp_tree> vinfo_slp_map;
+
void analyze_loop_vinfo (loop_vec_info);
+ void record_lmul_spills (loop_vec_info loop_vinfo);
void record_potential_vls_unrolling (loop_vec_info);
bool prefer_unrolled_loop () const;
@@ -103,6 +106,19 @@ private:
bool m_has_unexpected_spills_p = false;
void record_potential_unexpected_spills (loop_vec_info);
+ void compute_local_program_points (vec_info *,
+ hash_map<basic_block, vec<stmt_point>> &);
+ void update_local_live_ranges (vec_info *,
+ hash_map<basic_block, vec<stmt_point>> &,
+ hash_map<basic_block, hash_map<tree, pair>> &,
+ machine_mode *);
+ machine_mode compute_local_live_ranges
+ (loop_vec_info, const hash_map<basic_block, vec<stmt_point>> &,
+ hash_map<basic_block, hash_map<tree, pair>> &);
+
+ bool has_unexpected_spills_p (loop_vec_info);
+ bool need_additional_vector_vars_p (stmt_vec_info, slp_tree);
+
void adjust_vect_cost_per_loop (loop_vec_info);
unsigned adjust_stmt_cost (enum vect_cost_for_stmt kind,
loop_vec_info,
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 1275b03..0a9fcef 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -170,7 +170,7 @@ struct GTY(()) riscv_frame_info {
};
enum riscv_privilege_levels {
- UNKNOWN_MODE, USER_MODE, SUPERVISOR_MODE, MACHINE_MODE
+ UNKNOWN_MODE, SUPERVISOR_MODE, MACHINE_MODE, RNMI_MODE
};
struct GTY(()) mode_switching_info {
@@ -3967,13 +3967,27 @@ get_vector_binary_rtx_cost (rtx x, int scalar2vr_cost)
{
gcc_assert (riscv_v_ext_mode_p (GET_MODE (x)));
- rtx op_0 = XEXP (x, 0);
- rtx op_1 = XEXP (x, 1);
+ rtx neg;
+ rtx op_0;
+ rtx op_1;
+
+ if (GET_CODE (x) == UNSPEC)
+ {
+ op_0 = XVECEXP (x, 0, 0);
+ op_1 = XVECEXP (x, 0, 1);
+ }
+ else
+ {
+ op_0 = XEXP (x, 0);
+ op_1 = XEXP (x, 1);
+ }
if (GET_CODE (op_0) == VEC_DUPLICATE
|| GET_CODE (op_1) == VEC_DUPLICATE)
return (scalar2vr_cost + 1) * COSTS_N_INSNS (1);
- else if (GET_CODE (op_0) == NEG && GET_CODE (op_1) == VEC_DUPLICATE)
+ else if (GET_CODE (neg = op_0) == NEG
+ && (GET_CODE (op_1) == VEC_DUPLICATE
+ || GET_CODE (XEXP (neg, 0)) == VEC_DUPLICATE))
return (scalar2vr_cost + 1) * COSTS_N_INSNS (1);
else
return COSTS_N_INSNS (1);
@@ -4021,6 +4035,21 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
case SS_MINUS:
*total = get_vector_binary_rtx_cost (op, scalar2vr_cost);
break;
+ case UNSPEC:
+ {
+ switch (XINT (op, 1))
+ {
+ case UNSPEC_VAADDU:
+ case UNSPEC_VAADD:
+ *total
+ = get_vector_binary_rtx_cost (op, scalar2vr_cost);
+ break;
+ default:
+ *total = COSTS_N_INSNS (1);
+ break;
+ }
+ }
+ break;
default:
*total = COSTS_N_INSNS (1);
break;
@@ -6896,12 +6925,18 @@ riscv_handle_type_attribute (tree *node ATTRIBUTE_UNUSED, tree name, tree args,
}
string = TREE_STRING_POINTER (cst);
- if (strcmp (string, "user") && strcmp (string, "supervisor")
- && strcmp (string, "machine"))
+ if (!strcmp (string, "rnmi") && !TARGET_SMRNMI)
+ {
+ error ("attribute 'rnmi' requires the Smrnmi ISA extension");
+ *no_add_attrs = true;
+ }
+ else if (strcmp (string, "supervisor")
+ && strcmp (string, "machine")
+ && strcmp (string, "rnmi"))
{
warning (OPT_Wattributes,
- "argument to %qE attribute is not %<\"user\"%>, %<\"supervisor\"%>, "
- "or %<\"machine\"%>", name);
+ "argument to %qE attribute is not %<\"supervisor\"%>, "
+ "%<\"machine\"%>, or %<\"rnmi\"%>", name);
*no_add_attrs = true;
}
}
@@ -9049,7 +9084,7 @@ riscv_allocate_and_probe_stack_space (rtx temp1, HOST_WIDE_INT size)
/* We want the CFA independent of the stack pointer for the
duration of the loop. */
add_reg_note (insn, REG_CFA_DEF_CFA,
- plus_constant (Pmode, temp1,
+ plus_constant (Pmode, temp2,
initial_cfa_offset + rounded_size));
RTX_FRAME_RELATED_P (insn) = 1;
}
@@ -9682,12 +9717,12 @@ riscv_expand_epilogue (int style)
if (th_int_mask && TH_INT_INTERRUPT (cfun))
emit_jump_insn (gen_th_int_pop ());
- else if (mode == MACHINE_MODE)
- emit_jump_insn (gen_riscv_mret ());
else if (mode == SUPERVISOR_MODE)
emit_jump_insn (gen_riscv_sret ());
- else
- emit_jump_insn (gen_riscv_uret ());
+ else if (mode == RNMI_MODE)
+ emit_jump_insn (gen_riscv_mnret ());
+ else /* Must be MACHINE_MODE. */
+ emit_jump_insn (gen_riscv_mret ());
}
else if (style != SIBCALL_RETURN)
{
@@ -10359,10 +10394,10 @@ riscv_macro_fusion_pair_p (rtx_insn *prev, rtx_insn *curr)
bool simple_sets_p = prev_set && curr_set && !any_condjump_p (curr);
bool sched1 = can_create_pseudo_p ();
- unsigned int prev_dest_regno = (REG_P (SET_DEST (prev_set))
+ unsigned int prev_dest_regno = (prev_set && REG_P (SET_DEST (prev_set))
? REGNO (SET_DEST (prev_set))
: FIRST_PSEUDO_REGISTER);
- unsigned int curr_dest_regno = (REG_P (SET_DEST (curr_set))
+ unsigned int curr_dest_regno = (curr_set && REG_P (SET_DEST (curr_set))
? REGNO (SET_DEST (curr_set))
: FIRST_PSEUDO_REGISTER);
@@ -12029,10 +12064,10 @@ riscv_get_interrupt_type (tree decl)
{
const char *string = TREE_STRING_POINTER (TREE_VALUE (attr_args));
- if (!strcmp (string, "user"))
- return USER_MODE;
- else if (!strcmp (string, "supervisor"))
+ if (!strcmp (string, "supervisor"))
return SUPERVISOR_MODE;
+ else if (!strcmp (string, "rnmi"))
+ return RNMI_MODE;
else /* Must be "machine". */
return MACHINE_MODE;
}
@@ -12649,14 +12684,31 @@ riscv_estimated_poly_value (poly_int64 val,
/* Return true if the vector misalignment factor is supported by the
target. */
bool
-riscv_support_vector_misalignment (machine_mode mode,
- const_tree type ATTRIBUTE_UNUSED,
- int misalignment,
- bool is_packed ATTRIBUTE_UNUSED)
+riscv_support_vector_misalignment (machine_mode mode, const_tree type,
+ int misalignment, bool is_packed,
+ bool is_gather_scatter)
{
- /* Depend on movmisalign pattern. */
+ /* IS_PACKED is true if the corresponding scalar element is not naturally
+ aligned. If the misalignment is unknown and the the access is packed
+ we defer to the default hook which will check if movmisalign is present.
+ Movmisalign, in turn, depends on TARGET_VECTOR_MISALIGN_SUPPORTED. */
+ if (misalignment == DR_MISALIGNMENT_UNKNOWN)
+ {
+ if (!is_packed)
+ return true;
+ }
+ else
+ {
+ /* If we know that misalignment is a multiple of the element size, we're
+ good. */
+ if (misalignment % TYPE_ALIGN_UNIT (type) == 0)
+ return true;
+ }
+
+ /* Otherwise fall back to movmisalign again. */
return default_builtin_support_vector_misalignment (mode, type, misalignment,
- is_packed);
+ is_packed,
+ is_gather_scatter);
}
/* Implement TARGET_VECTORIZE_GET_MASK_MODE. */
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index c3b504d..578dd43 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -120,7 +120,7 @@
;; Interrupt handler instructions.
UNSPECV_MRET
UNSPECV_SRET
- UNSPECV_URET
+ UNSPECV_MNRET
;; Blockage and synchronization.
UNSPECV_BLOCKAGE
@@ -4166,11 +4166,11 @@
"sret"
[(set_attr "type" "ret")])
-(define_insn "riscv_uret"
+(define_insn "riscv_mnret"
[(return)
- (unspec_volatile [(const_int 0)] UNSPECV_URET)]
- ""
- "uret"
+ (unspec_volatile [(const_int 0)] UNSPECV_MNRET)]
+ "TARGET_SMRNMI"
+ "mnret"
[(set_attr "type" "ret")])
(define_insn "stack_tie<mode>"
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 5f6cc42..aa3b6fb 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -4013,6 +4013,14 @@
UNSPEC_VASUBU UNSPEC_VASUB UNSPEC_VSMUL
UNSPEC_VSSRL UNSPEC_VSSRA])
+(define_int_iterator VSAT_VX_OP_V_VDUP [
+ UNSPEC_VAADDU UNSPEC_VAADD
+])
+
+(define_int_iterator VSAT_VX_OP_VDUP_V [
+ UNSPEC_VAADDU UNSPEC_VAADD
+])
+
(define_int_iterator VSAT_ARITH_OP [UNSPEC_VAADDU UNSPEC_VAADD
UNSPEC_VASUBU UNSPEC_VASUB UNSPEC_VSMUL])
(define_int_iterator VSAT_SHIFT_OP [UNSPEC_VSSRL UNSPEC_VSSRA])
@@ -4047,6 +4055,14 @@
(UNSPEC_VSSRA "vsshift") (UNSPEC_VNCLIP "vnclip")
(UNSPEC_VNCLIPU "vnclip")])
+(define_int_attr sat_op_v_vdup [
+ (UNSPEC_VAADDU "aaddu") (UNSPEC_VAADD "aadd")
+])
+
+(define_int_attr sat_op_vdup_v [
+ (UNSPEC_VAADDU "aaddu") (UNSPEC_VAADD "aadd")
+])
+
(define_int_attr misc_op [(UNSPEC_VMSBF "sbf") (UNSPEC_VMSIF "sif") (UNSPEC_VMSOF "sof")
(UNSPEC_VFRSQRT7 "rsqrt7")])
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index baf215b..66b7670 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -1551,20 +1551,44 @@
(define_expand "vec_duplicate<mode>"
[(set (match_operand:V_VLS 0 "register_operand")
(vec_duplicate:V_VLS
- (match_operand:<VEL> 1 "direct_broadcast_operand")))]
+ (match_operand:<VEL> 1 "any_broadcast_operand")))]
"TARGET_VECTOR"
{
- /* Early expand DImode broadcast in RV32 system to avoid RA reload
- generate (set (reg) (vec_duplicate:DI)). */
+ /* Don't keep a DImode broadcast for RV32 in the vec_duplicate form.
+ Otherwise combine or late combine could end up doing
+ "64-bit broadcast" (!= vmv.v.x)
+ + vadd.vv
+ = vadd.vx
+ which would be invalid. */
bool gt_p = maybe_gt (GET_MODE_SIZE (<VEL>mode), GET_MODE_SIZE (Pmode));
if (!FLOAT_MODE_P (<VEL>mode) && gt_p)
{
- riscv_vector::emit_vlmax_insn (code_for_pred_broadcast (<MODE>mode),
- riscv_vector::UNARY_OP, operands);
- DONE;
+ riscv_vector::emit_vlmax_insn
+ (code_for_pred_strided_broadcast
+ (<MODE>mode), riscv_vector::UNARY_OP, operands);
+ DONE;
}
- /* Otherwise, allow it fall into general vec_duplicate pattern
- which allow us to have vv->vx combine optimization in later pass. */
+
+ /* Even though we can eventually broadcast any permissible
+ constant by moving it into a register we need to force
+ any non-immediate one into a register here.
+ If we didn't do that we couldn't fwprop/late-combine
+ vec_duplicate 123.45f
+ + vfadd.vv
+ = vfadd.vf
+ because the constant is valid for vec_duplicate but not
+ for vfadd.vf. Therefore we need to do
+ fa0 = 123.45f
+ vec_duplicate fa0
+ + vfadd.vv
+ = vfadd.vf */
+ if (!satisfies_constraint_P (operands[1])
+ && !satisfies_constraint_J (operands[1])
+ && !rtx_equal_p (operands[1], CONST0_RTX (<VEL>mode))
+ && !memory_operand (operands[1], <VEL>mode))
+ operands[1] = force_reg (<VEL>mode, operands[1]);
+
+ /* Otherwise keep the vec_duplicate pattern until split. */
})
;; According to GCC internal:
@@ -1574,28 +1598,20 @@
(define_insn_and_split "*vec_duplicate<mode>"
[(set (match_operand:V_VLS 0 "register_operand")
(vec_duplicate:V_VLS
- (match_operand:<VEL> 1 "direct_broadcast_operand")))]
+ (match_operand:<VEL> 1 "any_broadcast_operand")))]
"TARGET_VECTOR && can_create_pseudo_p ()"
"#"
"&& 1"
[(const_int 0)]
{
- if (!strided_load_broadcast_p ()
- && TARGET_ZVFHMIN && !TARGET_ZVFH && <VEL>mode == HFmode)
- {
- /* For Float16, reinterpret as HImode, broadcast and reinterpret
- back. */
- poly_uint64 nunits = GET_MODE_NUNITS (<MODE>mode);
- machine_mode vmodehi
- = riscv_vector::get_vector_mode (HImode, nunits).require ();
- rtx ops[] = {lowpart_subreg (vmodehi, operands[0], <MODE>mode),
- lowpart_subreg (HImode, operands[1], HFmode)};
- riscv_vector::emit_vlmax_insn (code_for_pred_broadcast (vmodehi),
- riscv_vector::UNARY_OP, ops);
- }
- else
+ if (riscv_vector::can_be_broadcast_p (operands[1]))
riscv_vector::emit_vlmax_insn (code_for_pred_broadcast (<MODE>mode),
riscv_vector::UNARY_OP, operands);
+ else
+ riscv_vector::emit_vlmax_insn (code_for_pred_strided_broadcast
+ (<MODE>mode), riscv_vector::UNARY_OP,
+ operands);
+
DONE;
}
[(set_attr "type" "vector")]
@@ -2141,69 +2157,45 @@
(match_operand:V_VLS 2 "vector_merge_operand")))]
"TARGET_VECTOR"
{
- /* Transform vmv.v.x/vfmv.v.f (avl = 1) into vmv.s.x since vmv.s.x/vfmv.s.f
- has better chances to do vsetvl fusion in vsetvl pass. */
bool wrap_vec_dup = true;
rtx vec_cst = NULL_RTX;
- if (riscv_vector::splat_to_scalar_move_p (operands))
- {
- operands[1] = riscv_vector::gen_scalar_move_mask (<VM>mode);
- operands[3] = force_reg (<VEL>mode, operands[3]);
- }
- else if (immediate_operand (operands[3], <VEL>mode)
- && (vec_cst = gen_const_vec_duplicate (<MODE>mode, operands[3]))
- && (/* -> pred_broadcast<mode>_zero */
- (vector_least_significant_set_mask_operand (operands[1],
- <VM>mode)
- && vector_const_0_operand (vec_cst, <MODE>mode))
- || (/* pred_broadcast<mode>_imm */
- vector_all_trues_mask_operand (operands[1], <VM>mode)
- && vector_const_int_or_double_0_operand (vec_cst,
- <MODE>mode))))
+ if (immediate_operand (operands[3], <VEL>mode)
+ && (vec_cst = gen_const_vec_duplicate (<MODE>mode, operands[3]))
+ && (/* -> pred_broadcast<mode>_zero */
+ (vector_least_significant_set_mask_operand (operands[1],
+ <VM>mode)
+ && vector_const_0_operand (vec_cst, <MODE>mode))
+ || (/* pred_broadcast<mode>_imm */
+ vector_all_trues_mask_operand (operands[1], <VM>mode)
+ && vector_const_int_or_double_0_operand (vec_cst,
+ <MODE>mode))))
{
operands[3] = vec_cst;
wrap_vec_dup = false;
}
- /* Handle vmv.s.x instruction (Wb1 mask) which has memory scalar. */
- else if (satisfies_constraint_Wdm (operands[3]))
- {
- if (satisfies_constraint_Wb1 (operands[1]))
- {
- /* Case 1: vmv.s.x (TA, x == memory) ==> vlse.v (TA) */
- if (satisfies_constraint_vu (operands[2]))
- operands[1] = CONSTM1_RTX (<VM>mode);
- else if (GET_MODE_BITSIZE (<VEL>mode) > GET_MODE_BITSIZE (Pmode))
- {
- /* Case 2: vmv.s.x (TU, x == memory) ==>
- vl = 0 or 1; + vlse.v (TU) in RV32 system */
- operands[4] = riscv_vector::gen_avl_for_scalar_move (operands[4]);
- operands[1] = CONSTM1_RTX (<VM>mode);
- }
- else
- /* Case 3: load x (memory) to register. */
- operands[3] = force_reg (<VEL>mode, operands[3]);
- }
- }
- else if (GET_MODE_BITSIZE (<VEL>mode) > GET_MODE_BITSIZE (Pmode)
- && (immediate_operand (operands[3], Pmode)
+ else if (GET_MODE_SIZE (<VEL>mode) > UNITS_PER_WORD
+ && satisfies_constraint_Wb1 (operands[1])
+ && (immediate_operand (operands[3], Xmode)
|| (CONST_POLY_INT_P (operands[3])
&& known_ge (rtx_to_poly_int64 (operands[3]), 0U)
- && known_le (rtx_to_poly_int64 (operands[3]), GET_MODE_SIZE (<MODE>mode)))))
+ && known_le (rtx_to_poly_int64 (operands[3]),
+ GET_MODE_SIZE (<MODE>mode)))))
{
rtx tmp = gen_reg_rtx (Pmode);
poly_int64 value = rtx_to_poly_int64 (operands[3]);
- emit_move_insn (tmp, gen_int_mode (value, Pmode));
+ emit_move_insn (tmp, gen_int_mode (value, Xmode));
operands[3] = gen_rtx_SIGN_EXTEND (<VEL>mode, tmp);
}
- /* Never load (const_int 0) into a register, that's silly. */
- else if (operands[3] == CONST0_RTX (<VEL>mode))
+
+ /* For a vmv.v.x never load (const_int 0) or valid immediate operands
+ into a register, because we can use vmv.v.i. */
+ else if (satisfies_constraint_Wc1 (operands[1])
+ && (satisfies_constraint_P (operands[3])
+ || operands[3] == CONST0_RTX (<VEL>mode)))
;
- /* If we're broadcasting [-16..15] across more than just
- element 0, then we can use vmv.v.i directly, thus avoiding
- the load of the constant into a GPR. */
- else if (CONST_INT_P (operands[3])
- && IN_RANGE (INTVAL (operands[3]), -16, 15)
- && !satisfies_constraint_Wb1 (operands[1]))
+ /* For vmv.s.x we have vmv.s.x v1, zero. */
+ else if (satisfies_constraint_Wb1 (operands[1])
+ && operands[3] == CONST0_RTX (<VEL>mode))
;
else
operands[3] = force_reg (<VEL>mode, operands[3]);
@@ -2211,131 +2203,68 @@
operands[3] = gen_rtx_VEC_DUPLICATE (<MODE>mode, operands[3]);
})
-(define_insn_and_split "*pred_broadcast<mode>"
- [(set (match_operand:V_VLSI 0 "register_operand" "=vr, vr, vd, vd, vr, vr, vr, vr")
+(define_insn_and_rewrite "*pred_broadcast<mode>"
+ [(set (match_operand:V_VLSI 0 "register_operand" "=vr, vr, vr, vr")
(if_then_else:V_VLSI
(unspec:<VM>
- [(match_operand:<VM> 1 "vector_broadcast_mask_operand" "Wc1,Wc1, vm, vm,Wc1,Wc1,Wb1,Wb1")
- (match_operand 4 "vector_length_operand" "rvl,rvl,rvl,rvl,rvl,rvl,rvl,rvl")
- (match_operand 5 "const_int_operand" " i, i, i, i, i, i, i, i")
- (match_operand 6 "const_int_operand" " i, i, i, i, i, i, i, i")
- (match_operand 7 "const_int_operand" " i, i, i, i, i, i, i, i")
+ [(match_operand:<VM> 1 "vector_broadcast_mask_operand" "Wc1,Wc1,Wb1,Wb1")
+ (match_operand 4 "vector_length_operand" "rvl,rvl,rvl,rvl")
+ (match_operand 5 "const_int_operand" " i, i, i, i")
+ (match_operand 6 "const_int_operand" " i, i, i, i")
+ (match_operand 7 "const_int_operand" " i, i, i, i")
(reg:SI VL_REGNUM)
(reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
(vec_duplicate:V_VLSI
- (match_operand:<VEL> 3 "direct_broadcast_operand" "rP,rP,Wdm,Wdm,Wdm,Wdm, rJ, rJ"))
- (match_operand:V_VLSI 2 "vector_merge_operand" "vu, 0, vu, 0, vu, 0, vu, 0")))]
+ (match_operand:<VEL> 3 "direct_broadcast_operand" " rP, rP, rJ, rJ"))
+ (match_operand:V_VLSI 2 "vector_merge_operand" " vu, 0, vu, 0")))]
"TARGET_VECTOR"
"@
vmv.v.%o3\t%0,%3
vmv.v.%o3\t%0,%3
- vlse<sew>.v\t%0,%3,zero,%1.t
- vlse<sew>.v\t%0,%3,zero,%1.t
- vlse<sew>.v\t%0,%3,zero
- vlse<sew>.v\t%0,%3,zero
vmv.s.x\t%0,%z3
vmv.s.x\t%0,%z3"
- "(register_operand (operands[3], <VEL>mode)
- || CONST_POLY_INT_P (operands[3]))
- && GET_MODE_BITSIZE (<VEL>mode) > GET_MODE_BITSIZE (Pmode)"
- [(const_int 0)]
- {
- gcc_assert (can_create_pseudo_p ());
- if (CONST_POLY_INT_P (operands[3]))
- {
- rtx tmp = gen_reg_rtx (<VEL>mode);
- emit_move_insn (tmp, operands[3]);
- operands[3] = tmp;
- }
-
- /* For SEW = 64 in RV32 system, we expand vmv.s.x:
- andi a2,a2,1
- vsetvl zero,a2,e64
- vlse64.v */
- if (satisfies_constraint_Wb1 (operands[1]))
- {
- operands[4] = riscv_vector::gen_avl_for_scalar_move (operands[4]);
- operands[1] = CONSTM1_RTX (<VM>mode);
- }
-
- /* If the target doesn't want a strided-load broadcast we go with a regular
- V1DImode load and a broadcast gather. */
- if (strided_load_broadcast_p ())
- {
- rtx mem = assign_stack_local (<VEL>mode, GET_MODE_SIZE (<VEL>mode),
- GET_MODE_ALIGNMENT (<VEL>mode));
- mem = validize_mem (mem);
- emit_move_insn (mem, operands[3]);
- mem = gen_rtx_MEM (<VEL>mode, force_reg (Pmode, XEXP (mem, 0)));
-
- emit_insn
- (gen_pred_broadcast<mode>
- (operands[0], operands[1], operands[2], mem,
- operands[4], operands[5], operands[6], operands[7]));
- }
- else
- {
- rtx tmp = gen_reg_rtx (V1DImode);
- emit_move_insn (tmp, lowpart_subreg (V1DImode, operands[3],
- <VEL>mode));
- tmp = lowpart_subreg (<MODE>mode, tmp, V1DImode);
-
- emit_insn
- (gen_pred_gather<mode>_scalar
- (operands[0], operands[1], operands[2], tmp, CONST0_RTX (Pmode),
- operands[4], operands[5], operands[6], operands[7]));
- }
- DONE;
- }
- [(set_attr "type" "vimov,vimov,vlds,vlds,vlds,vlds,vimovxv,vimovxv")
+ "&& (operands[1] == CONSTM1_RTX (<VM>mode)
+ && operands[4] == CONST1_RTX (Pmode)
+ && (register_operand (operands[3], <VEL>mode)
+ || satisfies_constraint_J (operands[3])))"
+{
+ /* A broadcast of a single element is just a vmv.s.x. */
+ operands[1] = riscv_vector::gen_scalar_move_mask (<VM>mode);
+}
+ [(set_attr "type" "vimov,vimov,vimovxv,vimovxv")
(set_attr "mode" "<MODE>")])
-(define_insn "*pred_broadcast<mode>_zvfh"
- [(set (match_operand:V_VLSF 0 "register_operand" "=vr, vr, vr, vr")
+(define_insn_and_rewrite "pred_broadcast<mode>_zvfh"
+ [(set (match_operand:V_VLSF 0 "register_operand" "=vr, vr, vr, vr")
(if_then_else:V_VLSF
(unspec:<VM>
- [(match_operand:<VM> 1 "vector_broadcast_mask_operand" "Wc1, Wc1, Wb1, Wb1")
- (match_operand 4 "vector_length_operand" "rvl, rvl, rvl, rvl")
- (match_operand 5 "const_int_operand" " i, i, i, i")
- (match_operand 6 "const_int_operand" " i, i, i, i")
- (match_operand 7 "const_int_operand" " i, i, i, i")
+ [(match_operand:<VM> 1 "vector_broadcast_mask_operand" "Wc1,Wc1,Wb1,Wb1")
+ (match_operand 4 "vector_length_operand" "rvl,rvl,rvl,rvl")
+ (match_operand 5 "const_int_operand" " i, i, i, i")
+ (match_operand 6 "const_int_operand" " i, i, i, i")
+ (match_operand 7 "const_int_operand" " i, i, i, i")
(reg:SI VL_REGNUM)
(reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
(vec_duplicate:V_VLSF
- (match_operand:<VEL> 3 "direct_broadcast_operand" " f, f, f, f"))
- (match_operand:V_VLSF 2 "vector_merge_operand" " vu, 0, vu, 0")))]
+ (match_operand:<VEL> 3 "direct_broadcast_operand" " f, f, f, f"))
+ (match_operand:V_VLSF 2 "vector_merge_operand" " vu, 0, vu, 0")))]
"TARGET_VECTOR"
"@
vfmv.v.f\t%0,%3
vfmv.v.f\t%0,%3
vfmv.s.f\t%0,%3
vfmv.s.f\t%0,%3"
+ "&& (operands[1] == CONSTM1_RTX (<VM>mode)
+ && operands[4] == CONST1_RTX (Pmode)
+ && (register_operand (operands[3], <VEL>mode)
+ || satisfies_constraint_J (operands[3])))"
+{
+ /* A broadcast of a single element is just a vfmv.s.f. */
+ operands[1] = riscv_vector::gen_scalar_move_mask (<VM>mode);
+}
[(set_attr "type" "vfmov,vfmov,vfmovfv,vfmovfv")
(set_attr "mode" "<MODE>")])
-(define_insn "*pred_broadcast<mode>_zvfhmin"
- [(set (match_operand:V_VLSF_ZVFHMIN 0 "register_operand" "=vr, vr, vr, vr")
- (if_then_else:V_VLSF_ZVFHMIN
- (unspec:<VM>
- [(match_operand:<VM> 1 "vector_broadcast_mask_operand" " vm, vm, Wc1, Wc1")
- (match_operand 4 "vector_length_operand" "rvl, rvl, rvl, rvl")
- (match_operand 5 "const_int_operand" " i, i, i, i")
- (match_operand 6 "const_int_operand" " i, i, i, i")
- (match_operand 7 "const_int_operand" " i, i, i, i")
- (reg:SI VL_REGNUM)
- (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
- (vec_duplicate:V_VLSF_ZVFHMIN
- (match_operand:<VEL> 3 "direct_broadcast_operand" " A, A, A, A"))
- (match_operand:V_VLSF_ZVFHMIN 2 "vector_merge_operand" " vu, 0, vu, 0")))]
- "TARGET_VECTOR && strided_load_broadcast_p ()"
- "@
- vlse<sew>.v\t%0,%3,zero,%1.t
- vlse<sew>.v\t%0,%3,zero,%1.t
- vlse<sew>.v\t%0,%3,zero
- vlse<sew>.v\t%0,%3,zero"
- [(set_attr "type" "vlds,vlds,vlds,vlds")
- (set_attr "mode" "<MODE>")])
-
(define_insn "*pred_broadcast<mode>_extended_scalar"
[(set (match_operand:V_VLSI_D 0 "register_operand" "=vr, vr, vr, vr")
(if_then_else:V_VLSI_D
@@ -2398,6 +2327,117 @@
[(set_attr "type" "vimov,vimov")
(set_attr "mode" "<MODE>")])
+(define_expand "@pred_strided_broadcast<mode>"
+ [(set (match_operand:V_VLS 0 "register_operand")
+ (if_then_else:V_VLS
+ (unspec:<VM>
+ [(match_operand:<VM> 1 "strided_broadcast_mask_operand")
+ (match_operand 4 "vector_length_operand")
+ (match_operand 5 "const_int_operand")
+ (match_operand 6 "const_int_operand")
+ (match_operand 7 "const_int_operand")
+ (reg:SI VL_REGNUM)
+ (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
+ (vec_duplicate:V_VLS
+ (match_operand:<VEL> 3 "strided_broadcast_operand"))
+ (match_operand:V_VLS 2 "vector_merge_operand")))]
+ "TARGET_VECTOR"
+{
+ if (satisfies_constraint_Wb1 (operands[1]))
+ {
+ /* If we're asked to set a single element (like vmv.s.x but we
+ need to go via memory here) and the tail policy is agnostic
+ we can overwrite all elements.
+ Thus, set the mask to broadcast. */
+ operands[1] = CONSTM1_RTX (<VM>mode);
+ if (!satisfies_constraint_vu (operands[2])
+ && GET_MODE_SIZE (<VEL>mode) > UNITS_PER_WORD)
+ {
+ /* Case 2: vmv.s.x (TU, x == memory) ==>
+ vl = 0 or 1; + vlse.v (TU) in RV32 system */
+ /* In this case we must not overwrite the residual elements,
+ so set the vector length to 0/1. */
+ operands[4] = riscv_vector::gen_avl_for_scalar_move (operands[4]);
+ }
+ }
+})
+
+(define_insn_and_split "*pred_strided_broadcast<mode>"
+ [(set (match_operand:V_VLSI 0 "register_operand" "=vd, vd, vr, vr")
+ (if_then_else:V_VLSI
+ (unspec:<VM>
+ [(match_operand:<VM> 1 "strided_broadcast_mask_operand" " vm, vm,Wc1,Wc1")
+ (match_operand 4 "vector_length_operand" "rvl,rvl,rvl,rvl")
+ (match_operand 5 "const_int_operand" " i, i, i, i")
+ (match_operand 6 "const_int_operand" " i, i, i, i")
+ (match_operand 7 "const_int_operand" " i, i, i, i")
+ (reg:SI VL_REGNUM)
+ (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
+ (vec_duplicate:V_VLSI
+ (match_operand:<VEL> 3 "strided_broadcast_operand" " A, A, A, A"))
+ (match_operand:V_VLSI 2 "vector_merge_operand" " vu, 0, vu, 0")))]
+ "TARGET_VECTOR"
+ "@
+ vlse<sew>.v\t%0,%3,zero,%1.t
+ vlse<sew>.v\t%0,%3,zero,%1.t
+ vlse<sew>.v\t%0,%3,zero
+ vlse<sew>.v\t%0,%3,zero"
+ "&& !strided_load_broadcast_p () && can_create_pseudo_p ()"
+ [(const_int 0)]
+ {
+ rtx tmp = gen_reg_rtx (V1DImode);
+ emit_move_insn (tmp, gen_lowpart (V1DImode, operands[3]));
+ tmp = lowpart_subreg (<MODE>mode, tmp, V1DImode);
+
+ emit_insn
+ (gen_pred_gather<mode>_scalar
+ (operands[0], operands[1], operands[2], tmp, CONST0_RTX (Pmode),
+ operands[4], operands[5], operands[6], operands[7]));
+ DONE;
+ }
+ [(set_attr "type" "vlds,vlds,vlds,vlds")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn_and_split "*pred_strided_broadcast<mode>_zvfhmin"
+ [(set (match_operand:V_VLSF_ZVFHMIN 0 "register_operand" "=vr, vr, vr, vr")
+ (if_then_else:V_VLSF_ZVFHMIN
+ (unspec:<VM>
+ [(match_operand:<VM> 1 "strided_broadcast_mask_operand" " vm, vm, Wc1, Wc1")
+ (match_operand 4 "vector_length_operand" "rvl, rvl, rvl, rvl")
+ (match_operand 5 "const_int_operand" " i, i, i, i")
+ (match_operand 6 "const_int_operand" " i, i, i, i")
+ (match_operand 7 "const_int_operand" " i, i, i, i")
+ (reg:SI VL_REGNUM)
+ (reg:SI VTYPE_REGNUM)] UNSPEC_VPREDICATE)
+ (vec_duplicate:V_VLSF_ZVFHMIN
+ (match_operand:<VEL> 3 "strided_broadcast_operand" " A, A, A, A"))
+ (match_operand:V_VLSF_ZVFHMIN 2 "vector_merge_operand" " vu, 0, vu, 0")))]
+ "TARGET_VECTOR"
+ "@
+ vlse<sew>.v\t%0,%3,zero,%1.t
+ vlse<sew>.v\t%0,%3,zero,%1.t
+ vlse<sew>.v\t%0,%3,zero
+ vlse<sew>.v\t%0,%3,zero"
+ "&& !strided_load_broadcast_p ()
+ && <VEL>mode == HFmode
+ && can_create_pseudo_p ()"
+ [(const_int 0)]
+ {
+ poly_uint64 nunits = GET_MODE_NUNITS (<MODE>mode);
+ machine_mode vmodehi
+ = riscv_vector::get_vector_mode (HImode, nunits).require ();
+ rtx ops[] = {gen_lowpart (vmodehi, operands[0]),
+ gen_lowpart (HImode, operands[3])};
+ riscv_vector::emit_avltype_insn (code_for_pred_broadcast (vmodehi),
+ riscv_vector::UNARY_OP, ops,
+ (riscv_vector::avl_type) INTVAL (operands[7]),
+ operands[4]);
+ DONE;
+ }
+ [(set_attr "type" "vlds,vlds,vlds,vlds")
+ (set_attr "mode" "<MODE>")])
+
+
;; -------------------------------------------------------------------------------
;; ---- Predicated Strided loads/stores
;; -------------------------------------------------------------------------------
@@ -4639,8 +4679,8 @@
;; Handle GET_MODE_INNER (mode) = DImode. We need to split them since
;; we need to deal with SEW = 64 in RV32 system.
(define_expand "@pred_<sat_op><mode>_scalar"
- [(set (match_operand:VI_D 0 "register_operand")
- (if_then_else:VI_D
+ [(set (match_operand:V_VLSI_D 0 "register_operand")
+ (if_then_else:V_VLSI_D
(unspec:<VM>
[(match_operand:<VM> 1 "vector_mask_operand")
(match_operand 5 "vector_length_operand")
@@ -4651,10 +4691,10 @@
(reg:SI VL_REGNUM)
(reg:SI VTYPE_REGNUM)
(reg:SI VXRM_REGNUM)] UNSPEC_VPREDICATE)
- (unspec:VI_D
- [(match_operand:VI_D 3 "register_operand")
+ (unspec:V_VLSI_D
+ [(match_operand:V_VLSI_D 3 "register_operand")
(match_operand:<VEL> 4 "reg_or_int_operand")] VSAT_ARITH_OP)
- (match_operand:VI_D 2 "vector_merge_operand")))]
+ (match_operand:V_VLSI_D 2 "vector_merge_operand")))]
"TARGET_VECTOR"
{
if (riscv_vector::sew64_scalar_helper (
@@ -4673,8 +4713,8 @@
})
(define_insn "*pred_<sat_op><mode>_scalar"
- [(set (match_operand:VI_D 0 "register_operand" "=vd, vr, vd, vr")
- (if_then_else:VI_D
+ [(set (match_operand:V_VLSI_D 0 "register_operand" "=vd, vr, vd, vr")
+ (if_then_else:V_VLSI_D
(unspec:<VM>
[(match_operand:<VM> 1 "vector_mask_operand" " vm, vm,Wc1,Wc1")
(match_operand 5 "vector_length_operand" "rvl,rvl,rvl,rvl")
@@ -4685,18 +4725,18 @@
(reg:SI VL_REGNUM)
(reg:SI VTYPE_REGNUM)
(reg:SI VXRM_REGNUM)] UNSPEC_VPREDICATE)
- (unspec:VI_D
- [(match_operand:VI_D 3 "register_operand" " vr, vr, vr, vr")
+ (unspec:V_VLSI_D
+ [(match_operand:V_VLSI_D 3 "register_operand" " vr, vr, vr, vr")
(match_operand:<VEL> 4 "reg_or_0_operand" " rJ, rJ, rJ, rJ")] VSAT_ARITH_OP)
- (match_operand:VI_D 2 "vector_merge_operand" " vu, 0, vu, 0")))]
+ (match_operand:V_VLSI_D 2 "vector_merge_operand" " vu, 0, vu, 0")))]
"TARGET_VECTOR"
"v<sat_op>.vx\t%0,%3,%z4%p1"
[(set_attr "type" "<sat_insn_type>")
(set_attr "mode" "<MODE>")])
(define_insn "*pred_<sat_op><mode>_extended_scalar"
- [(set (match_operand:VI_D 0 "register_operand" "=vd, vr, vd, vr")
- (if_then_else:VI_D
+ [(set (match_operand:V_VLSI_D 0 "register_operand" "=vd, vr, vd, vr")
+ (if_then_else:V_VLSI_D
(unspec:<VM>
[(match_operand:<VM> 1 "vector_mask_operand" " vm, vm,Wc1,Wc1")
(match_operand 5 "vector_length_operand" "rvl,rvl,rvl,rvl")
@@ -4707,11 +4747,11 @@
(reg:SI VL_REGNUM)
(reg:SI VTYPE_REGNUM)
(reg:SI VXRM_REGNUM)] UNSPEC_VPREDICATE)
- (unspec:VI_D
- [(match_operand:VI_D 3 "register_operand" " vr, vr, vr, vr")
+ (unspec:V_VLSI_D
+ [(match_operand:V_VLSI_D 3 "register_operand" " vr, vr, vr, vr")
(sign_extend:<VEL>
(match_operand:<VSUBEL> 4 "reg_or_0_operand" " rJ, rJ, rJ, rJ"))] VSAT_ARITH_OP)
- (match_operand:VI_D 2 "vector_merge_operand" " vu, 0, vu, 0")))]
+ (match_operand:V_VLSI_D 2 "vector_merge_operand" " vu, 0, vu, 0")))]
"TARGET_VECTOR && !TARGET_64BIT"
"v<sat_op>.vx\t%0,%3,%z4%p1"
[(set_attr "type" "<sat_insn_type>")
diff --git a/gcc/config/riscv/xiangshan.md b/gcc/config/riscv/xiangshan.md
index 5ed6bac..34b4a8f 100644
--- a/gcc/config/riscv/xiangshan.md
+++ b/gcc/config/riscv/xiangshan.md
@@ -107,7 +107,8 @@
;; they are just dummies like this one.
(define_insn_reservation "xiangshan_alu_unknown" 1
(and (eq_attr "tune" "xiangshan")
- (eq_attr "type" "zicond,min,max,minu,maxu,clz,ctz,cpop,ghost,rotate,clmul,condmove,crypto,mvpair,rdvlenb,rdvl,wrvxrm,wrfrm,rdfrm,vsetvl,vsetvl_pre,vlde,vste,vldm,vstm,vlds,vsts,vldux,vldox,vstux,vstox,vldff,vldr,vstr,vlsegde,vssegte,vlsegds,vssegts,vlsegdux,vlsegdox,vssegtux,vssegtox,vlsegdff,vialu,viwalu,vext,vicalu,vshift,vnshift,vicmp,viminmax,vimul,vidiv,viwmul,vimuladd,sf_vqmacc,viwmuladd,vimerge,vimov,vsalu,vaalu,vsmul,vsshift,vnclip,sf_vfnrclip,vfalu,vfwalu,vfmul,vfdiv,vfwmul,vfmuladd,vfwmuladd,vfsqrt,vfrecp,vfcmp,vfminmax,vfsgnj,vfclass,vfmerge,vfmov,vfcvtitof,vfcvtftoi,vfwcvtitof,vfwcvtftoi,vfwcvtftof,vfncvtitof,vfncvtftoi,vfncvtftof,vired,viwred,vfredu,vfredo,vfwredu,vfwredo,vmalu,vmpop,vmffs,vmsfs,vmiota,vmidx,vimovvx,vimovxv,vfmovvf,vfmovfv,vslideup,vslidedown,vislide1up,vislide1down,vfslide1up,vfslide1down,vgather,vcompress,vmov,vector,vandn,vbrev,vbrev8,vrev8,vclz,vctz,vcpop,vrol,vror,vwsll,vclmul,vclmulh,vghsh,vgmul,vaesef,vaesem,vaesdf,vaesdm,vaeskf1,vaeskf2,vaesz,vsha2ms,vsha2ch,vsha2cl,vsm4k,vsm4r,vsm3me,vsm3c,vfncvtbf16,vfwcvtbf16,vfwmaccbf16"))
+ (eq_attr "type" "zicond,min,max,minu,maxu,clz,ctz,cpop,ghost,rotate,clmul,condmove,crypto,mvpair,rdvlenb,rdvl,wrvxrm,wrfrm,rdfrm,vsetvl,vsetvl_pre,vlde,vste,vldm,vstm,vlds,vsts,vldux,vldox,vstux,vstox,vldff,vldr,vstr,vlsegde,vssegte,vlsegds,vssegts,vlsegdux,vlsegdox,vssegtux,vssegtox,vlsegdff,vialu,viwalu,vext,vicalu,vshift,vnshift,vicmp,viminmax,vimul,vidiv,viwmul,vimuladd,sf_vqmacc,viwmuladd,vimerge,vimov,vsalu,vaalu,vsmul,vsshift,vnclip,sf_vfnrclip,vfalu,vfwalu,vfmul,vfdiv,vfwmul,vfmuladd,vfwmuladd,vfsqrt,vfrecp,vfcmp,vfminmax,vfsgnj,vfclass,vfmerge,vfmov,vfcvtitof,vfcvtftoi,vfwcvtitof,vfwcvtftoi,vfwcvtftof,vfncvtitof,vfncvtftoi,vfncvtftof,vired,viwred,vfredu,vfredo,vfwredu,vfwredo,vmalu,vmpop,vmffs,vmsfs,vmiota,vmidx,vimovvx,vimovxv,vfmovvf,vfmovfv,vslideup,vslidedown,vislide1up,vislide1down,vfslide1up,vfslide1down,vgather,vcompress,vmov,vector,vandn,vbrev,vbrev8,vrev8,vclz,vctz,vcpop,vrol,vror,vwsll,vclmul,vclmulh,vghsh,vgmul,vaesef,vaesem,vaesdf,vaesdm,vaeskf1,vaeskf2,vaesz,vsha2ms,vsha2ch,vsha2cl,vsm4k,vsm4r,vsm3me,vsm3c,vfncvtbf16,vfwcvtbf16,vfwmaccbf16,sf_vc,sf_vc_se"))
+
"xs_alu_rs")
;; ----------------------------------------------------
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 7ee26e5..16227e5 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -4951,10 +4951,19 @@ static bool
rs6000_builtin_support_vector_misalignment (machine_mode mode,
const_tree type,
int misalignment,
- bool is_packed)
+ bool is_packed,
+ bool is_gather_scatter)
{
if (TARGET_VSX)
{
+ if (is_gather_scatter)
+ {
+ if (TARGET_ALTIVEC && is_packed)
+ return false;
+ else
+ return true;
+ }
+
if (TARGET_EFFICIENT_UNALIGNED_VSX)
return true;
diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc
index b5e636c..abe551c 100644
--- a/gcc/config/s390/s390.cc
+++ b/gcc/config/s390/s390.cc
@@ -16874,8 +16874,9 @@ s390_valid_target_attribute_inner_p (tree args,
generate_option (opt, NULL, value, CL_TARGET, &decoded);
s390_handle_option (opts, new_opts_set, &decoded, input_location);
set_option (opts, new_opts_set, opt, value,
- p + opt_len, DK_UNSPECIFIED, input_location,
- global_dc);
+ p + opt_len,
+ static_cast<int> (diagnostics::kind::unspecified),
+ input_location, global_dc);
}
else
{
@@ -16892,8 +16893,9 @@ s390_valid_target_attribute_inner_p (tree args,
arg_ok = opt_enum_arg_to_value (opt, p + opt_len, &value, CL_TARGET);
if (arg_ok)
set_option (opts, new_opts_set, opt, value,
- p + opt_len, DK_UNSPECIFIED, input_location,
- global_dc);
+ p + opt_len,
+ static_cast<int> (diagnostics::kind::unspecified),
+ input_location, global_dc);
else
{
error ("attribute %<target%> argument %qs is unknown", orig_p);
@@ -17345,13 +17347,15 @@ static bool
s390_support_vector_misalignment (machine_mode mode ATTRIBUTE_UNUSED,
const_tree type ATTRIBUTE_UNUSED,
int misalignment ATTRIBUTE_UNUSED,
- bool is_packed ATTRIBUTE_UNUSED)
+ bool is_packed ATTRIBUTE_UNUSED,
+ bool is_gather_scatter ATTRIBUTE_UNUSED)
{
if (TARGET_VX)
return true;
return default_builtin_support_vector_misalignment (mode, type, misalignment,
- is_packed);
+ is_packed,
+ is_gather_scatter);
}
/* The vector ABI requires vector types to be aligned on an 8 byte
@@ -17843,9 +17847,11 @@ f_constraint_p (const char *constraint)
for (size_t i = 0, c_len = strlen (constraint); i < c_len;
i += CONSTRAINT_LEN (constraint[i], constraint + i))
{
- if (constraint[i] == 'f')
+ if (constraint[i] == 'f'
+ || (constraint[i] == '{' && constraint[i + 1] == 'f'))
seen_f_p = true;
- if (constraint[i] == 'v')
+ if (constraint[i] == 'v'
+ || (constraint[i] == '{' && constraint[i + 1] == 'v'))
seen_v_p = true;
}
@@ -17935,7 +17941,8 @@ s390_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &inputs,
continue;
bool allows_mem, allows_reg, is_inout;
bool ok = parse_output_constraint (&constraint, i, ninputs, noutputs,
- &allows_mem, &allows_reg, &is_inout);
+ &allows_mem, &allows_reg, &is_inout,
+ nullptr);
gcc_assert (ok);
if (!f_constraint_p (constraint))
/* Long double with a constraint other than "=f" - nothing to do. */
@@ -17980,7 +17987,7 @@ s390_md_asm_adjust (vec<rtx> &outputs, vec<rtx> &inputs,
bool allows_mem, allows_reg;
bool ok = parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
constraints.address (), &allows_mem,
- &allows_reg);
+ &allows_reg, nullptr);
gcc_assert (ok);
if (!f_constraint_p (constraint))
/* Long double with a constraint other than "f" (or "=f" for inout
diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc
index b75cec1..02554c5 100644
--- a/gcc/config/xtensa/xtensa.cc
+++ b/gcc/config/xtensa/xtensa.cc
@@ -601,8 +601,8 @@ constantpool_address_p (const_rtx addr)
/* Make sure the address is word aligned. */
offset = XEXP (addr, 1);
- if ((!CONST_INT_P (offset))
- || ((INTVAL (offset) & 3) != 0))
+ if (! CONST_INT_P (offset)
+ || (INTVAL (offset) & 3) != 0)
return false;
sym = XEXP (addr, 0);
@@ -611,6 +611,7 @@ constantpool_address_p (const_rtx addr)
if (SYMBOL_REF_P (sym)
&& CONSTANT_POOL_ADDRESS_P (sym))
return true;
+
return false;
}
@@ -4694,29 +4695,32 @@ xtensa_rtx_costs (rtx x, machine_mode mode, int outer_code,
}
}
+/* Return TRUE if the specified insn corresponds to one or more L32R machine
+ instructions. */
+
static bool
xtensa_is_insn_L32R_p (const rtx_insn *insn)
{
- rtx x = PATTERN (insn);
+ rtx pat, dest, src;
- if (GET_CODE (x) != SET)
+ /* "PATTERN (insn)" can be used without checking, see insn_cost()
+ in gcc/rtlanal.cc. */
+ if (GET_CODE (pat = PATTERN (insn)) != SET
+ || ! register_operand (dest = SET_DEST (pat), VOIDmode))
return false;
- x = XEXP (x, 1);
- if (MEM_P (x))
- {
- x = XEXP (x, 0);
- return (SYMBOL_REF_P (x) || CONST_INT_P (x))
- && CONSTANT_POOL_ADDRESS_P (x);
- }
-
- /* relaxed MOVI instructions, that will be converted to L32R by the
- assembler. */
- if (CONST_INT_P (x)
- && ! xtensa_simm12b (INTVAL (x)))
+ if (constantpool_mem_p (src = SET_SRC (pat)))
return true;
- return false;
+ /* Return true if:
+ - CONST16 instruction is not configured, and
+ - the source is some constant, and also
+ - negation of "the source is integer and fits into the immediate
+ field". */
+ return (!TARGET_CONST16
+ && CONSTANT_P (src)
+ && ! ((GET_MODE (dest) == SImode || GET_MODE (dest) == HImode)
+ && CONST_INT_P (src) && xtensa_simm12b (INTVAL (src))));
}
/* Compute a relative costs of RTL insns. This is necessary in order to
@@ -4725,7 +4729,7 @@ xtensa_is_insn_L32R_p (const rtx_insn *insn)
static int
xtensa_insn_cost (rtx_insn *insn, bool speed)
{
- if (!(recog_memoized (insn) < 0))
+ if (! (recog_memoized (insn) < 0))
{
int len = get_attr_length (insn);
@@ -4738,7 +4742,7 @@ xtensa_insn_cost (rtx_insn *insn, bool speed)
/* "L32R" may be particular slow (implementation-dependent). */
if (xtensa_is_insn_L32R_p (insn))
- return COSTS_N_INSNS (1 + xtensa_extra_l32r_costs);
+ return COSTS_N_INSNS ((1 + xtensa_extra_l32r_costs) * n);
/* Cost based on the pipeline model. */
switch (get_attr_type (insn))
@@ -4783,7 +4787,7 @@ xtensa_insn_cost (rtx_insn *insn, bool speed)
{
/* "L32R" itself plus constant in litpool. */
if (xtensa_is_insn_L32R_p (insn))
- len = 3 + 4;
+ len += (len / 3) * 4;
/* Consider fractional instruction length (for example, ".n"
short instructions or "L32R" litpool constants. */
diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index 029be99..629dfdd 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -1297,7 +1297,10 @@
std::swap (operands[0], operands[1]);
std::swap (operands[2], operands[3]);
}
-})
+}
+ [(set_attr "type" "move,move,load,load,store")
+ (set_attr "mode" "DI")
+ (set_attr "length" "6,12,6,6,6")])
(define_split
[(set (match_operand:DI 0 "register_operand")
@@ -1344,7 +1347,7 @@
%v0s32i\t%1, %0
rsr\t%0, ACCLO
wsr\t%1, ACCLO"
- [(set_attr "type" "move,move,move,load,store,store,move,move,move,move,move,load,load,store,rsr,wsr")
+ [(set_attr "type" "move,move,move,load,store,store,move,move,move,load,move,load,load,store,rsr,wsr")
(set_attr "mode" "SI")
(set_attr "length" "2,2,2,2,2,2,3,3,3,3,6,3,3,3,3,3")])
@@ -1410,7 +1413,7 @@
%v0s16i\t%1, %0
rsr\t%0, ACCLO
wsr\t%1, ACCLO"
- [(set_attr "type" "move,move,move,move,move,load,load,store,rsr,wsr")
+ [(set_attr "type" "move,move,move,move,load,load,load,store,rsr,wsr")
(set_attr "mode" "HI")
(set_attr "length" "2,2,3,3,3,3,3,3,3,3")])
@@ -1519,7 +1522,7 @@
const16\t%0, %t1\;const16\t%0, %b1
%v1l32i\t%0, %1
%v0s32i\t%1, %0"
- [(set_attr "type" "farith,fload,fstore,move,load,load,store,move,farith,farith,move,move,load,store")
+ [(set_attr "type" "farith,fload,fstore,move,load,load,store,move,farith,farith,load,move,load,store")
(set_attr "mode" "SF")
(set_attr "length" "3,3,3,2,3,2,2,3,3,3,3,6,3,3")])
@@ -1643,7 +1646,10 @@
std::swap (operands[0], operands[1]);
std::swap (operands[2], operands[3]);
}
-})
+}
+ [(set_attr "type" "move,load,move,load,load,store")
+ (set_attr "mode" "DF")
+ (set_attr "length" "6,6,12,6,6,6")])
;; Block moves
diff --git a/gcc/configure b/gcc/configure
index 7537da2..bacdd29 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -36498,7 +36498,7 @@ $as_echo "$as_me: executing $ac_file commands" >&6;}
"depdir":C) $SHELL $ac_aux_dir/mkinstalldirs $DEPDIR ;;
"gccdepdir":C)
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs build/$DEPDIR
- for lang in $subdirs c-family common analyzer text-art rtl-ssa sym-exec
+ for lang in $subdirs c-family common analyzer diagnostics text-art rtl-ssa sym-exec
do
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs $lang/$DEPDIR
done ;;
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 24e0aa6..2c43b38 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -1397,7 +1397,7 @@ AC_CHECK_HEADERS(ext/hash_map)
ZW_CREATE_DEPDIR
AC_CONFIG_COMMANDS([gccdepdir],[
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs build/$DEPDIR
- for lang in $subdirs c-family common analyzer text-art rtl-ssa sym-exec
+ for lang in $subdirs c-family common analyzer diagnostics text-art rtl-ssa sym-exec
do
${CONFIG_SHELL-/bin/sh} $ac_aux_dir/mkinstalldirs $lang/$DEPDIR
done], [subdirs="$subdirs" ac_aux_dir=$ac_aux_dir DEPDIR=$DEPDIR])
diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index a11ebd1..b6a922a 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -164,8 +164,10 @@ struct cl_option;
struct cl_decoded_option;
struct cl_option_handlers;
class rich_location;
-class diagnostic_context;
-class diagnostic_text_output_format;
+namespace diagnostics {
+ class context;
+ class text_sink;
+} // namespace diagnostics
class pretty_printer;
class diagnostic_event_id_t;
typedef const char * (*diagnostic_input_charset_callback)(const char *);
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e9da5a6..08ec840 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,173 @@
+2025-07-27 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ * cp-tree.h (struct lang_type): Add comment mentioning modules.
+ * module.cc (trees_out::lang_type_bools): Stream new flags, use
+ gcc_checking_assert.
+ (trees_in::lang_type_bools): Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * constexpr.cc: Update usage of "diagnostic_info" to explicitly
+ refer to "diagnostics::diagnostic_info".
+ * cp-tree.h: Likewise.
+ * error.cc: Likewise.
+ * module.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * call.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * constexpr.cc: Likewise.
+ * cp-tree.h: Likewise.
+ * decl.cc: Likewise.
+ * error.cc: Likewise.
+ * init.cc: Likewise.
+ * method.cc: Likewise.
+ * module.cc: Likewise.
+ * parser.cc: Likewise.
+ * pt.cc: Likewise.
+ * semantics.cc: Likewise.
+ * typeck.cc: Likewise.
+ * typeck2.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * cp-tree.h: Update for renaming of diagnostic_option_id to
+ diagnostics::option_id.
+ * decl.cc: Likewise.
+ * error.cc: Likewise.
+ * name-lookup.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * error.cc: Update for move of diagnostic-color.h to
+ diagnostics/color.h.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * cp-tree.h: Update for diagnostic_context becoming
+ diagnostics::context.
+ * error.cc: Likewise.
+ * module.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * constexpr.cc: Update to add "m_" prefix to fields of
+ diagnostic_info throughout.
+ * error.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * cp-tree.h: Update for move of diagnostics output formats into
+ namespace "diagnostics" as "sinks".
+ * error.cc: Likewise.
+
+2025-07-25 Patrick Palka <ppalka@redhat.com>
+
+ * call.cc (build_new_op): If the selected candidate is
+ rewritten, communicate the LOOKUP_REWRITTEN/REVERSED flags to
+ the caller via the 'overload' out-parameter, and stop clearing
+ '*overload' in that case.
+ * tree.cc (build_min_non_dep_op_overload): Handle rebuilding all
+ C++20 rewritten comparison operator expressions.
+
+2025-07-25 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/121219
+ * coroutines.cc
+ (cp_coroutine_transform::build_ramp_function): Reorder the return
+ expressions for the 'normal' and 'allocation failed' cases so that
+ NRV constraints are met.
+
+2025-07-24 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/117294
+ PR c++/113854
+ * call.cc (implicit_conversion_error): Hide label when printing
+ a stub object.
+ (convert_like_internal): Likewise, and nest candidate
+ diagnostics.
+ * constexpr.cc (diagnose_failing_condition): Nest diagnostics,
+ attempt to provide more helpful diagnostics for traits.
+ * constraint.cc (satisfy_atom): Pass result before constant
+ evaluation to diagnose_atomic_constraint.
+ (diagnose_trait_expr): Adjust diagnostics for clarity and
+ detail.
+ (maybe_diagnose_standard_trait): New function.
+ (diagnose_atomic_constraint): Attempt to provide more helpful
+ diagnostics for more traits.
+ * cp-tree.h (explain_not_noexcept): Declare new function.
+ (is_trivially_xible): Add parameter.
+ (is_nothrow_xible): Likewise.
+ (is_xible): Likewise.
+ (is_convertible): Likewise.
+ (is_nothrow_convertible): Likewise.
+ (diagnose_trait_expr): Declare new function.
+ (maybe_diagnose_standard_trait): Declare new function.
+ * error.cc (dump_type) <case TREE_VEC>: Handle trait types.
+ * except.cc (explain_not_noexcept): New function.
+ * method.cc (build_trait_object): Add complain parameter.
+ (build_invoke): Propagate complain parameter.
+ (assignable_expr): Add explain parameter to show diagnostics.
+ (constructible_expr): Likewise.
+ (destructible_expr): Likewise.
+ (is_xible_helper): Replace trivial flag with explain flag,
+ add diagnostics.
+ (is_trivially_xible): New explain flag.
+ (is_nothrow_xible): Likewise.
+ (is_xible): Likewise.
+ (is_convertible_helper): Add complain flag.
+ (is_convertible): New explain flag.
+ (is_nothrow_convertible): Likewise.
+ * typeck.cc (cp_build_function_call_vec): Add handling for stub
+ objects.
+ (convert_arguments): Always return -1 on error.
+ * typeck2.cc (cxx_readonly_error): Add handling for stub
+ objects.
+
+2025-07-24 Jason Merrill <jason@redhat.com>
+
+ * pt.cc (tsubst_lambda_expr): Revert r9-5971 change.
+
+2025-07-24 Jason Merrill <jason@redhat.com>
+
+ PR c++/114632
+ PR c++/101233
+ * lambda.cc (maybe_add_lambda_conv_op): Not for xobj lambda.
+ * pt.cc (tsubst_function_decl): Add cp_evaluated.
+ (alias_ctad_tweaks): Revert PR101233 fix.
+
+2025-07-24 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120412
+ * module.cc (trees_out::core_vals): Write TU_LOCAL_ENTITY bits.
+ (trees_in::core_vals): Read it.
+ (trees_in::tree_node): Handle TU_LOCAL_ENTITY typedefs.
+
+2025-07-23 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/121179
+ * call.cc (build_new_op): Don't clear *overload for a simple
+ != to == rewrite.
+ * tree.cc (build_min_non_dep_op_overload): Handle TRUTH_NOT_EXPR
+ appearing in a rewritten operator expression.
+
+2025-07-23 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/121055
+ * method.cc (build_invoke): Correct reference_wrapper handling.
+
+2025-07-22 Jason Merrill <jason@redhat.com>
+
+ PR c++/121068
+ * constexpr.cc (cxx_eval_store_expression): Allow ARRAY_REFs
+ when activating an array member of a union.
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * semantics.cc (finish_asm_stmt): Pass null pointer to
+ parse_{input,output}_constraint().
+
2025-07-16 Kwok Cheung Yeung <kcyeung@baylibre.com>
* pt.cc (tsubst_omp_clause_decl): Use OMP_ITERATOR_DECL_P.
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 37ad0a9..9283d97 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -220,7 +220,8 @@ static void add_candidates (tree, tree, const vec<tree, va_gc> *, tree, tree,
bool, tree, tree, int, struct z_candidate **,
tsubst_flags_t);
static conversion *merge_conversion_sequences (conversion *, conversion *);
-static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t);
+static tree build_temp (tree, tree, int, enum diagnostics::kind *,
+ tsubst_flags_t);
static conversion *build_identity_conv (tree, tree);
static inline bool conv_binds_to_array_of_unknown_bound (conversion *);
static bool conv_is_prvalue (conversion *);
@@ -4927,6 +4928,11 @@ implicit_conversion_error (location_t loc, tree type, tree expr)
&& !CP_AGGREGATE_TYPE_P (type))
error_at (loc, "designated initializers cannot be used with a "
"non-aggregate type %qT", type);
+ else if (is_stub_object (expr))
+ /* The expression is generated by a trait check, we don't have
+ a useful location to highlight the label. */
+ error_at (loc, "could not convert %qH to %qI",
+ TREE_TYPE (expr), type);
else
{
range_label_for_type_mismatch label (TREE_TYPE (expr), type);
@@ -6455,7 +6461,9 @@ build_conditional_expr (const op_location_t &loc,
types when the enumeration is still being defined. */;
else if (complain & (cxx_dialect >= cxx26
? tf_warning_or_error : tf_warning))
- emit_diagnostic (cxx_dialect >= cxx26 ? DK_PEDWARN : DK_WARNING,
+ emit_diagnostic ((cxx_dialect >= cxx26
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning),
loc, OPT_Wenum_compare, "enumerated mismatch "
"in conditional expression: %qT vs %qT",
arg2_type, arg3_type);
@@ -7486,7 +7494,16 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
else if (TREE_CODE (cand->fn) == FUNCTION_DECL)
{
if (overload)
- *overload = cand->fn;
+ {
+ if (cand->rewritten ())
+ /* build_min_non_dep_op_overload needs to know whether the
+ candidate is rewritten/reversed. */
+ *overload = build_tree_list (build_int_cst (integer_type_node,
+ cand->flags),
+ cand->fn);
+ else
+ *overload = cand->fn;
+ }
if (resolve_args (arglist, complain) == NULL)
result = error_mark_node;
@@ -7535,9 +7552,6 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
/* If this was a C++20 rewritten comparison, adjust the result. */
if (cand->rewritten ())
{
- /* FIXME build_min_non_dep_op_overload can't handle rewrites. */
- if (overload)
- *overload = NULL_TREE;
switch (code)
{
case EQ_EXPR:
@@ -7636,8 +7650,9 @@ build_new_op (const op_location_t &loc, enum tree_code code, int flags,
&& (complain & tf_warning_or_error) == 0)
result = error_mark_node;
else if (cxx_dialect >= cxx26 || (complain & tf_warning))
- emit_diagnostic (cxx_dialect >= cxx26
- ? DK_PEDWARN : DK_WARNING,
+ emit_diagnostic ((cxx_dialect >= cxx26
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning),
loc, OPT_Wenum_compare,
"comparison between %q#T and %q#T",
arg1_type, arg2_type);
@@ -8451,11 +8466,11 @@ complain_about_access (tree decl, tree diag_decl, tree diag_location,
static tree
build_temp (tree expr, tree type, int flags,
- diagnostic_t *diagnostic_kind, tsubst_flags_t complain)
+ enum diagnostics::kind *diagnostic_kind, tsubst_flags_t complain)
{
int savew, savee;
- *diagnostic_kind = DK_UNSPECIFIED;
+ *diagnostic_kind = diagnostics::kind::unspecified;
/* If the source is a packed field, calling the copy constructor will require
binding the field to the reference parameter to the copy constructor, and
@@ -8479,9 +8494,9 @@ build_temp (tree expr, tree type, int flags,
expr = build_special_member_call (NULL_TREE, complete_ctor_identifier,
&args, type, flags, complain);
if (warningcount + werrorcount > savew)
- *diagnostic_kind = DK_WARNING;
+ *diagnostic_kind = diagnostics::kind::warning;
else if (errorcount > savee)
- *diagnostic_kind = DK_ERROR;
+ *diagnostic_kind = diagnostics::kind::error;
return expr;
}
@@ -8693,9 +8708,10 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
bool nested_p, tsubst_flags_t complain)
{
tree totype = convs->type;
- diagnostic_t diag_kind;
+ enum diagnostics::kind diag_kind;
int flags;
location_t loc = cp_expr_loc_or_input_loc (expr);
+ const bool stub_object_p = is_stub_object (expr);
if (convs->bad_p && !(complain & tf_error))
return error_mark_node;
@@ -8772,7 +8788,10 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
"from %qH to %qI", TREE_TYPE (expr),
totype);
if (complained)
- print_z_candidate (loc, N_("candidate is:"), t->cand);
+ {
+ auto_diagnostic_nesting_level sentinel;
+ print_z_candidate (loc, N_("candidate is:"), t->cand);
+ }
expr = convert_like (t, expr, fn, argnum,
/*issue_conversion_warnings=*/false,
/*c_cast_p=*/false, /*nested_p=*/true,
@@ -8797,7 +8816,14 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
else if (t->kind == ck_identity)
break;
}
- if (!complained && expr != error_mark_node)
+ if (!complained && stub_object_p)
+ {
+ /* An error diagnosed within a trait, don't give extra labels. */
+ error_at (loc, "invalid conversion from %qH to %qI",
+ TREE_TYPE (expr), totype);
+ complained = 1;
+ }
+ else if (!complained && expr != error_mark_node)
{
range_label_for_type_mismatch label (TREE_TYPE (expr), totype);
gcc_rich_location richloc (loc, &label, highlight_colors::percent_h);
@@ -9220,7 +9246,7 @@ convert_like_internal (conversion *convs, tree expr, tree fn, int argnum,
if (convs->copy_init_p)
flags |= LOOKUP_ONLYCONVERTING;
expr = build_temp (expr, totype, flags, &diag_kind, complain);
- if (diag_kind && complain)
+ if (diag_kind != diagnostics::kind::unspecified && complain)
{
auto_diagnostic_group d;
maybe_print_user_conv_context (convs);
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index ee06858..f92beb1 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -153,7 +153,7 @@ static bool
constexpr_error (location_t location, bool constexpr_fundef_p,
const char *gmsgid, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
rich_location richloc (line_table, location);
va_start (ap, gmsgid);
@@ -161,14 +161,17 @@ constexpr_error (location_t location, bool constexpr_fundef_p,
if (!constexpr_fundef_p)
{
/* Report an error that cannot be suppressed. */
- diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_ERROR);
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
+ diagnostics::kind::error);
ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
}
else if (warn_invalid_constexpr)
{
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
- cxx_dialect < cxx23 ? DK_PEDWARN : DK_WARNING);
- diagnostic.option_id = OPT_Winvalid_constexpr;
+ (cxx_dialect < cxx23
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning));
+ diagnostic.m_option_id = OPT_Winvalid_constexpr;
ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
}
else
@@ -2883,10 +2886,15 @@ diagnose_failing_condition (tree bad, location_t cloc, bool show_expr_p,
if (TREE_CODE (bad) == CLEANUP_POINT_EXPR)
bad = TREE_OPERAND (bad, 0);
+ auto_diagnostic_nesting_level sentinel;
+
/* Actually explain the failure if this is a concept check or a
requires-expression. */
if (concept_check_p (bad) || TREE_CODE (bad) == REQUIRES_EXPR)
diagnose_constraints (cloc, bad, NULL_TREE);
+ /* Similarly if this is a standard trait. */
+ else if (maybe_diagnose_standard_trait (cloc, bad))
+ ;
else if (COMPARISON_CLASS_P (bad)
&& ARITHMETIC_TYPE_P (TREE_TYPE (TREE_OPERAND (bad, 0))))
{
@@ -7736,13 +7744,24 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (*valp), first, NULL_TREE);
/* Check for implicit change of active member for a union. */
+
+ /* LWG3436, CWG2675, c++/121068: The array object model is confused. For
+ now allow initializing an array element to activate the array. */
+ auto only_array_refs = [](const releasing_vec &refs)
+ {
+ for (unsigned i = 1; i < refs->length(); i += 3)
+ if (TREE_CODE ((*refs)[i]) != INTEGER_CST)
+ return false;
+ return true;
+ };
+
if (code == UNION_TYPE
&& (CONSTRUCTOR_NELTS (*valp) == 0
|| CONSTRUCTOR_ELT (*valp, 0)->index != index)
/* An INIT_EXPR of the last member in an access chain is always OK,
but still check implicit change of members earlier on; see
cpp2a/constexpr-union6.C. */
- && !(TREE_CODE (t) == INIT_EXPR && refs->is_empty ()))
+ && !(TREE_CODE (t) == INIT_EXPR && only_array_refs (refs)))
{
bool has_active_member = CONSTRUCTOR_NELTS (*valp) != 0;
tree inner = strip_array_types (reftype);
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 8d7aec3..d4a83e4 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2490,10 +2490,11 @@ satisfy_atom (tree t, tree args, sat_info info)
result = force_rvalue (result, info.complain);
if (result == error_mark_node)
return cache.save (inst_cache.save (error_mark_node));
+ tree substituted = result;
if (!same_type_p (TREE_TYPE (result), boolean_type_node))
{
if (info.noisy ())
- diagnose_atomic_constraint (t, args, result, info);
+ diagnose_atomic_constraint (t, args, substituted, info);
return cache.save (inst_cache.save (error_mark_node));
}
@@ -2511,7 +2512,7 @@ satisfy_atom (tree t, tree args, sat_info info)
}
result = satisfaction_value (result);
if (result == boolean_false_node && info.diagnose_unsatisfaction_p ())
- diagnose_atomic_constraint (t, args, result, info);
+ diagnose_atomic_constraint (t, args, substituted, info);
return cache.save (inst_cache.save (result));
}
@@ -3063,11 +3064,9 @@ get_constraint_error_location (tree t)
/* Emit a diagnostic for a failed trait. */
-static void
-diagnose_trait_expr (tree expr, tree args)
+void
+diagnose_trait_expr (location_t loc, tree expr, tree args)
{
- location_t loc = cp_expr_location (expr);
-
/* Build a "fake" version of the instantiated trait, so we can
get the instantiated types from result. */
++processing_template_decl;
@@ -3076,218 +3075,246 @@ diagnose_trait_expr (tree expr, tree args)
tree t1 = TRAIT_EXPR_TYPE1 (expr);
tree t2 = TRAIT_EXPR_TYPE2 (expr);
- if (t2 && TREE_CODE (t2) == TREE_VEC)
- {
- /* Convert the TREE_VEC of arguments into a TREE_LIST, since we can't
- directly print a TREE_VEC but we can a TREE_LIST via the E format
- specifier. */
- tree list = NULL_TREE;
- for (tree t : tree_vec_range (t2))
- list = tree_cons (NULL_TREE, t, list);
- t2 = nreverse (list);
- }
+
+ /* For traits intrinsically about the properties of user-defined types,
+ decl_loc will point to the declaration of that type. */
+ location_t decl_loc = location_of (t1);
+ if (decl_loc == input_location)
+ decl_loc = loc;
+
switch (TRAIT_EXPR_KIND (expr))
{
case CPTK_HAS_NOTHROW_ASSIGN:
- inform (loc, " %qT is not nothrow copy assignable", t1);
+ inform (decl_loc, "%qT is not nothrow copy assignable", t1);
break;
case CPTK_HAS_NOTHROW_CONSTRUCTOR:
- inform (loc, " %qT is not nothrow default constructible", t1);
+ inform (decl_loc, "%qT is not nothrow default constructible", t1);
break;
case CPTK_HAS_NOTHROW_COPY:
- inform (loc, " %qT is not nothrow copy constructible", t1);
+ inform (decl_loc, "%qT is not nothrow copy constructible", t1);
break;
case CPTK_HAS_TRIVIAL_ASSIGN:
- inform (loc, " %qT is not trivially copy assignable", t1);
+ inform (decl_loc, "%qT is not trivially copy assignable", t1);
break;
case CPTK_HAS_TRIVIAL_CONSTRUCTOR:
- inform (loc, " %qT is not trivially default constructible", t1);
+ inform (decl_loc, "%qT is not trivially default constructible", t1);
break;
case CPTK_HAS_TRIVIAL_COPY:
- inform (loc, " %qT is not trivially copy constructible", t1);
+ inform (decl_loc, "%qT is not trivially copy constructible", t1);
break;
case CPTK_HAS_TRIVIAL_DESTRUCTOR:
- inform (loc, " %qT is not trivially destructible", t1);
+ inform (decl_loc, "%qT is not trivially destructible", t1);
break;
case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
- inform (loc, " %qT does not have unique object representations", t1);
+ inform (decl_loc, "%qT does not have unique object representations", t1);
break;
case CPTK_HAS_VIRTUAL_DESTRUCTOR:
- inform (loc, " %qT does not have a virtual destructor", t1);
+ {
+ location_t dtor_loc = decl_loc;
+ if (NON_UNION_CLASS_TYPE_P (t1))
+ if (tree dtor = CLASSTYPE_DESTRUCTOR (t1))
+ dtor_loc = DECL_SOURCE_LOCATION (dtor);
+ inform (dtor_loc, "%qT does not have a virtual destructor", t1);
+ }
break;
case CPTK_IS_ABSTRACT:
- inform (loc, " %qT is not an abstract class", t1);
+ inform (decl_loc, "%qT is not an abstract class", t1);
break;
case CPTK_IS_AGGREGATE:
- inform (loc, " %qT is not an aggregate", t1);
+ inform (decl_loc, "%qT is not an aggregate", t1);
break;
case CPTK_IS_ARRAY:
- inform (loc, " %qT is not an array", t1);
+ inform (loc, "%qT is not an array", t1);
break;
case CPTK_IS_ASSIGNABLE:
- inform (loc, " %qT is not assignable from %qT", t1, t2);
+ inform (loc, "%qT is not assignable from %qT, because", t1, t2);
+ is_xible (MODIFY_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_BASE_OF:
- inform (loc, " %qT is not a base of %qT", t1, t2);
+ inform (decl_loc, "%qT is not a base of %qT", t1, t2);
break;
case CPTK_IS_BOUNDED_ARRAY:
- inform (loc, " %qT is not a bounded array", t1);
+ inform (loc, "%qT is not a bounded array", t1);
break;
case CPTK_IS_CLASS:
- inform (loc, " %qT is not a class", t1);
+ inform (decl_loc, "%qT is not a class", t1);
break;
case CPTK_IS_CONST:
- inform (loc, " %qT is not a const type", t1);
+ inform (loc, "%qT is not a const type", t1);
break;
case CPTK_IS_CONSTRUCTIBLE:
- if (!t2)
- inform (loc, " %qT is not default constructible", t1);
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not default constructible, because", t1);
else
- inform (loc, " %qT is not constructible from %qE", t1, t2);
+ inform (loc, "%qT is not constructible from %qT, because", t1, t2);
+ is_xible (INIT_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_CONVERTIBLE:
- inform (loc, " %qT is not convertible from %qE", t2, t1);
+ /* The errors produced here all seem to mention "convertible" in the
+ diagnostic, so an extra inform here appears redundant. */
+ is_convertible (t1, t2, /*explain=*/true);
break;
case CPTK_IS_DESTRUCTIBLE:
- inform (loc, " %qT is not destructible", t1);
+ inform (loc, "%qT is not destructible, because", t1);
+ is_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true);
break;
case CPTK_IS_EMPTY:
- inform (loc, " %qT is not an empty class", t1);
+ inform (decl_loc, "%qT is not an empty class", t1);
break;
case CPTK_IS_ENUM:
- inform (loc, " %qT is not an enum", t1);
+ inform (decl_loc, "%qT is not an enum", t1);
break;
case CPTK_IS_FINAL:
- inform (loc, " %qT is not a final class", t1);
+ inform (decl_loc, "%qT is not a final class", t1);
break;
case CPTK_IS_FUNCTION:
- inform (loc, " %qT is not a function", t1);
+ inform (loc, "%qT is not a function", t1);
break;
case CPTK_IS_INVOCABLE:
- if (!t2)
- inform (loc, " %qT is not invocable", t1);
- else
- inform (loc, " %qT is not invocable by %qE", t1, t2);
+ {
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not invocable, because", t1);
+ else
+ inform (loc, "%qT is not invocable by %qT, because", t1, t2);
+ tree call = build_invoke (t1, t2, tf_error);
+ gcc_assert (call == error_mark_node);
+ }
break;
case CPTK_IS_LAYOUT_COMPATIBLE:
- inform (loc, " %qT is not layout compatible with %qT", t1, t2);
+ inform (loc, "%qT is not layout compatible with %qT", t1, t2);
break;
case CPTK_IS_LITERAL_TYPE:
- inform (loc, " %qT is not a literal type", t1);
+ inform (decl_loc, "%qT is not a literal type", t1);
break;
case CPTK_IS_MEMBER_FUNCTION_POINTER:
- inform (loc, " %qT is not a member function pointer", t1);
+ inform (loc, "%qT is not a member function pointer", t1);
break;
case CPTK_IS_MEMBER_OBJECT_POINTER:
- inform (loc, " %qT is not a member object pointer", t1);
+ inform (loc, "%qT is not a member object pointer", t1);
break;
case CPTK_IS_MEMBER_POINTER:
- inform (loc, " %qT is not a member pointer", t1);
+ inform (loc, "%qT is not a member pointer", t1);
break;
case CPTK_IS_NOTHROW_ASSIGNABLE:
- inform (loc, " %qT is not nothrow assignable from %qT", t1, t2);
+ inform (loc, "%qT is not nothrow assignable from %qT, because", t1, t2);
+ is_nothrow_xible (MODIFY_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
- if (!t2)
- inform (loc, " %qT is not nothrow default constructible", t1);
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not nothrow default constructible, because", t1);
else
- inform (loc, " %qT is not nothrow constructible from %qE", t1, t2);
+ inform (loc, "%qT is not nothrow constructible from %qT, because",
+ t1, t2);
+ is_nothrow_xible (INIT_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_CONVERTIBLE:
- inform (loc, " %qT is not nothrow convertible from %qE", t2, t1);
+ inform (loc, "%qT is not nothrow convertible from %qT, because", t1, t2);
+ is_nothrow_convertible (t1, t2, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_DESTRUCTIBLE:
- inform (loc, " %qT is not nothrow destructible", t1);
+ inform (loc, "%qT is not nothrow destructible, because", t1);
+ is_nothrow_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true);
break;
case CPTK_IS_NOTHROW_INVOCABLE:
- if (!t2)
- inform (loc, " %qT is not nothrow invocable", t1);
- else
- inform (loc, " %qT is not nothrow invocable by %qE", t1, t2);
+ {
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not nothrow invocable, because", t1);
+ else
+ inform (loc, "%qT is not nothrow invocable by %qT, because", t1, t2);
+ tree call = build_invoke (t1, t2, tf_error);
+ if (call != error_mark_node)
+ explain_not_noexcept (call);
+ }
break;
case CPTK_IS_NOTHROW_RELOCATABLE:
- inform (loc, " %qT is not nothrow relocatable", t1);
+ inform (loc, "%qT is not nothrow relocatable", t1);
break;
case CPTK_IS_OBJECT:
- inform (loc, " %qT is not an object type", t1);
+ inform (loc, "%qT is not an object type", t1);
break;
case CPTK_IS_POINTER_INTERCONVERTIBLE_BASE_OF:
- inform (loc, " %qT is not pointer-interconvertible base of %qT",
+ inform (decl_loc, "%qT is not a pointer-interconvertible base of %qT",
t1, t2);
break;
case CPTK_IS_POD:
- inform (loc, " %qT is not a POD type", t1);
+ inform (loc, "%qT is not a POD type", t1);
break;
case CPTK_IS_POINTER:
- inform (loc, " %qT is not a pointer", t1);
+ inform (loc, "%qT is not a pointer", t1);
break;
case CPTK_IS_POLYMORPHIC:
- inform (loc, " %qT is not a polymorphic type", t1);
+ inform (decl_loc, "%qT is not a polymorphic type", t1);
break;
case CPTK_IS_REFERENCE:
- inform (loc, " %qT is not a reference", t1);
+ inform (loc, "%qT is not a reference", t1);
break;
case CPTK_IS_REPLACEABLE:
- inform (loc, " %qT is not replaceable", t1);
+ inform (loc, "%qT is not replaceable", t1);
break;
case CPTK_IS_SAME:
- inform (loc, " %qT is not the same as %qT", t1, t2);
+ inform (loc, "%q#T is not the same as %q#T", t1, t2);
break;
case CPTK_IS_SCOPED_ENUM:
- inform (loc, " %qT is not a scoped enum", t1);
+ inform (decl_loc, "%qT is not a scoped enum", t1);
break;
case CPTK_IS_STD_LAYOUT:
- inform (loc, " %qT is not an standard layout type", t1);
+ inform (decl_loc, "%qT is not a standard layout type", t1);
break;
case CPTK_IS_TRIVIAL:
- inform (loc, " %qT is not a trivial type", t1);
+ inform (decl_loc, "%qT is not a trivial type", t1);
break;
case CPTK_IS_TRIVIALLY_ASSIGNABLE:
- inform (loc, " %qT is not trivially assignable from %qT", t1, t2);
+ inform (loc, "%qT is not trivially assignable from %qT, because", t1, t2);
+ is_trivially_xible (MODIFY_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
- if (!t2)
- inform (loc, " %qT is not trivially default constructible", t1);
+ if (!TREE_VEC_LENGTH (t2))
+ inform (loc, "%qT is not trivially default constructible, because", t1);
else
- inform (loc, " %qT is not trivially constructible from %qE", t1, t2);
+ inform (loc, "%qT is not trivially constructible from %qT, because",
+ t1, t2);
+ is_trivially_xible (INIT_EXPR, t1, t2, /*explain=*/true);
break;
case CPTK_IS_TRIVIALLY_COPYABLE:
- inform (loc, " %qT is not trivially copyable", t1);
+ inform (decl_loc, "%qT is not trivially copyable", t1);
break;
case CPTK_IS_TRIVIALLY_DESTRUCTIBLE:
- inform (loc, " %qT is not trivially destructible", t1);
+ inform (loc, "%qT is not trivially destructible, because", t1);
+ is_trivially_xible (BIT_NOT_EXPR, t1, NULL_TREE, /*explain=*/true);
break;
case CPTK_IS_TRIVIALLY_RELOCATABLE:
- inform (loc, " %qT is not trivially relocatable", t1);
+ inform (loc, "%qT is not trivially relocatable", t1);
break;
case CPTK_IS_UNBOUNDED_ARRAY:
- inform (loc, " %qT is not an unbounded array", t1);
+ inform (loc, "%qT is not an unbounded array", t1);
break;
case CPTK_IS_UNION:
- inform (loc, " %qT is not a union", t1);
+ inform (decl_loc, "%qT is not a union", t1);
break;
case CPTK_IS_VIRTUAL_BASE_OF:
- inform (loc, " %qT is not a virtual base of %qT", t1, t2);
+ inform (decl_loc, "%qT is not a virtual base of %qT", t1, t2);
+ if (CLASS_TYPE_P (t2))
+ inform (location_of (t2), "%qT declared here", t2);
break;
case CPTK_IS_VOLATILE:
- inform (loc, " %qT is not a volatile type", t1);
+ inform (loc, "%qT is not a volatile type", t1);
break;
case CPTK_RANK:
- inform (loc, " %qT cannot yield a rank", t1);
+ inform (loc, "%qT cannot yield a rank", t1);
break;
case CPTK_TYPE_ORDER:
- inform (loc, " %qT and %qT cannot be ordered", t1, t2);
+ inform (loc, "%qT and %qT cannot be ordered", t1, t2);
break;
case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
- inform (loc, " %qT is not a reference that binds to a temporary "
+ inform (loc, "%qT is not a reference that binds to a temporary "
"object of type %qT (direct-initialization)", t1, t2);
break;
case CPTK_REF_CONVERTS_FROM_TEMPORARY:
- inform (loc, " %qT is not a reference that binds to a temporary "
+ inform (loc, "%qT is not a reference that binds to a temporary "
"object of type %qT (copy-initialization)", t1, t2);
break;
case CPTK_IS_DEDUCIBLE:
- inform (loc, " %qD is not deducible from %qT", t1, t2);
+ inform (loc, "%qD is not deducible from %qT", t1, t2);
break;
#define DEFTRAIT_TYPE(CODE, NAME, ARITY) \
case CPTK_##CODE:
@@ -3300,10 +3327,50 @@ diagnose_trait_expr (tree expr, tree args)
}
}
+/* Attempt to detect if this is a standard type trait, defined in terms
+ of a compiler builtin (above). If so, this will allow us to provide
+ more helpful diagnostics. */
+
+bool
+maybe_diagnose_standard_trait (location_t loc, tree expr)
+{
+ gcc_assert (TREE_CODE (expr) != TRAIT_EXPR);
+ expr = tree_strip_nop_conversions (expr);
+
+ /* TODO: in some cases it would be possible to provide more helpful
+ diagnostics for negations of traits, e.g. '!is_same_v<T1, T2>'. */
+
+ tree args = NULL_TREE;
+ if (VAR_P (expr) && DECL_LANG_SPECIFIC (expr) && DECL_USE_TEMPLATE (expr))
+ {
+ tree tinfo = DECL_TEMPLATE_INFO (expr);
+ if (PRIMARY_TEMPLATE_P (TI_TEMPLATE (tinfo)) && TI_PARTIAL_INFO (tinfo))
+ tinfo = TI_PARTIAL_INFO (tinfo);
+ else if (DECL_TEMPLATE_SPECIALIZATION (expr))
+ /* In an explicit specialisation we no longer know what the original
+ initializer looked like. */
+ tinfo = NULL_TREE;
+
+ if (tinfo)
+ {
+ expr = DECL_INITIAL (DECL_TEMPLATE_RESULT (TI_TEMPLATE (tinfo)));
+ args = TI_ARGS (tinfo);
+ }
+ }
+
+ if (TREE_CODE (expr) == TRAIT_EXPR)
+ {
+ diagnose_trait_expr (loc, expr, args);
+ return true;
+ }
+
+ return false;
+}
+
/* Diagnose a substitution failure in the atomic constraint T using ARGS. */
static void
-diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info)
+diagnose_atomic_constraint (tree t, tree args, tree substituted, sat_info info)
{
/* If the constraint is already ill-formed, we've previously diagnosed
the reason. We should still say why the constraints aren't satisfied. */
@@ -3324,25 +3391,26 @@ diagnose_atomic_constraint (tree t, tree args, tree result, sat_info info)
/* Generate better diagnostics for certain kinds of expressions. */
tree expr = ATOMIC_CONSTR_EXPR (t);
STRIP_ANY_LOCATION_WRAPPER (expr);
- switch (TREE_CODE (expr))
+
+ if (TREE_CODE (expr) == REQUIRES_EXPR)
{
- case TRAIT_EXPR:
- diagnose_trait_expr (expr, args);
- break;
- case REQUIRES_EXPR:
gcc_checking_assert (info.diagnose_unsatisfaction_p ());
/* Clear in_decl before replaying the substitution to avoid emitting
seemingly unhelpful "in declaration ..." notes that follow some
substitution failure error messages. */
info.in_decl = NULL_TREE;
tsubst_requires_expr (expr, args, info);
- break;
- default:
- if (!same_type_p (TREE_TYPE (result), boolean_type_node))
- error_at (loc, "constraint %qE has type %qT, not %<bool%>",
- t, TREE_TYPE (result));
+ }
+ else if (!same_type_p (TREE_TYPE (substituted), boolean_type_node))
+ error_at (loc, "constraint %qE has type %qT, not %<bool%>",
+ t, TREE_TYPE (substituted));
+ else
+ {
+ inform (loc, "the expression %qE evaluated to %<false%>", t);
+ if (TREE_CODE (expr) == TRAIT_EXPR)
+ diagnose_trait_expr (loc, expr, args);
else
- inform (loc, "the expression %qE evaluated to %<false%>", t);
+ maybe_diagnose_standard_trait (loc, substituted);
}
}
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 52cc186..690e510 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -5050,6 +5050,8 @@ cp_coroutine_transform::build_ramp_function ()
check the returned pointer and call the func if it's null.
Otherwise, no check, and we fail for noexcept/fno-exceptions cases. */
+ tree grooaf_if_stmt = NULL_TREE;
+ tree alloc_ok_scope = NULL_TREE;
if (grooaf)
{
/* [dcl.fct.def.coroutine] / 10 (part 3)
@@ -5057,20 +5059,11 @@ cp_coroutine_transform::build_ramp_function ()
control to the caller of the coroutine and the return value is
obtained by a call to T::get_return_object_on_allocation_failure(),
where T is the promise type. */
- tree if_stmt = begin_if_stmt ();
tree cond = build1 (CONVERT_EXPR, frame_ptr_type, nullptr_node);
- cond = build2 (EQ_EXPR, boolean_type_node, coro_fp, cond);
- finish_if_stmt_cond (cond, if_stmt);
- r = NULL_TREE;
- if (void_ramp_p)
- /* Execute the get-return-object-on-alloc-fail call... */
- finish_expr_stmt (grooaf);
- else
- /* Get the fallback return object. */
- r = grooaf;
- finish_return_stmt (r);
- finish_then_clause (if_stmt);
- finish_if_stmt (if_stmt);
+ cond = build2 (NE_EXPR, boolean_type_node, coro_fp, cond);
+ grooaf_if_stmt = begin_if_stmt ();
+ finish_if_stmt_cond (cond, grooaf_if_stmt);
+ alloc_ok_scope = begin_compound_stmt (BCS_NORMAL);
}
/* Dereference the frame pointer, to use in member access code. */
@@ -5295,7 +5288,6 @@ cp_coroutine_transform::build_ramp_function ()
a temp which is then used to intialize the return object, including
NVRO. */
- /* Temporary var to hold the g_r_o across the function body. */
coro_gro
= coro_build_and_push_artificial_var (loc, "_Coro_gro", gro_type,
orig_fn_decl, NULL_TREE);
@@ -5328,9 +5320,28 @@ cp_coroutine_transform::build_ramp_function ()
/* The ramp is done, we just need the return statement, which we build from
the return object we constructed before we called the actor. */
+ /* This is our 'normal' exit. */
r = void_ramp_p ? NULL_TREE : convert_from_reference (coro_gro);
finish_return_stmt (r);
+ if (grooaf)
+ {
+ finish_compound_stmt (alloc_ok_scope);
+ finish_then_clause (grooaf_if_stmt);
+
+ begin_else_clause (grooaf_if_stmt);
+ /* We come here if the frame allocation failed. */
+ r = NULL_TREE;
+ if (void_ramp_p)
+ /* Execute the get-return-object-on-alloc-fail call... */
+ finish_expr_stmt (grooaf);
+ else
+ /* Get the fallback return object. */
+ r = grooaf;
+ finish_return_stmt (r);
+ finish_if_stmt (grooaf_if_stmt);
+ }
+
finish_compound_stmt (ramp_fnbody);
return true;
}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6810250..0ac3ecb 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -2508,7 +2508,9 @@ struct GTY(()) lang_type {
/* When adding a flag here, consider whether or not it ought to
apply to a template instance if it applies to the template. If
- so, make sure to copy it in instantiate_class_template! */
+ so, make sure to copy it in instantiate_class_template!
+
+ Also make sure new flags here are streamed in module.cc. */
/* There are some bits left to fill out a 32-bit word. Keep track
of this by updating the size of this bitfield whenever you add or
@@ -7455,7 +7457,7 @@ extern void maybe_warn_variadic_templates (void);
extern void maybe_warn_cpp0x (cpp0x_warn_str str,
location_t = input_location);
extern bool pedwarn_cxx98 (location_t,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
extern location_t location_of (tree);
extern void qualified_name_lookup_error (tree, tree, tree,
@@ -7481,6 +7483,7 @@ extern int nothrow_libfn_p (const_tree);
extern void check_handlers (tree);
extern tree finish_noexcept_expr (tree, tsubst_flags_t);
extern bool expr_noexcept_p (tree, tsubst_flags_t);
+extern void explain_not_noexcept (tree);
extern void perform_deferred_noexcept_checks (void);
extern bool nothrow_spec_p (const_tree);
extern bool type_noexcept_p (const_tree);
@@ -7602,11 +7605,14 @@ extern void finish_thunk (tree);
extern void use_thunk (tree, bool);
extern bool trivial_fn_p (tree);
extern tree forward_parm (tree);
-extern bool is_trivially_xible (enum tree_code, tree, tree);
-extern bool is_nothrow_xible (enum tree_code, tree, tree);
-extern bool is_xible (enum tree_code, tree, tree);
-extern bool is_convertible (tree, tree);
-extern bool is_nothrow_convertible (tree, tree);
+extern bool is_trivially_xible (enum tree_code, tree, tree,
+ bool = false);
+extern bool is_nothrow_xible (enum tree_code, tree, tree,
+ bool = false);
+extern bool is_xible (enum tree_code, tree, tree,
+ bool = false);
+extern bool is_convertible (tree, tree, bool = false);
+extern bool is_nothrow_convertible (tree, tree, bool = false);
extern bool ref_xes_from_temporary (tree, tree, bool);
extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error);
extern bool maybe_explain_implicit_delete (tree);
@@ -8459,9 +8465,9 @@ extern void cxx_print_xnode (FILE *, tree, int);
extern void cxx_print_decl (FILE *, tree, int);
extern void cxx_print_type (FILE *, tree, int);
extern void cxx_print_identifier (FILE *, tree, int);
-extern void cxx_print_error_function (diagnostic_text_output_format &,
+extern void cxx_print_error_function (diagnostics::text_sink &,
const char *,
- const diagnostic_info *);
+ const diagnostics::diagnostic_info *);
/* in typeck.cc */
/* Says how we should behave when comparing two arrays one of which
@@ -8648,7 +8654,7 @@ extern void maybe_warn_pessimizing_move (tree, tree, bool);
/* in typeck2.cc */
extern void require_complete_eh_spec_types (tree, tree);
extern bool cxx_incomplete_type_diagnostic (location_t, const_tree,
- const_tree, diagnostic_t);
+ const_tree, enum diagnostics::kind);
inline location_t
loc_or_input_loc (location_t loc)
{
@@ -8696,7 +8702,7 @@ cp_expr_loc_or_input_loc (const_tree t)
inline bool
cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
- diagnostic_t diag_kind)
+ enum diagnostics::kind diag_kind)
{
return cxx_incomplete_type_diagnostic (cp_expr_loc_or_input_loc (value),
value, type, diag_kind);
@@ -8707,7 +8713,7 @@ extern void cxx_incomplete_type_error (location_t, const_tree,
inline void
cxx_incomplete_type_error (const_tree value, const_tree type)
{
- cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+ cxx_incomplete_type_diagnostic (value, type, diagnostics::kind::error);
}
extern void cxx_incomplete_type_inform (const_tree);
@@ -8778,7 +8784,7 @@ extern alias_set_type cxx_get_alias_set (tree);
extern bool cxx_warn_unused_global_decl (const_tree);
extern size_t cp_tree_size (enum tree_code);
extern bool cp_var_mod_type_p (tree, tree);
-extern void cxx_initialize_diagnostics (diagnostic_context *);
+extern void cxx_initialize_diagnostics (diagnostics::context *);
extern int cxx_types_compatible_p (tree, tree);
extern bool cxx_block_may_fallthru (const_tree);
@@ -8923,6 +8929,8 @@ extern bool constraints_equivalent_p (tree, tree);
extern bool atomic_constraints_identical_p (tree, tree);
extern hashval_t iterative_hash_constraint (tree, hashval_t);
extern hashval_t hash_atomic_constraint (tree);
+extern void diagnose_trait_expr (location_t, tree, tree);
+extern bool maybe_diagnose_standard_trait (location_t, tree);
extern void diagnose_constraints (location_t, tree, tree);
extern void note_failed_type_completion (tree, tsubst_flags_t);
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 0ac92f8..cb3ebff 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -110,7 +110,7 @@ static void initialize_local_var (tree, tree, bool);
static void expand_static_init (tree, tree);
static location_t smallest_type_location (const cp_decl_specifier_seq*);
static bool identify_goto (tree, location_t, const location_t *,
- diagnostic_t, bool);
+ enum diagnostics::kind, bool);
/* The following symbols are subsumed in the cp_global_trees array, and
listed here individually for documentation purposes.
@@ -3737,10 +3737,10 @@ decl_jump_unsafe (tree decl)
static bool
identify_goto (tree decl, location_t loc, const location_t *locus,
- diagnostic_t diag_kind, bool computed)
+ enum diagnostics::kind diag_kind, bool computed)
{
if (computed)
- diag_kind = DK_WARNING;
+ diag_kind = diagnostics::kind::warning;
bool complained
= emit_diagnostic (diag_kind, loc, 0,
decl ? G_("jump to label %qD")
@@ -3776,7 +3776,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
if (exited_omp)
{
- complained = identify_goto (decl, input_location, locus, DK_ERROR,
+ complained = identify_goto (decl, input_location, locus,
+ diagnostics::kind::error,
computed);
if (complained)
inform (input_location, " exits OpenMP structured block");
@@ -3798,7 +3799,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
if (!identified)
{
- complained = identify_goto (decl, input_location, locus, DK_ERROR,
+ complained = identify_goto (decl, input_location, locus,
+ diagnostics::kind::error,
computed);
identified = 2;
}
@@ -3866,7 +3868,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
if (inf)
{
if (identified < 2)
- complained = identify_goto (decl, input_location, locus, DK_ERROR,
+ complained = identify_goto (decl, input_location, locus,
+ diagnostics::kind::error,
computed);
identified = 2;
if (complained)
@@ -3877,7 +3880,8 @@ check_previous_goto_1 (tree decl, cp_binding_level* level, tree names,
if (!vec_safe_is_empty (computed))
{
if (!identified)
- complained = identify_goto (decl, input_location, locus, DK_ERROR,
+ complained = identify_goto (decl, input_location, locus,
+ diagnostics::kind::error,
computed);
identified = 2;
if (complained)
@@ -3949,14 +3953,14 @@ check_goto_1 (named_label_entry *ent, bool computed)
|| ent->in_omp_scope || ent->in_stmt_expr
|| !vec_safe_is_empty (ent->bad_decls))
{
- diagnostic_t diag_kind = DK_PERMERROR;
+ enum diagnostics::kind diag_kind = diagnostics::kind::permerror;
if (ent->in_try_scope || ent->in_catch_scope || ent->in_constexpr_if
|| ent->in_consteval_if || ent->in_transaction_scope
|| ent->in_omp_scope || ent->in_stmt_expr)
- diag_kind = DK_ERROR;
+ diag_kind = diagnostics::kind::error;
complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl),
&input_location, diag_kind, computed);
- identified = 1 + (diag_kind == DK_ERROR);
+ identified = 1 + (diag_kind == diagnostics::kind::error);
}
FOR_EACH_VEC_SAFE_ELT (ent->bad_decls, ix, bad)
@@ -3969,7 +3973,9 @@ check_goto_1 (named_label_entry *ent, bool computed)
if (identified == 1)
{
complained = identify_goto (decl, DECL_SOURCE_LOCATION (decl),
- &input_location, DK_ERROR, computed);
+ &input_location,
+ diagnostics::kind::error,
+ computed);
identified = 2;
}
if (complained)
@@ -4013,7 +4019,8 @@ check_goto_1 (named_label_entry *ent, bool computed)
{
complained = identify_goto (decl,
DECL_SOURCE_LOCATION (decl),
- &input_location, DK_ERROR,
+ &input_location,
+ diagnostics::kind::error,
computed);
identified = 2;
}
@@ -4037,7 +4044,8 @@ check_goto_1 (named_label_entry *ent, bool computed)
{
complained
= identify_goto (decl, DECL_SOURCE_LOCATION (decl),
- &input_location, DK_ERROR, computed);
+ &input_location, diagnostics::kind::error,
+ computed);
identified = 2;
}
if (complained)
@@ -4053,7 +4061,8 @@ check_goto_1 (named_label_entry *ent, bool computed)
{
complained
= identify_goto (decl, DECL_SOURCE_LOCATION (decl),
- &input_location, DK_ERROR, computed);
+ &input_location, diagnostics::kind::error,
+ computed);
identified = 2;
}
if (complained)
@@ -11275,12 +11284,12 @@ grokfndecl (tree ctype,
t && t != void_list_node; t = TREE_CHAIN (t))
if (TREE_PURPOSE (t))
{
- diagnostic_t diag_kind = DK_PERMERROR;
+ enum diagnostics::kind diag_kind = diagnostics::kind::permerror;
/* For templates, mark the default argument as erroneous and give a
hard error. */
if (processing_template_decl)
{
- diag_kind = DK_ERROR;
+ diag_kind = diagnostics::kind::error;
TREE_PURPOSE (t) = error_mark_node;
}
if (!has_errored)
@@ -11288,7 +11297,7 @@ grokfndecl (tree ctype,
has_errored = true;
emit_diagnostic (diag_kind,
DECL_SOURCE_LOCATION (decl),
- /*diagnostic_option_id=*/0,
+ /*diagnostics::option_id=*/0,
"friend declaration of %qD specifies default "
"arguments and isn%'t a definition", decl);
}
@@ -17397,7 +17406,8 @@ xref_basetypes (tree ref, tree base_list)
compatibility. */
if (processing_template_decl
&& CLASS_TYPE_P (basetype) && TYPE_BEING_DEFINED (basetype))
- cxx_incomplete_type_diagnostic (NULL_TREE, basetype, DK_PEDWARN);
+ cxx_incomplete_type_diagnostic (NULL_TREE, basetype,
+ diagnostics::kind::pedwarn);
if (!dependent_type_p (basetype)
&& !complete_type_or_else (basetype, NULL))
/* An incomplete type. Remove it from the list. */
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index eb2ff33..c427163 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "cp-tree.h"
#include "stringpool.h"
#include "tree-diagnostic.h"
-#include "diagnostic-color.h"
+#include "diagnostics/color.h"
#include "langhooks-def.h"
#include "intl.h"
#include "cxx-pretty-print.h"
@@ -38,7 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "cp-name-hint.h"
#include "attribs.h"
#include "pretty-print-format-impl.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/text-sink.h"
#define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
#define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';')
@@ -96,17 +96,17 @@ static void dump_scope (cxx_pretty_printer *, tree, int);
static void dump_template_parms (cxx_pretty_printer *, tree, int, int);
static int get_non_default_template_args_count (tree, int);
static const char *function_category (tree);
-static void maybe_print_constexpr_context (diagnostic_text_output_format &);
-static void maybe_print_instantiation_context (diagnostic_text_output_format &);
-static void print_instantiation_full_context (diagnostic_text_output_format &);
-static void print_instantiation_partial_context (diagnostic_text_output_format &,
+static void maybe_print_constexpr_context (diagnostics::text_sink &);
+static void maybe_print_instantiation_context (diagnostics::text_sink &);
+static void print_instantiation_full_context (diagnostics::text_sink &);
+static void print_instantiation_partial_context (diagnostics::text_sink &,
struct tinst_level *,
location_t);
-static void maybe_print_constraint_context (diagnostic_text_output_format &);
-static void cp_diagnostic_text_starter (diagnostic_text_output_format &,
- const diagnostic_info *);
-static void cp_print_error_function (diagnostic_text_output_format &,
- const diagnostic_info *);
+static void maybe_print_constraint_context (diagnostics::text_sink &);
+static void cp_diagnostic_text_starter (diagnostics::text_sink &,
+ const diagnostics::diagnostic_info *);
+static void cp_print_error_function (diagnostics::text_sink &,
+ const diagnostics::diagnostic_info *);
static bool cp_printer (pretty_printer *, text_info *, const char *,
int, bool, bool, bool, bool *, pp_token_list &);
@@ -242,7 +242,7 @@ get_current_template ()
erroneous_templates_t *erroneous_templates;
-/* Callback function diagnostic_context::m_adjust_diagnostic_info.
+/* Callback function diagnostics::context::m_adjust_diagnostic_info.
Errors issued when parsing a template are automatically treated like
permerrors associated with the -Wtemplate-body flag and can be
@@ -250,16 +250,16 @@ erroneous_templates_t *erroneous_templates;
issue an error if we later need to instantiate the template. */
static void
-cp_adjust_diagnostic_info (diagnostic_context *context,
- diagnostic_info *diagnostic)
+cp_adjust_diagnostic_info (diagnostics::context *context,
+ diagnostics::diagnostic_info *diagnostic)
{
- if (diagnostic->kind == DK_ERROR)
+ if (diagnostic->m_kind == diagnostics::kind::error)
if (tree tmpl = get_current_template ())
{
- diagnostic->option_id = OPT_Wtemplate_body;
+ diagnostic->m_option_id = OPT_Wtemplate_body;
if (context->m_permissive)
- diagnostic->kind = DK_WARNING;
+ diagnostic->m_kind = diagnostics::kind::warning;
bool existed;
location_t &error_loc
@@ -269,7 +269,7 @@ cp_adjust_diagnostic_info (diagnostic_context *context,
/* Remember that this template had a parse-time error so
that we'll ensure a hard error has been issued upon
its instantiation. */
- error_loc = diagnostic->richloc->get_loc ();
+ error_loc = diagnostic->m_richloc->get_loc ();
}
}
@@ -298,14 +298,14 @@ cp_seen_error ()
capacities. */
void
-cxx_initialize_diagnostics (diagnostic_context *context)
+cxx_initialize_diagnostics (diagnostics::context *context)
{
cxx_pretty_printer *pp = new cxx_pretty_printer ();
pp->set_format_postprocessor (std::make_unique<cxx_format_postprocessor> ());
context->set_pretty_printer (std::unique_ptr<pretty_printer> (pp));
c_common_diagnostics_set_defaults (context);
- diagnostic_text_starter (context) = cp_diagnostic_text_starter;
+ diagnostics::text_starter (context) = cp_diagnostic_text_starter;
/* diagnostic_finalizer is already c_diagnostic_text_finalizer. */
context->set_format_decoder (cp_printer);
context->set_adjust_diagnostic_info_callback (cp_adjust_diagnostic_info);
@@ -704,6 +704,20 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags)
}
break;
+ case TREE_VEC:
+ {
+ /* A list of types used for a trait. */
+ bool need_comma = false;
+ for (tree arg : tree_vec_range (t))
+ {
+ if (need_comma)
+ pp_separate_with_comma (pp);
+ dump_type (pp, arg, flags);
+ need_comma = true;
+ }
+ }
+ break;
+
case TREE_LIST:
/* A list of function parms. */
dump_parameters (pp, t, flags);
@@ -3747,9 +3761,9 @@ eh_spec_to_string (tree p, int /*v*/)
/* Langhook for print_error_function. */
void
-cxx_print_error_function (diagnostic_text_output_format &text_output,
+cxx_print_error_function (diagnostics::text_sink &text_output,
const char *file,
- const diagnostic_info *diagnostic)
+ const diagnostics::diagnostic_info *diagnostic)
{
char *prefix;
if (file)
@@ -3763,8 +3777,8 @@ cxx_print_error_function (diagnostic_text_output_format &text_output,
}
static void
-cp_diagnostic_text_starter (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic)
+cp_diagnostic_text_starter (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic)
{
pp_set_prefix (text_output.get_printer (),
text_output.build_indent_prefix (true));
@@ -3780,8 +3794,8 @@ cp_diagnostic_text_starter (diagnostic_text_output_format &text_output,
/* Print current function onto BUFFER, in the process of reporting
a diagnostic message. Called from cp_diagnostic_starter. */
static void
-cp_print_error_function (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic)
+cp_print_error_function (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic)
{
/* If we are in an instantiation context, current_function_decl is likely
to be wrong, so just rely on print_instantiation_full_context. */
@@ -3790,7 +3804,7 @@ cp_print_error_function (diagnostic_text_output_format &text_output,
/* The above is true for constraint satisfaction also. */
if (current_failed_constraint)
return;
- diagnostic_context *const context = &text_output.get_context ();
+ diagnostics::context *const context = &text_output.get_context ();
if (diagnostic_last_function_changed (context, diagnostic))
{
pretty_printer *const pp = text_output.get_printer ();
@@ -3928,7 +3942,7 @@ function_category (tree fn)
/* Report the full context of a current template instantiation,
onto BUFFER. */
static void
-print_instantiation_full_context (diagnostic_text_output_format &text_output)
+print_instantiation_full_context (diagnostics::text_sink &text_output)
{
struct tinst_level *p = current_instantiation ();
location_t location = input_location;
@@ -3956,7 +3970,7 @@ print_instantiation_full_context (diagnostic_text_output_format &text_output)
}
static void
-print_location (diagnostic_text_output_format &text_output,
+print_location (diagnostics::text_sink &text_output,
location_t loc)
{
expanded_location xloc = expand_location (loc);
@@ -3970,7 +3984,7 @@ print_location (diagnostic_text_output_format &text_output,
}
/* A RAII class for use when emitting a line of contextual information
- via pp_verbatim to a diagnostic_text_output_format to add before/after
+ via pp_verbatim to a diagnostics::text_sink to add before/after
behaviors to the pp_verbatim calls.
If the text output has show_nesting_p (), then the ctor prints
@@ -3985,7 +3999,7 @@ print_location (diagnostic_text_output_format &text_output,
class auto_context_line
{
public:
- auto_context_line (diagnostic_text_output_format &text_output,
+ auto_context_line (diagnostics::text_sink &text_output,
location_t loc,
bool show_locus = false)
: m_text_output (text_output),
@@ -4016,7 +4030,7 @@ public:
diagnostic_show_locus (&m_text_output.get_context (),
m_text_output.get_source_printing_options (),
&rich_loc,
- DK_NOTE, pp);
+ diagnostics::kind::note, pp);
pp_set_prefix (pp, saved_prefix);
}
}
@@ -4028,12 +4042,12 @@ public:
diagnostic_show_locus (&m_text_output.get_context (),
m_text_output.get_source_printing_options (),
&rich_loc,
- DK_NOTE, pp);
+ diagnostics::kind::note, pp);
pp_set_prefix (pp, saved_prefix);
}
}
private:
- diagnostic_text_output_format &m_text_output;
+ diagnostics::text_sink &m_text_output;
location_t m_loc;
bool m_show_locus;
};
@@ -4042,7 +4056,7 @@ private:
prints a single line of instantiation context. */
static void
-print_instantiation_partial_context_line (diagnostic_text_output_format &text_output,
+print_instantiation_partial_context_line (diagnostics::text_sink &text_output,
struct tinst_level *t,
location_t loc, bool recursive_p)
{
@@ -4080,7 +4094,7 @@ print_instantiation_partial_context_line (diagnostic_text_output_format &text_ou
/* Same as print_instantiation_full_context but less verbose. */
static void
-print_instantiation_partial_context (diagnostic_text_output_format &text_output,
+print_instantiation_partial_context (diagnostics::text_sink &text_output,
struct tinst_level *t0, location_t loc)
{
struct tinst_level *t;
@@ -4151,7 +4165,7 @@ print_instantiation_partial_context (diagnostic_text_output_format &text_output,
/* Called from cp_thing to print the template context for an error. */
static void
-maybe_print_instantiation_context (diagnostic_text_output_format &text_output)
+maybe_print_instantiation_context (diagnostics::text_sink &text_output)
{
if (!problematic_instantiation_changed () || current_instantiation () == 0)
return;
@@ -4163,7 +4177,7 @@ maybe_print_instantiation_context (diagnostic_text_output_format &text_output)
/* Report what constexpr call(s) we're trying to expand, if any. */
void
-maybe_print_constexpr_context (diagnostic_text_output_format &text_output)
+maybe_print_constexpr_context (diagnostics::text_sink &text_output)
{
vec<tree> call_stack = cx_error_context ();
unsigned ix;
@@ -4183,7 +4197,7 @@ maybe_print_constexpr_context (diagnostic_text_output_format &text_output)
static void
-print_constrained_decl_info (diagnostic_text_output_format &text_output,
+print_constrained_decl_info (diagnostics::text_sink &text_output,
tree decl)
{
auto_context_line sentinel (text_output, DECL_SOURCE_LOCATION (decl));
@@ -4192,7 +4206,7 @@ print_constrained_decl_info (diagnostic_text_output_format &text_output,
}
static void
-print_concept_check_info (diagnostic_text_output_format &text_output,
+print_concept_check_info (diagnostics::text_sink &text_output,
tree expr, tree map, tree args)
{
gcc_assert (concept_check_p (expr));
@@ -4217,7 +4231,7 @@ print_concept_check_info (diagnostic_text_output_format &text_output,
context, if any. */
static tree
-print_constraint_context_head (diagnostic_text_output_format &text_output,
+print_constraint_context_head (diagnostics::text_sink &text_output,
tree cxt, tree args)
{
tree src = TREE_VALUE (cxt);
@@ -4241,7 +4255,7 @@ print_constraint_context_head (diagnostic_text_output_format &text_output,
}
static void
-print_requires_expression_info (diagnostic_text_output_format &text_output,
+print_requires_expression_info (diagnostics::text_sink &text_output,
tree constr, tree args)
{
@@ -4271,7 +4285,7 @@ print_requires_expression_info (diagnostic_text_output_format &text_output,
}
void
-maybe_print_single_constraint_context (diagnostic_text_output_format &text_output,
+maybe_print_single_constraint_context (diagnostics::text_sink &text_output,
tree failed)
{
if (!failed)
@@ -4302,7 +4316,7 @@ maybe_print_single_constraint_context (diagnostic_text_output_format &text_outpu
}
void
-maybe_print_constraint_context (diagnostic_text_output_format &text_output)
+maybe_print_constraint_context (diagnostics::text_sink &text_output)
{
if (!current_failed_constraint)
return;
@@ -4915,18 +4929,20 @@ maybe_warn_variadic_templates (void)
C++0x. */
bool
pedwarn_cxx98 (location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
bool ret;
rich_location richloc (line_table, location);
va_start (ap, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc,
- (cxx_dialect == cxx98) ? DK_PEDWARN : DK_WARNING);
- diagnostic.option_id = option_id;
+ (cxx_dialect == cxx98
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning));
+ diagnostic.m_option_id = option_id;
ret = diagnostic_report_diagnostic (global_dc, &diagnostic);
va_end (ap);
return ret;
diff --git a/gcc/cp/except.cc b/gcc/cp/except.cc
index a7f35e4..2c1ef4c 100644
--- a/gcc/cp/except.cc
+++ b/gcc/cp/except.cc
@@ -1218,6 +1218,18 @@ expr_noexcept_p (tree expr, tsubst_flags_t complain)
return true;
}
+/* Explain why EXPR is not noexcept. */
+
+void explain_not_noexcept (tree expr)
+{
+ tree fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0);
+ gcc_assert (fn);
+ if (DECL_P (fn))
+ inform (DECL_SOURCE_LOCATION (fn), "%qD is not %<noexcept%>", fn);
+ else
+ inform (location_of (fn), "%qT is not %<noexcept%>", TREE_TYPE (fn));
+}
+
/* Return true iff SPEC is throw() or noexcept(true). */
bool
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 0a389fb..09fb4f3 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -4181,7 +4181,8 @@ build_vec_delete_1 (location_t loc, tree base, tree maxindex, tree type,
"possible problem detected in invocation of "
"operator %<delete []%>"))
{
- cxx_incomplete_type_diagnostic (base, type, DK_WARNING);
+ cxx_incomplete_type_diagnostic (base, type,
+ diagnostics::kind::warning);
inform (loc, "neither the destructor nor the "
"class-specific operator %<delete []%> will be called, "
"even if they are declared when the class is defined");
@@ -5286,7 +5287,8 @@ build_delete (location_t loc, tree otype, tree addr,
"possible problem detected in invocation of "
"%<operator delete%>"))
{
- cxx_incomplete_type_diagnostic (addr, type, DK_WARNING);
+ cxx_incomplete_type_diagnostic (addr, type,
+ diagnostics::kind::warning);
inform (loc,
"neither the destructor nor the class-specific "
"%<operator delete%> will be called, even if "
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index 525e8ef..ecf55eb 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -1143,7 +1143,9 @@ maybe_add_lambda_conv_op (tree type)
tree lam = CLASSTYPE_LAMBDA_EXPR (type);
if (LAMBDA_EXPR_CAPTURE_LIST (lam) != NULL_TREE
- || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) != CPLD_NONE)
+ || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) != CPLD_NONE
+ /* CWG2561 ...and no explicit object parameter. */
+ || DECL_XOBJ_MEMBER_FUNCTION_P (callop))
return;
if (processing_template_decl)
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index a4089c5..62f8d80 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -1187,15 +1187,15 @@ early_check_defaulted_comparison (tree fn)
if (!DECL_OVERLOADED_OPERATOR_IS (fn, SPACESHIP_EXPR)
&& !same_type_p (TREE_TYPE (TREE_TYPE (fn)), boolean_type_node))
{
- diagnostic_t kind = DK_UNSPECIFIED;
+ enum diagnostics::kind kind = diagnostics::kind::unspecified;
int opt = 0;
if (is_auto (TREE_TYPE (fn)))
- kind = DK_PEDWARN;
+ kind = diagnostics::kind::pedwarn;
else
- kind = DK_ERROR;
+ kind = diagnostics::kind::error;
emit_diagnostic (kind, loc, opt,
"defaulted %qD must return %<bool%>", fn);
- if (kind == DK_ERROR)
+ if (kind == diagnostics::kind::error)
ok = false;
}
@@ -1928,8 +1928,8 @@ is_stub_object (tree expr)
/* Build a std::declval<TYPE>() expression and return it. */
-tree
-build_trait_object (tree type)
+static tree
+build_trait_object (tree type, tsubst_flags_t complain)
{
/* TYPE can't be a function with cv-/ref-qualifiers: std::declval is
defined as
@@ -1942,7 +1942,11 @@ build_trait_object (tree type)
if (FUNC_OR_METHOD_TYPE_P (type)
&& (type_memfn_quals (type) != TYPE_UNQUALIFIED
|| type_memfn_rqual (type) != REF_QUAL_NONE))
- return error_mark_node;
+ {
+ if (complain & tf_error)
+ error ("object cannot have qualified function type %qT", type);
+ return error_mark_node;
+ }
return build_stub_object (type);
}
@@ -2036,22 +2040,26 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
const_tree name = DECL_NAME (datum_decl);
if (name && (id_equal (name, "reference_wrapper")))
{
- /* 1.2 & 1.5: Retrieve T from std::reference_wrapper<T>,
+ /* 1.2 & 1.5: Retrieve T& from std::reference_wrapper<T>,
i.e., decltype(datum.get()). */
datum_type =
TREE_VEC_ELT (TYPE_TI_ARGS (non_ref_datum_type), 0);
+ datum_type = cp_build_reference_type (datum_type, false);
datum_is_refwrap = true;
}
}
}
- tree datum_expr = build_trait_object (datum_type);
+ tree datum_expr = build_trait_object (datum_type, complain);
if (!ptrmem_is_same_or_base_of_datum && !datum_is_refwrap)
/* 1.3 & 1.6: Try to dereference datum_expr. */
datum_expr = build_x_indirect_ref (UNKNOWN_LOCATION, datum_expr,
RO_UNARY_STAR, NULL_TREE, complain);
- tree fn_expr = build_trait_object (fn_type);
+ if (error_operand_p (datum_expr))
+ return error_mark_node;
+
+ tree fn_expr = build_trait_object (fn_type, complain);
ptrmem_expr = build_m_component_ref (datum_expr, fn_expr, complain);
if (error_operand_p (ptrmem_expr))
@@ -2068,7 +2076,9 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
for (int i = is_ptrmemfunc ? 1 : 0; i < TREE_VEC_LENGTH (arg_types); ++i)
{
tree arg_type = TREE_VEC_ELT (arg_types, i);
- tree arg = build_trait_object (arg_type);
+ tree arg = build_trait_object (arg_type, complain);
+ if (error_operand_p (arg))
+ return error_mark_node;
vec_safe_push (args, arg);
}
@@ -2077,8 +2087,8 @@ build_invoke (tree fn_type, const_tree arg_types, tsubst_flags_t complain)
invoke_expr = build_offset_ref_call_from_tree (ptrmem_expr, &args,
complain);
else /* 1.7. */
- invoke_expr = finish_call_expr (build_trait_object (fn_type), &args, false,
- false, complain);
+ invoke_expr = finish_call_expr (build_trait_object (fn_type, complain),
+ &args, false, false, complain);
return invoke_expr;
}
@@ -2227,12 +2237,20 @@ check_nontriv (tree *tp, int *, void *)
/* Return declval<T>() = declval<U>() treated as an unevaluated operand. */
static tree
-assignable_expr (tree to, tree from)
+assignable_expr (tree to, tree from, bool explain)
{
cp_unevaluated cp_uneval_guard;
- to = build_trait_object (to);
- from = build_trait_object (from);
- tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, tf_none);
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
+
+ to = build_trait_object (to, complain);
+ if (to == error_mark_node)
+ return error_mark_node;
+
+ from = build_trait_object (from, complain);
+ if (from == error_mark_node)
+ return error_mark_node;
+
+ tree r = cp_build_modify_expr (input_location, to, NOP_EXPR, from, complain);
return r;
}
@@ -2244,10 +2262,11 @@ assignable_expr (tree to, tree from)
Return something equivalent in well-formedness and triviality. */
static tree
-constructible_expr (tree to, tree from)
+constructible_expr (tree to, tree from, bool explain)
{
tree expr;
cp_unevaluated cp_uneval_guard;
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
const int len = TREE_VEC_LENGTH (from);
if (CLASS_TYPE_P (to))
{
@@ -2259,14 +2278,14 @@ constructible_expr (tree to, tree from)
to = cp_build_reference_type (to, /*rval*/false);
tree ob = build_stub_object (to);
if (len == 0)
- expr = build_value_init (ctype, tf_none);
+ expr = build_value_init (ctype, complain);
else
{
vec_alloc (args, len);
for (tree arg : tree_vec_range (from))
args->quick_push (build_stub_object (arg));
expr = build_special_member_call (ob, complete_ctor_identifier, &args,
- ctype, LOOKUP_NORMAL, tf_none);
+ ctype, LOOKUP_NORMAL, complain);
}
if (expr == error_mark_node)
return error_mark_node;
@@ -2276,7 +2295,7 @@ constructible_expr (tree to, tree from)
{
tree dtor = build_special_member_call (ob, complete_dtor_identifier,
NULL, ctype, LOOKUP_NORMAL,
- tf_none);
+ complain);
if (dtor == error_mark_node)
return error_mark_node;
if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (ctype))
@@ -2286,12 +2305,15 @@ constructible_expr (tree to, tree from)
else
{
if (len == 0)
- return build_value_init (strip_array_types (to), tf_none);
+ return build_value_init (strip_array_types (to), complain);
if (len > 1)
{
if (cxx_dialect < cxx20)
- /* Too many initializers. */
- return error_mark_node;
+ {
+ if (explain)
+ error ("too many initializers for non-class type %qT", to);
+ return error_mark_node;
+ }
/* In C++20 this is well-formed:
using T = int[2];
@@ -2312,9 +2334,11 @@ constructible_expr (tree to, tree from)
}
else
from = build_stub_object (TREE_VEC_ELT (from, 0));
+
+ tree orig_from = from;
expr = perform_direct_initialization_if_possible (to, from,
/*cast*/false,
- tf_none);
+ complain);
/* If t(e) didn't work, maybe t{e} will. */
if (expr == NULL_TREE
&& len == 1
@@ -2326,7 +2350,24 @@ constructible_expr (tree to, tree from)
CONSTRUCTOR_IS_PAREN_INIT (from) = true;
expr = perform_direct_initialization_if_possible (to, from,
/*cast*/false,
- tf_none);
+ complain);
+ }
+
+ if (expr == NULL_TREE && explain)
+ {
+ if (len > 1)
+ error ("too many initializers for non-class type %qT", to);
+ else
+ {
+ /* Redo the implicit conversion for diagnostics. */
+ int count = errorcount + warningcount;
+ perform_implicit_conversion_flags (to, orig_from, complain,
+ LOOKUP_NORMAL);
+ if (count == errorcount + warningcount)
+ /* The message may have been suppressed due to -w + -fpermissive,
+ emit a generic response instead. */
+ error ("the conversion is invalid");
+ }
}
}
return expr;
@@ -2340,20 +2381,25 @@ constructible_expr (tree to, tree from)
valid or error_mark_node if not. */
static tree
-destructible_expr (tree to)
+destructible_expr (tree to, bool explain)
{
cp_unevaluated cp_uneval_guard;
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
if (TYPE_REF_P (to))
return void_node;
if (!COMPLETE_TYPE_P (complete_type (to)))
- return error_mark_node;
+ {
+ if (explain)
+ error_at (location_of (to), "%qT is incomplete", to);
+ return error_mark_node;
+ }
to = strip_array_types (to);
if (CLASS_TYPE_P (to))
{
- to = build_trait_object (to);
+ to = build_trait_object (to, complain);
return build_delete (input_location, TREE_TYPE (to), to,
- sfk_complete_destructor, flags, 0, tf_none);
+ sfk_complete_destructor, flags, 0, complain);
}
/* [expr.prim.id.dtor] If the id-expression names a pseudo-destructor, T
shall be a scalar type.... */
@@ -2365,70 +2411,109 @@ destructible_expr (tree to)
/* Returns a tree iff TO is assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN is
+ set, emit a diagnostic explaining why the operation failed. */
static tree
-is_xible_helper (enum tree_code code, tree to, tree from, bool trivial)
+is_xible_helper (enum tree_code code, tree to, tree from, bool explain)
{
to = complete_type (to);
deferring_access_check_sentinel acs (dk_no_deferred);
- if (VOID_TYPE_P (to)
- || (from && FUNC_OR_METHOD_TYPE_P (from)
- && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from))))
- return error_mark_node;
+
+ if (VOID_TYPE_P (to))
+ {
+ if (explain)
+ error_at (location_of (to), "%qT is incomplete", to);
+ return error_mark_node;
+ }
+ if (from
+ && FUNC_OR_METHOD_TYPE_P (from)
+ && (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from)))
+ {
+ if (explain)
+ error ("%qT is a qualified function type", from);
+ return error_mark_node;
+ }
+
tree expr;
if (code == MODIFY_EXPR)
- expr = assignable_expr (to, from);
+ expr = assignable_expr (to, from, explain);
else if (code == BIT_NOT_EXPR)
- expr = destructible_expr (to);
- else if (trivial && TREE_VEC_LENGTH (from) > 1
- && cxx_dialect < cxx20)
- return error_mark_node; // only 0- and 1-argument ctors can be trivial
- // before C++20 aggregate paren init
+ expr = destructible_expr (to, explain);
else if (TREE_CODE (to) == ARRAY_TYPE && !TYPE_DOMAIN (to))
- return error_mark_node; // can't construct an array of unknown bound
+ {
+ if (explain)
+ error ("cannot construct an array of unknown bound");
+ return error_mark_node;
+ }
else
- expr = constructible_expr (to, from);
+ expr = constructible_expr (to, from, explain);
return expr;
}
/* Returns true iff TO is trivially assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN, diagnose
+ why we returned false. */
bool
-is_trivially_xible (enum tree_code code, tree to, tree from)
+is_trivially_xible (enum tree_code code, tree to, tree from,
+ bool explain/*=false*/)
{
- tree expr = is_xible_helper (code, to, from, /*trivial*/true);
+ /* In some cases, when producing errors is_xible_helper may not return
+ error_mark_node, so check if it looks like we've already emitted any
+ diagnostics to ensure we don't do so multiple times. */
+ int errs = errorcount + sorrycount;
+
+ tree expr = is_xible_helper (code, to, from, explain);
if (expr == NULL_TREE || expr == error_mark_node)
return false;
+
tree nt = cp_walk_tree_without_duplicates (&expr, check_nontriv, NULL);
+ if (explain && errs == (errorcount + sorrycount))
+ {
+ gcc_assert (nt);
+ inform (location_of (nt), "%qE is non-trivial", nt);
+ }
return !nt;
}
/* Returns true iff TO is nothrow assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN, diagnose
+ why we returned false. */
bool
-is_nothrow_xible (enum tree_code code, tree to, tree from)
+is_nothrow_xible (enum tree_code code, tree to, tree from,
+ bool explain/*=false*/)
{
+ /* As with is_trivially_xible. */
+ int errs = errorcount + sorrycount;
+
++cp_noexcept_operand;
- tree expr = is_xible_helper (code, to, from, /*trivial*/false);
+ tree expr = is_xible_helper (code, to, from, explain);
--cp_noexcept_operand;
if (expr == NULL_TREE || expr == error_mark_node)
return false;
- return expr_noexcept_p (expr, tf_none);
+
+ bool is_noexcept = expr_noexcept_p (expr, tf_none);
+ if (explain && errs == (errorcount + sorrycount))
+ {
+ gcc_assert (!is_noexcept);
+ explain_not_noexcept (expr);
+ }
+ return is_noexcept;
}
/* Returns true iff TO is assignable (if CODE is MODIFY_EXPR) or
constructible (otherwise) from FROM, which is a single type for
- assignment or a list of types for construction. */
+ assignment or a list of types for construction. If EXPLAIN, diagnose
+ why we returned false. */
bool
-is_xible (enum tree_code code, tree to, tree from)
+is_xible (enum tree_code code, tree to, tree from, bool explain/*=false*/)
{
- tree expr = is_xible_helper (code, to, from, /*trivial*/false);
+ tree expr = is_xible_helper (code, to, from, explain);
if (expr == error_mark_node)
return false;
return !!expr;
@@ -2453,7 +2538,7 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p)
return false;
/* We don't check is_constructible<T, U>: if T isn't constructible
from U, we won't be able to create a conversion. */
- tree val = build_trait_object (from);
+ tree val = build_trait_object (from, tf_none);
if (val == error_mark_node)
return false;
if (!TYPE_REF_P (from) && TREE_CODE (from) != FUNCTION_TYPE)
@@ -2462,25 +2547,36 @@ ref_xes_from_temporary (tree to, tree from, bool direct_init_p)
}
/* Worker for is_{,nothrow_}convertible. Attempt to perform an implicit
- conversion from FROM to TO and return the result. */
+ conversion from FROM to TO and return the result. If EXPLAIN, emit a
+ diagnostic about why the conversion failed. */
static tree
-is_convertible_helper (tree from, tree to)
+is_convertible_helper (tree from, tree to, bool explain)
{
if (VOID_TYPE_P (from) && VOID_TYPE_P (to))
return integer_one_node;
cp_unevaluated u;
- tree expr = build_trait_object (from);
+ tsubst_flags_t complain = explain ? tf_error : tf_none;
+
/* std::is_{,nothrow_}convertible test whether the imaginary function
definition
To test() { return std::declval<From>(); }
is well-formed. A function can't return a function. */
- if (FUNC_OR_METHOD_TYPE_P (to) || expr == error_mark_node)
+ if (FUNC_OR_METHOD_TYPE_P (to))
+ {
+ if (explain)
+ error ("%qT is a function type", to);
+ return error_mark_node;
+ }
+
+ tree expr = build_trait_object (from, complain);
+ if (expr == error_mark_node)
return error_mark_node;
+
deferring_access_check_sentinel acs (dk_no_deferred);
- return perform_implicit_conversion (to, expr, tf_none);
+ return perform_implicit_conversion (to, expr, complain);
}
/* Return true if FROM can be converted to TO using implicit conversions,
@@ -2489,9 +2585,9 @@ is_convertible_helper (tree from, tree to)
to either type" restriction. */
bool
-is_convertible (tree from, tree to)
+is_convertible (tree from, tree to, bool explain/*=false*/)
{
- tree expr = is_convertible_helper (from, to);
+ tree expr = is_convertible_helper (from, to, explain);
if (expr == error_mark_node)
return false;
return !!expr;
@@ -2500,12 +2596,18 @@ is_convertible (tree from, tree to)
/* Like is_convertible, but the conversion is also noexcept. */
bool
-is_nothrow_convertible (tree from, tree to)
+is_nothrow_convertible (tree from, tree to, bool explain/*=false*/)
{
- tree expr = is_convertible_helper (from, to);
+ tree expr = is_convertible_helper (from, to, explain);
if (expr == NULL_TREE || expr == error_mark_node)
return false;
- return expr_noexcept_p (expr, tf_none);
+ bool is_noexcept = expr_noexcept_p (expr, tf_none);
+ if (explain)
+ {
+ gcc_assert (!is_noexcept);
+ explain_not_noexcept (expr);
+ }
+ return is_noexcept;
}
/* Categorize various special_function_kinds. */
@@ -3586,21 +3688,24 @@ maybe_delete_defaulted_fn (tree fn, tree implicit_fn)
the program is ill-formed" */
|| !TYPE_REF_P (parmtype)));
/* Decide if we want to emit a pedwarn, error, or a warning. */
- diagnostic_t diag_kind;
+ enum diagnostics::kind diag_kind;
int opt;
if (illformed_p)
{
- diag_kind = DK_ERROR;
+ diag_kind = diagnostics::kind::error;
opt = 0;
}
else
{
- diag_kind = cxx_dialect >= cxx20 ? DK_WARNING : DK_PEDWARN;
+ diag_kind = (cxx_dialect >= cxx20
+ ? diagnostics::kind::warning
+ : diagnostics::kind::pedwarn);
opt = OPT_Wdefaulted_function_deleted;
}
/* Don't warn for template instantiations. */
- if (DECL_TEMPLATE_INSTANTIATION (fn) && diag_kind == DK_WARNING)
+ if (DECL_TEMPLATE_INSTANTIATION (fn)
+ && diag_kind == diagnostics::kind::warning)
return;
const char *wmsg;
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index e3c1a68..2f6a8ab 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -3883,9 +3883,9 @@ class GTY((chain_next ("%h.parent"), for_user)) module_state {
void write_macro_maps (elf_out *to, range_t &, unsigned *crc_ptr);
bool read_macro_maps (line_map_uint_t);
- void write_diagnostic_classification (elf_out *, diagnostic_context *,
+ void write_diagnostic_classification (elf_out *, diagnostics::context *,
unsigned *);
- bool read_diagnostic_classification (diagnostic_context *);
+ bool read_diagnostic_classification (diagnostics::context *);
private:
void write_define (bytes_out &, const cpp_macro *);
@@ -4822,7 +4822,8 @@ noisy_p ()
return false;
pp_needs_newline (global_dc->get_reference_printer ()) = true;
- diagnostic_set_last_function (global_dc, (diagnostic_info *) NULL);
+ diagnostic_set_last_function (global_dc,
+ (diagnostics::diagnostic_info *) nullptr);
return true;
}
@@ -6157,7 +6158,7 @@ trees_out::lang_type_bools (tree t, bits_out& bits)
WB (lang->declared_class);
WB (lang->diamond_shaped);
WB (lang->repeated_base);
- gcc_assert (!lang->being_defined);
+ gcc_checking_assert (!lang->being_defined);
// lang->debug_requested
WB (lang->fields_readonly);
WB (lang->ptrmemfunc_flag);
@@ -6183,6 +6184,14 @@ trees_out::lang_type_bools (tree t, bits_out& bits)
WB (lang->has_constexpr_ctor);
WB (lang->unique_obj_representations);
WB (lang->unique_obj_representations_set);
+ gcc_checking_assert (!lang->erroneous);
+ WB (lang->non_pod_aggregate);
+ WB (lang->non_aggregate_pod);
+ WB (lang->trivially_relocatable);
+ WB (lang->trivially_relocatable_computed);
+
+ WB (lang->replaceable);
+ WB (lang->replaceable_computed);
#undef WB
}
@@ -6227,8 +6236,8 @@ trees_in::lang_type_bools (tree t, bits_in& bits)
RB (lang->declared_class);
RB (lang->diamond_shaped);
RB (lang->repeated_base);
- gcc_assert (!lang->being_defined);
- gcc_assert (!lang->debug_requested);
+ gcc_checking_assert (!lang->being_defined);
+ gcc_checking_assert (!lang->debug_requested);
RB (lang->fields_readonly);
RB (lang->ptrmemfunc_flag);
@@ -6253,6 +6262,14 @@ trees_in::lang_type_bools (tree t, bits_in& bits)
RB (lang->has_constexpr_ctor);
RB (lang->unique_obj_representations);
RB (lang->unique_obj_representations_set);
+ gcc_checking_assert (!lang->erroneous);
+ RB (lang->non_pod_aggregate);
+ RB (lang->non_aggregate_pod);
+ RB (lang->trivially_relocatable);
+ RB (lang->trivially_relocatable_computed);
+
+ RB (lang->replaceable);
+ RB (lang->replaceable_computed);
#undef RB
return !get_overrun ();
}
@@ -6785,6 +6802,13 @@ trees_out::core_vals (tree t)
if (streaming_p ())
WU (((lang_tree_node *)t)->trait_expression.kind);
break;
+
+ case TU_LOCAL_ENTITY:
+ WT (((lang_tree_node *)t)->tu_local_entity.name);
+ if (state)
+ state->write_location
+ (*this, ((lang_tree_node *)t)->tu_local_entity.loc);
+ break;
}
if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
@@ -7328,6 +7352,11 @@ trees_in::core_vals (tree t)
RT (((lang_tree_node *)t)->trait_expression.type2);
RUC (cp_trait_kind, ((lang_tree_node *)t)->trait_expression.kind);
break;
+
+ case TU_LOCAL_ENTITY:
+ RT (((lang_tree_node *)t)->tu_local_entity.name);
+ ((lang_tree_node *)t)->tu_local_entity.loc
+ = state->read_location (*this);
}
if (CODE_CONTAINS_STRUCT (code, TS_TYPED))
@@ -10268,7 +10297,8 @@ trees_in::tree_node (bool is_use)
&& dump ("Read %stypedef %C:%N",
DECL_IMPLICIT_TYPEDEF_P (res) ? "implicit " : "",
TREE_CODE (res), res);
- res = TREE_TYPE (res);
+ if (TREE_CODE (res) != TU_LOCAL_ENTITY)
+ res = TREE_TYPE (res);
}
break;
@@ -18325,22 +18355,23 @@ module_state::write_ordinary_maps (elf_out *to, range_t &info,
/* Return the prefix to use for dumping a #pragma diagnostic change to DK. */
static const char *
-dk_string (diagnostic_t dk)
+dk_string (enum diagnostics::kind dk)
{
- gcc_assert (dk > DK_UNSPECIFIED && dk < DK_LAST_DIAGNOSTIC_KIND);
- if (dk == DK_IGNORED)
- /* diagnostic.def has an empty string for ignored. */
+ gcc_assert (dk > diagnostics::kind::unspecified
+ && dk < diagnostics::kind::last_diagnostic_kind);
+ if (dk == diagnostics::kind::ignored)
+ /* diagnostics/kinds.def has an empty string for ignored. */
return "ignored: ";
else
- return get_diagnostic_kind_text (dk);
+ return diagnostics::get_text_for_kind (dk);
}
/* Dump one #pragma GCC diagnostic entry. */
static bool
-dump_dc_change (unsigned index, unsigned opt, diagnostic_t dk)
+dump_dc_change (unsigned index, unsigned opt, enum diagnostics::kind dk)
{
- if (dk == DK_POP)
+ if (dk == diagnostics::kind::pop)
return dump (" Index %u: pop from %d", index, opt);
else
return dump (" Index %u: %s%s", index, dk_string (dk),
@@ -18351,7 +18382,7 @@ dump_dc_change (unsigned index, unsigned opt, diagnostic_t dk)
void
module_state::write_diagnostic_classification (elf_out *to,
- diagnostic_context *dc,
+ diagnostics::context *dc,
unsigned *crc_p)
{
auto &changes = dc->get_classification_history ();
@@ -18367,9 +18398,10 @@ module_state::write_diagnostic_classification (elf_out *to,
unsigned len = changes.length ();
/* We don't want to write out any entries that came from one of our imports.
- But then we need to adjust the total, and change DK_POP targets to match
- the index in our actual output. So remember how many lines we had skipped
- at each step, where -1 means this line itself is skipped. */
+ But then we need to adjust the total, and change diagnostics::kind::pop
+ targets to match the index in our actual output. So remember how many
+ lines we had skipped at each step, where -1 means this line itself
+ is skipped. */
int skips = 0;
auto_vec<int> skips_at (len);
skips_at.safe_grow (len);
@@ -18402,10 +18434,10 @@ module_state::write_diagnostic_classification (elf_out *to,
if (sec.streaming_p ())
{
unsigned opt = c.option;
- if (c.kind == DK_POP)
+ if (c.kind == diagnostics::kind::pop)
opt -= skips_at[opt];
sec.u (opt);
- sec.u (c.kind);
+ sec.u (static_cast<unsigned> (c.kind));
dump () && dump_dc_change (i - skips_at[i], opt, c.kind);
}
}
@@ -18420,7 +18452,7 @@ module_state::write_diagnostic_classification (elf_out *to,
/* Read any #pragma GCC diagnostic info from the .dgc section. */
bool
-module_state::read_diagnostic_classification (diagnostic_context *dc)
+module_state::read_diagnostic_classification (diagnostics::context *dc)
{
bytes_in sec;
@@ -18440,8 +18472,8 @@ module_state::read_diagnostic_classification (diagnostic_context *dc)
{
location_t loc = read_location (sec);
int opt = sec.u ();
- diagnostic_t kind = (diagnostic_t) sec.u ();
- if (kind == DK_POP)
+ enum diagnostics::kind kind = (enum diagnostics::kind) sec.u ();
+ if (kind == diagnostics::kind::pop)
/* For a pop, opt is the 'changes' index to return to. */
opt += offset;
changes.quick_push ({ loc, opt, kind });
@@ -18456,7 +18488,7 @@ module_state::read_diagnostic_classification (diagnostic_context *dc)
gcc_checking_assert (i >= offset);
const auto &c = changes[i];
- if (c.kind != DK_POP)
+ if (c.kind != diagnostics::kind::pop)
break;
else if (c.option == offset)
{
@@ -18473,7 +18505,7 @@ module_state::read_diagnostic_classification (diagnostic_context *dc)
/* It didn't, so add a pop at its last location to avoid affecting later
imports. */
location_t last_loc = ordinary_locs.first + ordinary_locs.second - 1;
- changes.quick_push ({ last_loc, offset, DK_POP });
+ changes.quick_push ({ last_loc, offset, diagnostics::kind::pop });
dump () && dump (" Adding final pop from index %d", offset);
}
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index 9aa7c16..f5b36c9 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -7195,7 +7195,7 @@ suggest_alternatives_for_1 (location_t location, tree name,
/* Look for exact matches for builtin defines that would have been
defined if the user had passed a command-line option (e.g. -fopenmp
for "_OPENMP"). */
- diagnostic_option_id option_id
+ diagnostics::option_id option_id
= get_option_for_builtin_define (IDENTIFIER_POINTER (name));
if (option_id.m_idx > 0)
return name_hint
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 0d9ed2e..9e9cd9b 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -5266,7 +5266,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
&& (id_equal (suffix_id, "i")
|| id_equal (suffix_id, "if")
|| id_equal (suffix_id, "il")));
- diagnostic_t kind = DK_ERROR;
+ enum diagnostics::kind kind = diagnostics::kind::error;
int opt = 0;
if (i14 && ext)
@@ -5276,7 +5276,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
if (cxlit == error_mark_node)
{
/* No <complex>, so pedwarn and use GNU semantics. */
- kind = DK_PEDWARN;
+ kind = diagnostics::kind::pedwarn;
opt = OPT_Wpedantic;
}
}
@@ -5303,7 +5303,7 @@ cp_parser_userdef_numeric_literal (cp_parser *parser)
"to enable more built-in suffixes");
}
- if (kind == DK_ERROR)
+ if (kind == diagnostics::kind::error)
value = error_mark_node;
else
{
@@ -6647,7 +6647,8 @@ cp_parser_primary_expression (cp_parser *parser,
member template. */
static void
-missing_template_diag (location_t loc, diagnostic_t diag_kind = DK_WARNING)
+missing_template_diag (location_t loc,
+ enum diagnostics::kind diag_kind = diagnostics::kind::warning)
{
if (warning_suppressed_at (loc, OPT_Wmissing_template_keyword))
return;
@@ -8854,8 +8855,10 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression,
{
/* In a template, be permissive by treating an object expression
of incomplete type as dependent (after a pedwarn). */
- diagnostic_t kind = (processing_template_decl
- && MAYBE_CLASS_TYPE_P (*scope) ? DK_PEDWARN : DK_ERROR);
+ enum diagnostics::kind kind = ((processing_template_decl
+ && MAYBE_CLASS_TYPE_P (*scope))
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::error);
switch (TREE_CODE (*postfix_expression))
{
@@ -8867,27 +8870,27 @@ cp_parser_dot_deref_incomplete (tree *scope, cp_expr *postfix_expression,
case IMPLICIT_CONV_EXPR:
case VIEW_CONVERT_EXPR:
case NON_LVALUE_EXPR:
- kind = DK_ERROR;
+ kind = diagnostics::kind::error;
break;
case OVERLOAD:
/* Don't emit any diagnostic for OVERLOADs. */
- kind = DK_IGNORED;
+ kind = diagnostics::kind::ignored;
break;
default:
/* Avoid clobbering e.g. DECLs. */
if (!EXPR_P (*postfix_expression))
- kind = DK_ERROR;
+ kind = diagnostics::kind::error;
break;
}
- if (kind == DK_IGNORED)
+ if (kind == diagnostics::kind::ignored)
return false;
location_t exploc = location_of (*postfix_expression);
cxx_incomplete_type_diagnostic (exploc, *postfix_expression, *scope, kind);
if (!MAYBE_CLASS_TYPE_P (*scope))
return true;
- if (kind == DK_ERROR)
+ if (kind == diagnostics::kind::error)
*scope = *postfix_expression = error_mark_node;
else if (processing_template_decl)
{
@@ -9510,7 +9513,7 @@ cp_parser_unary_expression (cp_parser *parser, cp_id_kind * pidk,
diagnostic_push_diagnostics (global_dc, input_location);
diagnostic_classify_diagnostic
(global_dc, OPT_Wconditionally_supported,
- DK_IGNORED, input_location);
+ diagnostics::kind::ignored, input_location);
/* Parse the cast-expression. */
expr = cp_parser_simple_cast_expression (parser);
/* Restore the PEDANTIC flag. */
@@ -33706,7 +33709,9 @@ cp_parser_constructor_declarator_p (cp_parser *parser, cp_parser_flags flags,
&& cp_lexer_peek_token (parser->lexer)->type == CPP_TEMPLATE_ID)
{
auto_diagnostic_group d;
- if (emit_diagnostic (cxx_dialect >= cxx20 ? DK_PEDWARN : DK_WARNING,
+ if (emit_diagnostic ((cxx_dialect >= cxx20
+ ? diagnostics::kind::pedwarn
+ : diagnostics::kind::warning),
input_location, OPT_Wtemplate_id_cdtor,
"template-id not allowed for constructor in C++20"))
inform (input_location, "remove the %qs", "< >");
@@ -53048,11 +53053,14 @@ cp_parser_omp_error (cp_parser *parser, cp_token *pragma_tok,
if (msg == NULL)
msg = _("<message unknown at compile time>");
}
+ const enum diagnostics::kind diag_kind = (severity_fatal
+ ? diagnostics::kind::error
+ : diagnostics::kind::warning);
if (msg)
- emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+ emit_diagnostic (diag_kind, loc, 0,
"%<pragma omp error%> encountered: %s", msg);
else
- emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+ emit_diagnostic (diag_kind, loc, 0,
"%<pragma omp error%> encountered");
return false;
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index d63fa68..71ae764 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -14916,6 +14916,9 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
argvec = NULL_TREE;
}
+ /* Make sure tsubst_decl substitutes all the parameters. */
+ cp_evaluated ev;
+
tree closure = (lambda_fntype ? TYPE_METHOD_BASETYPE (lambda_fntype)
: NULL_TREE);
tree ctx = closure ? closure : DECL_CONTEXT (t);
@@ -20494,11 +20497,6 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
r = error_mark_node;
else
{
- /* The body of a lambda-expression is not a subexpression of the
- enclosing expression. Parms are to have DECL_CHAIN tsubsted,
- which would be skipped if cp_unevaluated_operand. */
- cp_evaluated ev;
-
/* Fix the type of 'this'.
For static and xobj member functions we use this to transport the
lambda's closure type. It appears that in the regular case the
@@ -20524,6 +20522,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
/* Let finish_function set this. */
DECL_DECLARED_CONSTEXPR_P (fn) = false;
+ /* The body of a lambda-expression is not a subexpression of the
+ enclosing expression. */
+ cp_evaluated ev;
+
bool nested = cfun;
if (nested)
push_function_context ();
@@ -31214,14 +31216,8 @@ alias_ctad_tweaks (tree tmpl, tree uguides)
/* Substitute the deduced arguments plus the rewritten template
parameters into f to get g. This covers the type, copyness,
guideness, and explicit-specifier. */
- tree g;
- {
- /* Parms are to have DECL_CHAIN tsubsted, which would be skipped
- if cp_unevaluated_operand. */
- cp_evaluated ev;
- g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain,
+ tree g = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs, complain,
/*use_spec_table=*/false);
- }
if (g == error_mark_node)
continue;
DECL_NAME (g) = name;
@@ -31651,7 +31647,9 @@ do_class_deduction (tree ptype, tree tmpl, tree init, tree outer_targs,
/* Be permissive with equivalent alias templates. */
tree u = get_underlying_template (tmpl);
auto_diagnostic_group d;
- diagnostic_t dk = (u == tmpl) ? DK_ERROR : DK_PEDWARN;
+ const enum diagnostics::kind dk = ((u == tmpl)
+ ? diagnostics::kind::error
+ : diagnostics::kind::pedwarn);
bool complained
= emit_diagnostic (dk, input_location, 0,
"alias template deduction only available "
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 86b0904..52ecac4 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -2338,7 +2338,8 @@ finish_asm_stmt (location_t loc, int volatile_p, tree string,
oconstraints[i] = constraint;
if (parse_output_constraint (&constraint, i, ninputs, noutputs,
- &allows_mem, &allows_reg, &is_inout))
+ &allows_mem, &allows_reg, &is_inout,
+ nullptr))
{
/* If the operand is going to end up in memory,
mark it addressable. */
@@ -2397,7 +2398,8 @@ finish_asm_stmt (location_t loc, int volatile_p, tree string,
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
bool constraint_parsed
= parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
- oconstraints, &allows_mem, &allows_reg);
+ oconstraints, &allows_mem, &allows_reg,
+ nullptr);
/* If the operand is going to end up in memory, don't call
decay_conversion. */
if (constraint_parsed && !allows_reg && allows_mem)
@@ -13689,7 +13691,8 @@ check_trait_type (tree type, int kind = 1)
type = complete_type (strip_array_types (type));
if (!COMPLETE_TYPE_P (type)
- && cxx_incomplete_type_diagnostic (NULL_TREE, type, DK_PERMERROR)
+ && cxx_incomplete_type_diagnostic (NULL_TREE, type,
+ diagnostics::kind::permerror)
&& !flag_permissive)
return false;
return true;
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index a7b8908..d56d73f 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3696,6 +3696,58 @@ build_min_non_dep_op_overload (enum tree_code op,
int nargs, expected_nargs;
tree fn, call, obj = NULL_TREE;
+ releasing_vec args;
+ va_start (p, overload);
+
+ bool negated = false, rewritten = false, reversed = false;
+ if (cxx_dialect >= cxx20 && TREE_CODE (overload) == TREE_LIST)
+ {
+ /* Handle rebuilding a C++20 rewritten comparison operator expression,
+ e.g. !(x == y), y <=> x, (x <=> y) @ 0 etc, that resolved to a call
+ to a user-defined operator<=>/==. */
+ gcc_checking_assert (TREE_CODE_CLASS (op) == tcc_comparison
+ || op == SPACESHIP_EXPR);
+ int flags = TREE_INT_CST_LOW (TREE_PURPOSE (overload));
+ if (TREE_CODE (non_dep) == TRUTH_NOT_EXPR)
+ {
+ negated = true;
+ non_dep = TREE_OPERAND (non_dep, 0);
+ }
+ if (flags & LOOKUP_REWRITTEN)
+ rewritten = true;
+ if (flags & LOOKUP_REVERSED)
+ reversed = true;
+ if (rewritten
+ && DECL_OVERLOADED_OPERATOR_IS (TREE_VALUE (overload),
+ SPACESHIP_EXPR))
+ {
+ /* Handle (x <=> y) @ 0 and 0 @ (y <=> x) by recursing to first
+ rebuild the <=>. Note that both OVERLOAD and the provided arguments
+ in this case already correspond to the selected operator<=>. */
+
+ tree spaceship_non_dep = CALL_EXPR_ARG (non_dep, reversed ? 1 : 0);
+ gcc_checking_assert (TREE_CODE (spaceship_non_dep) == CALL_EXPR);
+ tree spaceship_op0 = va_arg (p, tree);
+ tree spaceship_op1 = va_arg (p, tree);
+ if (reversed)
+ std::swap (spaceship_op0, spaceship_op1);
+
+ /* Push the correct arguments for the operator OP expression, and
+ set OVERLOAD appropriately. */
+ tree op0 = build_min_non_dep_op_overload (SPACESHIP_EXPR,
+ spaceship_non_dep,
+ TREE_VALUE (overload),
+ spaceship_op0,
+ spaceship_op1);
+ tree op1 = CALL_EXPR_ARG (non_dep, reversed ? 0 : 1);
+ gcc_checking_assert (integer_zerop (op1));
+ vec_safe_push (args, op0);
+ vec_safe_push (args, op1);
+ overload = CALL_EXPR_FN (non_dep);
+ }
+ else
+ overload = TREE_VALUE (overload);
+ }
non_dep = extract_call_expr (non_dep);
nargs = call_expr_nargs (non_dep);
@@ -3716,32 +3768,40 @@ build_min_non_dep_op_overload (enum tree_code op,
expected_nargs += 1;
gcc_assert (nargs == expected_nargs);
- releasing_vec args;
- va_start (p, overload);
-
if (!DECL_OBJECT_MEMBER_FUNCTION_P (overload))
{
fn = overload;
- if (op == ARRAY_REF)
- obj = va_arg (p, tree);
- for (int i = 0; i < nargs; i++)
+ if (vec_safe_length (args) != 0)
+ /* The correct arguments were already pushed above. */
+ gcc_checking_assert (rewritten);
+ else
{
- tree arg = va_arg (p, tree);
- vec_safe_push (args, arg);
+ if (op == ARRAY_REF)
+ obj = va_arg (p, tree);
+ for (int i = 0; i < nargs; i++)
+ {
+ tree arg = va_arg (p, tree);
+ vec_safe_push (args, arg);
+ }
}
+ if (reversed)
+ std::swap ((*args)[0], (*args)[1]);
}
else
{
+ gcc_checking_assert (vec_safe_length (args) == 0);
tree object = va_arg (p, tree);
- tree binfo = TYPE_BINFO (TREE_TYPE (object));
- tree method = build_baselink (binfo, binfo, overload, NULL_TREE);
- fn = build_min (COMPONENT_REF, TREE_TYPE (overload),
- object, method, NULL_TREE);
for (int i = 0; i < nargs; i++)
{
tree arg = va_arg (p, tree);
vec_safe_push (args, arg);
}
+ if (reversed)
+ std::swap (object, (*args)[0]);
+ tree binfo = TYPE_BINFO (TREE_TYPE (object));
+ tree method = build_baselink (binfo, binfo, overload, NULL_TREE);
+ fn = build_min (COMPONENT_REF, TREE_TYPE (overload),
+ object, method, NULL_TREE);
}
va_end (p);
@@ -3753,6 +3813,8 @@ build_min_non_dep_op_overload (enum tree_code op,
CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (non_dep);
CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (non_dep);
+ if (negated)
+ call = build_min (TRUTH_NOT_EXPR, boolean_type_node, call);
if (obj)
return keep_unused_object_arg (call, obj, overload);
return call;
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index a604511..f592894 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -155,7 +155,7 @@ complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain)
else if (!COMPLETE_TYPE_P (type))
{
if (complain & tf_error)
- cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+ cxx_incomplete_type_diagnostic (value, type, diagnostics::kind::error);
note_failed_type_completion (type, complain);
return NULL_TREE;
}
@@ -618,7 +618,7 @@ type_after_usual_arithmetic_conversions (tree t1, tree t2)
static void
composite_pointer_error (const op_location_t &location,
- diagnostic_t kind, tree t1, tree t2,
+ enum diagnostics::kind kind, tree t1, tree t2,
composite_pointer_operation operation)
{
switch (operation)
@@ -690,7 +690,7 @@ composite_pointer_type_r (const op_location_t &location,
else
{
if (complain & tf_error)
- composite_pointer_error (location, DK_PERMERROR,
+ composite_pointer_error (location, diagnostics::kind::permerror,
t1, t2, operation);
else
return error_mark_node;
@@ -716,7 +716,7 @@ composite_pointer_type_r (const op_location_t &location,
TYPE_PTRMEM_CLASS_TYPE (t2)))
{
if (complain & tf_error)
- composite_pointer_error (location, DK_PERMERROR,
+ composite_pointer_error (location, diagnostics::kind::permerror,
t1, t2, operation);
else
return error_mark_node;
@@ -851,7 +851,8 @@ composite_pointer_type (const op_location_t &location,
else
{
if (complain & tf_error)
- composite_pointer_error (location, DK_ERROR, t1, t2, operation);
+ composite_pointer_error (location, diagnostics::kind::error,
+ t1, t2, operation);
return error_mark_node;
}
}
@@ -4530,7 +4531,11 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
{
if (complain & tf_error)
{
- if (!flag_diagnostics_show_caret)
+ if (is_stub_object (original))
+ error_at (input_location,
+ "%qT cannot be used as a function",
+ TREE_TYPE (original));
+ else if (!flag_diagnostics_show_caret)
error_at (input_location,
"%qE cannot be used as a function", original);
else if (DECL_P (original))
@@ -4672,12 +4677,8 @@ convert_arguments (tree typelist, vec<tree, va_gc> **values, tree fndecl,
if (type == void_type_node)
{
if (complain & tf_error)
- {
- error_args_num (input_location, fndecl, /*too_many_p=*/true);
- return i;
- }
- else
- return -1;
+ error_args_num (input_location, fndecl, /*too_many_p=*/true);
+ return -1;
}
/* build_c_cast puts on a NOP_EXPR to make the result not an lvalue.
@@ -10805,7 +10806,9 @@ maybe_warn_about_returning_address_of_local (tree retval, location_t loc)
{
if (TYPE_REF_P (valtype))
/* P2748 made this an error in C++26. */
- emit_diagnostic (cxx_dialect >= cxx26 ? DK_PERMERROR : DK_WARNING,
+ emit_diagnostic ((cxx_dialect >= cxx26
+ ? diagnostics::kind::permerror
+ : diagnostics::kind::warning),
loc, OPT_Wreturn_local_addr,
"returning reference to temporary");
else if (TYPE_PTR_P (valtype))
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 45edd18..faaf1df 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -119,6 +119,11 @@ cxx_readonly_error (location_t loc, tree arg, enum lvalue_use errstring)
G_("increment of read-only reference %qD"),
G_("decrement of read-only reference %qD"),
TREE_OPERAND (arg, 0));
+ else if (is_stub_object (arg))
+ {
+ gcc_assert (errstring == lv_assign);
+ error_at (loc, "assignment to read-only type %qT", TREE_TYPE (arg));
+ }
else
readonly_error (loc, arg, errstring);
}
@@ -290,11 +295,12 @@ cxx_incomplete_type_inform (const_tree type)
/* Print an error message for invalid use of an incomplete type.
VALUE is the expression that was used (or 0 if that isn't known)
and TYPE is the type that was invalid. DIAG_KIND indicates the
- type of diagnostic (see diagnostic.def). */
+ type of diagnostic (see diagnostics/kinds.def). */
bool
cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
- const_tree type, diagnostic_t diag_kind)
+ const_tree type,
+ enum diagnostics::kind diag_kind)
{
bool is_decl = false, complained = false;
@@ -440,7 +446,7 @@ cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
void
cxx_incomplete_type_error (location_t loc, const_tree value, const_tree type)
{
- cxx_incomplete_type_diagnostic (loc, value, type, DK_ERROR);
+ cxx_incomplete_type_diagnostic (loc, value, type, diagnostics::kind::error);
}
@@ -2627,7 +2633,7 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain)
bool ok;
tree core = spec;
bool is_ptr;
- diagnostic_t diag_type = DK_UNSPECIFIED; /* none */
+ enum diagnostics::kind diag_type = diagnostics::kind::unspecified; /* none */
if (spec == error_mark_node)
return list;
@@ -2659,7 +2665,7 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain)
and calls. So just give a pedwarn at this point; we will give an
error later if we hit one of those two cases. */
if (!COMPLETE_TYPE_P (complete_type (core)))
- diag_type = DK_PEDWARN; /* pedwarn */
+ diag_type = diagnostics::kind::pedwarn; /* pedwarn */
}
if (ok)
@@ -2673,9 +2679,9 @@ add_exception_specifier (tree list, tree spec, tsubst_flags_t complain)
list = tree_cons (NULL_TREE, spec, list);
}
else
- diag_type = DK_ERROR; /* error */
+ diag_type = diagnostics::kind::error; /* error */
- if (diag_type != DK_UNSPECIFIED
+ if (diag_type != diagnostics::kind::unspecified
&& (complain & tf_warning_or_error))
cxx_incomplete_type_diagnostic (NULL_TREE, core, diag_type);
diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog
index b6815d3..4fe6418 100644
--- a/gcc/d/ChangeLog
+++ b/gcc/d/ChangeLog
@@ -1,3 +1,22 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * d-diagnostic.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * d-diagnostic.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * d-diagnostic.cc (d_diagnostic_report_diagnostic): Update to add
+ "m_" prefix to fields of diagnostic_info throughout.
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * toir.cc: Pass null pointer to
+ parse_{input,output}_constraint().
+
2025-04-29 Iain Buclaw <ibuclaw@gdcproject.org>
PR d/103044
diff --git a/gcc/d/d-diagnostic.cc b/gcc/d/d-diagnostic.cc
index 55cb42e..e666ddf 100644
--- a/gcc/d/d-diagnostic.cc
+++ b/gcc/d/d-diagnostic.cc
@@ -185,7 +185,7 @@ escape_d_format (const char *format)
static void ATTRIBUTE_GCC_DIAG(3,0)
d_diagnostic_report_diagnostic (const SourceLoc &loc, int opt,
const char *format, va_list ap,
- diagnostic_t kind, bool verbatim)
+ enum diagnostics::kind kind, bool verbatim)
{
va_list argp;
va_copy (argp, ap);
@@ -193,13 +193,13 @@ d_diagnostic_report_diagnostic (const SourceLoc &loc, int opt,
if (loc.filename.length != 0 || !verbatim)
{
rich_location rich_loc (line_table, make_location_t (loc));
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
char *xformat = expand_d_format (format);
diagnostic_set_info_translated (&diagnostic, xformat, &argp,
&rich_loc, kind);
if (opt != 0)
- diagnostic.option_id = opt;
+ diagnostic.m_option_id = opt;
diagnostic_report_diagnostic (global_dc, &diagnostic);
}
@@ -224,7 +224,7 @@ void D_ATTRIBUTE_FORMAT(2,0) ATTRIBUTE_GCC_DIAG(2,0)
verrorReport (const SourceLoc loc, const char *format, va_list ap,
ErrorKind kind, const char *prefix1, const char *prefix2)
{
- diagnostic_t diag_kind = DK_UNSPECIFIED;
+ enum diagnostics::kind diag_kind = diagnostics::kind::unspecified;
int opt = 0;
bool verbatim = false;
char *xformat;
@@ -238,7 +238,9 @@ verrorReport (const SourceLoc loc, const char *format, va_list ap,
if (global.gag && !global.params.v.showGaggedErrors)
return;
- diag_kind = global.gag ? DK_ANACHRONISM : DK_ERROR;
+ diag_kind = (global.gag
+ ? diagnostics::kind::anachronism
+ : diagnostics::kind::error);
}
else if (kind == ErrorKind::warning)
{
@@ -254,7 +256,7 @@ verrorReport (const SourceLoc loc, const char *format, va_list ap,
if (global.params.useWarnings == DIAGNOSTICerror)
global.warnings++;
- diag_kind = DK_WARNING;
+ diag_kind = diagnostics::kind::warning;
}
else if (kind == ErrorKind::deprecation)
{
@@ -270,11 +272,11 @@ verrorReport (const SourceLoc loc, const char *format, va_list ap,
}
opt = OPT_Wdeprecated;
- diag_kind = DK_WARNING;
+ diag_kind = diagnostics::kind::warning;
}
else if (kind == ErrorKind::message)
{
- diag_kind = DK_NOTE;
+ diag_kind = diagnostics::kind::note;
verbatim = true;
}
else if (kind == ErrorKind::tip)
@@ -282,7 +284,7 @@ verrorReport (const SourceLoc loc, const char *format, va_list ap,
if (global.gag)
return;
- diag_kind = DK_DEBUG;
+ diag_kind = diagnostics::kind::debug;
verbatim = true;
}
else
@@ -328,7 +330,8 @@ verrorReportSupplemental (const SourceLoc loc, const char* format, va_list ap,
else
gcc_unreachable ();
- d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
+ d_diagnostic_report_diagnostic (loc, 0, format, ap, diagnostics::kind::note,
+ false);
}
/* Call this after printing out fatal error messages to clean up and
diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc
index b70db7a..554399b 100644
--- a/gcc/d/toir.cc
+++ b/gcc/d/toir.cc
@@ -1450,7 +1450,8 @@ public:
oconstraints[i] = constraint;
if (parse_output_constraint (&constraint, i, ninputs, noutputs,
- &allows_mem, &allows_reg, &is_inout))
+ &allows_mem, &allows_reg, &is_inout,
+ nullptr))
{
/* If the output argument is going to end up in memory. */
if (!allows_reg)
@@ -1469,7 +1470,8 @@ public:
= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
- oconstraints, &allows_mem, &allows_reg))
+ oconstraints, &allows_mem, &allows_reg,
+ nullptr))
{
/* If the input argument is going to end up in memory. */
if (!allows_reg && allows_mem)
diff --git a/gcc/diagnostic-core.h b/gcc/diagnostic-core.h
index 1e89c9f..fc32f48 100644
--- a/gcc/diagnostic-core.h
+++ b/gcc/diagnostic-core.h
@@ -23,21 +23,8 @@ along with GCC; see the file COPYING3. If not see
#define GCC_DIAGNOSTIC_CORE_H
#include "bversion.h"
-
-/* Constants used to discriminate diagnostics. */
-typedef enum
-{
-#define DEFINE_DIAGNOSTIC_KIND(K, msgid, C) K,
-#include "diagnostic.def"
-#undef DEFINE_DIAGNOSTIC_KIND
- DK_LAST_DIAGNOSTIC_KIND,
- /* This is used for tagging pragma pops in the diagnostic
- classification history chain. */
- DK_POP,
- /* This is used internally to note that a diagnostic is enabled
- without mandating any specific type. */
- DK_ANY,
-} diagnostic_t;
+#include "diagnostics/kinds.h"
+#include "diagnostics/option-id.h"
/* RAII-style class for grouping related diagnostics within global_dc. */
@@ -61,28 +48,9 @@ class auto_diagnostic_nesting_level
};
/* Forward decl. */
-class diagnostic_metadata; /* See diagnostic-metadata.h. */
-
-/* A class to use for the ID of an option that controls
- a particular diagnostic.
- This is just a wrapper around "int", but better documents
- the intent of the code. */
-
-struct diagnostic_option_id
-{
- diagnostic_option_id () : m_idx (0) {}
-
- diagnostic_option_id (int idx) : m_idx (idx) {}
- /* Ideally we'd take an enum opt_code here, but we don't
- want to depend on its decl. */
-
- bool operator== (diagnostic_option_id other) const
- {
- return m_idx == other.m_idx;
- }
-
- int m_idx;
-};
+namespace diagnostics {
+ class metadata; /* See diagnostics/metadata.h. */
+} // namespace diagnostics
extern const char *progname;
@@ -109,29 +77,29 @@ extern void internal_error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2)
extern void internal_error_no_backtrace (const char *, ...)
ATTRIBUTE_GCC_DIAG(1,2) ATTRIBUTE_NORETURN;
/* Pass one of the OPT_W* from options.h as the first parameter. */
-extern bool warning (diagnostic_option_id,
+extern bool warning (diagnostics::option_id,
const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
extern bool warning_n (location_t,
- diagnostic_option_id,
+ diagnostics::option_id,
unsigned HOST_WIDE_INT,
const char *, const char *, ...)
ATTRIBUTE_GCC_DIAG(4,6) ATTRIBUTE_GCC_DIAG(5,6);
extern bool warning_n (rich_location *,
- diagnostic_option_id,
+ diagnostics::option_id,
unsigned HOST_WIDE_INT,
const char *, const char *, ...)
ATTRIBUTE_GCC_DIAG(4, 6) ATTRIBUTE_GCC_DIAG(5, 6);
extern bool warning_at (location_t,
- diagnostic_option_id,
+ diagnostics::option_id,
const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern bool warning_at (rich_location *,
- diagnostic_option_id,
+ diagnostics::option_id,
const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern bool warning_meta (rich_location *,
- const diagnostic_metadata &,
- diagnostic_option_id,
+ const diagnostics::metadata &,
+ diagnostics::option_id,
const char *, ...)
ATTRIBUTE_GCC_DIAG(4,5);
extern void error (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
@@ -141,29 +109,29 @@ extern void error_n (location_t, unsigned HOST_WIDE_INT, const char *,
extern void error_at (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
extern void error_at (rich_location *, const char *, ...)
ATTRIBUTE_GCC_DIAG(2,3);
-extern void error_meta (rich_location *, const diagnostic_metadata &,
+extern void error_meta (rich_location *, const diagnostics::metadata &,
const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern void fatal_error (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3)
ATTRIBUTE_NORETURN;
/* Pass one of the OPT_W* from options.h as the second parameter. */
extern bool pedwarn (location_t,
- diagnostic_option_id,
+ diagnostics::option_id,
const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern bool pedwarn (rich_location *,
- diagnostic_option_id,
+ diagnostics::option_id,
const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern bool permerror (location_t, const char *, ...) ATTRIBUTE_GCC_DIAG(2,3);
extern bool permerror (rich_location *, const char *,
...) ATTRIBUTE_GCC_DIAG(2,3);
extern bool permerror_opt (location_t,
- diagnostic_option_id,
+ diagnostics::option_id,
const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern bool permerror_opt (rich_location *,
- diagnostic_option_id,
+ diagnostics::option_id,
const char *, ...)
ATTRIBUTE_GCC_DIAG(3,4);
extern void sorry (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
@@ -174,23 +142,23 @@ extern void inform_n (location_t, unsigned HOST_WIDE_INT, const char *,
const char *, ...)
ATTRIBUTE_GCC_DIAG(3,5) ATTRIBUTE_GCC_DIAG(4,5);
extern void verbatim (const char *, ...) ATTRIBUTE_GCC_DIAG(1,2);
-extern bool emit_diagnostic (diagnostic_t,
+extern bool emit_diagnostic (enum diagnostics::kind,
location_t,
- diagnostic_option_id,
+ diagnostics::option_id,
const char *, ...) ATTRIBUTE_GCC_DIAG(4,5);
-extern bool emit_diagnostic (diagnostic_t,
+extern bool emit_diagnostic (enum diagnostics::kind,
rich_location *,
- diagnostic_option_id,
+ diagnostics::option_id,
const char *, ...) ATTRIBUTE_GCC_DIAG(4,5);
-extern bool emit_diagnostic_valist (diagnostic_t,
+extern bool emit_diagnostic_valist (enum diagnostics::kind,
location_t,
- diagnostic_option_id,
+ diagnostics::option_id,
const char *, va_list *)
ATTRIBUTE_GCC_DIAG (4,0);
-extern bool emit_diagnostic_valist_meta (diagnostic_t,
+extern bool emit_diagnostic_valist_meta (enum diagnostics::kind,
rich_location *,
- const diagnostic_metadata *,
- diagnostic_option_id,
+ const diagnostics::metadata *,
+ diagnostics::option_id,
const char *,
va_list *) ATTRIBUTE_GCC_DIAG (5,0);
extern bool seen_error (void);
diff --git a/gcc/diagnostic-global-context.cc b/gcc/diagnostic-global-context.cc
index 1165915..500f19c 100644
--- a/gcc/diagnostic-global-context.cc
+++ b/gcc/diagnostic-global-context.cc
@@ -27,11 +27,11 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "intl.h"
#include "diagnostic.h"
-#include "diagnostic-format.h"
+#include "diagnostics/sink.h"
-/* A diagnostic_context surrogate for stderr. */
-static diagnostic_context global_diagnostic_context;
-diagnostic_context *global_dc = &global_diagnostic_context;
+/* A diagnostics::context surrogate for stderr. */
+static diagnostics::context global_diagnostic_context;
+diagnostics::context *global_dc = &global_diagnostic_context;
/* Standard error reporting routines in increasing order of severity. */
@@ -49,13 +49,13 @@ verbatim (const char *gmsgid, ...)
va_end (ap);
}
-/* Wrapper around diagnostic_context::diagnostic_impl
+/* Wrapper around diagnostics::context::diagnostic_impl
implying global_dc and taking a variable argument list. */
bool
-emit_diagnostic (diagnostic_t kind,
+emit_diagnostic (enum diagnostics::kind kind,
location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
auto_diagnostic_group d;
@@ -71,9 +71,9 @@ emit_diagnostic (diagnostic_t kind,
/* As above, but for rich_location *. */
bool
-emit_diagnostic (diagnostic_t kind,
+emit_diagnostic (enum diagnostics::kind kind,
rich_location *richloc,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
auto_diagnostic_group d;
@@ -88,9 +88,9 @@ emit_diagnostic (diagnostic_t kind,
/* As above, but taking a variable argument list. */
bool
-emit_diagnostic_valist (diagnostic_t kind,
+emit_diagnostic_valist (enum diagnostics::kind kind,
location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, va_list *ap)
{
rich_location richloc (line_table, location);
@@ -101,10 +101,10 @@ emit_diagnostic_valist (diagnostic_t kind,
/* As above, but with rich_location and metadata. */
bool
-emit_diagnostic_valist_meta (diagnostic_t kind,
+emit_diagnostic_valist_meta (enum diagnostics::kind kind,
rich_location *richloc,
- const diagnostic_metadata *metadata,
- diagnostic_option_id option_id,
+ const diagnostics::metadata *metadata,
+ diagnostics::option_id option_id,
const char *gmsgid, va_list *ap)
{
return global_dc->diagnostic_impl (richloc, metadata, option_id,
@@ -120,7 +120,8 @@ inform (location_t location, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, location);
- global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap, DK_NOTE);
+ global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap,
+ diagnostics::kind::note);
va_end (ap);
}
@@ -133,7 +134,8 @@ inform (rich_location *richloc, const char *gmsgid, ...)
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
- global_dc->diagnostic_impl (richloc, nullptr, -1, gmsgid, &ap, DK_NOTE);
+ global_dc->diagnostic_impl (richloc, nullptr, -1, gmsgid, &ap,
+ diagnostics::kind::note);
va_end (ap);
}
@@ -149,7 +151,7 @@ inform_n (location_t location, unsigned HOST_WIDE_INT n,
rich_location richloc (line_table, location);
global_dc->diagnostic_n_impl (&richloc, nullptr, -1, n,
singular_gmsgid, plural_gmsgid,
- &ap, DK_NOTE);
+ &ap, diagnostics::kind::note);
va_end (ap);
}
@@ -157,14 +159,15 @@ inform_n (location_t location, unsigned HOST_WIDE_INT n,
to the relevant language specification but is likely to be buggy anyway.
Returns true if the warning was printed, false if it was inhibited. */
bool
-warning (diagnostic_option_id option_id, const char *gmsgid, ...)
+warning (diagnostics::option_id option_id, const char *gmsgid, ...)
{
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, input_location);
bool ret = global_dc->diagnostic_impl (&richloc, nullptr, option_id,
- gmsgid, &ap, DK_WARNING);
+ gmsgid, &ap,
+ diagnostics::kind::warning);
va_end (ap);
return ret;
}
@@ -175,7 +178,7 @@ warning (diagnostic_option_id option_id, const char *gmsgid, ...)
bool
warning_at (location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
auto_diagnostic_group d;
@@ -183,7 +186,8 @@ warning_at (location_t location,
va_start (ap, gmsgid);
rich_location richloc (line_table, location);
bool ret = global_dc->diagnostic_impl (&richloc, nullptr, option_id,
- gmsgid, &ap, DK_WARNING);
+ gmsgid, &ap,
+ diagnostics::kind::warning);
va_end (ap);
return ret;
}
@@ -192,7 +196,7 @@ warning_at (location_t location,
bool
warning_at (rich_location *richloc,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
gcc_assert (richloc);
@@ -201,7 +205,8 @@ warning_at (rich_location *richloc,
va_list ap;
va_start (ap, gmsgid);
bool ret = global_dc->diagnostic_impl (richloc, nullptr, option_id,
- gmsgid, &ap, DK_WARNING);
+ gmsgid, &ap,
+ diagnostics::kind::warning);
va_end (ap);
return ret;
}
@@ -210,8 +215,8 @@ warning_at (rich_location *richloc,
bool
warning_meta (rich_location *richloc,
- const diagnostic_metadata &metadata,
- diagnostic_option_id option_id,
+ const diagnostics::metadata &metadata,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
gcc_assert (richloc);
@@ -220,7 +225,8 @@ warning_meta (rich_location *richloc,
va_list ap;
va_start (ap, gmsgid);
bool ret = global_dc->diagnostic_impl (richloc, &metadata, option_id,
- gmsgid, &ap, DK_WARNING);
+ gmsgid, &ap,
+ diagnostics::kind::warning);
va_end (ap);
return ret;
}
@@ -229,7 +235,7 @@ warning_meta (rich_location *richloc,
bool
warning_n (rich_location *richloc,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
unsigned HOST_WIDE_INT n,
const char *singular_gmsgid, const char *plural_gmsgid, ...)
{
@@ -240,7 +246,7 @@ warning_n (rich_location *richloc,
va_start (ap, plural_gmsgid);
bool ret = global_dc->diagnostic_n_impl (richloc, nullptr, option_id, n,
singular_gmsgid, plural_gmsgid,
- &ap, DK_WARNING);
+ &ap, diagnostics::kind::warning);
va_end (ap);
return ret;
}
@@ -251,7 +257,7 @@ warning_n (rich_location *richloc,
bool
warning_n (location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
unsigned HOST_WIDE_INT n,
const char *singular_gmsgid, const char *plural_gmsgid, ...)
{
@@ -261,7 +267,7 @@ warning_n (location_t location,
rich_location richloc (line_table, location);
bool ret = global_dc->diagnostic_n_impl (&richloc, nullptr, option_id, n,
singular_gmsgid, plural_gmsgid,
- &ap, DK_WARNING);
+ &ap, diagnostics::kind::warning);
va_end (ap);
return ret;
}
@@ -281,7 +287,7 @@ warning_n (location_t location,
bool
pedwarn (location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
auto_diagnostic_group d;
@@ -289,7 +295,8 @@ pedwarn (location_t location,
va_start (ap, gmsgid);
rich_location richloc (line_table, location);
bool ret = global_dc->diagnostic_impl (&richloc, nullptr, option_id,
- gmsgid, &ap, DK_PEDWARN);
+ gmsgid, &ap,
+ diagnostics::kind::pedwarn);
va_end (ap);
return ret;
}
@@ -298,7 +305,7 @@ pedwarn (location_t location,
bool
pedwarn (rich_location *richloc,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
gcc_assert (richloc);
@@ -307,7 +314,8 @@ pedwarn (rich_location *richloc,
va_list ap;
va_start (ap, gmsgid);
bool ret = global_dc->diagnostic_impl (richloc, nullptr, option_id,
- gmsgid, &ap, DK_PEDWARN);
+ gmsgid, &ap,
+ diagnostics::kind::pedwarn);
va_end (ap);
return ret;
}
@@ -327,7 +335,7 @@ permerror (location_t location, const char *gmsgid, ...)
va_start (ap, gmsgid);
rich_location richloc (line_table, location);
bool ret = global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap,
- DK_PERMERROR);
+ diagnostics::kind::permerror);
va_end (ap);
return ret;
}
@@ -343,7 +351,7 @@ permerror (rich_location *richloc, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
bool ret = global_dc->diagnostic_impl (richloc, nullptr, -1, gmsgid, &ap,
- DK_PERMERROR);
+ diagnostics::kind::permerror);
va_end (ap);
return ret;
}
@@ -354,7 +362,7 @@ permerror (rich_location *richloc, const char *gmsgid, ...)
bool
permerror_opt (location_t location,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
auto_diagnostic_group d;
@@ -362,7 +370,8 @@ permerror_opt (location_t location,
va_start (ap, gmsgid);
rich_location richloc (line_table, location);
bool ret = global_dc->diagnostic_impl (&richloc, nullptr, option_id,
- gmsgid, &ap, DK_PERMERROR);
+ gmsgid, &ap,
+ diagnostics::kind::permerror);
va_end (ap);
return ret;
}
@@ -371,7 +380,7 @@ permerror_opt (location_t location,
bool
permerror_opt (rich_location *richloc,
- diagnostic_option_id option_id,
+ diagnostics::option_id option_id,
const char *gmsgid, ...)
{
gcc_assert (richloc);
@@ -380,7 +389,8 @@ permerror_opt (rich_location *richloc,
va_list ap;
va_start (ap, gmsgid);
bool ret = global_dc->diagnostic_impl (richloc, nullptr, option_id,
- gmsgid, &ap, DK_PERMERROR);
+ gmsgid, &ap,
+ diagnostics::kind::permerror);
va_end (ap);
return ret;
}
@@ -394,7 +404,8 @@ error (const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, input_location);
- global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap, DK_ERROR);
+ global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap,
+ diagnostics::kind::error);
va_end (ap);
}
@@ -410,7 +421,7 @@ error_n (location_t location, unsigned HOST_WIDE_INT n,
rich_location richloc (line_table, location);
global_dc->diagnostic_n_impl (&richloc, nullptr, -1, n,
singular_gmsgid, plural_gmsgid,
- &ap, DK_ERROR);
+ &ap, diagnostics::kind::error);
va_end (ap);
}
@@ -422,7 +433,8 @@ error_at (location_t loc, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, loc);
- global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap, DK_ERROR);
+ global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap,
+ diagnostics::kind::error);
va_end (ap);
}
@@ -436,14 +448,15 @@ error_at (rich_location *richloc, const char *gmsgid, ...)
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
- global_dc->diagnostic_impl (richloc, nullptr, -1, gmsgid, &ap, DK_ERROR);
+ global_dc->diagnostic_impl (richloc, nullptr, -1, gmsgid, &ap,
+ diagnostics::kind::error);
va_end (ap);
}
/* Same as above, but with metadata. */
void
-error_meta (rich_location *richloc, const diagnostic_metadata &metadata,
+error_meta (rich_location *richloc, const diagnostics::metadata &metadata,
const char *gmsgid, ...)
{
gcc_assert (richloc);
@@ -451,7 +464,8 @@ error_meta (rich_location *richloc, const diagnostic_metadata &metadata,
auto_diagnostic_group d;
va_list ap;
va_start (ap, gmsgid);
- global_dc->diagnostic_impl (richloc, &metadata, -1, gmsgid, &ap, DK_ERROR);
+ global_dc->diagnostic_impl (richloc, &metadata, -1, gmsgid, &ap,
+ diagnostics::kind::error);
va_end (ap);
}
@@ -465,7 +479,8 @@ sorry (const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, input_location);
- global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap, DK_SORRY);
+ global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap,
+ diagnostics::kind::sorry);
va_end (ap);
}
@@ -477,7 +492,8 @@ sorry_at (location_t loc, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, loc);
- global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap, DK_SORRY);
+ global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap,
+ diagnostics::kind::sorry);
va_end (ap);
}
@@ -499,7 +515,8 @@ fatal_error (location_t loc, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, loc);
- global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap, DK_FATAL);
+ global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap,
+ diagnostics::kind::fatal);
va_end (ap);
gcc_unreachable ();
@@ -514,7 +531,8 @@ internal_error (const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, input_location);
- global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap, DK_ICE);
+ global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap,
+ diagnostics::kind::ice);
va_end (ap);
gcc_unreachable ();
@@ -530,7 +548,8 @@ internal_error_no_backtrace (const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
rich_location richloc (line_table, input_location);
- global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap, DK_ICE_NOBT);
+ global_dc->diagnostic_impl (&richloc, nullptr, -1, gmsgid, &ap,
+ diagnostics::kind::ice_nobt);
va_end (ap);
gcc_unreachable ();
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 04eb2b1..7572e04 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -21,1146 +21,31 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_DIAGNOSTIC_H
#define GCC_DIAGNOSTIC_H
-#include "unique-argv.h"
#include "rich-location.h"
#include "pretty-print.h"
#include "diagnostic-core.h"
-namespace diagnostics {
- namespace digraphs {
- class lazy_digraph;
- } // namespace digraphs
-} // namespace diagnostics
-
-namespace text_art
-{
- class theme;
-} // namespace text_art
-
-namespace xml
-{
- class printer;
-} // namespace xml
-
-/* An enum for controlling what units to use for the column number
- when diagnostics are output, used by the -fdiagnostics-column-unit option.
- Tabs will be expanded or not according to the value of -ftabstop. The origin
- (default 1) is controlled by -fdiagnostics-column-origin. */
-
-enum diagnostics_column_unit
-{
- /* The default from GCC 11 onwards: display columns. */
- DIAGNOSTICS_COLUMN_UNIT_DISPLAY,
-
- /* The behavior in GCC 10 and earlier: simple bytes. */
- DIAGNOSTICS_COLUMN_UNIT_BYTE
-};
-
-/* An enum for controlling how to print non-ASCII characters/bytes when
- a diagnostic suggests escaping the source code on output. */
-
-enum diagnostics_escape_format
-{
- /* Escape non-ASCII Unicode characters in the form <U+XXXX> and
- non-UTF-8 bytes in the form <XX>. */
- DIAGNOSTICS_ESCAPE_FORMAT_UNICODE,
-
- /* Escape non-ASCII bytes in the form <XX> (thus showing the underlying
- encoding of non-ASCII Unicode characters). */
- DIAGNOSTICS_ESCAPE_FORMAT_BYTES
-};
-
-/* Enum for overriding the standard output format. */
-
-enum diagnostics_output_format
-{
- /* The default: textual output. */
- DIAGNOSTICS_OUTPUT_FORMAT_TEXT,
-
- /* SARIF-based output, as JSON to stderr. */
- DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR,
-
- /* SARIF-based output, to a JSON file. */
- DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE
-};
-
-/* An enum for controlling how diagnostic_paths should be printed. */
-enum diagnostic_path_format
-{
- /* Don't print diagnostic_paths. */
- DPF_NONE,
-
- /* Print diagnostic_paths by emitting a separate "note" for every event
- in the path. */
- DPF_SEPARATE_EVENTS,
-
- /* Print diagnostic_paths by consolidating events together where they
- are close enough, and printing such runs of events with multiple
- calls to diagnostic_show_locus, showing the individual events in
- each run via labels in the source. */
- DPF_INLINE_EVENTS
-};
-
-/* An enum for capturing values of GCC_EXTRA_DIAGNOSTIC_OUTPUT,
- and for -fdiagnostics-parseable-fixits. */
-
-enum diagnostics_extra_output_kind
-{
- /* No extra output, or an unrecognized value. */
- EXTRA_DIAGNOSTIC_OUTPUT_none,
-
- /* Emit fix-it hints using the "fixits-v1" format, equivalent to
- -fdiagnostics-parseable-fixits. */
- EXTRA_DIAGNOSTIC_OUTPUT_fixits_v1,
-
- /* Emit fix-it hints using the "fixits-v2" format. */
- EXTRA_DIAGNOSTIC_OUTPUT_fixits_v2
-};
-
-/* Values for -fdiagnostics-text-art-charset=. */
-
-enum diagnostic_text_art_charset
-{
- /* No text art diagrams shall be emitted. */
- DIAGNOSTICS_TEXT_ART_CHARSET_NONE,
-
- /* Use pure ASCII for text art diagrams. */
- DIAGNOSTICS_TEXT_ART_CHARSET_ASCII,
-
- /* Use ASCII + conservative use of other unicode characters
- in text art diagrams. */
- DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE,
-
- /* Use Emoji. */
- DIAGNOSTICS_TEXT_ART_CHARSET_EMOJI
-};
-
-/* A diagnostic is described by the MESSAGE to send, the FILE and LINE of
- its context and its KIND (ice, error, warning, note, ...) See complete
- list in diagnostic.def. */
-struct diagnostic_info
-{
- diagnostic_info ()
- : message (), richloc (), metadata (), x_data (), kind (), option_id (),
- m_iinfo ()
- { }
-
- /* Text to be formatted. */
- text_info message;
-
- /* The location at which the diagnostic is to be reported. */
- rich_location *richloc;
-
- /* An optional bundle of metadata associated with the diagnostic
- (or NULL). */
- const diagnostic_metadata *metadata;
-
- /* Auxiliary data for client. */
- void *x_data;
- /* The kind of diagnostic it is about. */
- diagnostic_t kind;
- /* Which OPT_* directly controls this diagnostic. */
- diagnostic_option_id option_id;
-
- /* Inlining context containing locations for each call site along
- the inlining stack. */
- struct inlining_info
- {
- /* Locations along the inlining stack. */
- auto_vec<location_t, 8> m_ilocs;
- /* The abstract origin of the location. */
- void *m_ao;
- /* Set if every M_ILOCS element is in a system header. */
- bool m_allsyslocs;
- } m_iinfo;
-};
-
-/* Forward declarations. */
-class diagnostic_location_print_policy;
-class diagnostic_source_print_policy;
-
-typedef void (*diagnostic_text_starter_fn) (diagnostic_text_output_format &,
- const diagnostic_info *);
-
-struct to_text;
-struct to_html;
-
-extern pretty_printer *get_printer (to_text &);
-
-template <typename Sink>
-using diagnostic_start_span_fn = void (*) (const diagnostic_location_print_policy &,
- Sink &sink,
- expanded_location);
-
-typedef void (*diagnostic_text_finalizer_fn) (diagnostic_text_output_format &,
- const diagnostic_info *,
- diagnostic_t);
-
-/* Abstract base class for the diagnostic subsystem to make queries
- about command-line options. */
-
-class diagnostic_option_manager
-{
-public:
- virtual ~diagnostic_option_manager () {}
-
- /* Return 1 if option OPTION_ID is enabled, 0 if it is disabled,
- or -1 if it isn't a simple on-off switch
- (or if the value is unknown, typically set later in target). */
- virtual int option_enabled_p (diagnostic_option_id option_id) const = 0;
-
- /* Return malloced memory for the name of the option OPTION_ID
- which enabled a diagnostic, originally of type ORIG_DIAG_KIND but
- possibly converted to DIAG_KIND by options such as -Werror.
- May return NULL if no name is to be printed.
- May be passed 0 as well as the index of a particular option. */
- virtual char *make_option_name (diagnostic_option_id option_id,
- diagnostic_t orig_diag_kind,
- diagnostic_t diag_kind) const = 0;
-
- /* Return malloced memory for a URL describing the option that controls
- a diagnostic.
- May return NULL if no URL is available.
- May be passed 0 as well as the index of a particular option. */
- virtual char *make_option_url (diagnostic_option_id option_id) const = 0;
-};
-
-class edit_context;
-class diagnostic_client_data_hooks;
-class logical_location_manager;
-class diagnostic_diagram;
-class diagnostic_source_effect_info;
-class diagnostic_output_format;
- class diagnostic_text_output_format;
-class diagnostic_buffer;
-
-/* A stack of sets of classifications: each entry in the stack is
- a mapping from option index to diagnostic severity that can be changed
- via pragmas. The stack can be pushed and popped. */
-
-class diagnostic_option_classifier
-{
-public:
- void init (int n_opts);
- void fini ();
-
- /* Save all diagnostic classifications in a stack. */
- void push ();
-
- /* Restore the topmost classification set off the stack. If the stack
- is empty, revert to the state based on command line parameters. */
- void pop (location_t where);
-
- bool option_unspecified_p (diagnostic_option_id option_id) const
- {
- return get_current_override (option_id) == DK_UNSPECIFIED;
- }
-
- diagnostic_t get_current_override (diagnostic_option_id option_id) const
- {
- gcc_assert (option_id.m_idx < m_n_opts);
- return m_classify_diagnostic[option_id.m_idx];
- }
-
- diagnostic_t
- classify_diagnostic (const diagnostic_context *context,
- diagnostic_option_id option_id,
- diagnostic_t new_kind,
- location_t where);
-
- diagnostic_t
- update_effective_level_from_pragmas (diagnostic_info *diagnostic) const;
-
- int pch_save (FILE *);
- int pch_restore (FILE *);
-
-private:
- /* Each time a diagnostic's classification is changed with a pragma,
- we record the change and the location of the change in an array of
- these structs. */
- struct diagnostic_classification_change_t
- {
- location_t location;
-
- /* For DK_POP, this is the index of the corresponding push (as stored
- in m_push_list).
- Otherwise, this is an option index. */
- int option;
-
- diagnostic_t kind;
- };
-
- int m_n_opts;
-
- /* For each option index that can be passed to warning() et al
- (OPT_* from options.h when using this code with the core GCC
- options), this array may contain a new kind that the diagnostic
- should be changed to before reporting, or DK_UNSPECIFIED to leave
- it as the reported kind, or DK_IGNORED to not report it at
- all. */
- diagnostic_t *m_classify_diagnostic;
-
- /* History of all changes to the classifications above. This list
- is stored in location-order, so we can search it, either
- binary-wise or end-to-front, to find the most recent
- classification for a given diagnostic, given the location of the
- diagnostic. */
- vec<diagnostic_classification_change_t> m_classification_history;
-
- /* For diagnostic_context::get_classification_history, declared later. */
- friend class diagnostic_context;
-
- /* For pragma push/pop. */
- vec<int> m_push_list;
-};
-
-/* A bundle of options relating to printing the user's source code
- (potentially with a margin, underlining, labels, etc). */
-
-struct diagnostic_source_printing_options
-{
- /* True if we should print the source line with a caret indicating
- the location.
- Corresponds to -fdiagnostics-show-caret. */
- bool enabled;
-
- /* Maximum width of the source line printed. */
- int max_width;
-
- /* Character used at the caret when printing source locations. */
- char caret_chars[rich_location::STATICALLY_ALLOCATED_RANGES];
-
- /* When printing source code, should the characters at carets and ranges
- be colorized? (assuming colorization is on at all).
- This should be true for frontends that generate range information
- (so that the ranges of code are colorized),
- and false for frontends that merely specify points within the
- source code (to avoid e.g. colorizing just the first character in
- a token, which would look strange). */
- bool colorize_source_p;
-
- /* When printing source code, should labelled ranges be printed?
- Corresponds to -fdiagnostics-show-labels. */
- bool show_labels_p;
-
- /* When printing source code, should there be a left-hand margin
- showing line numbers?
- Corresponds to -fdiagnostics-show-line-numbers. */
- bool show_line_numbers_p;
-
- /* If printing source code, what should the minimum width of the margin
- be? Line numbers will be right-aligned, and padded to this width.
- Corresponds to -fdiagnostics-minimum-margin-width=VALUE. */
- int min_margin_width;
-
- /* Usable by plugins; if true, print a debugging ruler above the
- source output. */
- bool show_ruler_p;
-
- /* When printing events in an inline path, should we print lines
- visualizing links between related events (e.g. for CFG paths)?
- Corresponds to -fdiagnostics-show-event-links. */
- bool show_event_links_p;
-};
-
-/* A bundle of state for determining column numbers in diagnostics
- (tab stops, whether to start at 0 or 1, etc).
- Uses a file_cache to handle tabs. */
-
-class diagnostic_column_policy
-{
-public:
- diagnostic_column_policy (const diagnostic_context &dc);
-
- int converted_column (expanded_location s) const;
-
- label_text get_location_text (const expanded_location &s,
- bool show_column,
- bool colorize) const;
-
- int get_tabstop () const { return m_tabstop; }
-
-private:
- file_cache &m_file_cache;
- enum diagnostics_column_unit m_column_unit;
- int m_column_origin;
- int m_tabstop;
-};
-
-/* A bundle of state for printing locations within diagnostics
- (e.g. "FILENAME:LINE:COLUMN"), to isolate the interactions between
- diagnostic_context and the start_span callbacks. */
-
-class diagnostic_location_print_policy
-{
-public:
- diagnostic_location_print_policy (const diagnostic_context &dc);
- diagnostic_location_print_policy (const diagnostic_text_output_format &);
-
- bool show_column_p () const { return m_show_column; }
-
- const diagnostic_column_policy &
- get_column_policy () const { return m_column_policy; }
-
- void
- print_text_span_start (const diagnostic_context &dc,
- pretty_printer &pp,
- const expanded_location &exploc);
-
- void
- print_html_span_start (const diagnostic_context &dc,
- xml::printer &xp,
- const expanded_location &exploc);
-
-private:
- diagnostic_column_policy m_column_policy;
- bool m_show_column;
-};
-
-/* Abstract base class for optionally supplying extra tags when writing
- out annotation labels in HTML output. */
-
-class html_label_writer
-{
-public:
- virtual ~html_label_writer () {}
- virtual void begin_label () = 0;
- virtual void end_label () = 0;
-};
-
-/* A bundle of state for printing source within a diagnostic,
- to isolate the interactions between diagnostic_context and the
- implementation of diagnostic_show_locus. */
-
-class diagnostic_source_print_policy
-{
-public:
- diagnostic_source_print_policy (const diagnostic_context &);
- diagnostic_source_print_policy (const diagnostic_context &,
- const diagnostic_source_printing_options &);
-
- void
- print (pretty_printer &pp,
- const rich_location &richloc,
- diagnostic_t diagnostic_kind,
- diagnostic_source_effect_info *effect_info) const;
-
- void
- print_as_html (xml::printer &xp,
- const rich_location &richloc,
- diagnostic_t diagnostic_kind,
- diagnostic_source_effect_info *effect_info,
- html_label_writer *label_writer) const;
-
- const diagnostic_source_printing_options &
- get_options () const { return m_options; }
-
- diagnostic_start_span_fn<to_text>
- get_text_start_span_fn () const { return m_text_start_span_cb; }
-
- diagnostic_start_span_fn<to_html>
- get_html_start_span_fn () const { return m_html_start_span_cb; }
-
- file_cache &
- get_file_cache () const { return m_file_cache; }
-
- enum diagnostics_escape_format
- get_escape_format () const
- {
- return m_escape_format;
- }
-
- text_art::theme *
- get_diagram_theme () const { return m_diagram_theme; }
-
- const diagnostic_column_policy &get_column_policy () const
- {
- return m_location_policy.get_column_policy ();
- }
-
- const diagnostic_location_print_policy &get_location_policy () const
- {
- return m_location_policy;
- }
-
-private:
- const diagnostic_source_printing_options &m_options;
- class diagnostic_location_print_policy m_location_policy;
- diagnostic_start_span_fn<to_text> m_text_start_span_cb;
- diagnostic_start_span_fn<to_html> m_html_start_span_cb;
- file_cache &m_file_cache;
-
- /* Other data copied from diagnostic_context. */
- text_art::theme *m_diagram_theme;
- enum diagnostics_escape_format m_escape_format;
-};
-
-/* A collection of counters of diagnostics, per-kind
- (e.g. "3 errors and 1 warning"), for use by both diagnostic_context
- and by diagnostic_buffer. */
-
-struct diagnostic_counters
-{
- diagnostic_counters ();
-
- void dump (FILE *out, int indent) const;
- void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
-
- int get_count (diagnostic_t kind) const { return m_count_for_kind[kind]; }
-
- void move_to (diagnostic_counters &dest);
- void clear ();
-
- int m_count_for_kind[DK_LAST_DIAGNOSTIC_KIND];
-};
-
-/* This class encapsulates the state of the diagnostics subsystem
- as a whole (either directly, or via owned objects of other classes, to
- avoid global variables).
-
- It has responsibility for:
- - being a central place for clients to report diagnostics
- - reporting those diagnostics to zero or more output sinks
- (e.g. text vs SARIF)
- - providing a "dump" member function for a debug dump of the state of
- the diagnostics subsytem
- - direct vs buffered diagnostics (see class diagnostic_buffer)
- - tracking the original argv of the program (for SARIF output)
- - crash-handling
-
- It delegates responsibility to various other classes:
- - the various output sinks (instances of diagnostic_output_format
- subclasses)
- - formatting of messages (class pretty_printer)
- - an optional urlifier to inject URLs into formatted messages
- - counting the number of diagnostics reported of each kind
- (class diagnostic_counters)
- - calling out to a diagnostic_option_manager to determine if
- a particular warning is enabled or disabled
- - tracking pragmas that enable/disable warnings in a range of
- source code
- - a cache for use when quoting the user's source code (class file_cache)
- - a text_art::theme
- - an edit_context for generating patches from fix-it hints
- - diagnostic_client_data_hooks for metadata.
-
- Try to avoid adding new responsibilities to this class itself, to avoid
- the "blob" anti-pattern. */
-
-class diagnostic_context
-{
-public:
- /* Give access to m_text_callbacks. */
- friend diagnostic_text_starter_fn &
- diagnostic_text_starter (diagnostic_context *context);
- friend diagnostic_start_span_fn<to_text> &
- diagnostic_start_span (diagnostic_context *context);
- friend diagnostic_text_finalizer_fn &
- diagnostic_text_finalizer (diagnostic_context *context);
-
- friend class diagnostic_source_print_policy;
- friend class diagnostic_text_output_format;
- friend class diagnostic_buffer;
-
- typedef void (*set_locations_callback_t) (diagnostic_context *,
- diagnostic_info *);
-
- void initialize (int n_opts);
- void color_init (int value);
- void urls_init (int value);
- void set_pretty_printer (std::unique_ptr<pretty_printer> pp);
- void refresh_output_sinks ();
-
- void finish ();
-
- void dump (FILE *out) const;
- void DEBUG_FUNCTION dump () const { dump (stderr); }
-
- bool execution_failed_p () const;
-
- void set_original_argv (unique_argv original_argv);
- const char * const *get_original_argv ()
- {
- return const_cast<const char * const *> (m_original_argv);
- }
-
- void set_set_locations_callback (set_locations_callback_t cb)
- {
- m_set_locations_cb = cb;
- }
-
- void
- initialize_input_context (diagnostic_input_charset_callback ccb,
- bool should_skip_bom);
-
- void begin_group ();
- void end_group ();
-
- void push_nesting_level ();
- void pop_nesting_level ();
-
- bool warning_enabled_at (location_t loc, diagnostic_option_id option_id);
-
- bool option_unspecified_p (diagnostic_option_id option_id) const
- {
- return m_option_classifier.option_unspecified_p (option_id);
- }
-
- bool emit_diagnostic_with_group (diagnostic_t kind,
- rich_location &richloc,
- const diagnostic_metadata *metadata,
- diagnostic_option_id option_id,
- const char *gmsgid, ...)
- ATTRIBUTE_GCC_DIAG(6,7);
- bool emit_diagnostic_with_group_va (diagnostic_t kind,
- rich_location &richloc,
- const diagnostic_metadata *metadata,
- diagnostic_option_id option_id,
- const char *gmsgid, va_list *ap)
- ATTRIBUTE_GCC_DIAG(6,0);
-
- bool report_diagnostic (diagnostic_info *);
- void report_verbatim (text_info &);
-
- /* Report a directed graph associated with the run as a whole
- to any sinks that support directed graphs. */
- void
- report_global_digraph (const diagnostics::digraphs::lazy_digraph &);
-
- diagnostic_t
- classify_diagnostic (diagnostic_option_id option_id,
- diagnostic_t new_kind,
- location_t where)
- {
- return m_option_classifier.classify_diagnostic (this,
- option_id,
- new_kind,
- where);
- }
-
- void push_diagnostics (location_t where ATTRIBUTE_UNUSED)
- {
- m_option_classifier.push ();
- }
- void pop_diagnostics (location_t where)
- {
- m_option_classifier.pop (where);
- }
-
- void maybe_show_locus (const rich_location &richloc,
- const diagnostic_source_printing_options &opts,
- diagnostic_t diagnostic_kind,
- pretty_printer &pp,
- diagnostic_source_effect_info *effect_info);
- void maybe_show_locus_as_html (const rich_location &richloc,
- const diagnostic_source_printing_options &opts,
- diagnostic_t diagnostic_kind,
- xml::printer &xp,
- diagnostic_source_effect_info *effect_info,
- html_label_writer *label_writer);
-
- void emit_diagram (const diagnostic_diagram &diagram);
-
- /* Various setters for use by option-handling logic. */
- void set_output_format (std::unique_ptr<diagnostic_output_format> output_format);
- void set_text_art_charset (enum diagnostic_text_art_charset charset);
- void set_client_data_hooks (std::unique_ptr<diagnostic_client_data_hooks> hooks);
-
- void push_owned_urlifier (std::unique_ptr<urlifier>);
- void push_borrowed_urlifier (const urlifier &);
- void pop_urlifier ();
-
- void create_edit_context ();
- void set_warning_as_error_requested (bool val)
- {
- m_warning_as_error_requested = val;
- }
- void set_report_bug (bool val) { m_report_bug = val; }
- void set_extra_output_kind (enum diagnostics_extra_output_kind kind)
- {
- m_extra_output_kind = kind;
- }
- void set_show_cwe (bool val) { m_show_cwe = val; }
- void set_show_rules (bool val) { m_show_rules = val; }
- void set_show_highlight_colors (bool val);
- void set_path_format (enum diagnostic_path_format val)
- {
- m_path_format = val;
- }
- void set_show_path_depths (bool val) { m_show_path_depths = val; }
- void set_show_option_requested (bool val) { m_show_option_requested = val; }
- void set_max_errors (int val) { m_max_errors = val; }
- void set_escape_format (enum diagnostics_escape_format val)
- {
- m_escape_format = val;
- }
-
- void set_format_decoder (printer_fn format_decoder);
- void set_prefixing_rule (diagnostic_prefixing_rule_t rule);
-
- /* Various accessors. */
- bool warning_as_error_requested_p () const
- {
- return m_warning_as_error_requested;
- }
- bool show_path_depths_p () const { return m_show_path_depths; }
- diagnostic_output_format &get_output_format (size_t idx) const;
- enum diagnostic_path_format get_path_format () const { return m_path_format; }
- enum diagnostics_escape_format get_escape_format () const
- {
- return m_escape_format;
- }
-
- file_cache &
- get_file_cache () const
- {
- gcc_assert (m_file_cache);
- return *m_file_cache;
- }
-
- edit_context *get_edit_context () const
- {
- return m_edit_context_ptr;
- }
- const diagnostic_client_data_hooks *get_client_data_hooks () const
- {
- return m_client_data_hooks;
- }
-
- const logical_location_manager *
- get_logical_location_manager () const;
-
- const urlifier *get_urlifier () const;
-
- text_art::theme *get_diagram_theme () const { return m_diagrams.m_theme; }
-
- int &diagnostic_count (diagnostic_t kind)
- {
- return m_diagnostic_counters.m_count_for_kind[kind];
- }
- int diagnostic_count (diagnostic_t kind) const
- {
- return m_diagnostic_counters.get_count (kind);
- }
-
- /* Option-related member functions. */
- inline bool option_enabled_p (diagnostic_option_id option_id) const
- {
- if (!m_option_mgr)
- return true;
- return m_option_mgr->option_enabled_p (option_id);
- }
-
- inline char *make_option_name (diagnostic_option_id option_id,
- diagnostic_t orig_diag_kind,
- diagnostic_t diag_kind) const
- {
- if (!m_option_mgr)
- return nullptr;
- return m_option_mgr->make_option_name (option_id,
- orig_diag_kind,
- diag_kind);
- }
-
- inline char *make_option_url (diagnostic_option_id option_id) const
- {
- if (!m_option_mgr)
- return nullptr;
- return m_option_mgr->make_option_url (option_id);
- }
-
- void
- set_option_manager (std::unique_ptr<diagnostic_option_manager> mgr,
- unsigned lang_mask);
-
- unsigned get_lang_mask () const
- {
- return m_lang_mask;
- }
-
- bool diagnostic_impl (rich_location *, const diagnostic_metadata *,
- diagnostic_option_id, const char *,
- va_list *, diagnostic_t) ATTRIBUTE_GCC_DIAG(5,0);
- bool diagnostic_n_impl (rich_location *, const diagnostic_metadata *,
- diagnostic_option_id, unsigned HOST_WIDE_INT,
- const char *, const char *, va_list *,
- diagnostic_t) ATTRIBUTE_GCC_DIAG(7,0);
-
- int get_diagnostic_nesting_level () const
- {
- return m_diagnostic_groups.m_diagnostic_nesting_level;
- }
-
- char *build_indent_prefix () const;
-
- int
- pch_save (FILE *f)
- {
- return m_option_classifier.pch_save (f);
- }
-
- int
- pch_restore (FILE *f)
- {
- return m_option_classifier.pch_restore (f);
- }
-
-
- void set_diagnostic_buffer (diagnostic_buffer *);
- diagnostic_buffer *get_diagnostic_buffer () const
- {
- return m_diagnostic_buffer;
- }
- void clear_diagnostic_buffer (diagnostic_buffer &);
- void flush_diagnostic_buffer (diagnostic_buffer &);
-
- std::unique_ptr<pretty_printer> clone_printer () const
- {
- return m_reference_printer->clone ();
- }
-
- pretty_printer *get_reference_printer () const
- {
- return m_reference_printer;
- }
-
- void
- add_sink (std::unique_ptr<diagnostic_output_format>);
-
- void remove_all_output_sinks ();
-
- bool supports_fnotice_on_stderr_p () const;
-
- /* Raise SIGABRT on any diagnostic of severity DK_ERROR or higher. */
- void
- set_abort_on_error (bool val)
- {
- m_abort_on_error = val;
- }
-
- /* Accessor for use in serialization, e.g. by C++ modules. */
- auto &
- get_classification_history ()
- {
- return m_option_classifier.m_classification_history;
- }
-
- void set_main_input_filename (const char *filename);
-
- void
- set_permissive_option (diagnostic_option_id opt_permissive)
- {
- m_opt_permissive = opt_permissive;
- }
-
- void
- set_fatal_errors (bool fatal_errors)
- {
- m_fatal_errors = fatal_errors;
- }
-
- void
- set_internal_error_callback (void (*cb) (diagnostic_context *,
- const char *,
- va_list *))
- {
- m_internal_error = cb;
- }
-
- void
- set_adjust_diagnostic_info_callback (void (*cb) (diagnostic_context *,
- diagnostic_info *))
- {
- m_adjust_diagnostic_info = cb;
- }
-
- void
- inhibit_notes () { m_inhibit_notes_p = true; }
-
-private:
- void error_recursion () ATTRIBUTE_NORETURN;
-
- bool diagnostic_enabled (diagnostic_info *diagnostic);
-
- void get_any_inlining_info (diagnostic_info *diagnostic);
-
- void check_max_errors (bool flush);
- void action_after_output (diagnostic_t diag_kind);
-
- /* Data members.
- Ideally, all of these would be private. */
-
-private:
- /* A reference instance of pretty_printer created by the client
- and owned by the context. Used for cloning when creating/adding
- output formats.
- Owned by the context; this would be a std::unique_ptr if
- diagnostic_context had a proper ctor. */
- pretty_printer *m_reference_printer;
-
- /* Cache of source code.
- Owned by the context; this would be a std::unique_ptr if
- diagnostic_context had a proper ctor. */
- file_cache *m_file_cache;
-
- /* The number of times we have issued diagnostics. */
- diagnostic_counters m_diagnostic_counters;
-
- /* True if it has been requested that warnings be treated as errors. */
- bool m_warning_as_error_requested;
-
- /* The number of option indexes that can be passed to warning() et
- al. */
- int m_n_opts;
-
- /* The stack of sets of overridden diagnostic option severities. */
- diagnostic_option_classifier m_option_classifier;
-
- /* True if we should print any CWE identifiers associated with
- diagnostics. */
- bool m_show_cwe;
-
- /* True if we should print any rules associated with diagnostics. */
- bool m_show_rules;
-
- /* How should diagnostic_path objects be printed. */
- enum diagnostic_path_format m_path_format;
-
- /* True if we should print stack depths when printing diagnostic paths. */
- bool m_show_path_depths;
-
- /* True if we should print the command line option which controls
- each diagnostic, if known. */
- bool m_show_option_requested;
-
- /* True if we should raise a SIGABRT on errors. */
- bool m_abort_on_error;
-
-public:
- /* True if we should show the column number on diagnostics. */
- bool m_show_column;
-
- /* True if pedwarns are errors. */
- bool m_pedantic_errors;
-
- /* True if permerrors are warnings. */
- bool m_permissive;
-
-private:
- /* The option to associate with turning permerrors into warnings,
- if any. */
- diagnostic_option_id m_opt_permissive;
-
- /* True if errors are fatal. */
- bool m_fatal_errors;
-
-public:
- /* True if all warnings should be disabled. */
- bool m_inhibit_warnings;
-
- /* True if warnings should be given in system headers. */
- bool m_warn_system_headers;
-
-private:
- /* Maximum number of errors to report. */
- int m_max_errors;
-
- /* Client-supplied callbacks for use in text output. */
- struct {
- /* This function is called before any message is printed out. It is
- responsible for preparing message prefix and such. For example, it
- might say:
- In file included from "/usr/local/include/curses.h:5:
- from "/home/gdr/src/nifty_printer.h:56:
- ...
- */
- diagnostic_text_starter_fn m_begin_diagnostic;
-
- /* This function is called by diagnostic_show_locus in between
- disjoint spans of source code, so that the context can print
- something to indicate that a new span of source code has begun. */
- diagnostic_start_span_fn<to_text> m_text_start_span;
- diagnostic_start_span_fn<to_html> m_html_start_span;
-
- /* This function is called after the diagnostic message is printed. */
- diagnostic_text_finalizer_fn m_end_diagnostic;
- } m_text_callbacks;
-
- /* Client hook to report an internal error. */
- void (*m_internal_error) (diagnostic_context *, const char *, va_list *);
-
- /* Client hook to adjust properties of the given diagnostic that we're
- about to issue, such as its kind. */
- void (*m_adjust_diagnostic_info)(diagnostic_context *, diagnostic_info *);
-
- /* Owned by the context; this would be a std::unique_ptr if
- diagnostic_context had a proper ctor. */
- diagnostic_option_manager *m_option_mgr;
- unsigned m_lang_mask;
-
- /* A stack of optional hooks for adding URLs to quoted text strings in
- diagnostics. Only used for the main diagnostic message.
- Typically a single one owner by the context, but can be temporarily
- overridden by a borrowed urlifier (e.g. on-stack). */
- struct urlifier_stack_node
- {
- urlifier *m_urlifier;
- bool m_owned;
- };
- auto_vec<urlifier_stack_node> *m_urlifier_stack;
-
-public:
- /* Auxiliary data for client. */
- void *m_client_aux_data;
-
- /* Used to detect that the last caret was printed at the same location. */
- location_t m_last_location;
-
-private:
- int m_lock;
-
- bool m_inhibit_notes_p;
-
-public:
- diagnostic_source_printing_options m_source_printing;
-
-private:
- /* True if -freport-bug option is used. */
- bool m_report_bug;
-
- /* Used to specify additional diagnostic output to be emitted after the
- rest of the diagnostic. This is for implementing
- -fdiagnostics-parseable-fixits and GCC_EXTRA_DIAGNOSTIC_OUTPUT. */
- enum diagnostics_extra_output_kind m_extra_output_kind;
-
-public:
- /* What units to use when outputting the column number. */
- enum diagnostics_column_unit m_column_unit;
-
- /* The origin for the column number (1-based or 0-based typically). */
- int m_column_origin;
-
- /* The size of the tabstop for tab expansion. */
- int m_tabstop;
-
-private:
- /* How should non-ASCII/non-printable bytes be escaped when
- a diagnostic suggests escaping the source code on output. */
- enum diagnostics_escape_format m_escape_format;
-
- /* If non-NULL, an edit_context to which fix-it hints should be
- applied, for generating patches.
- Owned by the context; this would be a std::unique_ptr if
- diagnostic_context had a proper ctor. */
- edit_context *m_edit_context_ptr;
-
- /* Fields relating to diagnostic groups. */
- struct {
- /* How many diagnostic_group instances are currently alive. */
- int m_group_nesting_depth;
-
- /* How many nesting levels have been pushed within this group. */
- int m_diagnostic_nesting_level;
-
- /* How many diagnostics have been emitted since the bottommost
- diagnostic_group was pushed. */
- int m_emission_count;
-
- /* The "group+diagnostic" nesting depth from which to inhibit notes. */
- int m_inhibiting_notes_from;
- } m_diagnostic_groups;
-
- void inhibit_notes_in_group (bool inhibit = true);
- bool notes_inhibited_in_group () const;
-
- /* The various sinks to which diagnostics are to be outputted
- (text vs structured formats such as SARIF).
- The sinks are owned by the context; this would be a
- std::vector<std::unique_ptr> if diagnostic_context had a
- proper ctor. */
- auto_vec<diagnostic_output_format *> m_output_sinks;
-
- /* Callback to set the locations of call sites along the inlining
- stack corresponding to a diagnostic location. Needed to traverse
- the BLOCK_SUPERCONTEXT() chain hanging off the LOCATION_BLOCK()
- of a diagnostic's location. */
- set_locations_callback_t m_set_locations_cb;
-
- /* A bundle of hooks for providing data to the context about its client
- e.g. version information, plugins, etc.
- Used by SARIF output to give metadata about the client that's
- producing diagnostics.
- Owned by the context; this would be a std::unique_ptr if
- diagnostic_context had a proper ctor. */
- diagnostic_client_data_hooks *m_client_data_hooks;
-
- /* Support for diagrams. */
- struct
- {
- /* Theme to use when generating diagrams.
- Can be NULL (if text art is disabled).
- Owned by the context; this would be a std::unique_ptr if
- diagnostic_context had a proper ctor. */
- text_art::theme *m_theme;
-
- } m_diagrams;
-
- /* Owned by the context. */
- char **m_original_argv;
-
- /* Borrowed pointer to the active diagnostic_buffer, if any.
- If null (the default), then diagnostics that are reported to the
- context are immediately issued to the output format.
- If non-null, then diagnostics that are reported to the context
- are buffered in the buffer, and may be issued to the output format
- later (if the buffer is flushed), moved to other buffers, or
- discarded (if the buffer is cleared). */
- diagnostic_buffer *m_diagnostic_buffer;
-};
-
-/* Client supplied function to announce a diagnostic
- (for text-based diagnostic output). */
-inline diagnostic_text_starter_fn &
-diagnostic_text_starter (diagnostic_context *context)
-{
- return context->m_text_callbacks.m_begin_diagnostic;
-}
-
-/* Client supplied function called between disjoint spans of source code,
- so that the context can print
- something to indicate that a new span of source code has begun. */
-inline diagnostic_start_span_fn<to_text> &
-diagnostic_start_span (diagnostic_context *context)
-{
- return context->m_text_callbacks.m_text_start_span;
-}
-
-/* Client supplied function called after a diagnostic message is
- displayed (for text-based diagnostic output). */
-inline diagnostic_text_finalizer_fn &
-diagnostic_text_finalizer (diagnostic_context *context)
-{
- return context->m_text_callbacks.m_end_diagnostic;
-}
+#include "diagnostics/diagnostic-info.h"
+#include "diagnostics/context.h"
/* Extension hooks for client. */
#define diagnostic_context_auxiliary_data(DC) (DC)->m_client_aux_data
-#define diagnostic_info_auxiliary_data(DI) (DI)->x_data
+#define diagnostic_info_auxiliary_data(DI) (DI)->m_x_data
-/* This diagnostic_context is used by front-ends that directly output
+/* This diagnostics::context is used by front-ends that directly output
diagnostic messages without going through `error', `warning',
and similar functions. */
-extern diagnostic_context *global_dc;
+extern diagnostics::context *global_dc;
/* The number of errors that have been issued so far. Ideally, these
- would take a diagnostic_context as an argument. */
-#define errorcount global_dc->diagnostic_count (DK_ERROR)
+ would take a diagnostics::context as an argument. */
+#define errorcount global_dc->diagnostic_count (diagnostics::kind::error)
/* Similarly, but for warnings. */
-#define warningcount global_dc->diagnostic_count (DK_WARNING)
+#define warningcount global_dc->diagnostic_count (diagnostics::kind::warning)
/* Similarly, but for warnings promoted to errors. */
-#define werrorcount global_dc->diagnostic_count (DK_WERROR)
+#define werrorcount global_dc->diagnostic_count (diagnostics::kind::werror)
/* Similarly, but for sorrys. */
-#define sorrycount global_dc->diagnostic_count (DK_SORRY)
+#define sorrycount global_dc->diagnostic_count (diagnostics::kind::sorry)
/* Returns nonzero if warnings should be emitted. */
#define diagnostic_report_warnings_p(DC, LOC) \
@@ -1171,45 +56,45 @@ extern diagnostic_context *global_dc;
diagnostic. */
inline void
-diagnostic_set_option_id (diagnostic_info *info,
- diagnostic_option_id option_id)
+diagnostic_set_option_id (diagnostics::diagnostic_info *info,
+ diagnostics::option_id opt_id)
{
- info->option_id = option_id;
+ info->m_option_id = opt_id;
}
/* Diagnostic related functions. */
inline void
-diagnostic_initialize (diagnostic_context *context, int n_opts)
+diagnostic_initialize (diagnostics::context *context, int n_opts)
{
context->initialize (n_opts);
}
inline void
-diagnostic_color_init (diagnostic_context *context, int value = -1)
+diagnostic_color_init (diagnostics::context *context, int value = -1)
{
context->color_init (value);
}
inline void
-diagnostic_urls_init (diagnostic_context *context, int value = -1)
+diagnostic_urls_init (diagnostics::context *context, int value = -1)
{
context->urls_init (value);
}
inline void
-diagnostic_finish (diagnostic_context *context)
+diagnostic_finish (diagnostics::context *context)
{
context->finish ();
}
inline void
-diagnostic_show_locus (diagnostic_context *context,
- const diagnostic_source_printing_options &opts,
+diagnostic_show_locus (diagnostics::context *context,
+ const diagnostics::source_printing_options &opts,
rich_location *richloc,
- diagnostic_t diagnostic_kind,
+ enum diagnostics::kind diagnostic_kind,
pretty_printer *pp,
- diagnostic_source_effect_info *effect_info = nullptr)
+ diagnostics::source_effect_info *effect_info = nullptr)
{
gcc_assert (context);
gcc_assert (richloc);
@@ -1218,13 +103,13 @@ diagnostic_show_locus (diagnostic_context *context,
}
inline void
-diagnostic_show_locus_as_html (diagnostic_context *context,
- const diagnostic_source_printing_options &opts,
+diagnostic_show_locus_as_html (diagnostics::context *context,
+ const diagnostics::source_printing_options &opts,
rich_location *richloc,
- diagnostic_t diagnostic_kind,
+ enum diagnostics::kind diagnostic_kind,
xml::printer &xp,
- diagnostic_source_effect_info *effect_info = nullptr,
- html_label_writer *label_writer = nullptr)
+ diagnostics::source_effect_info *effect_info = nullptr,
+ diagnostics::html_label_writer *label_writer = nullptr)
{
gcc_assert (context);
gcc_assert (richloc);
@@ -1248,7 +133,7 @@ diagnostic_show_locus_as_html (diagnostic_context *context,
rather skipped as part of the conversion process.) */
inline void
-diagnostic_initialize_input_context (diagnostic_context *context,
+diagnostic_initialize_input_context (diagnostics::context *context,
diagnostic_input_charset_callback ccb,
bool should_skip_bom)
{
@@ -1256,23 +141,23 @@ diagnostic_initialize_input_context (diagnostic_context *context,
}
/* Force diagnostics controlled by OPTIDX to be kind KIND. */
-inline diagnostic_t
-diagnostic_classify_diagnostic (diagnostic_context *context,
- diagnostic_option_id option_id,
- diagnostic_t kind,
+inline diagnostics::kind
+diagnostic_classify_diagnostic (diagnostics::context *context,
+ diagnostics::option_id opt_id,
+ enum diagnostics::kind kind,
location_t where)
{
- return context->classify_diagnostic (option_id, kind, where);
+ return context->classify_diagnostic (opt_id, kind, where);
}
inline void
-diagnostic_push_diagnostics (diagnostic_context *context,
+diagnostic_push_diagnostics (diagnostics::context *context,
location_t where)
{
context->push_diagnostics (where);
}
inline void
-diagnostic_pop_diagnostics (diagnostic_context *context,
+diagnostic_pop_diagnostics (diagnostics::context *context,
location_t where)
{
context->pop_diagnostics (where);
@@ -1286,8 +171,8 @@ diagnostic_pop_diagnostics (diagnostic_context *context,
Return true if a diagnostic was printed, false otherwise. */
inline bool
-diagnostic_report_diagnostic (diagnostic_context *context,
- diagnostic_info *diagnostic)
+diagnostic_report_diagnostic (diagnostics::context *context,
+ diagnostics::diagnostic_info *diagnostic)
{
context->begin_group ();
bool warned = context->report_diagnostic (diagnostic);
@@ -1296,23 +181,30 @@ diagnostic_report_diagnostic (diagnostic_context *context,
}
#ifdef ATTRIBUTE_GCC_DIAG
-extern void diagnostic_set_info (diagnostic_info *, const char *, va_list *,
- rich_location *, diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0);
-extern void diagnostic_set_info_translated (diagnostic_info *, const char *,
- va_list *, rich_location *,
- diagnostic_t)
+extern void diagnostic_set_info (diagnostics::diagnostic_info *,
+ const char *, va_list *,
+ rich_location *,
+ enum diagnostics::kind)
+ ATTRIBUTE_GCC_DIAG(2,0);
+extern void diagnostic_set_info_translated (diagnostics::diagnostic_info *,
+ const char *, va_list *,
+ rich_location *,
+ enum diagnostics::kind)
ATTRIBUTE_GCC_DIAG(2,0);
#endif
-void default_diagnostic_text_starter (diagnostic_text_output_format &,
- const diagnostic_info *);
-template <typename Sink>
-void default_diagnostic_start_span_fn (const diagnostic_location_print_policy &,
- Sink &sink,
- expanded_location);
-void default_diagnostic_text_finalizer (diagnostic_text_output_format &,
- const diagnostic_info *,
- diagnostic_t);
-void diagnostic_set_caret_max_width (diagnostic_context *context, int value);
+
+namespace diagnostics {
+
+void default_text_starter (diagnostics::text_sink &,
+ const diagnostics::diagnostic_info *);
+template <typename TextOrHtml>
+void default_start_span_fn (const diagnostics::location_print_policy &,
+ TextOrHtml &text_or_html,
+ expanded_location);
+void default_text_finalizer (diagnostics::text_sink &,
+ const diagnostics::diagnostic_info *,
+ enum diagnostics::kind);
+} // namespace diagnostics
int get_terminal_width (void);
@@ -1320,17 +212,18 @@ int get_terminal_width (void);
specifies which location. By default, expand the first one. */
inline location_t
-diagnostic_location (const diagnostic_info * diagnostic, int which = 0)
+diagnostic_location (const diagnostics::diagnostic_info *diagnostic,
+ int which = 0)
{
- return diagnostic->message.get_location (which);
+ return diagnostic->m_message.get_location (which);
}
/* Return the number of locations to be printed in DIAGNOSTIC. */
inline unsigned int
-diagnostic_num_locations (const diagnostic_info * diagnostic)
+diagnostic_num_locations (const diagnostics::diagnostic_info *diagnostic)
{
- return diagnostic->message.m_richloc->get_num_locations ();
+ return diagnostic->m_message.m_richloc->get_num_locations ();
}
/* Expand the location of this diagnostic. Use this function for
@@ -1338,9 +231,10 @@ diagnostic_num_locations (const diagnostic_info * diagnostic)
expand the first one. */
inline expanded_location
-diagnostic_expand_location (const diagnostic_info * diagnostic, int which = 0)
+diagnostic_expand_location (const diagnostics::diagnostic_info *diagnostic,
+ int which = 0)
{
- return diagnostic->richloc->get_expanded_location (which);
+ return diagnostic->m_richloc->get_expanded_location (which);
}
/* This is somehow the right-side margin of a caret line, that is, we
@@ -1353,39 +247,39 @@ const int CARET_LINE_MARGIN = 10;
whether to print one or two caret lines. */
inline bool
-diagnostic_same_line (const diagnostic_context *context,
- expanded_location s1, expanded_location s2)
+diagnostic_same_line (const diagnostics::context *context,
+ expanded_location s1, expanded_location s2)
{
return (s2.column && s1.line == s2.line
- && (context->m_source_printing.max_width - CARET_LINE_MARGIN
+ && ((context->get_source_printing_options ().max_width
+ - CARET_LINE_MARGIN)
> abs (s1.column - s2.column)));
}
-extern const char *diagnostic_get_color_for_kind (diagnostic_t kind);
-
/* Pure text formatting support functions. */
extern char *build_message_string (const char *, ...) ATTRIBUTE_PRINTF_1;
-/* Compute the number of digits in the decimal representation of an integer. */
-extern int num_digits (int);
-
inline bool
-warning_enabled_at (location_t loc, diagnostic_option_id option_id)
+warning_enabled_at (location_t loc, diagnostics::option_id opt_id)
{
- return global_dc->warning_enabled_at (loc, option_id);
+ return global_dc->warning_enabled_at (loc, opt_id);
}
inline bool
-option_unspecified_p (diagnostic_option_id option_id)
+option_unspecified_p (diagnostics::option_id opt_id)
{
- return global_dc->option_unspecified_p (option_id);
+ return global_dc->option_unspecified_p (opt_id);
}
-extern char *get_cwe_url (int cwe);
+namespace diagnostics {
+
+/* Compute the number of digits in the decimal representation of an integer. */
+extern int num_digits (int);
-extern const char *get_diagnostic_kind_text (diagnostic_t kind);
+extern char *get_cwe_url (int cwe);
+extern const char *maybe_line_and_column (int line, int col);
-const char *maybe_line_and_column (int line, int col);
+} // namespace diagnostics
#endif /* ! GCC_DIAGNOSTIC_H */
diff --git a/gcc/diagnostics/buffering.cc b/gcc/diagnostics/buffering.cc
new file mode 100644
index 0000000..29f039f
--- /dev/null
+++ b/gcc/diagnostics/buffering.cc
@@ -0,0 +1,199 @@
+/* Support for buffering diagnostics before flushing them to output sinks.
+ Copyright (C) 2024-2025 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"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic.h"
+#include "diagnostics/buffering.h"
+#include "diagnostics/sink.h"
+
+namespace diagnostics {
+
+/* Methods fns of diagnostics::context relating to buffering. */
+
+/* If BUFFER_ is non-null, use BUFFER as the active diagnostics::buffer on
+ this context. BUFFER is borrowed.
+
+ If BUFFER_ is null, stop any buffering on this context until the next call
+ to this function. */
+
+void
+context::set_diagnostic_buffer (buffer *buffer_)
+{
+ /* We don't allow changing buffering within a diagnostic group
+ (to simplify handling of buffered diagnostics within the
+ diagnostic_format implementations). */
+ gcc_assert (m_diagnostic_groups.m_group_nesting_depth == 0);
+
+ /* Likewise, for simplicity, we only allow changing buffers
+ at nesting level 0. */
+ gcc_assert (m_diagnostic_groups.m_diagnostic_nesting_level == 0);
+
+ m_diagnostic_buffer = buffer_;
+
+ if (buffer_)
+ {
+ buffer_->ensure_per_sink_buffers ();
+ gcc_assert (buffer_->m_per_sink_buffers);
+ gcc_assert (buffer_->m_per_sink_buffers->length ()
+ == m_sinks.length ());
+ for (unsigned idx = 0; idx < m_sinks.length (); ++idx)
+ {
+ auto sink_ = m_sinks[idx];
+ auto per_sink_buffer = (*buffer_->m_per_sink_buffers)[idx];
+ sink_->set_buffer (per_sink_buffer);
+ }
+ }
+ else
+ for (auto sink_ : m_sinks)
+ sink_->set_buffer (nullptr);
+}
+
+/* Clear BUFFER_ without flushing it. */
+
+void
+context::clear_diagnostic_buffer (buffer &buffer_)
+{
+ if (buffer_.m_per_sink_buffers)
+ for (auto per_sink_buffer_ : *buffer_.m_per_sink_buffers)
+ per_sink_buffer_->clear ();
+
+ buffer_.m_diagnostic_counters.clear ();
+
+ /* We need to reset last_location, otherwise we may skip caret lines
+ when we actually give a diagnostic. */
+ m_last_location = UNKNOWN_LOCATION;
+}
+
+/* Flush the diagnostics in BUFFER_ to this context, clearing BUFFER_. */
+
+void
+context::flush_diagnostic_buffer (buffer &buffer_)
+{
+ bool had_errors
+ = (buffer_.diagnostic_count (kind::error) > 0
+ || buffer_.diagnostic_count (kind::werror) > 0);
+ if (buffer_.m_per_sink_buffers)
+ for (auto per_sink_buffer_ : *buffer_.m_per_sink_buffers)
+ per_sink_buffer_->flush ();
+ buffer_.m_diagnostic_counters.move_to (m_diagnostic_counters);
+
+ action_after_output (had_errors ? kind::error : kind::warning);
+ check_max_errors (true);
+}
+
+/* class diagnostics::buffer. */
+
+buffer::buffer (context &ctxt)
+: m_ctxt (ctxt),
+ m_per_sink_buffers (nullptr)
+{
+}
+
+buffer::~buffer ()
+{
+ if (m_per_sink_buffers)
+ {
+ for (auto iter : *m_per_sink_buffers)
+ delete iter;
+ delete m_per_sink_buffers;
+ }
+}
+
+void
+buffer::dump (FILE *out, int indent) const
+{
+ m_diagnostic_counters.dump (out, indent + 2);
+ fprintf (out, "%*sm_per_sink_buffers:\n", indent, "");
+ if (m_per_sink_buffers)
+ for (auto per_sink_buffer_ : *m_per_sink_buffers)
+ per_sink_buffer_->dump (out, indent + 2);
+ else
+ fprintf (out, "%*s(none)\n", indent + 2, "");
+}
+
+bool
+buffer::empty_p () const
+{
+ if (m_per_sink_buffers)
+ for (auto per_sink_buffer_ : *m_per_sink_buffers)
+ /* Query initial buffer. */
+ return per_sink_buffer_->empty_p ();
+ return true;
+}
+
+void
+buffer::move_to (buffer &dest)
+{
+ /* Bail if there's nothing to move. */
+ if (!m_per_sink_buffers)
+ return;
+
+ m_diagnostic_counters.move_to (dest.m_diagnostic_counters);
+
+ if (!dest.m_per_sink_buffers)
+ {
+ /* Optimization for the "move to empty" case:
+ simply move the vec to the dest. */
+ dest.m_per_sink_buffers = m_per_sink_buffers;
+ m_per_sink_buffers = nullptr;
+ return;
+ }
+
+ dest.ensure_per_sink_buffers ();
+ gcc_assert (m_per_sink_buffers);
+ gcc_assert (m_per_sink_buffers->length ()
+ == m_ctxt.m_sinks.length ());
+ gcc_assert (dest.m_per_sink_buffers);
+ gcc_assert (dest.m_per_sink_buffers->length ()
+ == m_ctxt.m_sinks.length ());
+ for (unsigned idx = 0; idx < m_ctxt.m_sinks.length (); ++idx)
+ {
+ auto per_sink_buffer_src = (*m_per_sink_buffers)[idx];
+ auto per_sink_buffer_dest = (*dest.m_per_sink_buffers)[idx];
+ per_sink_buffer_src->move_to (*per_sink_buffer_dest);
+ }
+}
+
+/* Lazily get the output formats to create their own kind of buffers.
+ We can't change the output sinks on a context once this has been called
+ on any diagnostics::buffer instances for that context, since there's no
+ way to update all diagnostics::buffer instances for that context. */
+
+void
+buffer::ensure_per_sink_buffers ()
+{
+ if (!m_per_sink_buffers)
+ {
+ m_per_sink_buffers = new auto_vec<per_sink_buffer *> ();
+ for (unsigned idx = 0; idx < m_ctxt.m_sinks.length (); ++idx)
+ {
+ auto sink_ = m_ctxt.m_sinks[idx];
+ auto per_sink_buffer = sink_->make_per_sink_buffer ();
+ m_per_sink_buffers->safe_push (per_sink_buffer.release ());
+ }
+ }
+ gcc_assert (m_per_sink_buffers);
+ gcc_assert (m_per_sink_buffers->length ()
+ == m_ctxt.m_sinks.length ());
+}
+
+} // namespace diagnostics
diff --git a/gcc/diagnostic-buffer.h b/gcc/diagnostics/buffering.h
index e766a3b..c3ac070 100644
--- a/gcc/diagnostic-buffer.h
+++ b/gcc/diagnostics/buffering.h
@@ -1,4 +1,4 @@
-/* Support for buffering diagnostics before flushing them to output format.
+/* Support for buffering diagnostics before flushing them to output sinks.
Copyright (C) 2024-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -18,26 +18,28 @@ 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_DIAGNOSTIC_BUFFER_H
-#define GCC_DIAGNOSTIC_BUFFER_H
+#ifndef GCC_DIAGNOSTICS_BUFFERING_H
+#define GCC_DIAGNOSTICS_BUFFERING_H
#include "diagnostic.h"
-class diagnostic_per_format_buffer;
-class diagnostic_output_format;
- class diagnostic_text_output_format;
+namespace diagnostics {
+
+class per_sink_buffer;
+class sink;
+ class text_sink;
/* Class representing a buffer of zero or more diagnostics that
- have been reported to a diagnostic_context, but which haven't
+ have been reported to a diagnostics::context, but which haven't
yet been flushed.
- A diagnostic_buffer can be:
+ A diagnostics::buffer can be:
- * flushed to the diagnostic_context, which issues
+ * flushed to the diagnostics::context, which issues
the diagnostics within the buffer to the output format
and checks for limits such as -fmax-errors=, or
- * moved to another diagnostic_buffer, which moves the diagnostics
+ * moved to another diagnostics::buffer, which moves the diagnostics
within the first buffer to the other buffer, appending them after any
existing diagnostics within the destination buffer, emptying the
source buffer, or
@@ -47,63 +49,65 @@ class diagnostic_output_format;
Since a buffer needs to contain output-format-specific data,
it's not possible to change the output format of the
- diagnostic_context once any buffers are non-empty.
+ diagnostics::context once any buffers are non-empty.
To simplify implementing output formats, it's not possible
- to change buffering on a diagnostic_context whilst within a
+ to change buffering on a diagnostics::context whilst within a
diagnostic group. */
-class diagnostic_buffer
+class buffer
{
public:
- friend class diagnostic_context;
+ friend class context;
- diagnostic_buffer (diagnostic_context &ctxt);
- ~diagnostic_buffer ();
+ buffer (context &ctxt);
+ ~buffer ();
void dump (FILE *out, int indent) const;
void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
- int diagnostic_count (diagnostic_t kind) const
+ int diagnostic_count (enum kind kind) const
{
return m_diagnostic_counters.get_count (kind);
}
bool empty_p () const;
- void move_to (diagnostic_buffer &dest);
+ void move_to (buffer &dest);
private:
- void ensure_per_format_buffers ();
+ void ensure_per_sink_buffers ();
- diagnostic_context &m_ctxt;
- auto_vec<diagnostic_per_format_buffer *> *m_per_format_buffers;
+ context &m_ctxt;
+ auto_vec<per_sink_buffer *> *m_per_sink_buffers;
/* The number of buffered diagnostics of each kind. */
- diagnostic_counters m_diagnostic_counters;
+ counters m_diagnostic_counters;
};
-/* Implementation detail of diagnostic_buffer.
+/* Implementation detail of diagnostics::buffer.
Abstract base class describing how to represent zero of more
- buffered diagnostics for a particular diagnostic_output_format
+ buffered diagnostics for a particular diagnostics::sink
(e.g. text vs SARIF).
- Each diagnostic_output_format subclass should implement its own
- subclass for handling diagnostic_buffer. */
+ Each diagnostics::sink subclass should implement its own
+ subclass for handling diagnostics::buffer. */
-class diagnostic_per_format_buffer
+class per_sink_buffer
{
public:
- virtual ~diagnostic_per_format_buffer () {}
+ virtual ~per_sink_buffer () {}
virtual void dump (FILE *out, int indent) const = 0;
void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
virtual bool empty_p () const = 0;
- virtual void move_to (diagnostic_per_format_buffer &dest) = 0;
+ virtual void move_to (per_sink_buffer &dest) = 0;
virtual void clear () = 0;
virtual void flush () = 0;
};
-#endif /* ! GCC_DIAGNOSTIC_BUFFER_H */
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_BUFFERING_H */
diff --git a/gcc/edit-context.cc b/gcc/diagnostics/changes.cc
index c767394..290d602 100644
--- a/gcc/edit-context.cc
+++ b/gcc/diagnostics/changes.cc
@@ -21,14 +21,18 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "line-map.h"
-#include "edit-context.h"
+#include "diagnostics/changes.h"
#include "pretty-print.h"
-#include "diagnostic-color.h"
+#include "diagnostics/color.h"
+#include "diagnostics/file-cache.h"
#include "selftest.h"
+namespace diagnostics {
+namespace changes {
+
/* This file implements a way to track the effect of fix-its,
- via a class edit_context; the other classes are support classes for
- edit_context.
+ via a class change_set; the other classes are support classes for
+ change_set.
A complication here is that fix-its are expressed relative to coordinates
in the file when it was parsed, before any changes have been made, and
@@ -36,14 +40,14 @@ along with GCC; see the file COPYING3. If not see
later fix-its to allow for the changes made by earlier ones. This
is done by the various "get_effective_column" methods.
- The "filename" params are required to outlive the edit_context (no
+ The "filename" params are required to outlive the change_set (no
copy of the underlying str is taken, just the ptr). */
-/* Forward decls. class edit_context is declared within edit-context.h.
+/* Forward decls. class change_set is declared within changes.h.
The other types are declared here. */
-class edit_context;
-class edited_file;
-class edited_line;
+class change_set;
+class changed_file;
+class changed_line;
class line_event;
/* A struct to hold the params of a print_diff call. */
@@ -58,14 +62,14 @@ public:
bool m_show_filenames;
};
-/* The state of one named file within an edit_context: the filename,
+/* The state of one named file within an change_set: the filename,
and the lines that have been edited so far. */
-class edited_file
+class changed_file
{
public:
- edited_file (edit_context &ec, const char *filename);
- static void delete_cb (edited_file *file);
+ changed_file (change_set &ec, const char *filename);
+ static void delete_cb (changed_file *file);
const char *get_filename () const { return m_filename; }
char *get_content ();
@@ -76,7 +80,7 @@ class edited_file
int replacement_len);
int get_effective_column (int line, int column);
- static int call_print_diff (const char *, edited_file *file,
+ static int call_print_diff (const char *, changed_file *file,
void *user_data)
{
diff *d = (diff *)user_data;
@@ -86,7 +90,7 @@ class edited_file
file_cache &get_file_cache () const
{
- return m_edit_context.get_file_cache ();
+ return m_change_set.get_file_cache ();
}
private:
@@ -94,8 +98,8 @@ class edited_file
void print_diff (pretty_printer *pp, bool show_filenames);
int print_diff_hunk (pretty_printer *pp, int old_start_of_hunk,
int old_end_of_hunk, int new_start_of_hunk);
- edited_line *get_line (int line);
- edited_line *get_or_insert_line (int line);
+ changed_line *get_line (int line);
+ changed_line *get_or_insert_line (int line);
int get_num_lines (bool *missing_trailing_newline);
int get_effective_line_count (int old_start_of_hunk,
@@ -105,13 +109,13 @@ class edited_file
int start_of_run,
int end_of_run);
- edit_context &m_edit_context;
+ change_set &m_change_set;
const char *m_filename;
- typed_splay_tree<int, edited_line *> m_edited_lines;
+ typed_splay_tree<int, changed_line *> m_changed_lines;
int m_num_lines;
};
-/* A line added before an edited_line. */
+/* A line added before an changed_line. */
class added_line
{
@@ -154,24 +158,24 @@ class line_event
int m_delta;
};
-/* The state of one edited line within an edited_file.
+/* The state of one edited line within an changed_file.
As well as the current content of the line, it contains a record of
the changes, so that further changes can be applied in the correct
place.
When handling fix-it hints containing newlines, new lines are added
- as added_line predecessors to an edited_line. Hence it's possible
- for an "edited_line" to not actually have been changed, but to merely
+ as added_line predecessors to an changed_line. Hence it's possible
+ for an "changed_line" to not actually have been changed, but to merely
be a placeholder for the lines added before it. This can be tested
for with actuall_edited_p, and has a slight effect on how diff hunks
are generated. */
-class edited_line
+class changed_line
{
public:
- edited_line (file_cache &fc, const char *filename, int line_num);
- ~edited_line ();
- static void delete_cb (edited_line *el);
+ changed_line (file_cache &fc, const char *filename, int line_num);
+ ~changed_line ();
+ static void delete_cb (changed_line *el);
int get_line_num () const { return m_line_num; }
const char *get_content () const { return m_content; }
@@ -210,21 +214,21 @@ static void
print_diff_line (pretty_printer *pp, char prefix_char,
const char *line, int line_size);
-/* Implementation of class edit_context. */
+/* Implementation of class change_set. */
-/* edit_context's ctor. */
+/* change_set's ctor. */
-edit_context::edit_context (file_cache &fc)
+change_set::change_set (file_cache &fc)
: m_file_cache (fc),
m_valid (true),
- m_files (strcmp, NULL, edited_file::delete_cb)
+ m_files (strcmp, NULL, changed_file::delete_cb)
{}
/* Add any fixits within RICHLOC to this context, recording the
changes that they make. */
void
-edit_context::add_fixits (rich_location *richloc)
+change_set::add_fixits (rich_location *richloc)
{
if (!m_valid)
return;
@@ -242,15 +246,15 @@ edit_context::add_fixits (rich_location *richloc)
}
/* Get the content of the given file, with fix-its applied.
- If any errors occurred in this edit_context, return NULL.
+ If any errors occurred in this change_set, return NULL.
The ptr should be freed by the caller. */
char *
-edit_context::get_content (const char *filename)
+change_set::get_content (const char *filename)
{
if (!m_valid)
return NULL;
- edited_file &file = get_or_insert_file (filename);
+ changed_file &file = get_or_insert_file (filename);
return file.get_content ();
}
@@ -258,10 +262,10 @@ edit_context::get_content (const char *filename)
This method is for the selftests. */
int
-edit_context::get_effective_column (const char *filename, int line,
+change_set::get_effective_column (const char *filename, int line,
int column)
{
- edited_file *file = get_file (filename);
+ changed_file *file = get_file (filename);
if (!file)
return column;
return file->get_effective_column (line, column);
@@ -269,10 +273,10 @@ edit_context::get_effective_column (const char *filename, int line,
/* Generate a unified diff. The resulting string should be freed by the
caller. Primarily for selftests.
- If any errors occurred in this edit_context, return NULL. */
+ If any errors occurred in this change_set, return NULL. */
char *
-edit_context::generate_diff (bool show_filenames)
+change_set::generate_diff (bool show_filenames)
{
if (!m_valid)
return NULL;
@@ -286,19 +290,19 @@ edit_context::generate_diff (bool show_filenames)
context. */
void
-edit_context::print_diff (pretty_printer *pp, bool show_filenames)
+change_set::print_diff (pretty_printer *pp, bool show_filenames)
{
if (!m_valid)
return;
diff d (pp, show_filenames);
- m_files.foreach (edited_file::call_print_diff, &d);
+ m_files.foreach (changed_file::call_print_diff, &d);
}
/* Attempt to apply the given fixit. Return true if it can be
applied, or false otherwise. */
bool
-edit_context::apply_fixit (const fixit_hint *hint)
+change_set::apply_fixit (const fixit_hint *hint)
{
expanded_location start = expand_location (hint->get_start_loc ());
expanded_location next_loc = expand_location (hint->get_next_loc ());
@@ -311,7 +315,7 @@ edit_context::apply_fixit (const fixit_hint *hint)
if (next_loc.column == 0)
return false;
- edited_file &file = get_or_insert_file (start.file);
+ changed_file &file = get_or_insert_file (start.file);
if (!m_valid)
return false;
return file.apply_fixit (start.line, start.column, next_loc.column,
@@ -319,57 +323,57 @@ edit_context::apply_fixit (const fixit_hint *hint)
hint->get_length ());
}
-/* Locate the edited_file * for FILENAME, if any
+/* Locate the changed_file * for FILENAME, if any
Return NULL if there isn't one. */
-edited_file *
-edit_context::get_file (const char *filename)
+changed_file *
+change_set::get_file (const char *filename)
{
gcc_assert (filename);
return m_files.lookup (filename);
}
-/* Locate the edited_file for FILENAME, adding one if there isn't one. */
+/* Locate the changed_file for FILENAME, adding one if there isn't one. */
-edited_file &
-edit_context::get_or_insert_file (const char *filename)
+changed_file &
+change_set::get_or_insert_file (const char *filename)
{
gcc_assert (filename);
- edited_file *file = get_file (filename);
+ changed_file *file = get_file (filename);
if (file)
return *file;
/* Not found. */
- file = new edited_file (*this, filename);
+ file = new changed_file (*this, filename);
m_files.insert (filename, file);
return *file;
}
-/* Implementation of class edited_file. */
+/* Implementation of class changed_file. */
-/* Callback for m_edited_lines, for comparing line numbers. */
+/* Callback for m_changed_lines, for comparing line numbers. */
static int line_comparator (int a, int b)
{
return a - b;
}
-/* edited_file's constructor. */
+/* changed_file's constructor. */
-edited_file::edited_file (edit_context &ec, const char *filename)
-: m_edit_context (ec),
+changed_file::changed_file (change_set &ec, const char *filename)
+: m_change_set (ec),
m_filename (filename),
- m_edited_lines (line_comparator, NULL, edited_line::delete_cb),
+ m_changed_lines (line_comparator, NULL, changed_line::delete_cb),
m_num_lines (-1)
{
}
-/* A callback for deleting edited_file *, for use as a
- delete_value_fn for edit_context::m_files. */
+/* A callback for deleting changed_file *, for use as a
+ delete_value_fn for change_set::m_files. */
void
-edited_file::delete_cb (edited_file *file)
+changed_file::delete_cb (changed_file *file)
{
delete file;
}
@@ -378,7 +382,7 @@ edited_file::delete_cb (edited_file *file)
The ptr should be freed by the caller. */
char *
-edited_file::get_content ()
+changed_file::get_content ()
{
pretty_printer pp;
if (!print_content (&pp))
@@ -392,11 +396,11 @@ edited_file::get_content ()
the line. */
bool
-edited_file::apply_fixit (int line, int start_column, int next_column,
+changed_file::apply_fixit (int line, int start_column, int next_column,
const char *replacement_str,
int replacement_len)
{
- edited_line *el = get_or_insert_line (line);
+ changed_line *el = get_or_insert_line (line);
if (!el)
return false;
return el->apply_fixit (start_column, next_column, replacement_str,
@@ -407,9 +411,9 @@ edited_file::apply_fixit (int line, int start_column, int next_column,
column after edits have been applied. */
int
-edited_file::get_effective_column (int line, int column)
+changed_file::get_effective_column (int line, int column)
{
- const edited_line *el = get_line (line);
+ const changed_line *el = get_line (line);
if (!el)
return column;
return el->get_effective_column (column);
@@ -419,13 +423,13 @@ edited_file::get_effective_column (int line, int column)
Return true if successful, false otherwise. */
bool
-edited_file::print_content (pretty_printer *pp)
+changed_file::print_content (pretty_printer *pp)
{
bool missing_trailing_newline;
int line_count = get_num_lines (&missing_trailing_newline);
for (int line_num = 1; line_num <= line_count; line_num++)
{
- edited_line *el = get_line (line_num);
+ changed_line *el = get_line (line_num);
if (el)
el->print_content (pp);
else
@@ -451,7 +455,7 @@ edited_file::print_content (pretty_printer *pp)
to this file. */
void
-edited_file::print_diff (pretty_printer *pp, bool show_filenames)
+changed_file::print_diff (pretty_printer *pp, bool show_filenames)
{
if (show_filenames)
{
@@ -466,7 +470,7 @@ edited_file::print_diff (pretty_printer *pp, bool show_filenames)
pp_string (pp, colorize_stop (pp_show_color (pp)));
}
- edited_line *el = m_edited_lines.min ();
+ changed_line *el = m_changed_lines.min ();
bool missing_trailing_newline;
int line_count = get_num_lines (&missing_trailing_newline);
@@ -488,8 +492,8 @@ edited_file::print_diff (pretty_printer *pp, bool show_filenames)
that are sufficiently close. */
while (true)
{
- edited_line *next_el
- = m_edited_lines.successor (el->get_line_num ());
+ changed_line *next_el
+ = m_changed_lines.successor (el->get_line_num ());
if (!next_el)
break;
@@ -514,7 +518,7 @@ edited_file::print_diff (pretty_printer *pp, bool show_filenames)
int new_start_of_hunk = start_of_hunk + line_delta;
line_delta += print_diff_hunk (pp, start_of_hunk, end_of_hunk,
new_start_of_hunk);
- el = m_edited_lines.successor (el->get_line_num ());
+ el = m_changed_lines.successor (el->get_line_num ());
}
}
@@ -525,7 +529,7 @@ edited_file::print_diff (pretty_printer *pp, bool show_filenames)
Return the change in the line count within the hunk. */
int
-edited_file::print_diff_hunk (pretty_printer *pp, int old_start_of_hunk,
+changed_file::print_diff_hunk (pretty_printer *pp, int old_start_of_hunk,
int old_end_of_hunk, int new_start_of_hunk)
{
int old_num_lines = old_end_of_hunk - old_start_of_hunk + 1;
@@ -541,7 +545,7 @@ edited_file::print_diff_hunk (pretty_printer *pp, int old_start_of_hunk,
int line_num = old_start_of_hunk;
while (line_num <= old_end_of_hunk)
{
- edited_line *el = get_line (line_num);
+ changed_line *el = get_line (line_num);
if (el)
{
/* We have an edited line.
@@ -566,12 +570,12 @@ edited_file::print_diff_hunk (pretty_printer *pp, int old_start_of_hunk,
return new_num_lines - old_num_lines;
}
-/* Subroutine of edited_file::print_diff_hunk: given a run of lines
- from START_OF_RUN to END_OF_RUN that all have edited_line instances,
+/* Subroutine of changed_file::print_diff_hunk: given a run of lines
+ from START_OF_RUN to END_OF_RUN that all have changed_line instances,
print the diff to PP. */
void
-edited_file::print_run_of_changed_lines (pretty_printer *pp,
+changed_file::print_run_of_changed_lines (pretty_printer *pp,
int start_of_run,
int end_of_run)
{
@@ -582,7 +586,7 @@ edited_file::print_run_of_changed_lines (pretty_printer *pp,
line_num <= end_of_run;
line_num++)
{
- edited_line *el_in_run = get_line (line_num);
+ changed_line *el_in_run = get_line (line_num);
gcc_assert (el_in_run);
if (el_in_run->actually_edited_p ())
{
@@ -601,7 +605,7 @@ edited_file::print_run_of_changed_lines (pretty_printer *pp,
line_num <= end_of_run;
line_num++)
{
- edited_line *el_in_run = get_line (line_num);
+ changed_line *el_in_run = get_line (line_num);
gcc_assert (el_in_run);
el_in_run->print_diff_lines (pp);
}
@@ -627,14 +631,14 @@ print_diff_line (pretty_printer *pp, char prefix_char,
OLD_END_OF_HUNK inclusive. */
int
-edited_file::get_effective_line_count (int old_start_of_hunk,
+changed_file::get_effective_line_count (int old_start_of_hunk,
int old_end_of_hunk)
{
int line_count = 0;
for (int old_line_num = old_start_of_hunk; old_line_num <= old_end_of_hunk;
old_line_num++)
{
- edited_line *el = get_line (old_line_num);
+ changed_line *el = get_line (old_line_num);
if (el)
line_count += el->get_effective_line_count ();
else
@@ -645,28 +649,28 @@ edited_file::get_effective_line_count (int old_start_of_hunk,
/* Get the state of LINE within the file, or NULL if it is untouched. */
-edited_line *
-edited_file::get_line (int line)
+changed_line *
+changed_file::get_line (int line)
{
- return m_edited_lines.lookup (line);
+ return m_changed_lines.lookup (line);
}
/* Get the state of LINE within the file, creating a state for it
if necessary. Return NULL if an error occurs. */
-edited_line *
-edited_file::get_or_insert_line (int line)
+changed_line *
+changed_file::get_or_insert_line (int line)
{
- edited_line *el = get_line (line);
+ changed_line *el = get_line (line);
if (el)
return el;
- el = new edited_line (get_file_cache (), m_filename, line);
+ el = new changed_line (get_file_cache (), m_filename, line);
if (el->get_content () == NULL)
{
delete el;
return NULL;
}
- m_edited_lines.insert (line, el);
+ m_changed_lines.insert (line, el);
return el;
}
@@ -675,7 +679,7 @@ edited_file::get_or_insert_line (int line)
if missing a newline, false otherwise. */
int
-edited_file::get_num_lines (bool *missing_trailing_newline)
+changed_file::get_num_lines (bool *missing_trailing_newline)
{
gcc_assert (missing_trailing_newline);
if (m_num_lines == -1)
@@ -696,11 +700,11 @@ edited_file::get_num_lines (bool *missing_trailing_newline)
return m_num_lines;
}
-/* Implementation of class edited_line. */
+/* Implementation of class changed_line. */
-/* edited_line's ctor. */
+/* changed_line's ctor. */
-edited_line::edited_line (file_cache &fc, const char *filename, int line_num)
+changed_line::changed_line (file_cache &fc, const char *filename, int line_num)
: m_line_num (line_num),
m_content (NULL), m_len (0), m_alloc_sz (0),
m_line_events (),
@@ -715,9 +719,9 @@ edited_line::edited_line (file_cache &fc, const char *filename, int line_num)
ensure_terminated ();
}
-/* edited_line's dtor. */
+/* changed_line's dtor. */
-edited_line::~edited_line ()
+changed_line::~changed_line ()
{
unsigned i;
added_line *pred;
@@ -727,11 +731,11 @@ edited_line::~edited_line ()
delete pred;
}
-/* A callback for deleting edited_line *, for use as a
- delete_value_fn for edited_file::m_edited_lines. */
+/* A callback for deleting changed_line *, for use as a
+ delete_value_fn for changed_file::m_changed_lines. */
void
-edited_line::delete_cb (edited_line *el)
+changed_line::delete_cb (changed_line *el)
{
delete el;
}
@@ -740,7 +744,7 @@ edited_line::delete_cb (edited_line *el)
within a specific line. */
int
-edited_line::get_effective_column (int orig_column) const
+changed_line::get_effective_column (int orig_column) const
{
int i;
line_event *event;
@@ -756,7 +760,7 @@ edited_line::get_effective_column (int orig_column) const
Return true if successful; false if an error occurred. */
bool
-edited_line::apply_fixit (int start_column,
+changed_line::apply_fixit (int start_column,
int next_column,
const char *replacement_str,
int replacement_len)
@@ -824,16 +828,16 @@ edited_line::apply_fixit (int start_column,
also be counted. */
int
-edited_line::get_effective_line_count () const
+changed_line::get_effective_line_count () const
{
return m_predecessors.length () + 1;
}
-/* Subroutine of edited_file::print_content.
+/* Subroutine of changed_file::print_content.
Print this line and any new lines added before it, to PP. */
void
-edited_line::print_content (pretty_printer *pp) const
+changed_line::print_content (pretty_printer *pp) const
{
unsigned i;
added_line *pred;
@@ -845,18 +849,18 @@ edited_line::print_content (pretty_printer *pp) const
pp_string (pp, m_content);
}
-/* Subroutine of edited_file::print_run_of_changed_lines for
+/* Subroutine of changed_file::print_run_of_changed_lines for
printing diff hunks to PP.
Print the '+' line for this line, and any newlines added
before it.
- Note that if this edited_line was actually edited, the '-'
+ Note that if this changed_line was actually edited, the '-'
line has already been printed. If it wasn't, then we merely
- have a placeholder edited_line for adding newlines to, and
- we need to print a ' ' line for the edited_line as we haven't
+ have a placeholder changed_line for adding newlines to, and
+ we need to print a ' ' line for the changed_line as we haven't
printed it yet. */
void
-edited_line::print_diff_lines (pretty_printer *pp) const
+changed_line::print_diff_lines (pretty_printer *pp) const
{
unsigned i;
added_line *pred;
@@ -874,7 +878,7 @@ edited_line::print_diff_lines (pretty_printer *pp) const
allocations. */
void
-edited_line::ensure_capacity (int len)
+changed_line::ensure_capacity (int len)
{
/* Allow 1 extra byte for 0-termination. */
if (m_alloc_sz < (len + 1))
@@ -888,7 +892,7 @@ edited_line::ensure_capacity (int len)
/* Ensure that m_content is 0-terminated. */
void
-edited_line::ensure_terminated ()
+changed_line::ensure_terminated ()
{
/* 0-terminate the buffer. */
gcc_assert (m_len < m_alloc_sz);
@@ -901,6 +905,11 @@ edited_line::ensure_terminated ()
namespace selftest {
+using line_table_case = ::selftest::line_table_case;
+using line_table_test = ::selftest::line_table_test;
+using temp_source_file = ::selftest::temp_source_file;
+using named_temp_file = ::selftest::named_temp_file;
+
/* A wrapper class for ensuring that the underlying pointer is freed. */
template <typename POINTER_T>
@@ -916,7 +925,7 @@ class auto_free
POINTER_T m_ptr;
};
-/* Verify that edit_context::get_content works for unedited files. */
+/* Verify that change_set::get_content works for unedited files. */
static void
test_get_content ()
@@ -926,7 +935,7 @@ test_get_content ()
const char *content = ("");
temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
auto_free <char *> result = edit.get_content (tmp.get_filename ());
ASSERT_STREQ ("", result);
}
@@ -938,7 +947,7 @@ test_get_content ()
"/* after */\n");
temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
auto_free <char *> result = edit.get_content (tmp.get_filename ());
ASSERT_STREQ ("/* before */\n"
"foo = bar.field;\n"
@@ -952,7 +961,7 @@ test_get_content ()
"/* after */");
temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
auto_free <char *> result = edit.get_content (tmp.get_filename ());
/* We should respect the omitted trailing newline. */
ASSERT_STREQ ("/* before */\n"
@@ -986,7 +995,7 @@ test_applying_fixits_insert_before (const line_table_case &case_)
return;
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&richloc);
auto_free <char *> new_content = edit.get_content (filename);
if (start <= LINE_MAP_MAX_LOCATION_WITH_COLS)
@@ -1045,7 +1054,7 @@ test_applying_fixits_insert_after (const line_table_case &case_)
/* Verify that the text was inserted after the end of "field". */
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&richloc);
auto_free <char *> new_content = edit.get_content (filename);
ASSERT_STREQ ("/* before */\n"
@@ -1088,7 +1097,7 @@ test_applying_fixits_insert_after_at_line_end (const line_table_case &case_)
return;
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&richloc);
auto_free <char *> new_content = edit.get_content (filename);
ASSERT_STREQ ("/* before */\n"
@@ -1147,7 +1156,7 @@ test_applying_fixits_insert_after_failure (const line_table_case &case_)
ASSERT_TRUE (richloc.seen_impossible_fixit_p ());
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&richloc);
ASSERT_FALSE (edit.valid_p ());
ASSERT_EQ (NULL, edit.get_content (filename));
@@ -1185,7 +1194,7 @@ test_applying_fixits_insert_containing_newline (const line_table_case &case_)
return;
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&richloc);
auto_free <char *> new_content = edit.get_content (filename);
ASSERT_STREQ ((" case 'a':\n"
@@ -1230,7 +1239,7 @@ test_applying_fixits_growing_replace (const line_table_case &case_)
richloc.add_fixit_replace ("m_field");
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&richloc);
auto_free <char *> new_content = edit.get_content (filename);
if (finish <= LINE_MAP_MAX_LOCATION_WITH_COLS)
@@ -1276,7 +1285,7 @@ test_applying_fixits_shrinking_replace (const line_table_case &case_)
richloc.add_fixit_replace ("field");
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&richloc);
auto_free <char *> new_content = edit.get_content (filename);
if (finish <= LINE_MAP_MAX_LOCATION_WITH_COLS)
@@ -1331,7 +1340,7 @@ test_applying_fixits_replace_containing_newline (const line_table_case &case_)
return;
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&richloc);
auto_free <char *> new_content = edit.get_content (filename);
//ASSERT_STREQ ("foo\n = bar ();\n", new_content);
@@ -1363,7 +1372,7 @@ test_applying_fixits_remove (const line_table_case &case_)
richloc.add_fixit_remove (range);
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&richloc);
auto_free <char *> new_content = edit.get_content (filename);
if (finish <= LINE_MAP_MAX_LOCATION_WITH_COLS)
@@ -1429,7 +1438,7 @@ test_applying_fixits_multiple (const line_table_case &case_)
"meadow");
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&insert_a);
ASSERT_EQ (100, edit.get_effective_column (filename, 1, 100));
ASSERT_EQ (1, edit.get_effective_column (filename, 2, 1));
@@ -1464,7 +1473,7 @@ test_applying_fixits_multiple (const line_table_case &case_)
Add the text "CHANGED: " to the front of the given line. */
static location_t
-change_line (edit_context &edit, int line_num)
+change_line (change_set &edit, int line_num)
{
const line_map_ordinary *ord_map
= LINEMAPS_LAST_ORDINARY_MAP (line_table);
@@ -1490,7 +1499,7 @@ change_line (edit_context &edit, int line_num)
Add the text "INSERTED\n" in front of the given line. */
static location_t
-insert_line (edit_context &edit, int line_num)
+insert_line (change_set &edit, int line_num)
{
const line_map_ordinary *ord_map
= LINEMAPS_LAST_ORDINARY_MAP (line_table);
@@ -1532,7 +1541,7 @@ test_applying_fixits_multiple_lines (const line_table_case &case_)
linemap_position_for_column (line_table, 127);
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
/* A run of consecutive lines. */
change_line (edit, 2);
@@ -1621,7 +1630,7 @@ test_applying_fixits_modernize_named_init (const line_table_case &case_)
/* The order should not matter. Do r1 then r2. */
{
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&r1);
/* Verify state after first replacement. */
@@ -1655,7 +1664,7 @@ test_applying_fixits_modernize_named_init (const line_table_case &case_)
/* Try again, doing r2 then r1; the new_content should be the same. */
{
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&r2);
edit.add_fixits (&r1);
auto_free <char *> new_content = edit.get_content (tmp.get_filename ());
@@ -1684,7 +1693,7 @@ test_applying_fixits_unreadable_file ()
insert.add_fixit_insert_before ("change 2");
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
/* Attempting to add the fixits affecting the unreadable file
should transition the edit from valid to invalid. */
ASSERT_TRUE (edit.valid_p ());
@@ -1715,10 +1724,10 @@ test_applying_fixits_line_out_of_range ()
rich_location insert (line_table, loc);
insert.add_fixit_insert_before ("change");
- /* Verify that attempting the insertion puts an edit_context
+ /* Verify that attempting the insertion puts an change_set
into an invalid state. */
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
ASSERT_TRUE (edit.valid_p ());
edit.add_fixits (&insert);
ASSERT_FALSE (edit.valid_p ());
@@ -1727,7 +1736,7 @@ test_applying_fixits_line_out_of_range ()
}
/* Verify the boundary conditions of column values in fix-it
- hints applied to edit_context instances. */
+ hints applied to change_set instances. */
static void
test_applying_fixits_column_validation (const line_table_case &case_)
@@ -1756,7 +1765,7 @@ test_applying_fixits_column_validation (const line_table_case &case_)
/* Col 15 is at the end of the line, so the insertion
should succeed. */
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&richloc);
auto_free <char *> new_content = edit.get_content (tmp.get_filename ());
if (c15 <= LINE_MAP_MAX_LOCATION_WITH_COLS)
@@ -1773,7 +1782,7 @@ test_applying_fixits_column_validation (const line_table_case &case_)
/* Col 16 is beyond the end of the line, so the insertion
should fail gracefully. */
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
ASSERT_TRUE (edit.valid_p ());
edit.add_fixits (&richloc);
ASSERT_FALSE (edit.valid_p ());
@@ -1792,7 +1801,7 @@ test_applying_fixits_column_validation (const line_table_case &case_)
/* Col 14 is at the end of the line, so the replacement
should succeed. */
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
edit.add_fixits (&richloc);
auto_free <char *> new_content = edit.get_content (tmp.get_filename ());
if (c14 <= LINE_MAP_MAX_LOCATION_WITH_COLS)
@@ -1810,7 +1819,7 @@ test_applying_fixits_column_validation (const line_table_case &case_)
/* Col 15 is after the end of the line, so the replacement
should fail; verify that the attempt fails gracefully. */
file_cache fc;
- edit_context edit (fc);
+ change_set edit (fc);
ASSERT_TRUE (edit.valid_p ());
edit.add_fixits (&richloc);
ASSERT_FALSE (edit.valid_p ());
@@ -1819,10 +1828,8 @@ test_applying_fixits_column_validation (const line_table_case &case_)
}
}
-/* Run all of the selftests within this file. */
-
-void
-edit_context_cc_tests ()
+static void
+run_all_tests ()
{
test_get_content ();
for_each_line_table_case (test_applying_fixits_insert_before);
@@ -1842,6 +1849,20 @@ edit_context_cc_tests ()
for_each_line_table_case (test_applying_fixits_column_validation);
}
+} // namespace diagnostics::changes::selftest
+} // namespace diagnostics::changes
+
+namespace selftest { // diagnostics::selftest
+
+/* Run all of the selftests within this file. */
+
+void
+changes_cc_tests ()
+{
+ diagnostics::changes::selftest::run_all_tests ();
+}
+
} // namespace selftest
+} // namespace diagnostics
#endif /* CHECKING_P */
diff --git a/gcc/edit-context.h b/gcc/diagnostics/changes.h
index 9bd2aba..a5fe4b0 100644
--- a/gcc/edit-context.h
+++ b/gcc/diagnostics/changes.h
@@ -17,21 +17,25 @@ 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_EDIT_CONTEXT_H
-#define GCC_EDIT_CONTEXT_H
+#ifndef GCC_DIAGNOSTICS_CHANGES_H
+#define GCC_DIAGNOSTICS_CHANGES_H
#include "typed-splay-tree.h"
class fixit_hint;
-class edit_context;
-class edited_file;
+
+namespace diagnostics {
+namespace changes {
+
+class change_set;
+class changed_file;
/* A set of changes to the source code.
The changes are "atomic" - if any changes can't be applied,
none of them can be (tracked by the m_valid flag).
Similarly, attempts to add the changes from a rich_location flagged
- as containing invalid changes mean that the whole of the edit_context
+ as containing invalid changes mean that the whole of the change_set
is flagged as invalid.
A complication here is that fix-its are expressed relative to coordinates
@@ -40,10 +44,10 @@ class edited_file;
later fix-its to allow for the changes made by earlier ones. This
is done by the various "get_effective_column" methods. */
-class edit_context
+class change_set
{
public:
- edit_context (file_cache &);
+ change_set (file_cache &);
bool valid_p () const { return m_valid; }
@@ -60,12 +64,15 @@ class edit_context
private:
bool apply_fixit (const fixit_hint *hint);
- edited_file *get_file (const char *filename);
- edited_file &get_or_insert_file (const char *filename);
+ changed_file *get_file (const char *filename);
+ changed_file &get_or_insert_file (const char *filename);
file_cache &m_file_cache;
bool m_valid;
- typed_splay_tree<const char *, edited_file *> m_files;
+ typed_splay_tree<const char *, changed_file *> m_files;
};
-#endif /* GCC_EDIT_CONTEXT_H. */
+} // namespace diagnostics::changes
+} // namespace diagnostics
+
+#endif /* GCC_DIAGNOSTICS_CHANGES_H. */
diff --git a/gcc/diagnostic-client-data-hooks.h b/gcc/diagnostics/client-data-hooks.h
index 9909172..94c51b2 100644
--- a/gcc/diagnostic-client-data-hooks.h
+++ b/gcc/diagnostics/client-data-hooks.h
@@ -18,32 +18,36 @@ 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_DIAGNOSTIC_CLIENT_DATA_HOOKS_H
-#define GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H
+#ifndef GCC_DIAGNOSTICS_CLIENT_DATA_HOOKS_H
+#define GCC_DIAGNOSTICS_CLIENT_DATA_HOOKS_H
-#include "logical-location.h"
+#include "diagnostics/logical-locations.h"
+
+namespace diagnostics {
class sarif_object;
class client_version_info;
-/* A bundle of additional metadata, owned by the diagnostic_context,
+/* A bundle of additional metadata, owned by the diagnostics::context,
for querying things about the client, like version data. */
-class diagnostic_client_data_hooks
+class client_data_hooks
{
public:
- virtual ~diagnostic_client_data_hooks () {}
+ virtual ~client_data_hooks () {}
/* Get version info for this client, or NULL. */
virtual const client_version_info *get_any_version_info () const = 0;
- /* Get the current logical_location_manager for this client, or NULL. */
- virtual const logical_location_manager *get_logical_location_manager () const = 0;
+ /* Get the current logical_locations::manager for this client, or null. */
+ virtual const logical_locations::manager *
+ get_logical_location_manager () const = 0;
- /* Get the current logical_location, or null.
- If this returns a non-null logical_location, then
- get_logical_location_manager must return non-NULL. */
- virtual logical_location get_current_logical_location () const = 0;
+ /* Get the current logical location, or null.
+ If this returns a non-null logical location, then
+ get_logical_location_manager must return non-null. */
+ virtual logical_locations::key
+ get_current_logical_location () const = 0;
/* Get a sourceLanguage value for FILENAME, or return NULL.
See SARIF v2.1.0 Appendix J for suggested values. */
@@ -56,15 +60,9 @@ class diagnostic_client_data_hooks
add_sarif_invocation_properties (sarif_object &invocation_obj) const = 0;
};
-/* Factory function for making an instance of diagnostic_client_data_hooks
- for use in the compiler (i.e. with knowledge of "tree", access to
- langhooks, etc). */
-
-extern std::unique_ptr<diagnostic_client_data_hooks> make_compiler_data_hooks ();
-
-class diagnostic_client_plugin_info;
+class client_plugin_info;
-/* Abstract base class for a diagnostic_context to get at
+/* Abstract base class for a diagnostics::context to get at
version information about the client. */
class client_version_info
@@ -73,7 +71,7 @@ public:
class plugin_visitor
{
public:
- virtual void on_plugin (const diagnostic_client_plugin_info &) = 0;
+ virtual void on_plugin (const client_plugin_info &) = 0;
};
virtual ~client_version_info () {}
@@ -97,10 +95,10 @@ public:
virtual void for_each_plugin (plugin_visitor &v) const = 0;
};
-/* Abstract base class for a diagnostic_context to get at
+/* Abstract base class for a diagnostics::context to get at
information about a specific plugin within a client. */
-class diagnostic_client_plugin_info
+class client_plugin_info
{
public:
/* For use e.g. by SARIF "name" property (SARIF v2.1.0 section 3.19.8). */
@@ -115,4 +113,13 @@ public:
virtual const char *get_version () const = 0;
};
-#endif /* ! GCC_DIAGNOSTIC_CLIENT_DATA_HOOKS_H */
+} // namespace diagnostics
+
+/* Factory function for making an instance of client_data_hooks
+ for use in the compiler (i.e. with knowledge of "tree", access to
+ langhooks, etc). */
+
+extern std::unique_ptr<diagnostics::client_data_hooks>
+make_compiler_data_hooks ();
+
+#endif /* ! GCC_DIAGNOSTICS_CLIENT_DATA_HOOKS_H */
diff --git a/gcc/diagnostic-color.cc b/gcc/diagnostics/color.cc
index e95aaeb..7b499fe 100644
--- a/gcc/diagnostic-color.cc
+++ b/gcc/diagnostics/color.cc
@@ -19,8 +19,8 @@
#include "config.h"
#define INCLUDE_VECTOR
#include "system.h"
-#include "diagnostic-color.h"
-#include "diagnostic-url.h"
+#include "diagnostics/color.h"
+#include "diagnostics/url.h"
#include "label-text.h"
#ifdef __MINGW32__
@@ -475,6 +475,7 @@ determine_url_format (diagnostic_url_rule_t rule)
#if CHECKING_P
+namespace diagnostics {
namespace selftest {
/* Test of an empty diagnostic_color_dict. */
@@ -522,7 +523,7 @@ test_color_dict_envvar_parsing ()
/* Run all of the selftests within this file. */
void
-diagnostic_color_cc_tests ()
+color_cc_tests ()
{
test_empty_color_dict ();
test_default_color_dict ();
@@ -530,5 +531,6 @@ diagnostic_color_cc_tests ()
}
} // namespace selftest
+} // namespace diagnostics
#endif /* #if CHECKING_P */
diff --git a/gcc/diagnostic-color.h b/gcc/diagnostics/color.h
index 8aeaa57..42b67eb 100644
--- a/gcc/diagnostic-color.h
+++ b/gcc/diagnostics/color.h
@@ -38,8 +38,8 @@ along with GCC; see the file COPYING3. If not see
Written July 1992 by Mike Haertel. */
-#ifndef GCC_DIAGNOSTIC_COLOR_H
-#define GCC_DIAGNOSTIC_COLOR_H
+#ifndef GCC_DIAGNOSTICS_COLOR_H
+#define GCC_DIAGNOSTICS_COLOR_H
/* Whether to add color to diagnostics:
o DIAGNOSTICS_COLOR_NO: never
@@ -62,4 +62,4 @@ colorize_start (bool show_color, const char *name)
return colorize_start (show_color, name, strlen (name));
}
-#endif /* ! GCC_DIAGNOSTIC_COLOR_H */
+#endif /* ! GCC_DIAGNOSTICS_COLOR_H */
diff --git a/gcc/diagnostics/context-options.h b/gcc/diagnostics/context-options.h
new file mode 100644
index 0000000..c4e92eb
--- /dev/null
+++ b/gcc/diagnostics/context-options.h
@@ -0,0 +1,116 @@
+/* Declare enums for diagnostics::context and related types.
+ Copyright (C) 2000-2025 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/>. */
+
+#ifndef GCC_DIAGNOSTICS_CONTEXT_OPTIONS_H
+#define GCC_DIAGNOSTICS_CONTEXT_OPTIONS_H
+
+/* An enum for controlling what units to use for the column number
+ when diagnostics are output, used by the -fdiagnostics-column-unit option.
+ Tabs will be expanded or not according to the value of -ftabstop. The origin
+ (default 1) is controlled by -fdiagnostics-column-origin. */
+
+enum diagnostics_column_unit
+{
+ /* The default from GCC 11 onwards: display columns. */
+ DIAGNOSTICS_COLUMN_UNIT_DISPLAY,
+
+ /* The behavior in GCC 10 and earlier: simple bytes. */
+ DIAGNOSTICS_COLUMN_UNIT_BYTE
+};
+
+/* An enum for controlling how to print non-ASCII characters/bytes when
+ a diagnostic suggests escaping the source code on output. */
+
+enum diagnostics_escape_format
+{
+ /* Escape non-ASCII Unicode characters in the form <U+XXXX> and
+ non-UTF-8 bytes in the form <XX>. */
+ DIAGNOSTICS_ESCAPE_FORMAT_UNICODE,
+
+ /* Escape non-ASCII bytes in the form <XX> (thus showing the underlying
+ encoding of non-ASCII Unicode characters). */
+ DIAGNOSTICS_ESCAPE_FORMAT_BYTES
+};
+
+/* Enum for overriding the standard output format. */
+
+enum diagnostics_output_format
+{
+ /* The default: textual output. */
+ DIAGNOSTICS_OUTPUT_FORMAT_TEXT,
+
+ /* SARIF-based output, as JSON to stderr. */
+ DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR,
+
+ /* SARIF-based output, to a JSON file. */
+ DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE
+};
+
+/* An enum for controlling how diagnostic paths should be printed. */
+enum diagnostic_path_format
+{
+ /* Don't print diagnostic paths. */
+ DPF_NONE,
+
+ /* Print diagnostic paths by emitting a separate "note" for every event
+ in the path. */
+ DPF_SEPARATE_EVENTS,
+
+ /* Print diagnostic paths by consolidating events together where they
+ are close enough, and printing such runs of events with multiple
+ calls to diagnostic_show_locus, showing the individual events in
+ each run via labels in the source. */
+ DPF_INLINE_EVENTS
+};
+
+/* An enum for capturing values of GCC_EXTRA_DIAGNOSTIC_OUTPUT,
+ and for -fdiagnostics-parseable-fixits. */
+
+enum diagnostics_extra_output_kind
+{
+ /* No extra output, or an unrecognized value. */
+ EXTRA_DIAGNOSTIC_OUTPUT_none,
+
+ /* Emit fix-it hints using the "fixits-v1" format, equivalent to
+ -fdiagnostics-parseable-fixits. */
+ EXTRA_DIAGNOSTIC_OUTPUT_fixits_v1,
+
+ /* Emit fix-it hints using the "fixits-v2" format. */
+ EXTRA_DIAGNOSTIC_OUTPUT_fixits_v2
+};
+
+/* Values for -fdiagnostics-text-art-charset=. */
+
+enum diagnostic_text_art_charset
+{
+ /* No text art diagrams shall be emitted. */
+ DIAGNOSTICS_TEXT_ART_CHARSET_NONE,
+
+ /* Use pure ASCII for text art diagrams. */
+ DIAGNOSTICS_TEXT_ART_CHARSET_ASCII,
+
+ /* Use ASCII + conservative use of other unicode characters
+ in text art diagrams. */
+ DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE,
+
+ /* Use Emoji. */
+ DIAGNOSTICS_TEXT_ART_CHARSET_EMOJI
+};
+
+#endif /* ! GCC_DIAGNOSTICS_CONTEXT_OPTIONS_H */
diff --git a/gcc/diagnostic.cc b/gcc/diagnostics/context.cc
index 7e5ac87..0dbc148 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostics/context.cc
@@ -31,24 +31,25 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "backtrace.h"
#include "diagnostic.h"
-#include "diagnostic-color.h"
-#include "diagnostic-url.h"
-#include "diagnostic-metadata.h"
-#include "diagnostic-path.h"
-#include "diagnostic-client-data-hooks.h"
-#include "diagnostic-diagram.h"
-#include "diagnostic-format.h"
-#include "diagnostic-format-sarif.h"
-#include "diagnostic-format-text.h"
-#include "edit-context.h"
+#include "diagnostics/color.h"
+#include "diagnostics/url.h"
+#include "diagnostics/metadata.h"
+#include "diagnostics/paths.h"
+#include "diagnostics/client-data-hooks.h"
+#include "diagnostics/diagram.h"
+#include "diagnostics/sink.h"
+#include "diagnostics/sarif-sink.h"
+#include "diagnostics/text-sink.h"
+#include "diagnostics/changes.h"
#include "selftest.h"
-#include "selftest-diagnostic.h"
+#include "diagnostics/selftest-context.h"
#include "opts.h"
#include "cpplib.h"
#include "text-art/theme.h"
#include "pretty-print-urlifier.h"
-#include "logical-location.h"
-#include "diagnostic-buffer.h"
+#include "diagnostics/logical-locations.h"
+#include "diagnostics/buffering.h"
+#include "diagnostics/file-cache.h"
#ifdef HAVE_TERMIOS_H
# include <termios.h>
@@ -111,114 +112,28 @@ get_terminal_width (void)
return INT_MAX;
}
+namespace diagnostics {
+
/* Set caret_max_width to value. */
+
void
-diagnostic_set_caret_max_width (diagnostic_context *context, int value)
+context::set_caret_max_width (int value)
{
/* One minus to account for the leading empty space. */
value = value ? value - 1
- : (isatty (fileno (pp_buffer (context->get_reference_printer ())->m_stream))
+ : (isatty (fileno (pp_buffer (get_reference_printer ())->m_stream))
? get_terminal_width () - 1 : INT_MAX);
if (value <= 0)
value = INT_MAX;
- context->m_source_printing.max_width = value;
-}
-
-void
-diagnostic_option_classifier::init (int n_opts)
-{
- m_n_opts = n_opts;
- m_classify_diagnostic = XNEWVEC (diagnostic_t, n_opts);
- for (int i = 0; i < n_opts; i++)
- m_classify_diagnostic[i] = DK_UNSPECIFIED;
- m_push_list = vNULL;
- m_classification_history = vNULL;
-}
-
-void
-diagnostic_option_classifier::fini ()
-{
- XDELETEVEC (m_classify_diagnostic);
- m_classify_diagnostic = nullptr;
- m_classification_history.release ();
- m_push_list.release ();
-}
-
-/* Save the diagnostic_option_classifier state to F for PCH
- output. Returns 0 on success, -1 on error. */
-
-int
-diagnostic_option_classifier::pch_save (FILE *f)
-{
- unsigned int lengths[2] = { m_classification_history.length (),
- m_push_list.length () };
- if (fwrite (lengths, sizeof (lengths), 1, f) != 1
- || (lengths[0]
- && fwrite (m_classification_history.address (),
- sizeof (diagnostic_classification_change_t),
- lengths[0], f) != lengths[0])
- || (lengths[1]
- && fwrite (m_push_list.address (), sizeof (int),
- lengths[1], f) != lengths[1]))
- return -1;
- return 0;
-}
-
-/* Read the diagnostic_option_classifier state from F for PCH
- read. Returns 0 on success, -1 on error. */
-
-int
-diagnostic_option_classifier::pch_restore (FILE *f)
-{
- unsigned int lengths[2];
- if (fread (lengths, sizeof (lengths), 1, f) != 1)
- return -1;
- gcc_checking_assert (m_classification_history.is_empty ());
- gcc_checking_assert (m_push_list.is_empty ());
- m_classification_history.safe_grow (lengths[0]);
- m_push_list.safe_grow (lengths[1]);
- if ((lengths[0]
- && fread (m_classification_history.address (),
- sizeof (diagnostic_classification_change_t),
- lengths[0], f) != lengths[0])
- || (lengths[1]
- && fread (m_push_list.address (), sizeof (int),
- lengths[1], f) != lengths[1]))
- return -1;
- return 0;
-}
-
-/* Save all diagnostic classifications in a stack. */
-
-void
-diagnostic_option_classifier::push ()
-{
- m_push_list.safe_push (m_classification_history.length ());
-}
-
-/* Restore the topmost classification set off the stack. If the stack
- is empty, revert to the state based on command line parameters. */
-
-void
-diagnostic_option_classifier::pop (location_t where)
-{
- int jump_to;
-
- if (!m_push_list.is_empty ())
- jump_to = m_push_list.pop ();
- else
- jump_to = 0;
-
- diagnostic_classification_change_t v = { where, jump_to, DK_POP };
- m_classification_history.safe_push (v);
+ m_source_printing.max_width = value;
}
/* Initialize the diagnostic message outputting machinery. */
void
-diagnostic_context::initialize (int n_opts)
+context::initialize (int n_opts)
{
/* Allocate a basic pretty-printer. Clients will replace this a
much more elaborated pretty-printer if they wish. */
@@ -230,7 +145,7 @@ diagnostic_context::initialize (int n_opts)
m_n_opts = n_opts;
m_option_classifier.init (n_opts);
m_source_printing.enabled = false;
- diagnostic_set_caret_max_width (this, pp_line_cutoff (get_reference_printer ()));
+ set_caret_max_width (pp_line_cutoff (get_reference_printer ()));
for (int i = 0; i < rich_location::STATICALLY_ALLOCATED_RANGES; i++)
m_source_printing.caret_chars[i] = '^';
m_show_cwe = false;
@@ -249,12 +164,12 @@ diagnostic_context::initialize (int n_opts)
m_max_errors = 0;
m_internal_error = nullptr;
m_adjust_diagnostic_info = nullptr;
- m_text_callbacks.m_begin_diagnostic = default_diagnostic_text_starter;
+ m_text_callbacks.m_begin_diagnostic = default_text_starter;
m_text_callbacks.m_text_start_span
- = default_diagnostic_start_span_fn<to_text>;
+ = default_start_span_fn<to_text>;
m_text_callbacks.m_html_start_span
- = default_diagnostic_start_span_fn<to_html>;
- m_text_callbacks.m_end_diagnostic = default_diagnostic_text_finalizer;
+ = default_start_span_fn<to_html>;
+ m_text_callbacks.m_end_diagnostic = default_text_finalizer;
m_option_mgr = nullptr;
m_urlifier_stack = new auto_vec<urlifier_stack_node> ();
m_last_location = UNKNOWN_LOCATION;
@@ -281,13 +196,12 @@ diagnostic_context::initialize (int n_opts)
m_column_origin = 1;
m_tabstop = 8;
m_escape_format = DIAGNOSTICS_ESCAPE_FORMAT_UNICODE;
- m_edit_context_ptr = nullptr;
+ m_fixits_change_set = nullptr;
m_diagnostic_groups.m_group_nesting_depth = 0;
m_diagnostic_groups.m_diagnostic_nesting_level = 0;
m_diagnostic_groups.m_emission_count = 0;
m_diagnostic_groups.m_inhibiting_notes_from = 0;
- m_output_sinks.safe_push
- (new diagnostic_text_output_format (*this, nullptr, true));
+ m_sinks.safe_push (new text_sink (*this, nullptr, true));
m_set_locations_cb = nullptr;
m_client_data_hooks = nullptr;
m_diagrams.m_theme = nullptr;
@@ -311,7 +225,7 @@ diagnostic_context::initialize (int n_opts)
without a VALUE, it initializes with DIAGNOSTICS_COLOR_DEFAULT. */
void
-diagnostic_context::color_init (int value)
+context::color_init (int value)
{
/* value == -1 is the default value. */
if (value < 0)
@@ -332,9 +246,9 @@ diagnostic_context::color_init (int value)
}
pp_show_color (m_reference_printer)
= colorize_init ((diagnostic_color_rule_t) value);
- for (auto sink : m_output_sinks)
- if (sink->follows_reference_printer_p ())
- pp_show_color (sink->get_printer ())
+ for (auto sink_ : m_sinks)
+ if (sink_->follows_reference_printer_p ())
+ pp_show_color (sink_->get_printer ())
= pp_show_color (m_reference_printer);
}
@@ -342,7 +256,7 @@ diagnostic_context::color_init (int value)
handling "auto". */
void
-diagnostic_context::urls_init (int value)
+context::urls_init (int value)
{
/* value == -1 is the default value. */
if (value < 0)
@@ -364,18 +278,17 @@ diagnostic_context::urls_init (int value)
m_reference_printer->set_url_format
(determine_url_format ((diagnostic_url_rule_t) value));
- for (auto sink : m_output_sinks)
- if (sink->follows_reference_printer_p ())
- sink->get_printer ()->set_url_format
+ for (auto sink_ : m_sinks)
+ if (sink_->follows_reference_printer_p ())
+ sink_->get_printer ()->set_url_format
(m_reference_printer->get_url_format ());
}
/* Create the file_cache, if not already created, and tell it how to
translate files on input. */
void
-diagnostic_context::
-initialize_input_context (diagnostic_input_charset_callback ccb,
- bool should_skip_bom)
+context::initialize_input_context (diagnostic_input_charset_callback ccb,
+ bool should_skip_bom)
{
m_file_cache->initialize_input_context (ccb, should_skip_bom);
}
@@ -383,7 +296,7 @@ initialize_input_context (diagnostic_input_charset_callback ccb,
/* Do any cleaning up required after the last diagnostic is emitted. */
void
-diagnostic_context::finish ()
+context::finish ()
{
/* We might be handling a fatal error.
Close any active diagnostic groups, which may trigger flushing
@@ -395,8 +308,8 @@ diagnostic_context::finish ()
/* Clean ups. */
- while (!m_output_sinks.is_empty ())
- delete m_output_sinks.pop ();
+ while (!m_sinks.is_empty ())
+ delete m_sinks.pop ();
if (m_diagrams.m_theme)
{
@@ -412,10 +325,10 @@ diagnostic_context::finish ()
delete m_reference_printer;
m_reference_printer = nullptr;
- if (m_edit_context_ptr)
+ if (m_fixits_change_set)
{
- delete m_edit_context_ptr;
- m_edit_context_ptr = nullptr;
+ delete m_fixits_change_set;
+ m_fixits_change_set = nullptr;
}
if (m_client_data_hooks)
@@ -439,22 +352,22 @@ diagnostic_context::finish ()
m_original_argv = nullptr;
}
-/* Dump state of this diagnostic_context to OUT, for debugging. */
+/* Dump state of this diagnostics::context to OUT, for debugging. */
void
-diagnostic_context::dump (FILE *out) const
+context::dump (FILE *out) const
{
- fprintf (out, "diagnostic_context:\n");
+ fprintf (out, "diagnostics::context:\n");
m_diagnostic_counters.dump (out, 2);
fprintf (out, " reference printer:\n");
m_reference_printer->dump (out, 4);
fprintf (out, " output sinks:\n");
- if (m_output_sinks.length () > 0)
+ if (m_sinks.length () > 0)
{
- for (unsigned i = 0; i < m_output_sinks.length (); ++i)
+ for (unsigned i = 0; i < m_sinks.length (); ++i)
{
fprintf (out, " sink %i:\n", i);
- m_output_sinks[i]->dump (out, 4);
+ m_sinks[i]->dump (out, 4);
}
}
else
@@ -475,65 +388,63 @@ diagnostic_context::dump (FILE *out) const
we ought to exit with a non-zero exit code. */
bool
-diagnostic_context::execution_failed_p () const
+context::execution_failed_p () const
{
/* Equivalent to (seen_error () || werrorcount), but on
this context, rather than global_dc. */
- return (diagnostic_count (DK_ERROR)
- || diagnostic_count (DK_SORRY)
- || diagnostic_count (DK_WERROR));
+ return (diagnostic_count (kind::error)
+ || diagnostic_count (kind::sorry)
+ || diagnostic_count (kind::werror));
}
void
-diagnostic_context::remove_all_output_sinks ()
+context::remove_all_output_sinks ()
{
- while (!m_output_sinks.is_empty ())
- delete m_output_sinks.pop ();
+ while (!m_sinks.is_empty ())
+ delete m_sinks.pop ();
}
void
-diagnostic_context::
-set_output_format (std::unique_ptr<diagnostic_output_format> output_format)
+context::set_sink (std::unique_ptr<sink> sink_)
{
remove_all_output_sinks ();
- m_output_sinks.safe_push (output_format.release ());
+ m_sinks.safe_push (sink_.release ());
}
-diagnostic_output_format &
-diagnostic_context::get_output_format (size_t idx) const
+sink &
+context::get_sink (size_t idx) const
{
- gcc_assert (idx < m_output_sinks.length ());
- gcc_assert (m_output_sinks[idx]);
- return *m_output_sinks[idx];
+ gcc_assert (idx < m_sinks.length ());
+ gcc_assert (m_sinks[idx]);
+ return *m_sinks[idx];
}
void
-diagnostic_context::add_sink (std::unique_ptr<diagnostic_output_format> sink)
+context::add_sink (std::unique_ptr<sink> sink_)
{
- m_output_sinks.safe_push (sink.release ());
+ m_sinks.safe_push (sink_.release ());
}
/* Return true if there are no machine-readable formats writing to stderr. */
bool
-diagnostic_context::supports_fnotice_on_stderr_p () const
+context::supports_fnotice_on_stderr_p () const
{
- for (auto sink : m_output_sinks)
- if (sink->machine_readable_stderr_p ())
+ for (auto sink_ : m_sinks)
+ if (sink_->machine_readable_stderr_p ())
return false;
return true;
}
void
-diagnostic_context::set_main_input_filename (const char *filename)
+context::set_main_input_filename (const char *filename)
{
- for (auto sink : m_output_sinks)
- sink->set_main_input_filename (filename);
+ for (auto sink_ : m_sinks)
+ sink_->set_main_input_filename (filename);
}
void
-diagnostic_context::
-set_client_data_hooks (std::unique_ptr<diagnostic_client_data_hooks> hooks)
+context::set_client_data_hooks (std::unique_ptr<client_data_hooks> hooks)
{
delete m_client_data_hooks;
/* Ideally the field would be a std::unique_ptr here. */
@@ -541,10 +452,10 @@ set_client_data_hooks (std::unique_ptr<diagnostic_client_data_hooks> hooks)
}
void
-diagnostic_context::set_original_argv (unique_argv original_argv)
+context::set_original_argv (unique_argv original_argv)
{
/* Ideally we'd use a unique_argv for m_original_argv, but
- diagnostic_context doesn't yet have a ctor/dtor pair. */
+ diagnostics::context doesn't yet have a ctor/dtor pair. */
// Ensure any old value is freed
freeargv (m_original_argv);
@@ -554,9 +465,8 @@ diagnostic_context::set_original_argv (unique_argv original_argv)
}
void
-diagnostic_context::
-set_option_manager (std::unique_ptr<diagnostic_option_manager> mgr,
- unsigned lang_mask)
+context::set_option_manager (std::unique_ptr<option_manager> mgr,
+ unsigned lang_mask)
{
delete m_option_mgr;
m_option_mgr = mgr.release ();
@@ -564,7 +474,7 @@ set_option_manager (std::unique_ptr<diagnostic_option_manager> mgr,
}
void
-diagnostic_context::push_owned_urlifier (std::unique_ptr<urlifier> ptr)
+context::push_owned_urlifier (std::unique_ptr<urlifier> ptr)
{
gcc_assert (m_urlifier_stack);
const urlifier_stack_node node = { ptr.release (), true };
@@ -572,7 +482,7 @@ diagnostic_context::push_owned_urlifier (std::unique_ptr<urlifier> ptr)
}
void
-diagnostic_context::push_borrowed_urlifier (const urlifier &loan)
+context::push_borrowed_urlifier (const urlifier &loan)
{
gcc_assert (m_urlifier_stack);
const urlifier_stack_node node = { const_cast <urlifier *> (&loan), false };
@@ -580,7 +490,7 @@ diagnostic_context::push_borrowed_urlifier (const urlifier &loan)
}
void
-diagnostic_context::pop_urlifier ()
+context::pop_urlifier ()
{
gcc_assert (m_urlifier_stack);
gcc_assert (m_urlifier_stack->length () > 0);
@@ -590,8 +500,8 @@ diagnostic_context::pop_urlifier ()
delete node.m_urlifier;
}
-const logical_location_manager *
-diagnostic_context::get_logical_location_manager () const
+const logical_locations::manager *
+context::get_logical_location_manager () const
{
if (!m_client_data_hooks)
return nullptr;
@@ -599,7 +509,7 @@ diagnostic_context::get_logical_location_manager () const
}
const urlifier *
-diagnostic_context::get_urlifier () const
+context::get_urlifier () const
{
if (!m_urlifier_stack)
return nullptr;
@@ -613,7 +523,7 @@ diagnostic_context::get_urlifier () const
Refresh all output sinks. */
void
-diagnostic_context::set_pretty_printer (std::unique_ptr<pretty_printer> pp)
+context::set_pretty_printer (std::unique_ptr<pretty_printer> pp)
{
delete m_reference_printer;
m_reference_printer = pp.release ();
@@ -623,81 +533,102 @@ diagnostic_context::set_pretty_printer (std::unique_ptr<pretty_printer> pp)
/* Give all output sinks a chance to rebuild their pretty_printer. */
void
-diagnostic_context::refresh_output_sinks ()
+context::refresh_output_sinks ()
{
- for (auto sink : m_output_sinks)
- sink->update_printer ();
+ for (auto sink_ : m_sinks)
+ sink_->update_printer ();
}
/* Set FORMAT_DECODER on the reference printer and on the pretty_printer
of all output sinks. */
void
-diagnostic_context::set_format_decoder (printer_fn format_decoder)
+context::set_format_decoder (printer_fn format_decoder)
{
pp_format_decoder (m_reference_printer) = format_decoder;
- for (auto sink : m_output_sinks)
- pp_format_decoder (sink->get_printer ()) = format_decoder;
+ for (auto sink_ : m_sinks)
+ pp_format_decoder (sink_->get_printer ()) = format_decoder;
}
void
-diagnostic_context::set_show_highlight_colors (bool val)
+context::set_show_highlight_colors (bool val)
{
pp_show_highlight_colors (m_reference_printer) = val;
- for (auto sink : m_output_sinks)
- if (sink->follows_reference_printer_p ())
- pp_show_highlight_colors (sink->get_printer ()) = val;
+ for (auto sink_ : m_sinks)
+ if (sink_->follows_reference_printer_p ())
+ pp_show_highlight_colors (sink_->get_printer ()) = val;
}
void
-diagnostic_context::set_prefixing_rule (diagnostic_prefixing_rule_t rule)
+context::set_prefixing_rule (diagnostic_prefixing_rule_t rule)
{
pp_prefixing_rule (m_reference_printer) = rule;
- for (auto sink : m_output_sinks)
- if (sink->follows_reference_printer_p ())
- pp_prefixing_rule (sink->get_printer ()) = rule;
+ for (auto sink_ : m_sinks)
+ if (sink_->follows_reference_printer_p ())
+ pp_prefixing_rule (sink_->get_printer ()) = rule;
}
void
-diagnostic_context::create_edit_context ()
+context::initialize_fixits_change_set ()
{
- delete m_edit_context_ptr;
+ delete m_fixits_change_set;
gcc_assert (m_file_cache);
- m_edit_context_ptr = new edit_context (*m_file_cache);
+ m_fixits_change_set = new changes::change_set (*m_file_cache);
}
+} // namespace diagnostics
+
/* Initialize DIAGNOSTIC, where the message MSG has already been
translated. */
void
-diagnostic_set_info_translated (diagnostic_info *diagnostic, const char *msg,
- va_list *args, rich_location *richloc,
- diagnostic_t kind)
+diagnostic_set_info_translated (diagnostics::diagnostic_info *diagnostic,
+ const char *msg, va_list *args,
+ rich_location *richloc,
+ enum diagnostics::kind kind)
{
gcc_assert (richloc);
- diagnostic->message.m_err_no = errno;
- diagnostic->message.m_args_ptr = args;
- diagnostic->message.m_format_spec = msg;
- diagnostic->message.m_richloc = richloc;
- diagnostic->richloc = richloc;
- diagnostic->metadata = nullptr;
- diagnostic->kind = kind;
- diagnostic->option_id = 0;
+ diagnostic->m_message.m_err_no = errno;
+ diagnostic->m_message.m_args_ptr = args;
+ diagnostic->m_message.m_format_spec = msg;
+ diagnostic->m_message.m_richloc = richloc;
+ diagnostic->m_richloc = richloc;
+ diagnostic->m_metadata = nullptr;
+ diagnostic->m_kind = kind;
+ diagnostic->m_option_id = 0;
}
/* Initialize DIAGNOSTIC, where the message GMSGID has not yet been
translated. */
void
-diagnostic_set_info (diagnostic_info *diagnostic, const char *gmsgid,
- va_list *args, rich_location *richloc,
- diagnostic_t kind)
+diagnostic_set_info (diagnostics::diagnostic_info *diagnostic,
+ const char *gmsgid, va_list *args,
+ rich_location *richloc,
+ enum diagnostics::kind kind)
{
gcc_assert (richloc);
diagnostic_set_info_translated (diagnostic, _(gmsgid), args, richloc, kind);
}
+namespace diagnostics {
+
+static const char *const diagnostic_kind_text[] = {
+#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
+#include "diagnostics/kinds.def"
+#undef DEFINE_DIAGNOSTIC_KIND
+ "must-not-happen"
+};
+
+/* Get unlocalized string describing KIND. */
+
+const char *
+get_text_for_kind (enum kind kind)
+{
+ return diagnostic_kind_text[static_cast<int> (kind)];
+}
+
static const char *const diagnostic_kind_color[] = {
#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (C),
-#include "diagnostic.def"
+#include "diagnostics/kinds.def"
#undef DEFINE_DIAGNOSTIC_KIND
nullptr
};
@@ -706,9 +637,9 @@ static const char *const diagnostic_kind_color[] = {
Result could be nullptr. */
const char *
-diagnostic_get_color_for_kind (diagnostic_t kind)
+get_color_for_kind (enum kind kind)
{
- return diagnostic_kind_color[kind];
+ return diagnostic_kind_color[static_cast<int> (kind)];
}
/* Given an expanded_location, convert the column (which is in 1-based bytes)
@@ -740,8 +671,7 @@ convert_column_unit (file_cache &fc,
}
}
-diagnostic_column_policy::
-diagnostic_column_policy (const diagnostic_context &dc)
+column_policy::column_policy (const context &dc)
: m_file_cache (dc.get_file_cache ()),
m_column_unit (dc.m_column_unit),
m_column_origin (dc.m_column_origin),
@@ -753,7 +683,7 @@ diagnostic_column_policy (const diagnostic_context &dc)
to the requested units and origin. Return -1 if the column is
invalid (<= 0). */
int
-diagnostic_column_policy::converted_column (expanded_location s) const
+column_policy::converted_column (expanded_location s) const
{
int one_based_col = convert_column_unit (m_file_cache,
m_column_unit, m_tabstop, s);
@@ -765,9 +695,9 @@ diagnostic_column_policy::converted_column (expanded_location s) const
/* Return a string describing a location e.g. "foo.c:42:10". */
label_text
-diagnostic_column_policy::get_location_text (const expanded_location &s,
- bool show_column,
- bool colorize) const
+column_policy::get_location_text (const expanded_location &s,
+ bool show_column,
+ bool colorize) const
{
const char *locus_cs = colorize_start (colorize, "locus");
const char *locus_ce = colorize_stop (colorize);
@@ -786,35 +716,22 @@ diagnostic_column_policy::get_location_text (const expanded_location &s,
line_col, locus_ce));
}
-diagnostic_location_print_policy::
-diagnostic_location_print_policy (const diagnostic_context &dc)
+location_print_policy::
+location_print_policy (const context &dc)
: m_column_policy (dc),
m_show_column (dc.m_show_column)
{
}
-diagnostic_location_print_policy::
-diagnostic_location_print_policy (const diagnostic_text_output_format &text_output)
+location_print_policy::
+location_print_policy (const text_sink &text_output)
:
m_column_policy (text_output.get_context ()),
m_show_column (text_output.get_context ().m_show_column)
{
}
-static const char *const diagnostic_kind_text[] = {
-#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
-#include "diagnostic.def"
-#undef DEFINE_DIAGNOSTIC_KIND
- "must-not-happen"
-};
-
-/* Get unlocalized string describing KIND. */
-
-const char *
-get_diagnostic_kind_text (diagnostic_t kind)
-{
- return diagnostic_kind_text[kind];
-}
+} // namespace diagnostics
/* Functions at which to stop the backtrace print. It's not
particularly helpful to print the callers of these functions. */
@@ -840,10 +757,10 @@ bt_callback (void *data, uintptr_t pc, const char *filename, int lineno,
if (filename == nullptr && function == nullptr)
return 0;
- /* Skip functions in diagnostic.cc. */
+ /* Skip functions in context.cc. */
if (*pcount == 0
&& filename != nullptr
- && strcmp (lbasename (filename), "diagnostic.cc") == 0)
+ && strcmp (lbasename (filename), "context.cc") == 0)
return 0;
/* Print up to 20 functions. We could make this a --param, but
@@ -909,19 +826,21 @@ bt_err_callback (void *data ATTRIBUTE_UNUSED, const char *msg, int errnum)
errnum == 0 ? "" : xstrerror (errnum));
}
+namespace diagnostics {
+
/* Check if we've met the maximum error limit, and if so fatally exit
with a message.
- FLUSH indicates whether a diagnostic_context::finish call is needed. */
+ FLUSH indicates whether a diagnostics::context::finish call is needed. */
void
-diagnostic_context::check_max_errors (bool flush)
+context::check_max_errors (bool flush)
{
if (!m_max_errors)
return;
- int count = (diagnostic_count (DK_ERROR)
- + diagnostic_count (DK_SORRY)
- + diagnostic_count (DK_WERROR));
+ int count = (diagnostic_count (kind::error)
+ + diagnostic_count (kind::sorry)
+ + diagnostic_count (kind::werror));
if (count >= m_max_errors)
{
@@ -938,18 +857,18 @@ diagnostic_context::check_max_errors (bool flush)
is written out. This function does not always return. */
void
-diagnostic_context::action_after_output (diagnostic_t diag_kind)
+context::action_after_output (enum kind diag_kind)
{
switch (diag_kind)
{
- case DK_DEBUG:
- case DK_NOTE:
- case DK_ANACHRONISM:
- case DK_WARNING:
+ case kind::debug:
+ case kind::note:
+ case kind::anachronism:
+ case kind::warning:
break;
- case DK_ERROR:
- case DK_SORRY:
+ case kind::error:
+ case kind::sorry:
if (m_abort_on_error)
real_abort ();
if (m_fatal_errors)
@@ -960,8 +879,8 @@ diagnostic_context::action_after_output (diagnostic_t diag_kind)
}
break;
- case DK_ICE:
- case DK_ICE_NOBT:
+ case kind::ice:
+ case kind::ice_nobt:
{
/* Attempt to ensure that any outputs are flushed e.g. that .sarif
files are written out.
@@ -974,7 +893,7 @@ diagnostic_context::action_after_output (diagnostic_t diag_kind)
}
struct backtrace_state *state = nullptr;
- if (diag_kind == DK_ICE)
+ if (diag_kind == kind::ice)
state = backtrace_create_state (nullptr, 0, bt_err_callback, nullptr);
int count = 0;
if (state != nullptr)
@@ -999,7 +918,7 @@ diagnostic_context::action_after_output (diagnostic_t diag_kind)
exit (ICE_EXIT_CODE);
}
- case DK_FATAL:
+ case kind::fatal:
if (m_abort_on_error)
real_abort ();
fnotice (stderr, "compilation terminated.\n");
@@ -1015,7 +934,7 @@ diagnostic_context::action_after_output (diagnostic_t diag_kind)
its future children if any. */
void
-diagnostic_context::inhibit_notes_in_group (bool inhibit)
+context::inhibit_notes_in_group (bool inhibit)
{
int curr_depth = (m_diagnostic_groups.m_group_nesting_depth
+ m_diagnostic_groups.m_diagnostic_nesting_level);
@@ -1045,7 +964,7 @@ diagnostic_context::inhibit_notes_in_group (bool inhibit)
/* Return whether notes must be inhibited in the current diagnostic_group. */
bool
-diagnostic_context::notes_inhibited_in_group () const
+context::notes_inhibited_in_group () const
{
if (m_diagnostic_groups.m_inhibiting_notes_from
&& (m_diagnostic_groups.m_group_nesting_depth
@@ -1055,84 +974,32 @@ diagnostic_context::notes_inhibited_in_group () const
return false;
}
-/* class logical_location_manager. */
+/* class diagnostics::logical_locations::manager. */
/* Return true iff this is a function or method. */
bool
-logical_location_manager::function_p (key k) const
+logical_locations::manager::function_p (key k) const
{
switch (get_kind (k))
{
default:
gcc_unreachable ();
- case logical_location_kind::unknown:
- case logical_location_kind::module_:
- case logical_location_kind::namespace_:
- case logical_location_kind::type:
- case logical_location_kind::return_type:
- case logical_location_kind::parameter:
- case logical_location_kind::variable:
+ case kind::unknown:
+ case kind::module_:
+ case kind::namespace_:
+ case kind::type:
+ case kind::return_type:
+ case kind::parameter:
+ case kind::variable:
return false;
- case logical_location_kind::function:
- case logical_location_kind::member:
+ case kind::function:
+ case kind::member:
return true;
}
}
-/* Interface to specify diagnostic kind overrides. Returns the
- previous setting, or DK_UNSPECIFIED if the parameters are out of
- range. If OPTION_ID is zero, the new setting is for all the
- diagnostics. */
-diagnostic_t
-diagnostic_option_classifier::
-classify_diagnostic (const diagnostic_context *context,
- diagnostic_option_id option_id,
- diagnostic_t new_kind,
- location_t where)
-{
- diagnostic_t old_kind;
-
- if (option_id.m_idx < 0
- || option_id.m_idx >= m_n_opts
- || new_kind >= DK_LAST_DIAGNOSTIC_KIND)
- return DK_UNSPECIFIED;
-
- old_kind = m_classify_diagnostic[option_id.m_idx];
-
- /* Handle pragmas separately, since we need to keep track of *where*
- the pragmas were. */
- if (where != UNKNOWN_LOCATION)
- {
- unsigned i;
-
- /* Record the command-line status, so we can reset it back on DK_POP. */
- if (old_kind == DK_UNSPECIFIED)
- {
- old_kind = (!context->option_enabled_p (option_id)
- ? DK_IGNORED : DK_ANY);
- m_classify_diagnostic[option_id.m_idx] = old_kind;
- }
-
- diagnostic_classification_change_t *p;
- FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
- if (p->option == option_id.m_idx)
- {
- old_kind = p->kind;
- break;
- }
-
- diagnostic_classification_change_t v
- = { where, option_id.m_idx, new_kind };
- m_classification_history.safe_push (v);
- }
- else
- m_classify_diagnostic[option_id.m_idx] = new_kind;
-
- return old_kind;
-}
-
/* Helper function for print_parseable_fixits. Print TEXT to PP, obeying the
escaping rules for -fdiagnostics-parseable-fixits. */
@@ -1223,7 +1090,7 @@ print_parseable_fixits (file_cache &fc,
/* Update the inlining info in this context for a DIAGNOSTIC. */
void
-diagnostic_context::get_any_inlining_info (diagnostic_info *diagnostic)
+context::get_any_inlining_info (diagnostic_info *diagnostic)
{
auto &ilocs = diagnostic->m_iinfo.m_ilocs;
@@ -1242,58 +1109,6 @@ diagnostic_context::get_any_inlining_info (diagnostic_info *diagnostic)
}
}
-/* Update the kind of DIAGNOSTIC based on its location(s), including
- any of those in its inlining stack, relative to any
- #pragma GCC diagnostic
- directives recorded within this object.
-
- Return the new kind of DIAGNOSTIC if it was updated, or DK_UNSPECIFIED
- otherwise. */
-
-diagnostic_t
-diagnostic_option_classifier::
-update_effective_level_from_pragmas (diagnostic_info *diagnostic) const
-{
- if (m_classification_history.is_empty ())
- return DK_UNSPECIFIED;
-
- /* Iterate over the locations, checking the diagnostic disposition
- for the diagnostic at each. If it's explicitly set as opposed
- to unspecified, update the disposition for this instance of
- the diagnostic and return it. */
- for (location_t loc: diagnostic->m_iinfo.m_ilocs)
- {
- /* FIXME: Stupid search. Optimize later. */
- unsigned int i;
- diagnostic_classification_change_t *p;
- FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
- {
- location_t pragloc = p->location;
- if (!linemap_location_before_p (line_table, pragloc, loc))
- continue;
-
- if (p->kind == (int) DK_POP)
- {
- /* Move on to the next region. */
- i = p->option;
- continue;
- }
-
- diagnostic_option_id option = p->option;
- /* The option 0 is for all the diagnostics. */
- if (option == 0 || option == diagnostic->option_id)
- {
- diagnostic_t kind = p->kind;
- if (kind != DK_UNSPECIFIED)
- diagnostic->kind = kind;
- return kind;
- }
- }
- }
-
- return DK_UNSPECIFIED;
-}
-
/* Generate a URL string describing CWE. The caller is responsible for
freeing the string. */
@@ -1307,80 +1122,79 @@ get_cwe_url (int cwe)
as appropriate for #pragma GCC diagnostic and -Werror=foo. */
bool
-diagnostic_context::diagnostic_enabled (diagnostic_info *diagnostic)
+context::diagnostic_enabled (diagnostic_info *diagnostic)
{
/* Update the inlining stack for this diagnostic. */
get_any_inlining_info (diagnostic);
/* Diagnostics with no option or -fpermissive are always enabled. */
- if (!diagnostic->option_id.m_idx
- || diagnostic->option_id == m_opt_permissive)
+ if (!diagnostic->m_option_id.m_idx
+ || diagnostic->m_option_id == m_opt_permissive)
return true;
/* This tests if the user provided the appropriate -Wfoo or
-Wno-foo option. */
- if (!option_enabled_p (diagnostic->option_id))
+ if (!option_enabled_p (diagnostic->m_option_id))
return false;
/* This tests for #pragma diagnostic changes. */
- diagnostic_t diag_class
+ enum kind diag_class
= m_option_classifier.update_effective_level_from_pragmas (diagnostic);
/* This tests if the user provided the appropriate -Werror=foo
option. */
- if (diag_class == DK_UNSPECIFIED
- && !option_unspecified_p (diagnostic->option_id))
+ if (diag_class == kind::unspecified
+ && !option_unspecified_p (diagnostic->m_option_id))
{
- const diagnostic_t new_kind
- = m_option_classifier.get_current_override (diagnostic->option_id);
- if (new_kind != DK_ANY)
- /* DK_ANY means the diagnostic is not to be ignored, but we don't want
- to change it specifically to DK_ERROR or DK_WARNING; we want to
+ const enum kind new_kind
+ = m_option_classifier.get_current_override (diagnostic->m_option_id);
+ if (new_kind != kind::any)
+ /* kind::any means the diagnostic is not to be ignored, but we don't want
+ to change it specifically to kind::error or kind::warning; we want to
preserve whatever the caller has specified. */
- diagnostic->kind = new_kind;
+ diagnostic->m_kind = new_kind;
}
/* This allows for future extensions, like temporarily disabling
warnings for ranges of source code. */
- if (diagnostic->kind == DK_IGNORED)
+ if (diagnostic->m_kind == kind::ignored)
return false;
return true;
}
-/* Returns whether warning OPTION_ID is enabled at LOC. */
+/* Returns whether warning OPT_ID is enabled at LOC. */
bool
-diagnostic_context::warning_enabled_at (location_t loc,
- diagnostic_option_id option_id)
+context::warning_enabled_at (location_t loc,
+ option_id opt_id)
{
if (!diagnostic_report_warnings_p (this, loc))
return false;
rich_location richloc (line_table, loc);
diagnostic_info diagnostic = {};
- diagnostic.option_id = option_id;
- diagnostic.richloc = &richloc;
- diagnostic.message.m_richloc = &richloc;
- diagnostic.kind = DK_WARNING;
+ diagnostic.m_option_id = opt_id;
+ diagnostic.m_richloc = &richloc;
+ diagnostic.m_message.m_richloc = &richloc;
+ diagnostic.m_kind = kind::warning;
return diagnostic_enabled (&diagnostic);
}
/* Emit a diagnostic within a diagnostic group on this context. */
bool
-diagnostic_context::
-emit_diagnostic_with_group (diagnostic_t kind,
- rich_location &richloc,
- const diagnostic_metadata *metadata,
- diagnostic_option_id option_id,
- const char *gmsgid, ...)
+context::emit_diagnostic_with_group (enum kind kind,
+ rich_location &richloc,
+ const metadata *metadata,
+ option_id opt_id,
+ const char *gmsgid, ...)
{
begin_group ();
va_list ap;
va_start (ap, gmsgid);
- bool ret = emit_diagnostic_with_group_va (kind, richloc, metadata, option_id,
+ bool ret = emit_diagnostic_with_group_va (kind, richloc, metadata, opt_id,
gmsgid, &ap);
va_end (ap);
@@ -1392,16 +1206,15 @@ emit_diagnostic_with_group (diagnostic_t kind,
/* As above, but taking a va_list *. */
bool
-diagnostic_context::
-emit_diagnostic_with_group_va (diagnostic_t kind,
- rich_location &richloc,
- const diagnostic_metadata *metadata,
- diagnostic_option_id option_id,
- const char *gmsgid, va_list *ap)
+context::emit_diagnostic_with_group_va (enum kind kind,
+ rich_location &richloc,
+ const metadata *metadata,
+ option_id opt_id,
+ const char *gmsgid, va_list *ap)
{
begin_group ();
- bool ret = diagnostic_impl (&richloc, metadata, option_id,
+ bool ret = diagnostic_impl (&richloc, metadata, opt_id,
gmsgid, ap, kind);
end_group ();
@@ -1410,15 +1223,15 @@ emit_diagnostic_with_group_va (diagnostic_t kind,
}
/* Report a diagnostic message (an error or a warning) as specified by
- this diagnostic_context.
+ this diagnostics::context.
front-end independent format specifiers are exactly those described
in the documentation of output_format.
Return true if a diagnostic was printed, false otherwise. */
bool
-diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
+context::report_diagnostic (diagnostic_info *diagnostic)
{
- diagnostic_t orig_diag_kind = diagnostic->kind;
+ enum kind orig_diag_kind = diagnostic->m_kind;
/* Every call to report_diagnostic should be within a
begin_group/end_group pair so that output formats can reliably
@@ -1427,8 +1240,8 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
/* Give preference to being able to inhibit warnings, before they
get reclassified to something else. */
- bool was_warning = (diagnostic->kind == DK_WARNING
- || diagnostic->kind == DK_PEDWARN);
+ bool was_warning = (diagnostic->m_kind == kind::warning
+ || diagnostic->m_kind == kind::pedwarn);
if (was_warning && m_inhibit_warnings)
{
inhibit_notes_in_group ();
@@ -1438,15 +1251,15 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
if (m_adjust_diagnostic_info)
m_adjust_diagnostic_info (this, diagnostic);
- if (diagnostic->kind == DK_PEDWARN)
+ if (diagnostic->m_kind == kind::pedwarn)
{
- diagnostic->kind = m_pedantic_errors ? DK_ERROR : DK_WARNING;
+ diagnostic->m_kind = m_pedantic_errors ? kind::error : kind::warning;
/* We do this to avoid giving the message for -pedantic-errors. */
- orig_diag_kind = diagnostic->kind;
+ orig_diag_kind = diagnostic->m_kind;
}
- if (diagnostic->kind == DK_NOTE && m_inhibit_notes_p)
+ if (diagnostic->m_kind == kind::note && m_inhibit_notes_p)
return false;
/* If the user requested that warnings be treated as errors, so be
@@ -1454,10 +1267,10 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
individual warnings can be overridden back to warnings with
-Wno-error=*. */
if (m_warning_as_error_requested
- && diagnostic->kind == DK_WARNING)
- diagnostic->kind = DK_ERROR;
+ && diagnostic->m_kind == kind::warning)
+ diagnostic->m_kind = kind::error;
- diagnostic->message.m_data = &diagnostic->x_data;
+ diagnostic->m_message.m_data = &diagnostic->m_x_data;
/* Check to see if the diagnostic is enabled at the location and
not disabled by #pragma GCC diagnostic anywhere along the inlining
@@ -1468,7 +1281,7 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
return false;
}
- if ((was_warning || diagnostic->kind == DK_WARNING)
+ if ((was_warning || diagnostic->m_kind == kind::warning)
&& ((!m_warn_system_headers
&& diagnostic->m_iinfo.m_allsyslocs)
|| m_inhibit_warnings))
@@ -1476,11 +1289,11 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
inlining stack (if there is one) are in system headers. */
return false;
- if (diagnostic->kind == DK_NOTE && notes_inhibited_in_group ())
+ if (diagnostic->m_kind == kind::note && notes_inhibited_in_group ())
/* Bail for all the notes in the diagnostic_group that started to inhibit notes. */
return false;
- if (diagnostic->kind != DK_NOTE && diagnostic->kind != DK_ICE)
+ if (diagnostic->m_kind != kind::note && diagnostic->m_kind != kind::ice)
check_max_errors (false);
if (m_lock > 0)
@@ -1488,7 +1301,8 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
/* If we're reporting an ICE in the middle of some other error,
try to flush out the previous error, then let this one
through. Don't do this more than once. */
- if ((diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
+ if ((diagnostic->m_kind == kind::ice
+ || diagnostic->m_kind == kind::ice_nobt)
&& m_lock == 1)
pp_newline_and_flush (m_reference_printer);
else
@@ -1500,14 +1314,14 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
m_lock++;
- if (diagnostic->kind == DK_ICE || diagnostic->kind == DK_ICE_NOBT)
+ if (diagnostic->m_kind == kind::ice || diagnostic->m_kind == kind::ice_nobt)
{
/* When not checking, ICEs are converted to fatal errors when an
error has already occurred. This is counteracted by
abort_on_error. */
if (!CHECKING_P
- && (diagnostic_count (DK_ERROR) > 0
- || diagnostic_count (DK_SORRY) > 0)
+ && (diagnostic_count (kind::error) > 0
+ || diagnostic_count (kind::sorry) > 0)
&& !m_abort_on_error)
{
expanded_location s
@@ -1518,32 +1332,32 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
}
if (m_internal_error)
(*m_internal_error) (this,
- diagnostic->message.m_format_spec,
- diagnostic->message.m_args_ptr);
+ diagnostic->m_message.m_format_spec,
+ diagnostic->m_message.m_args_ptr);
}
/* Increment the counter for the appropriate diagnostic kind, either
within this context, or within the diagnostic_buffer. */
{
- const diagnostic_t kind_for_count =
- ((diagnostic->kind == DK_ERROR && orig_diag_kind == DK_WARNING)
- ? DK_WERROR
- : diagnostic->kind);
- diagnostic_counters &counters
+ const enum kind kind_for_count =
+ ((diagnostic->m_kind == kind::error && orig_diag_kind == kind::warning)
+ ? kind::werror
+ : diagnostic->m_kind);
+ counters &cs
= (m_diagnostic_buffer
? m_diagnostic_buffer->m_diagnostic_counters
: m_diagnostic_counters);
- ++counters.m_count_for_kind[kind_for_count];
+ ++cs.m_count_for_kind[static_cast<size_t> (kind_for_count)];
}
/* Is this the initial diagnostic within the stack of groups? */
if (m_diagnostic_groups.m_emission_count == 0)
- for (auto sink : m_output_sinks)
- sink->on_begin_group ();
+ for (auto sink_ : m_sinks)
+ sink_->on_begin_group ();
m_diagnostic_groups.m_emission_count++;
- va_list *orig_args = diagnostic->message.m_args_ptr;
- for (auto sink : m_output_sinks)
+ va_list *orig_args = diagnostic->m_message.m_args_ptr;
+ for (auto sink_ : m_sinks)
{
/* Formatting the message is done per-output-format,
so that each output format gets its own set of pp_token_lists
@@ -1562,13 +1376,13 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
so that each has its own set to consume. */
va_list copied_args;
va_copy (copied_args, *orig_args);
- diagnostic->message.m_args_ptr = &copied_args;
- pp_format (sink->get_printer (), &diagnostic->message);
+ diagnostic->m_message.m_args_ptr = &copied_args;
+ pp_format (sink_->get_printer (), &diagnostic->m_message);
va_end (copied_args);
/* Call vfunc in the output format. This is responsible for
phase 3 of formatting, and for printing the result. */
- sink->on_report_diagnostic (*diagnostic, orig_diag_kind);
+ sink_->on_report_diagnostic (*diagnostic, orig_diag_kind);
}
switch (m_extra_output_kind)
@@ -1577,59 +1391,58 @@ diagnostic_context::report_diagnostic (diagnostic_info *diagnostic)
break;
case EXTRA_DIAGNOSTIC_OUTPUT_fixits_v1:
print_parseable_fixits (get_file_cache (),
- m_reference_printer, diagnostic->richloc,
+ m_reference_printer, diagnostic->m_richloc,
DIAGNOSTICS_COLUMN_UNIT_BYTE,
m_tabstop);
pp_flush (m_reference_printer);
break;
case EXTRA_DIAGNOSTIC_OUTPUT_fixits_v2:
print_parseable_fixits (get_file_cache (),
- m_reference_printer, diagnostic->richloc,
+ m_reference_printer, diagnostic->m_richloc,
DIAGNOSTICS_COLUMN_UNIT_DISPLAY,
m_tabstop);
pp_flush (m_reference_printer);
break;
}
if (m_diagnostic_buffer == nullptr
- || diagnostic->kind == DK_ICE
- || diagnostic->kind == DK_ICE_NOBT)
- action_after_output (diagnostic->kind);
- diagnostic->x_data = nullptr;
+ || diagnostic->m_kind == kind::ice
+ || diagnostic->m_kind == kind::ice_nobt)
+ action_after_output (diagnostic->m_kind);
+ diagnostic->m_x_data = nullptr;
- if (m_edit_context_ptr)
- if (diagnostic->richloc->fixits_can_be_auto_applied_p ())
+ if (m_fixits_change_set)
+ if (diagnostic->m_richloc->fixits_can_be_auto_applied_p ())
if (!m_diagnostic_buffer)
- m_edit_context_ptr->add_fixits (diagnostic->richloc);
+ m_fixits_change_set->add_fixits (diagnostic->m_richloc);
m_lock--;
if (!m_diagnostic_buffer)
- for (auto sink : m_output_sinks)
- sink->after_diagnostic (*diagnostic);
+ for (auto sink_ : m_sinks)
+ sink_->after_diagnostic (*diagnostic);
return true;
}
void
-diagnostic_context::report_verbatim (text_info &text)
+context::report_verbatim (text_info &text)
{
va_list *orig_args = text.m_args_ptr;
- for (auto sink : m_output_sinks)
+ for (auto sink_ : m_sinks)
{
va_list copied_args;
va_copy (copied_args, *orig_args);
text.m_args_ptr = &copied_args;
- sink->on_report_verbatim (text);
+ sink_->on_report_verbatim (text);
va_end (copied_args);
}
}
void
-diagnostic_context::
-report_global_digraph (const diagnostics::digraphs::lazy_digraph &ldg)
+context::report_global_digraph (const lazily_created<digraphs::digraph> &ldg)
{
- for (auto sink : m_output_sinks)
- sink->report_global_digraph (ldg);
+ for (auto sink_ : m_sinks)
+ sink_->report_global_digraph (ldg);
}
/* Get the number of digits in the decimal representation of VALUE. */
@@ -1653,6 +1466,8 @@ num_digits (int value)
return digits;
}
+} // namespace diagnostics
+
/* Given a partial pathname as input, return another pathname that
shares no directory elements with the pathname of __FILE__. This
is used by fancy_abort() to print `internal compiler error in expr.cc'
@@ -1683,43 +1498,48 @@ trim_filename (const char *name)
return p;
}
+namespace diagnostics {
+
/* Implement emit_diagnostic, inform, warning, warning_at, pedwarn,
permerror, error, error_at, error_at, sorry, fatal_error, internal_error,
and internal_error_no_backtrace, as documented and defined below. */
bool
-diagnostic_context::diagnostic_impl (rich_location *richloc,
- const diagnostic_metadata *metadata,
- diagnostic_option_id option_id,
- const char *gmsgid,
- va_list *ap, diagnostic_t kind)
+context::diagnostic_impl (rich_location *richloc,
+ const metadata *metadata,
+ option_id opt_id,
+ const char *gmsgid,
+ va_list *ap, enum kind kind)
{
diagnostic_info diagnostic;
- if (kind == DK_PERMERROR)
+ if (kind == diagnostics::kind::permerror)
{
diagnostic_set_info (&diagnostic, gmsgid, ap, richloc,
- m_permissive ? DK_WARNING : DK_ERROR);
- diagnostic.option_id = (option_id.m_idx != -1 ? option_id : m_opt_permissive);
+ (m_permissive
+ ? diagnostics::kind::warning
+ : diagnostics::kind::error));
+ diagnostic.m_option_id = (opt_id.m_idx != -1 ? opt_id : m_opt_permissive);
}
else
{
diagnostic_set_info (&diagnostic, gmsgid, ap, richloc, kind);
- if (kind == DK_WARNING || kind == DK_PEDWARN)
- diagnostic.option_id = option_id;
+ if (kind == diagnostics::kind::warning
+ || kind == diagnostics::kind::pedwarn)
+ diagnostic.m_option_id = opt_id;
}
- diagnostic.metadata = metadata;
+ diagnostic.m_metadata = metadata;
return report_diagnostic (&diagnostic);
}
/* Implement inform_n, warning_n, and error_n, as documented and
defined below. */
bool
-diagnostic_context::diagnostic_n_impl (rich_location *richloc,
- const diagnostic_metadata *metadata,
- diagnostic_option_id option_id,
- unsigned HOST_WIDE_INT n,
- const char *singular_gmsgid,
- const char *plural_gmsgid,
- va_list *ap, diagnostic_t kind)
+context::diagnostic_n_impl (rich_location *richloc,
+ const metadata *metadata,
+ option_id opt_id,
+ unsigned HOST_WIDE_INT n,
+ const char *singular_gmsgid,
+ const char *plural_gmsgid,
+ va_list *ap, enum kind kind)
{
diagnostic_info diagnostic;
unsigned long gtn;
@@ -1734,9 +1554,9 @@ diagnostic_context::diagnostic_n_impl (rich_location *richloc,
const char *text = ngettext (singular_gmsgid, plural_gmsgid, gtn);
diagnostic_set_info_translated (&diagnostic, text, ap, richloc, kind);
- if (kind == DK_WARNING)
- diagnostic.option_id = option_id;
- diagnostic.metadata = metadata;
+ if (kind == diagnostics::kind::warning)
+ diagnostic.m_option_id = opt_id;
+ diagnostic.m_metadata = metadata;
return report_diagnostic (&diagnostic);
}
@@ -1744,13 +1564,13 @@ diagnostic_context::diagnostic_n_impl (rich_location *richloc,
/* Emit DIAGRAM to this context, respecting the output format. */
void
-diagnostic_context::emit_diagram (const diagnostic_diagram &diagram)
+context::emit_diagram (const diagram &diag)
{
if (m_diagrams.m_theme == nullptr)
return;
- for (auto sink : m_output_sinks)
- sink->on_diagram (diagram);
+ for (auto sink_ : m_sinks)
+ sink_->on_diagram (diag);
}
/* Inform the user that an error occurred while trying to report some
@@ -1759,7 +1579,7 @@ diagnostic_context::emit_diagram (const diagnostic_diagram &diagram)
This mustn't use internal_error, that will cause infinite recursion. */
void
-diagnostic_context::error_recursion ()
+context::error_recursion ()
{
if (m_lock < 3)
pp_newline_and_flush (m_reference_printer);
@@ -1769,13 +1589,15 @@ diagnostic_context::error_recursion ()
/* Call action_after_output to get the "please submit a bug report"
message. */
- action_after_output (DK_ICE);
+ action_after_output (kind::ice);
/* Do not use gcc_unreachable here; that goes through internal_error
and therefore would cause infinite recursion. */
real_abort ();
}
+} // namespace diagnostics
+
/* Report an internal compiler error in a friendly manner. This is
the function that gets called upon use of abort() in the source
code generally, thanks to a special macro. */
@@ -1795,7 +1617,7 @@ fancy_abort (const char *file, int line, const char *function)
if (global_dc->get_reference_printer () == nullptr)
{
/* Print the error message. */
- fnotice (stderr, diagnostic_kind_text[DK_ICE]);
+ fnotice (stderr, diagnostics::get_text_for_kind (diagnostics::kind::ice));
fnotice (stderr, "in %s, at %s:%d", function, trim_filename (file), line);
fputc ('\n', stderr);
@@ -1818,16 +1640,18 @@ fancy_abort (const char *file, int line, const char *function)
internal_error ("in %s, at %s:%d", function, trim_filename (file), line);
}
-/* class diagnostic_context. */
+namespace diagnostics {
+
+/* class diagnostics::context. */
void
-diagnostic_context::begin_group ()
+context::begin_group ()
{
m_diagnostic_groups.m_group_nesting_depth++;
}
void
-diagnostic_context::end_group ()
+context::end_group ()
{
if (--m_diagnostic_groups.m_group_nesting_depth == 0)
{
@@ -1835,8 +1659,8 @@ diagnostic_context::end_group ()
If any diagnostics were emitted, give the context a chance
to do something. */
if (m_diagnostic_groups.m_emission_count > 0)
- for (auto sink : m_output_sinks)
- sink->on_end_group ();
+ for (auto sink_ : m_sinks)
+ sink_->on_end_group ();
m_diagnostic_groups.m_emission_count = 0;
}
/* We're popping one level, so might need to stop inhibiting notes. */
@@ -1844,13 +1668,13 @@ diagnostic_context::end_group ()
}
void
-diagnostic_context::push_nesting_level ()
+context::push_nesting_level ()
{
++m_diagnostic_groups.m_diagnostic_nesting_level;
}
void
-diagnostic_context::pop_nesting_level ()
+context::pop_nesting_level ()
{
--m_diagnostic_groups.m_diagnostic_nesting_level;
/* We're popping one level, so might need to stop inhibiting notes. */
@@ -1858,29 +1682,29 @@ diagnostic_context::pop_nesting_level ()
}
void
-diagnostic_output_format::dump (FILE *out, int indent) const
+sink::dump (FILE *out, int indent) const
{
fprintf (out, "%*sprinter:\n", indent, "");
m_printer->dump (out, indent + 2);
}
void
-diagnostic_output_format::on_report_verbatim (text_info &)
+sink::on_report_verbatim (text_info &)
{
/* No-op. */
}
-/* Set the output format for CONTEXT to FORMAT, using BASE_FILE_NAME for
+/* Set the output format for DC to FORMAT, using BASE_FILE_NAME for
file-based output formats. */
void
-diagnostic_output_format_init (diagnostic_context &context,
- const char *main_input_filename_,
- const char *base_file_name,
- enum diagnostics_output_format format,
- bool json_formatting)
+output_format_init (context &dc,
+ const char *main_input_filename_,
+ const char *base_file_name,
+ enum diagnostics_output_format format,
+ bool json_formatting)
{
- diagnostic_output_format *new_sink = nullptr;
+ sink *new_sink = nullptr;
switch (format)
{
default:
@@ -1890,16 +1714,16 @@ diagnostic_output_format_init (diagnostic_context &context,
break;
case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR:
- new_sink = &diagnostic_output_format_init_sarif_stderr (context,
- line_table,
- json_formatting);
+ new_sink = &init_sarif_stderr (dc,
+ line_table,
+ json_formatting);
break;
case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE:
- new_sink = &diagnostic_output_format_init_sarif_file (context,
- line_table,
- json_formatting,
- base_file_name);
+ new_sink = &init_sarif_file (dc,
+ line_table,
+ json_formatting,
+ base_file_name);
break;
}
if (new_sink)
@@ -1911,8 +1735,7 @@ diagnostic_output_format_init (diagnostic_context &context,
(or nullptr for "no diagrams"). */
void
-diagnostic_context::
-set_text_art_charset (enum diagnostic_text_art_charset charset)
+context::set_text_art_charset (enum diagnostic_text_art_charset charset)
{
delete m_diagrams.m_theme;
switch (charset)
@@ -1938,95 +1761,24 @@ set_text_art_charset (enum diagnostic_text_art_charset charset)
}
}
-/* If BUFFER is non-null, use BUFFER as the active diagnostic_buffer on
- this context. BUFFER is borrowed.
+/* struct diagnostics::counters. */
- If BUFFER is null, stop any buffering on this context until the next call
- to this function. */
-
-void
-diagnostic_context::set_diagnostic_buffer (diagnostic_buffer *buffer)
-{
- /* We don't allow changing buffering within a diagnostic group
- (to simplify handling of buffered diagnostics within the
- diagnostic_format implementations). */
- gcc_assert (m_diagnostic_groups.m_group_nesting_depth == 0);
-
- /* Likewise, for simplicity, we only allow changing buffers
- at nesting level 0. */
- gcc_assert (m_diagnostic_groups.m_diagnostic_nesting_level == 0);
-
- m_diagnostic_buffer = buffer;
-
- if (buffer)
- {
- buffer->ensure_per_format_buffers ();
- gcc_assert (buffer->m_per_format_buffers);
- gcc_assert (buffer->m_per_format_buffers->length ()
- == m_output_sinks.length ());
- for (unsigned idx = 0; idx < m_output_sinks.length (); ++idx)
- {
- auto sink = m_output_sinks[idx];
- auto per_format_buffer = (*buffer->m_per_format_buffers)[idx];
- sink->set_buffer (per_format_buffer);
- }
- }
- else
- for (auto sink : m_output_sinks)
- sink->set_buffer (nullptr);
-}
-
-/* Clear BUFFER without flushing it. */
-
-void
-diagnostic_context::clear_diagnostic_buffer (diagnostic_buffer &buffer)
-{
- if (buffer.m_per_format_buffers)
- for (auto per_format_buffer : *buffer.m_per_format_buffers)
- per_format_buffer->clear ();
-
- buffer.m_diagnostic_counters.clear ();
-
- /* We need to reset last_location, otherwise we may skip caret lines
- when we actually give a diagnostic. */
- m_last_location = UNKNOWN_LOCATION;
-}
-
-/* Flush the diagnostics in BUFFER to this context, clearing BUFFER. */
-
-void
-diagnostic_context::flush_diagnostic_buffer (diagnostic_buffer &buffer)
-{
- bool had_errors
- = (buffer.m_diagnostic_counters.m_count_for_kind[DK_ERROR] > 0
- || buffer.m_diagnostic_counters.m_count_for_kind[DK_WERROR] > 0);
- if (buffer.m_per_format_buffers)
- for (auto per_format_buffer : *buffer.m_per_format_buffers)
- per_format_buffer->flush ();
- buffer.m_diagnostic_counters.move_to (m_diagnostic_counters);
-
- action_after_output (had_errors ? DK_ERROR : DK_WARNING);
- check_max_errors (true);
-}
-
-/* struct diagnostic_counters. */
-
-diagnostic_counters::diagnostic_counters ()
+counters::counters ()
{
clear ();
}
void
-diagnostic_counters::dump (FILE *out, int indent) const
+counters::dump (FILE *out, int indent) const
{
fprintf (out, "%*scounts:\n", indent, "");
bool none = true;
- for (int i = 0; i < DK_LAST_DIAGNOSTIC_KIND; i++)
+ for (int i = 0; i < static_cast<int> (kind::last_diagnostic_kind); i++)
if (m_count_for_kind[i] > 0)
{
fprintf (out, "%*s%s%i\n",
indent + 2, "",
- get_diagnostic_kind_text (static_cast<diagnostic_t> (i)),
+ get_text_for_kind (static_cast<enum kind> (i)),
m_count_for_kind[i]);
none = false;
}
@@ -2035,133 +1787,31 @@ diagnostic_counters::dump (FILE *out, int indent) const
}
void
-diagnostic_counters::move_to (diagnostic_counters &dest)
+counters::move_to (counters &dest)
{
- for (int i = 0; i < DK_LAST_DIAGNOSTIC_KIND; i++)
+ for (int i = 0; i < static_cast<int> (kind::last_diagnostic_kind); i++)
dest.m_count_for_kind[i] += m_count_for_kind[i];
clear ();
}
void
-diagnostic_counters::clear ()
+counters::clear ()
{
memset (&m_count_for_kind, 0, sizeof m_count_for_kind);
}
-/* class diagnostic_buffer. */
-
-diagnostic_buffer::diagnostic_buffer (diagnostic_context &ctxt)
-: m_ctxt (ctxt),
- m_per_format_buffers (nullptr)
-{
-}
-
-diagnostic_buffer::~diagnostic_buffer ()
-{
- if (m_per_format_buffers)
- {
- for (auto iter : *m_per_format_buffers)
- delete iter;
- delete m_per_format_buffers;
- }
-}
-
-void
-diagnostic_buffer::dump (FILE *out, int indent) const
-{
- m_diagnostic_counters.dump (out, indent + 2);
- fprintf (out, "%*sm_per_format_buffers:\n", indent, "");
- if (m_per_format_buffers)
- for (auto per_format_buffer : *m_per_format_buffers)
- per_format_buffer->dump (out, indent + 2);
- else
- fprintf (out, "%*s(none)\n", indent + 2, "");
-}
-
-bool
-diagnostic_buffer::empty_p () const
-{
- if (m_per_format_buffers)
- for (auto per_format_buffer : *m_per_format_buffers)
- /* Query initial buffer. */
- return per_format_buffer->empty_p ();
- return true;
-}
-
-void
-diagnostic_buffer::move_to (diagnostic_buffer &dest)
-{
- /* Bail if there's nothing to move. */
- if (!m_per_format_buffers)
- return;
-
- m_diagnostic_counters.move_to (dest.m_diagnostic_counters);
-
- if (!dest.m_per_format_buffers)
- {
- /* Optimization for the "move to empty" case:
- simply move the vec to the dest. */
- dest.m_per_format_buffers = m_per_format_buffers;
- m_per_format_buffers = nullptr;
- return;
- }
-
- dest.ensure_per_format_buffers ();
- gcc_assert (m_per_format_buffers);
- gcc_assert (m_per_format_buffers->length ()
- == m_ctxt.m_output_sinks.length ());
- gcc_assert (dest.m_per_format_buffers);
- gcc_assert (dest.m_per_format_buffers->length ()
- == m_ctxt.m_output_sinks.length ());
- for (unsigned idx = 0; idx < m_ctxt.m_output_sinks.length (); ++idx)
- {
- auto per_format_buffer_src = (*m_per_format_buffers)[idx];
- auto per_format_buffer_dest = (*dest.m_per_format_buffers)[idx];
- per_format_buffer_src->move_to (*per_format_buffer_dest);
- }
-}
-
-/* Lazily get the output formats to create their own kind of buffers.
- We can't change the output sinks on a context once this has been called
- on any diagnostic_buffer instances for that context, since there's no
- way to update all diagnostic_buffer instances for that context. */
-
-void
-diagnostic_buffer::ensure_per_format_buffers ()
-{
- if (!m_per_format_buffers)
- {
- m_per_format_buffers = new auto_vec<diagnostic_per_format_buffer *> ();
- for (unsigned idx = 0; idx < m_ctxt.m_output_sinks.length (); ++idx)
- {
- auto sink = m_ctxt.m_output_sinks[idx];
- auto per_format_buffer = sink->make_per_format_buffer ();
- m_per_format_buffers->safe_push (per_format_buffer.release ());
- }
- }
- gcc_assert (m_per_format_buffers);
- gcc_assert (m_per_format_buffers->length ()
- == m_ctxt.m_output_sinks.length ());
-}
-
-/* Really call the system 'abort'. This has to go right at the end of
- this file, so that there are no functions after it that call abort
- and get the system abort instead of our macro. */
-#undef abort
-static void
-real_abort (void)
-{
- abort ();
-}
-
#if CHECKING_P
namespace selftest {
+using line_table_test = ::selftest::line_table_test;
+using temp_source_file = ::selftest::temp_source_file;
+
/* Helper function for test_print_escaped_string. */
static void
-assert_print_escaped_string (const location &loc, const char *expected_output,
+assert_print_escaped_string (const ::selftest::location &loc,
+ const char *expected_output,
const char *input)
{
pretty_printer pp;
@@ -2346,7 +1996,7 @@ test_print_parseable_fixits_bytes_vs_display_columns ()
}
/* Verify that
- diagnostic_column_policy::get_location_text (..., SHOW_COLUMN, ...)
+ diagnostics::column_policy::get_location_text (..., SHOW_COLUMN, ...)
generates EXPECTED_LOC_TEXT, given FILENAME, LINE, COLUMN, with
colorization disabled. */
@@ -2358,7 +2008,7 @@ assert_location_text (const char *expected_loc_text,
enum diagnostics_column_unit column_unit
= DIAGNOSTICS_COLUMN_UNIT_BYTE)
{
- test_diagnostic_context dc;
+ diagnostics::selftest::test_context dc;
dc.m_column_unit = column_unit;
dc.m_column_origin = origin;
@@ -2369,7 +2019,7 @@ assert_location_text (const char *expected_loc_text,
xloc.data = nullptr;
xloc.sysp = false;
- diagnostic_column_policy column_policy (dc);
+ diagnostics::column_policy column_policy (dc);
label_text actual_loc_text
= column_policy.get_location_text (xloc, show_column, false);
ASSERT_STREQ (expected_loc_text, actual_loc_text.get ());
@@ -2396,8 +2046,8 @@ test_get_location_text ()
assert_location_text ("foo.c:42:", "foo.c", 42, 10, false);
assert_location_text ("foo.c:", "foo.c", 0, 10, false);
- maybe_line_and_column (INT_MAX, INT_MAX);
- maybe_line_and_column (INT_MIN, INT_MIN);
+ diagnostics::maybe_line_and_column (INT_MAX, INT_MAX);
+ diagnostics::maybe_line_and_column (INT_MIN, INT_MIN);
{
/* In order to test display columns vs byte columns, we need to create a
@@ -2460,10 +2110,14 @@ test_num_digits ()
ASSERT_EQ (8, num_digits (99999999));
}
-/* Run all of the selftests within this file. */
+/* Run all of the selftests within this file.
+
+ According to https://gcc.gnu.org/pipermail/gcc/2021-November/237703.html
+ there are some language-specific assumptions within these tests, so only
+ run them from C/C++. */
void
-c_diagnostic_cc_tests ()
+context_cc_tests ()
{
test_print_escaped_string ();
test_print_parseable_fixits_none ();
@@ -2475,10 +2129,23 @@ c_diagnostic_cc_tests ()
test_num_digits ();
}
-} // namespace selftest
+} // namespace diagnostics::selftest
+} // namespace diagnostics
#endif /* #if CHECKING_P */
#if __GNUC__ >= 10
# pragma GCC diagnostic pop
#endif
+
+static void real_abort (void) ATTRIBUTE_NORETURN;
+
+/* Really call the system 'abort'. This has to go right at the end of
+ this file, so that there are no functions after it that call abort
+ and get the system abort instead of our macro. */
+#undef abort
+static void
+real_abort (void)
+{
+ abort ();
+}
diff --git a/gcc/diagnostics/context.h b/gcc/diagnostics/context.h
new file mode 100644
index 0000000..f47370b
--- /dev/null
+++ b/gcc/diagnostics/context.h
@@ -0,0 +1,959 @@
+/* Declare diagnostics::context and related types.
+ Copyright (C) 2000-2025 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/>. */
+
+#ifndef GCC_DIAGNOSTICS_CONTEXT_H
+#define GCC_DIAGNOSTICS_CONTEXT_H
+
+#include "lazily-created.h"
+#include "unique-argv.h"
+#include "diagnostics/option-classifier.h"
+#include "diagnostics/context-options.h"
+
+namespace diagnostics {
+
+ namespace changes {
+ class change_set;
+ }
+
+ namespace digraphs { class digraph; }
+
+ namespace logical_locations {
+ class manager;
+ }
+
+ class buffer;
+ class client_data_hooks;
+ class diagram;
+ class sink;
+ class text_sink;
+
+ class source_effect_info;
+
+} // namespace diagnostics
+
+namespace text_art
+{
+ class theme;
+} // namespace text_art
+
+namespace xml
+{
+ class printer;
+} // namespace xml
+
+namespace diagnostics {
+
+/* Forward declarations. */
+class context;
+class location_print_policy;
+class source_print_policy;
+
+typedef void (*text_starter_fn) (text_sink &,
+ const diagnostic_info *);
+
+struct to_text;
+struct to_html;
+
+extern pretty_printer *get_printer (to_text &);
+
+template <typename TextOrHtml>
+using start_span_fn = void (*) (const location_print_policy &,
+ TextOrHtml &text_or_html,
+ expanded_location);
+
+typedef void (*text_finalizer_fn) (text_sink &,
+ const diagnostic_info *,
+ enum kind);
+
+/* Abstract base class for the diagnostic subsystem to make queries
+ about command-line options. */
+
+class option_manager
+{
+public:
+ virtual ~option_manager () {}
+
+ /* Return 1 if option OPT_ID is enabled, 0 if it is disabled,
+ or -1 if it isn't a simple on-off switch
+ (or if the value is unknown, typically set later in target). */
+ virtual int option_enabled_p (option_id opt_id) const = 0;
+
+ /* Return malloced memory for the name of the option OPT_ID
+ which enabled a diagnostic, originally of type ORIG_DIAG_KIND but
+ possibly converted to DIAG_KIND by options such as -Werror.
+ May return NULL if no name is to be printed.
+ May be passed 0 as well as the index of a particular option. */
+ virtual char *make_option_name (option_id opt_id,
+ enum kind orig_diag_kind,
+ enum kind diag_kind) const = 0;
+
+ /* Return malloced memory for a URL describing the option that controls
+ a diagnostic.
+ May return NULL if no URL is available.
+ May be passed 0 as well as the index of a particular option. */
+ virtual char *make_option_url (option_id opt_id) const = 0;
+};
+
+/* A bundle of options relating to printing the user's source code
+ (potentially with a margin, underlining, labels, etc). */
+
+struct source_printing_options
+{
+ /* True if we should print the source line with a caret indicating
+ the location.
+ Corresponds to -fdiagnostics-show-caret. */
+ bool enabled;
+
+ /* Maximum width of the source line printed. */
+ int max_width;
+
+ /* Character used at the caret when printing source locations. */
+ char caret_chars[rich_location::STATICALLY_ALLOCATED_RANGES];
+
+ /* When printing source code, should the characters at carets and ranges
+ be colorized? (assuming colorization is on at all).
+ This should be true for frontends that generate range information
+ (so that the ranges of code are colorized),
+ and false for frontends that merely specify points within the
+ source code (to avoid e.g. colorizing just the first character in
+ a token, which would look strange). */
+ bool colorize_source_p;
+
+ /* When printing source code, should labelled ranges be printed?
+ Corresponds to -fdiagnostics-show-labels. */
+ bool show_labels_p;
+
+ /* When printing source code, should there be a left-hand margin
+ showing line numbers?
+ Corresponds to -fdiagnostics-show-line-numbers. */
+ bool show_line_numbers_p;
+
+ /* If printing source code, what should the minimum width of the margin
+ be? Line numbers will be right-aligned, and padded to this width.
+ Corresponds to -fdiagnostics-minimum-margin-width=VALUE. */
+ int min_margin_width;
+
+ /* Usable by plugins; if true, print a debugging ruler above the
+ source output. */
+ bool show_ruler_p;
+
+ /* When printing events in an inline path, should we print lines
+ visualizing links between related events (e.g. for CFG paths)?
+ Corresponds to -fdiagnostics-show-event-links. */
+ bool show_event_links_p;
+};
+
+/* A bundle of state for determining column numbers in diagnostics
+ (tab stops, whether to start at 0 or 1, etc).
+ Uses a file_cache to handle tabs. */
+
+class column_policy
+{
+public:
+ column_policy (const context &dc);
+
+ int converted_column (expanded_location s) const;
+
+ label_text get_location_text (const expanded_location &s,
+ bool show_column,
+ bool colorize) const;
+
+ int get_tabstop () const { return m_tabstop; }
+
+private:
+ file_cache &m_file_cache;
+ enum diagnostics_column_unit m_column_unit;
+ int m_column_origin;
+ int m_tabstop;
+};
+
+/* A bundle of state for printing locations within diagnostics
+ (e.g. "FILENAME:LINE:COLUMN"), to isolate the interactions between
+ context and the start_span callbacks. */
+
+class location_print_policy
+{
+public:
+ location_print_policy (const context &dc);
+ location_print_policy (const text_sink &);
+
+ bool show_column_p () const { return m_show_column; }
+
+ const column_policy &
+ get_column_policy () const { return m_column_policy; }
+
+ void
+ print_text_span_start (const context &dc,
+ pretty_printer &pp,
+ const expanded_location &exploc);
+
+ void
+ print_html_span_start (const context &dc,
+ xml::printer &xp,
+ const expanded_location &exploc);
+
+private:
+ column_policy m_column_policy;
+ bool m_show_column;
+};
+
+/* Abstract base class for optionally supplying extra tags when writing
+ out annotation labels in HTML output. */
+
+class html_label_writer
+{
+public:
+ virtual ~html_label_writer () {}
+ virtual void begin_label () = 0;
+ virtual void end_label () = 0;
+};
+
+/* A bundle of state for printing source within a diagnostic,
+ to isolate the interactions between context and the
+ implementation of diagnostic_show_locus. */
+
+class source_print_policy
+{
+public:
+ source_print_policy (const context &);
+ source_print_policy (const context &,
+ const source_printing_options &);
+
+ void
+ print (pretty_printer &pp,
+ const rich_location &richloc,
+ enum kind diagnostic_kind,
+ source_effect_info *effect_info) const;
+
+ void
+ print_as_html (xml::printer &xp,
+ const rich_location &richloc,
+ enum kind diagnostic_kind,
+ source_effect_info *effect_info,
+ html_label_writer *label_writer) const;
+
+ const source_printing_options &
+ get_options () const { return m_options; }
+
+ start_span_fn<to_text>
+ get_text_start_span_fn () const { return m_text_start_span_cb; }
+
+ start_span_fn<to_html>
+ get_html_start_span_fn () const { return m_html_start_span_cb; }
+
+ file_cache &
+ get_file_cache () const { return m_file_cache; }
+
+ enum diagnostics_escape_format
+ get_escape_format () const
+ {
+ return m_escape_format;
+ }
+
+ text_art::theme *
+ get_diagram_theme () const { return m_diagram_theme; }
+
+ const column_policy &get_column_policy () const
+ {
+ return m_location_policy.get_column_policy ();
+ }
+
+ const location_print_policy &get_location_policy () const
+ {
+ return m_location_policy;
+ }
+
+private:
+ const source_printing_options &m_options;
+ location_print_policy m_location_policy;
+ start_span_fn<to_text> m_text_start_span_cb;
+ start_span_fn<to_html> m_html_start_span_cb;
+ file_cache &m_file_cache;
+
+ /* Other data copied from context. */
+ text_art::theme *m_diagram_theme;
+ enum diagnostics_escape_format m_escape_format;
+};
+
+/* A collection of counters of diagnostics, per-kind
+ (e.g. "3 errors and 1 warning"), for use by both context
+ and by diagnostics::buffer. */
+
+struct counters
+{
+ counters ();
+
+ void dump (FILE *out, int indent) const;
+ void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
+
+ int get_count (enum kind kind) const
+ {
+ return m_count_for_kind[static_cast<size_t> (kind)];
+ }
+
+ void move_to (counters &dest);
+ void clear ();
+
+ int m_count_for_kind[static_cast<size_t> (kind::last_diagnostic_kind)];
+};
+
+/* This class encapsulates the state of the diagnostics subsystem
+ as a whole (either directly, or via owned objects of other classes, to
+ avoid global variables).
+
+ It has responsibility for:
+ - being a central place for clients to report diagnostics
+ - reporting those diagnostics to zero or more output sinks
+ (e.g. text vs SARIF)
+ - providing a "dump" member function for a debug dump of the state of
+ the diagnostics subsytem
+ - direct vs buffered diagnostics (see class diagnostics::buffer)
+ - tracking the original argv of the program (for SARIF output)
+ - crash-handling
+
+ It delegates responsibility to various other classes:
+ - the various output sinks (instances of diagnostics::sink
+ subclasses)
+ - formatting of messages (class pretty_printer)
+ - an optional urlifier to inject URLs into formatted messages
+ - counting the number of diagnostics reported of each kind
+ (class diagnostics::counters)
+ - calling out to a option_manager to determine if
+ a particular warning is enabled or disabled
+ - tracking pragmas that enable/disable warnings in a range of
+ source code
+ - a cache for use when quoting the user's source code (class file_cache)
+ - a text_art::theme
+ - a diagnostics::changes::change_set for generating patches from fix-it hints
+ - diagnostics::client_data_hooks for metadata.
+
+ Try to avoid adding new responsibilities to this class itself, to avoid
+ the "blob" anti-pattern. */
+
+class context
+{
+public:
+ /* Give access to m_text_callbacks. */
+ // FIXME: these need updating
+ friend text_starter_fn &
+ text_starter (context *dc);
+ friend start_span_fn<to_text> &
+ start_span (context *dc);
+ friend text_finalizer_fn &
+ text_finalizer (context *dc);
+
+ friend class source_print_policy;
+ friend class text_sink;
+ friend class buffer;
+
+ typedef void (*set_locations_callback_t) (context *,
+ diagnostic_info *);
+
+ void initialize (int n_opts);
+ void color_init (int value);
+ void urls_init (int value);
+ void set_pretty_printer (std::unique_ptr<pretty_printer> pp);
+ void refresh_output_sinks ();
+
+ void finish ();
+
+ void dump (FILE *out) const;
+ void DEBUG_FUNCTION dump () const { dump (stderr); }
+
+ bool execution_failed_p () const;
+
+ void set_original_argv (unique_argv original_argv);
+ const char * const *get_original_argv ()
+ {
+ return const_cast<const char * const *> (m_original_argv);
+ }
+
+ void set_set_locations_callback (set_locations_callback_t cb)
+ {
+ m_set_locations_cb = cb;
+ }
+
+ void
+ initialize_input_context (diagnostic_input_charset_callback ccb,
+ bool should_skip_bom);
+
+ void begin_group ();
+ void end_group ();
+
+ void push_nesting_level ();
+ void pop_nesting_level ();
+
+ bool warning_enabled_at (location_t loc, option_id opt_id);
+
+ bool option_unspecified_p (option_id opt_id) const
+ {
+ return m_option_classifier.option_unspecified_p (opt_id);
+ }
+
+ bool emit_diagnostic_with_group (enum kind kind,
+ rich_location &richloc,
+ const metadata *metadata,
+ option_id opt_id,
+ const char *gmsgid, ...)
+ ATTRIBUTE_GCC_DIAG(6,7);
+ bool emit_diagnostic_with_group_va (enum kind kind,
+ rich_location &richloc,
+ const metadata *metadata,
+ option_id opt_id,
+ const char *gmsgid, va_list *ap)
+ ATTRIBUTE_GCC_DIAG(6,0);
+
+ bool report_diagnostic (diagnostic_info *);
+ void report_verbatim (text_info &);
+
+ /* Report a directed graph associated with the run as a whole
+ to any sinks that support directed graphs. */
+ void
+ report_global_digraph (const lazily_created<digraphs::digraph> &);
+
+ enum kind
+ classify_diagnostic (option_id opt_id,
+ enum kind new_kind,
+ location_t where)
+ {
+ return m_option_classifier.classify_diagnostic (this,
+ opt_id,
+ new_kind,
+ where);
+ }
+
+ void push_diagnostics (location_t where ATTRIBUTE_UNUSED)
+ {
+ m_option_classifier.push ();
+ }
+ void pop_diagnostics (location_t where)
+ {
+ m_option_classifier.pop (where);
+ }
+
+ void maybe_show_locus (const rich_location &richloc,
+ const source_printing_options &opts,
+ enum kind diagnostic_kind,
+ pretty_printer &pp,
+ source_effect_info *effect_info);
+ void maybe_show_locus_as_html (const rich_location &richloc,
+ const source_printing_options &opts,
+ enum kind diagnostic_kind,
+ xml::printer &xp,
+ source_effect_info *effect_info,
+ html_label_writer *label_writer);
+
+ void emit_diagram (const diagram &diag);
+
+ /* Various setters for use by option-handling logic. */
+ void set_sink (std::unique_ptr<sink> sink_);
+ void set_text_art_charset (enum diagnostic_text_art_charset charset);
+ void set_client_data_hooks (std::unique_ptr<client_data_hooks> hooks);
+
+ void push_owned_urlifier (std::unique_ptr<urlifier>);
+ void push_borrowed_urlifier (const urlifier &);
+ void pop_urlifier ();
+
+ void initialize_fixits_change_set ();
+ void set_warning_as_error_requested (bool val)
+ {
+ m_warning_as_error_requested = val;
+ }
+ void set_report_bug (bool val) { m_report_bug = val; }
+ void set_extra_output_kind (enum diagnostics_extra_output_kind kind)
+ {
+ m_extra_output_kind = kind;
+ }
+ void set_show_cwe (bool val) { m_show_cwe = val; }
+ void set_show_rules (bool val) { m_show_rules = val; }
+ void set_show_highlight_colors (bool val);
+ void set_path_format (enum diagnostic_path_format val)
+ {
+ m_path_format = val;
+ }
+ void set_show_path_depths (bool val) { m_show_path_depths = val; }
+ void set_show_option_requested (bool val) { m_show_option_requested = val; }
+ void set_max_errors (int val) { m_max_errors = val; }
+ void set_escape_format (enum diagnostics_escape_format val)
+ {
+ m_escape_format = val;
+ }
+
+ void set_format_decoder (printer_fn format_decoder);
+ void set_prefixing_rule (diagnostic_prefixing_rule_t rule);
+
+ /* Various accessors. */
+ bool warning_as_error_requested_p () const
+ {
+ return m_warning_as_error_requested;
+ }
+ bool show_path_depths_p () const { return m_show_path_depths; }
+ sink &get_sink (size_t idx) const;
+ enum diagnostic_path_format get_path_format () const { return m_path_format; }
+ enum diagnostics_escape_format get_escape_format () const
+ {
+ return m_escape_format;
+ }
+
+ file_cache &
+ get_file_cache () const
+ {
+ gcc_assert (m_file_cache);
+ return *m_file_cache;
+ }
+
+ changes::change_set *get_fixits_change_set () const
+ {
+ return m_fixits_change_set;
+ }
+ const client_data_hooks *get_client_data_hooks () const
+ {
+ return m_client_data_hooks;
+ }
+
+ const logical_locations::manager *
+ get_logical_location_manager () const;
+
+ const urlifier *get_urlifier () const;
+
+ text_art::theme *get_diagram_theme () const { return m_diagrams.m_theme; }
+
+ int &diagnostic_count (enum kind kind)
+ {
+ return m_diagnostic_counters.m_count_for_kind[static_cast<size_t> (kind)];
+ }
+ int diagnostic_count (enum kind kind) const
+ {
+ return m_diagnostic_counters.get_count (kind);
+ }
+
+ /* Option-related member functions. */
+ inline bool option_enabled_p (option_id opt_id) const
+ {
+ if (!m_option_mgr)
+ return true;
+ return m_option_mgr->option_enabled_p (opt_id);
+ }
+
+ inline char *make_option_name (option_id opt_id,
+ enum kind orig_diag_kind,
+ enum kind diag_kind) const
+ {
+ if (!m_option_mgr)
+ return nullptr;
+ return m_option_mgr->make_option_name (opt_id,
+ orig_diag_kind,
+ diag_kind);
+ }
+
+ inline char *make_option_url (option_id opt_id) const
+ {
+ if (!m_option_mgr)
+ return nullptr;
+ return m_option_mgr->make_option_url (opt_id);
+ }
+
+ void
+ set_option_manager (std::unique_ptr<option_manager> mgr,
+ unsigned lang_mask);
+
+ unsigned get_lang_mask () const
+ {
+ return m_lang_mask;
+ }
+
+ bool diagnostic_impl (rich_location *, const metadata *,
+ option_id, const char *,
+ va_list *, enum kind) ATTRIBUTE_GCC_DIAG(5,0);
+ bool diagnostic_n_impl (rich_location *, const metadata *,
+ option_id, unsigned HOST_WIDE_INT,
+ const char *, const char *, va_list *,
+ enum kind) ATTRIBUTE_GCC_DIAG(7,0);
+
+ int get_diagnostic_nesting_level () const
+ {
+ return m_diagnostic_groups.m_diagnostic_nesting_level;
+ }
+
+ char *build_indent_prefix () const;
+
+ int
+ pch_save (FILE *f)
+ {
+ return m_option_classifier.pch_save (f);
+ }
+
+ int
+ pch_restore (FILE *f)
+ {
+ return m_option_classifier.pch_restore (f);
+ }
+
+
+ void set_diagnostic_buffer (buffer *);
+ buffer *get_diagnostic_buffer () const
+ {
+ return m_diagnostic_buffer;
+ }
+ void clear_diagnostic_buffer (buffer &);
+ void flush_diagnostic_buffer (buffer &);
+
+ std::unique_ptr<pretty_printer> clone_printer () const
+ {
+ return m_reference_printer->clone ();
+ }
+
+ pretty_printer *get_reference_printer () const
+ {
+ return m_reference_printer;
+ }
+
+ void
+ add_sink (std::unique_ptr<sink>);
+
+ void remove_all_output_sinks ();
+
+ bool supports_fnotice_on_stderr_p () const;
+
+ /* Raise SIGABRT on any diagnostic of severity kind::error or higher. */
+ void
+ set_abort_on_error (bool val)
+ {
+ m_abort_on_error = val;
+ }
+
+ /* Accessor for use in serialization, e.g. by C++ modules. */
+ auto &
+ get_classification_history ()
+ {
+ return m_option_classifier.m_classification_history;
+ }
+
+ void set_main_input_filename (const char *filename);
+
+ void
+ set_permissive_option (option_id opt_permissive)
+ {
+ m_opt_permissive = opt_permissive;
+ }
+
+ void
+ set_fatal_errors (bool fatal_errors)
+ {
+ m_fatal_errors = fatal_errors;
+ }
+
+ void
+ set_internal_error_callback (void (*cb) (context *,
+ const char *,
+ va_list *))
+ {
+ m_internal_error = cb;
+ }
+
+ void
+ set_adjust_diagnostic_info_callback (void (*cb) (context *,
+ diagnostic_info *))
+ {
+ m_adjust_diagnostic_info = cb;
+ }
+
+ void
+ inhibit_notes () { m_inhibit_notes_p = true; }
+
+ source_printing_options &
+ get_source_printing_options ()
+ {
+ return m_source_printing;
+ }
+ const source_printing_options &
+ get_source_printing_options () const
+ {
+ return m_source_printing;
+ }
+
+ void set_caret_max_width (int value);
+
+private:
+ void error_recursion () ATTRIBUTE_NORETURN;
+
+ bool diagnostic_enabled (diagnostic_info *diagnostic);
+
+ void get_any_inlining_info (diagnostic_info *diagnostic);
+
+ void check_max_errors (bool flush);
+ void action_after_output (enum kind diag_kind);
+
+ /* Data members.
+ Ideally, all of these would be private. */
+
+private:
+ /* A reference instance of pretty_printer created by the client
+ and owned by the context. Used for cloning when creating/adding
+ output formats.
+ Owned by the context; this would be a std::unique_ptr if
+ context had a proper ctor. */
+ pretty_printer *m_reference_printer;
+
+ /* Cache of source code.
+ Owned by the context; this would be a std::unique_ptr if
+ context had a proper ctor. */
+ file_cache *m_file_cache;
+
+ /* The number of times we have issued diagnostics. */
+ counters m_diagnostic_counters;
+
+ /* True if it has been requested that warnings be treated as errors. */
+ bool m_warning_as_error_requested;
+
+ /* The number of option indexes that can be passed to warning() et
+ al. */
+ int m_n_opts;
+
+ /* The stack of sets of overridden diagnostic option severities. */
+ option_classifier m_option_classifier;
+
+ /* True if we should print any CWE identifiers associated with
+ diagnostics. */
+ bool m_show_cwe;
+
+ /* True if we should print any rules associated with diagnostics. */
+ bool m_show_rules;
+
+ /* How should diagnostics::paths::path objects be printed. */
+ enum diagnostic_path_format m_path_format;
+
+ /* True if we should print stack depths when printing diagnostic paths. */
+ bool m_show_path_depths;
+
+ /* True if we should print the command line option which controls
+ each diagnostic, if known. */
+ bool m_show_option_requested;
+
+ /* True if we should raise a SIGABRT on errors. */
+ bool m_abort_on_error;
+
+public:
+ /* True if we should show the column number on diagnostics. */
+ bool m_show_column;
+
+ /* True if pedwarns are errors. */
+ bool m_pedantic_errors;
+
+ /* True if permerrors are warnings. */
+ bool m_permissive;
+
+private:
+ /* The option to associate with turning permerrors into warnings,
+ if any. */
+ option_id m_opt_permissive;
+
+ /* True if errors are fatal. */
+ bool m_fatal_errors;
+
+public:
+ /* True if all warnings should be disabled. */
+ bool m_inhibit_warnings;
+
+ /* True if warnings should be given in system headers. */
+ bool m_warn_system_headers;
+
+private:
+ /* Maximum number of errors to report. */
+ int m_max_errors;
+
+ /* Client-supplied callbacks for use in text output. */
+ struct {
+ /* This function is called before any message is printed out. It is
+ responsible for preparing message prefix and such. For example, it
+ might say:
+ In file included from "/usr/local/include/curses.h:5:
+ from "/home/gdr/src/nifty_printer.h:56:
+ ...
+ */
+ text_starter_fn m_begin_diagnostic;
+
+ /* This function is called by diagnostic_show_locus in between
+ disjoint spans of source code, so that the context can print
+ something to indicate that a new span of source code has begun. */
+ start_span_fn<to_text> m_text_start_span;
+ start_span_fn<to_html> m_html_start_span;
+
+ /* This function is called after the diagnostic message is printed. */
+ text_finalizer_fn m_end_diagnostic;
+ } m_text_callbacks;
+
+ /* Client hook to report an internal error. */
+ void (*m_internal_error) (context *, const char *, va_list *);
+
+ /* Client hook to adjust properties of the given diagnostic that we're
+ about to issue, such as its kind. */
+ void (*m_adjust_diagnostic_info)(context *, diagnostic_info *);
+
+ /* Owned by the context; this would be a std::unique_ptr if
+ context had a proper ctor. */
+ option_manager *m_option_mgr;
+ unsigned m_lang_mask;
+
+ /* A stack of optional hooks for adding URLs to quoted text strings in
+ diagnostics. Only used for the main diagnostic message.
+ Typically a single one owner by the context, but can be temporarily
+ overridden by a borrowed urlifier (e.g. on-stack). */
+ struct urlifier_stack_node
+ {
+ urlifier *m_urlifier;
+ bool m_owned;
+ };
+ auto_vec<urlifier_stack_node> *m_urlifier_stack;
+
+public:
+ /* Auxiliary data for client. */
+ void *m_client_aux_data;
+
+ /* Used to detect that the last caret was printed at the same location. */
+ location_t m_last_location;
+
+private:
+ int m_lock;
+
+ bool m_inhibit_notes_p;
+
+ source_printing_options m_source_printing;
+
+ /* True if -freport-bug option is used. */
+ bool m_report_bug;
+
+ /* Used to specify additional diagnostic output to be emitted after the
+ rest of the diagnostic. This is for implementing
+ -fdiagnostics-parseable-fixits and GCC_EXTRA_DIAGNOSTIC_OUTPUT. */
+ enum diagnostics_extra_output_kind m_extra_output_kind;
+
+public:
+ /* What units to use when outputting the column number. */
+ enum diagnostics_column_unit m_column_unit;
+
+ /* The origin for the column number (1-based or 0-based typically). */
+ int m_column_origin;
+
+ /* The size of the tabstop for tab expansion. */
+ int m_tabstop;
+
+private:
+ /* How should non-ASCII/non-printable bytes be escaped when
+ a diagnostic suggests escaping the source code on output. */
+ enum diagnostics_escape_format m_escape_format;
+
+ /* If non-NULL, a diagnostics::changes::change_set to which fix-it hints
+ should be applied, for generating patches.
+ Owned by the context; this would be a std::unique_ptr if
+ context had a proper ctor. */
+ changes::change_set *m_fixits_change_set;
+
+ /* Fields relating to diagnostic groups. */
+ struct {
+ /* How many diagnostic_group instances are currently alive. */
+ int m_group_nesting_depth;
+
+ /* How many nesting levels have been pushed within this group. */
+ int m_diagnostic_nesting_level;
+
+ /* How many diagnostics have been emitted since the bottommost
+ diagnostic_group was pushed. */
+ int m_emission_count;
+
+ /* The "group+diagnostic" nesting depth from which to inhibit notes. */
+ int m_inhibiting_notes_from;
+ } m_diagnostic_groups;
+
+ void inhibit_notes_in_group (bool inhibit = true);
+ bool notes_inhibited_in_group () const;
+
+ /* The various sinks to which diagnostics are to be outputted
+ (text vs structured formats such as SARIF).
+ The sinks are owned by the context; this would be a
+ std::vector<std::unique_ptr> if context had a
+ proper ctor. */
+ auto_vec<sink *> m_sinks;
+
+ /* Callback to set the locations of call sites along the inlining
+ stack corresponding to a diagnostic location. Needed to traverse
+ the BLOCK_SUPERCONTEXT() chain hanging off the LOCATION_BLOCK()
+ of a diagnostic's location. */
+ set_locations_callback_t m_set_locations_cb;
+
+ /* A bundle of hooks for providing data to the context about its client
+ e.g. version information, plugins, etc.
+ Used by SARIF output to give metadata about the client that's
+ producing diagnostics.
+ Owned by the context; this would be a std::unique_ptr if
+ context had a proper ctor. */
+ client_data_hooks *m_client_data_hooks;
+
+ /* Support for diagrams. */
+ struct
+ {
+ /* Theme to use when generating diagrams.
+ Can be NULL (if text art is disabled).
+ Owned by the context; this would be a std::unique_ptr if
+ context had a proper ctor. */
+ text_art::theme *m_theme;
+
+ } m_diagrams;
+
+ /* Owned by the context. */
+ char **m_original_argv;
+
+ /* Borrowed pointer to the active diagnostics::buffer, if any.
+ If null (the default), then diagnostics that are reported to the
+ context are immediately issued to the output format.
+ If non-null, then diagnostics that are reported to the context
+ are buffered in the buffer, and may be issued to the output format
+ later (if the buffer is flushed), moved to other buffers, or
+ discarded (if the buffer is cleared). */
+ buffer *m_diagnostic_buffer;
+};
+
+/* Client supplied function to announce a diagnostic
+ (for text-based diagnostic output). */
+inline text_starter_fn &
+text_starter (context *dc)
+{
+ return dc->m_text_callbacks.m_begin_diagnostic;
+}
+
+/* Client supplied function called between disjoint spans of source code,
+ so that the context can print
+ something to indicate that a new span of source code has begun. */
+inline start_span_fn<to_text> &
+start_span (context *dc)
+{
+ return dc->m_text_callbacks.m_text_start_span;
+}
+
+/* Client supplied function called after a diagnostic message is
+ displayed (for text-based diagnostic output). */
+inline text_finalizer_fn &
+text_finalizer (context *dc)
+{
+ return dc->m_text_callbacks.m_end_diagnostic;
+}
+
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_CONTEXT_H */
diff --git a/gcc/diagnostics/diagnostic-info.h b/gcc/diagnostics/diagnostic-info.h
new file mode 100644
index 0000000..052fef5
--- /dev/null
+++ b/gcc/diagnostics/diagnostic-info.h
@@ -0,0 +1,75 @@
+/* Various declarations for language-independent diagnostics subroutines.
+ Copyright (C) 2000-2025 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/>. */
+
+#ifndef GCC_DIAGNOSTICS_DIAGNOSTIC_INFO_H
+#define GCC_DIAGNOSTICS_DIAGNOSTIC_INFO_H
+
+namespace diagnostics {
+
+class metadata;
+
+/* A diagnostic is described by the MESSAGE to send, the FILE and LINE of
+ its context and its KIND (ice, error, warning, note, ...) See complete
+ list in diagnostics/kinds.def. */
+
+struct diagnostic_info
+{
+ diagnostic_info ()
+ : m_message (),
+ m_richloc (),
+ m_metadata (),
+ m_x_data (),
+ m_kind (),
+ m_option_id (),
+ m_iinfo ()
+ { }
+
+ /* Text to be formatted. */
+ text_info m_message;
+
+ /* The location at which the diagnostic is to be reported. */
+ rich_location *m_richloc;
+
+ /* An optional bundle of metadata associated with the diagnostic
+ (or NULL). */
+ const metadata *m_metadata;
+
+ /* Auxiliary data for client. */
+ void *m_x_data;
+ /* The kind of diagnostic it is about. */
+ kind m_kind;
+ /* Which OPT_* directly controls this diagnostic. */
+ option_id m_option_id;
+
+ /* Inlining context containing locations for each call site along
+ the inlining stack. */
+ struct inlining_info
+ {
+ /* Locations along the inlining stack. */
+ auto_vec<location_t, 8> m_ilocs;
+ /* The abstract origin of the location. */
+ void *m_ao;
+ /* Set if every M_ILOCS element is in a system header. */
+ bool m_allsyslocs;
+ } m_iinfo;
+};
+
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_DIAGNOSTIC_INFO_H */
diff --git a/gcc/diagnostics/diagnostics-selftests.cc b/gcc/diagnostics/diagnostics-selftests.cc
new file mode 100644
index 0000000..94a212a
--- /dev/null
+++ b/gcc/diagnostics/diagnostics-selftests.cc
@@ -0,0 +1,59 @@
+/* Selftest support for diagnostics.
+ Copyright (C) 2019-2025 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"
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+#include "diagnostics/diagnostics-selftests.h"
+
+#if CHECKING_P
+
+namespace diagnostics {
+
+namespace selftest {
+
+/* Run all diagnostics-specific selftests,
+ apart from context_cc_tests, which according to
+ https://gcc.gnu.org/pipermail/gcc/2021-November/237703.html
+ has some language-specific assumptions, and thus is run from
+ c_family_tests instead. */
+
+void
+run_diagnostics_selftests ()
+{
+ color_cc_tests ();
+ file_cache_cc_tests ();
+ source_printing_cc_tests ();
+ html_sink_cc_tests ();
+ sarif_sink_cc_tests ();
+ digraphs_cc_tests ();
+ output_spec_cc_tests ();
+ state_graphs_cc_tests ();
+ lazy_paths_cc_tests ();
+ paths_output_cc_tests ();
+ changes_cc_tests ();
+}
+
+} /* end of namespace diagnostics::selftest. */
+
+} // namespace diagnostics
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/diagnostics/diagnostics-selftests.h b/gcc/diagnostics/diagnostics-selftests.h
new file mode 100644
index 0000000..994ebad
--- /dev/null
+++ b/gcc/diagnostics/diagnostics-selftests.h
@@ -0,0 +1,55 @@
+/* Selftests for diagnostics.
+ Copyright (C) 2019-2025 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_DIAGNOSTICS_SELFTESTS_H
+#define GCC_DIAGNOSTICS_SELFTESTS_H
+
+#if CHECKING_P
+
+namespace diagnostics {
+
+namespace selftest {
+
+extern void run_diagnostics_selftests ();
+
+/* Declarations for specific families of tests (by source file within
+ "diagnostics/"), in alphabetical order. */
+
+extern void changes_cc_tests ();
+extern void color_cc_tests ();
+extern void context_cc_tests ();
+extern void digraphs_cc_tests ();
+extern void file_cache_cc_tests ();
+extern void html_sink_cc_tests ();
+extern void lazy_paths_cc_tests ();
+extern void output_spec_cc_tests ();
+extern void paths_output_cc_tests ();
+extern void sarif_sink_cc_tests ();
+extern void selftest_logical_locations_cc_tests ();
+extern void source_printing_cc_tests ();
+extern void state_graphs_cc_tests ();
+
+} /* end of namespace diagnostics::selftest. */
+
+} // namespace diagnostics
+
+#endif /* #if CHECKING_P */
+
+#endif /* GCC_DIAGNOSTICS_SELFTESTS_H */
diff --git a/gcc/diagnostic-diagram.h b/gcc/diagnostics/diagram.h
index b1ff9a9..2d33b10 100644
--- a/gcc/diagnostic-diagram.h
+++ b/gcc/diagnostics/diagram.h
@@ -18,22 +18,24 @@ 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_DIAGNOSTIC_DIAGRAM_H
-#define GCC_DIAGNOSTIC_DIAGRAM_H
+#ifndef GCC_DIAGNOSTICS_DIAGRAM_H
+#define GCC_DIAGNOSTICS_DIAGRAM_H
namespace text_art
{
class canvas;
} // namespace text_art
+namespace diagnostics {
+
/* A text art diagram, along with an "alternative text" string
describing it. */
-class diagnostic_diagram
+class diagram
{
public:
- diagnostic_diagram (const text_art::canvas &canvas,
- const char *alt_text)
+ diagram (const text_art::canvas &canvas,
+ const char *alt_text)
: m_canvas (canvas),
m_alt_text (alt_text)
{
@@ -48,4 +50,6 @@ class diagnostic_diagram
const char *const m_alt_text;
};
-#endif /* ! GCC_DIAGNOSTIC_DIAGRAM_H */
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_DIAGRAM_H */
diff --git a/gcc/diagnostic-digraphs.cc b/gcc/diagnostics/digraphs.cc
index 85c0c51..4a2ea4f 100644
--- a/gcc/diagnostic-digraphs.cc
+++ b/gcc/diagnostics/digraphs.cc
@@ -28,8 +28,8 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "graphviz.h"
-#include "diagnostic-digraphs.h"
-#include "diagnostic-format-sarif.h"
+#include "diagnostics/digraphs.h"
+#include "diagnostics/sarif-sink.h"
#include "selftest.h"
@@ -351,30 +351,9 @@ diagnostics::digraphs::edge::to_json_sarif_edge () const
return make_sarif_edge (*this, nullptr);
}
-// class lazy_digraph
-
-const diagnostics::digraphs::digraph &
-diagnostics::digraphs::lazy_digraph::get_or_create_digraph () const
-{
- if (!m_digraph)
- m_digraph = create_digraph ();
- gcc_assert (m_digraph);
- return *m_digraph;
-}
-
-// class lazy_digraphs
-
-const std::vector<std::unique_ptr<diagnostics::digraphs::digraph>> &
-diagnostics::digraphs::lazy_digraphs::get_or_create_digraphs () const
-{
- if (!m_digraphs)
- m_digraphs = create_digraphs ();
- gcc_assert (m_digraphs);
- return *m_digraphs;
-}
-
#if CHECKING_P
+namespace diagnostics {
namespace selftest {
static void
@@ -473,12 +452,13 @@ test_simple_graph ()
/* Run all of the selftests within this file. */
void
-diagnostic_digraphs_cc_tests ()
+digraphs_cc_tests ()
{
test_empty_graph ();
test_simple_graph ();
}
-} // namespace selftest
+} // namespace diagnostics::selftest
+} // namespace diagnostics
#endif /* CHECKING_P */
diff --git a/gcc/diagnostic-digraphs.h b/gcc/diagnostics/digraphs.h
index d6f8e7e..7193ee4 100644
--- a/gcc/diagnostic-digraphs.h
+++ b/gcc/diagnostics/digraphs.h
@@ -18,11 +18,11 @@ 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_DIAGNOSTIC_DIGRAPHS_H
-#define GCC_DIAGNOSTIC_DIGRAPHS_H
+#ifndef GCC_DIAGNOSTICS_DIGRAPHS_H
+#define GCC_DIAGNOSTICS_DIGRAPHS_H
#include "json.h"
-#include "logical-location.h"
+#include "diagnostics/logical-locations.h"
class graphviz_out;
@@ -276,14 +276,14 @@ class node : public object
m_physical_loc = physical_loc;
}
- logical_location
+ logical_locations::key
get_logical_loc () const
{
return m_logical_loc;
}
void
- set_logical_loc (logical_location logical_loc)
+ set_logical_loc (logical_locations::key logical_loc)
{
m_logical_loc = logical_loc;
}
@@ -305,7 +305,7 @@ class node : public object
std::unique_ptr<std::string> m_label;
std::vector<std::unique_ptr<node>> m_children;
location_t m_physical_loc;
- logical_location m_logical_loc;
+ logical_locations::key m_logical_loc;
};
// An edge in a directed graph, corresponding to SARIF v2.1.0 section 3.41.
@@ -373,49 +373,7 @@ private:
node &m_dst_node;
};
-/* Abstract base class for lazily creating
- a digraph on demand.
-
- This allows us to avoid the work of creating the digraph for
- the common case where we just have a text sink. */
-
-class lazy_digraph
-{
-public:
- virtual ~lazy_digraph () {}
-
- const digraph &
- get_or_create_digraph () const;
-
-private:
- virtual std::unique_ptr<digraph>
- create_digraph () const = 0;
-
- mutable std::unique_ptr<digraph> m_digraph;
-};
-
-/* Abstract base class for lazily creating a collection of
- digraphs on demand.
-
- This allows us to avoid the work of creating the digraphs for
- the common case where we just have a text sink. */
-
-class lazy_digraphs
-{
-public:
- virtual ~lazy_digraphs () {}
-
- const std::vector<std::unique_ptr<digraph>> &
- get_or_create_digraphs () const;
-
-private:
- virtual std::unique_ptr<std::vector<std::unique_ptr<digraph>>>
- create_digraphs () const = 0;
-
- mutable std::unique_ptr<std::vector<std::unique_ptr<digraph>>> m_digraphs;
-};
-
} // namespace digraphs
} // namespace diagnostics
-#endif /* ! GCC_DIAGNOSTIC_DIGRAPHS_H */
+#endif /* ! GCC_DIAGNOSTICS_DIGRAPHS_H */
diff --git a/gcc/diagnostic-event-id.h b/gcc/diagnostics/event-id.h
index 7a45a72..167599d 100644
--- a/gcc/diagnostic-event-id.h
+++ b/gcc/diagnostics/event-id.h
@@ -1,4 +1,4 @@
-/* A class for referring to events within a diagnostic_path.
+/* A class for referring to events within a diagnostics::paths::path.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>
@@ -18,10 +18,10 @@ 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_DIAGNOSTIC_EVENT_ID_H
-#define GCC_DIAGNOSTIC_EVENT_ID_H
+#ifndef GCC_DIAGNOSTICS_EVENT_ID_H
+#define GCC_DIAGNOSTICS_EVENT_ID_H
-/* A class for referring to events within a diagnostic_path.
+/* A class for referring to events within a diagnostics::paths::path.
They are stored as 0-based offsets into the events, but
printed (e.g. via %@) as 1-based numbers.
@@ -30,8 +30,10 @@ along with GCC; see the file COPYING3. If not see
which would be shown to the user as "(1)", "(2)" and "(3)".
This has its own header so that pretty-print.cc can use this
- to implement "%@" without bringing in all of diagnostic_path
- (which e.g. refers to "tree"). */
+ to implement "%@" without bringing in all of diagnostics::paths.
+
+ This has to be in the global namespace for compatibility with
+ c-format.cc in GCC 10 onwards. */
class diagnostic_event_id_t
{
@@ -58,15 +60,24 @@ class diagnostic_event_id_t
int m_index; // zero-based
};
+namespace diagnostics {
+namespace paths {
+
+typedef diagnostic_event_id_t event_id_t;
+
+/* A type for compactly referring to a particular thread within a
+ diagnostics::paths::path. Typically there is just one thread per path,
+ with id 0. */
+typedef int thread_id_t;
+
+} // namespace paths
+} // namespace diagnostics
+
+
/* A pointer to a diagnostic_event_id_t, for use with the "%@" format
code, which will print a 1-based representation for it, with suitable
colorization, e.g. "(1)".
The %@ format code requires that known_p be true for the event ID. */
typedef diagnostic_event_id_t *diagnostic_event_id_ptr;
-/* A type for compactly referring to a particular thread within a
- diagnostic_path. Typically there is just one thread per path,
- with id 0. */
-typedef int diagnostic_thread_id_t;
-
-#endif /* ! GCC_DIAGNOSTIC_EVENT_ID_H */
+#endif /* ! GCC_DIAGNOSTICS_EVENT_ID_H */
diff --git a/gcc/diagnostics/file-cache.cc b/gcc/diagnostics/file-cache.cc
new file mode 100644
index 0000000..febeb03
--- /dev/null
+++ b/gcc/diagnostics/file-cache.cc
@@ -0,0 +1,1083 @@
+/* Caching input files for use by diagnostics.
+ Copyright (C) 2004-2025 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"
+#include "system.h"
+#include "coretypes.h"
+#include "cpplib.h"
+#include "diagnostics/file-cache.h"
+#include "selftest.h"
+
+#ifndef HAVE_ICONV
+#define HAVE_ICONV 0
+#endif
+
+namespace diagnostics {
+
+/* Input charset configuration. */
+static const char *default_charset_callback (const char *)
+{
+ return nullptr;
+}
+
+void
+file_cache::initialize_input_context (diagnostic_input_charset_callback ccb,
+ bool should_skip_bom)
+{
+ m_input_context.ccb = (ccb ? ccb : default_charset_callback);
+ m_input_context.should_skip_bom = should_skip_bom;
+}
+
+/* This is a cache used by get_next_line to store the content of a
+ file to be searched for file lines. */
+class file_cache_slot
+{
+public:
+ file_cache_slot ();
+ ~file_cache_slot ();
+
+ void dump (FILE *out, int indent) const;
+ void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
+
+ bool read_line_num (size_t line_num,
+ char ** line, ssize_t *line_len);
+
+ /* Accessors. */
+ const char *get_file_path () const { return m_file_path; }
+ unsigned get_use_count () const { return m_use_count; }
+ bool missing_trailing_newline_p () const
+ {
+ return m_missing_trailing_newline;
+ }
+ char_span get_full_file_content ();
+
+ void inc_use_count () { m_use_count++; }
+
+ bool create (const file_cache::input_context &in_context,
+ const char *file_path, FILE *fp, unsigned highest_use_count);
+ void evict ();
+ void set_content (const char *buf, size_t sz);
+
+ static size_t tune (size_t line_record_size_)
+ {
+ size_t ret = line_record_size;
+ line_record_size = line_record_size_;
+ return ret;
+ }
+
+ private:
+ /* These are information used to store a line boundary. */
+ class line_info
+ {
+ public:
+ /* The line number. It starts from 1. */
+ size_t line_num;
+
+ /* The position (byte count) of the beginning of the line,
+ relative to the file data pointer. This starts at zero. */
+ size_t start_pos;
+
+ /* The position (byte count) of the last byte of the line. This
+ normally points to the '\n' character, or to one byte after the
+ last byte of the file, if the file doesn't contain a '\n'
+ character. */
+ size_t end_pos;
+
+ line_info (size_t l, size_t s, size_t e)
+ : line_num (l), start_pos (s), end_pos (e)
+ {}
+
+ line_info ()
+ :line_num (0), start_pos (0), end_pos (0)
+ {}
+
+ static bool less_than(const line_info &a, const line_info &b)
+ {
+ return a.line_num < b.line_num;
+ }
+ };
+
+ bool needs_read_p () const;
+ bool needs_grow_p () const;
+ void maybe_grow ();
+ bool read_data ();
+ bool maybe_read_data ();
+ bool get_next_line (char **line, ssize_t *line_len);
+ bool read_next_line (char ** line, ssize_t *line_len);
+ bool goto_next_line ();
+
+ static const size_t buffer_size = 4 * 1024;
+ static size_t line_record_size;
+ static size_t recent_cached_lines_shift;
+
+ /* The number of time this file has been accessed. This is used
+ to designate which file cache to evict from the cache
+ array. */
+ unsigned m_use_count;
+
+ /* The file_path is the key for identifying a particular file in
+ the cache. This copy is owned by the slot. */
+ char *m_file_path;
+
+ FILE *m_fp;
+
+ /* True when an read error happened. */
+ bool m_error;
+
+ /* This points to the content of the file that we've read so
+ far. */
+ char *m_data;
+
+ /* The allocated buffer to be freed may start a little earlier than DATA,
+ e.g. if a UTF8 BOM was skipped at the beginning. */
+ int m_alloc_offset;
+
+ /* The size of the DATA array above.*/
+ size_t m_size;
+
+ /* The number of bytes read from the underlying file so far. This
+ must be less (or equal) than SIZE above. */
+ size_t m_nb_read;
+
+ /* The index of the beginning of the current line. */
+ size_t m_line_start_idx;
+
+ /* The number of the previous line read. This starts at 1. Zero
+ means we've read no line so far. */
+ size_t m_line_num;
+
+ /* Could this file be missing a trailing newline on its final line?
+ Initially true (to cope with empty files), set to true/false
+ as each line is read. */
+ bool m_missing_trailing_newline;
+
+ /* This is a record of the beginning and end of the lines we've seen
+ while reading the file. This is useful to avoid walking the data
+ from the beginning when we are asked to read a line that is
+ before LINE_START_IDX above. When the lines exceed line_record_size
+ this is scaled down dynamically, with the line_info becoming anchors. */
+ vec<line_info, va_heap> m_line_record;
+
+ /* A cache of the recently seen lines. This is maintained as a ring
+ buffer. */
+ vec<line_info, va_heap> m_line_recent;
+
+ /* First and last valid entry in m_line_recent. */
+ size_t m_line_recent_last, m_line_recent_first;
+
+ void offset_buffer (int offset)
+ {
+ gcc_assert (offset < 0 ? m_alloc_offset + offset >= 0
+ : (size_t) offset <= m_size);
+ gcc_assert (m_data);
+ m_alloc_offset += offset;
+ m_data += offset;
+ m_size -= offset;
+ }
+
+};
+
+size_t file_cache_slot::line_record_size = 0;
+size_t file_cache_slot::recent_cached_lines_shift = 8;
+
+/* Tune file_cache. */
+void
+file_cache::tune (size_t num_file_slots, size_t lines)
+{
+ if (file_cache_slot::tune (lines) != lines
+ || m_num_file_slots != num_file_slots)
+ {
+ delete[] m_file_slots;
+ m_file_slots = new file_cache_slot[num_file_slots];
+ }
+ m_num_file_slots = num_file_slots;
+}
+
+static const char *
+find_end_of_line (const char *s, size_t len);
+
+/* Lookup the cache used for the content of a given file accessed by
+ caret diagnostic. Return the found cached file, or NULL if no
+ cached file was found. */
+
+file_cache_slot *
+file_cache::lookup_file (const char *file_path)
+{
+ gcc_assert (file_path);
+
+ /* This will contain the found cached file. */
+ file_cache_slot *r = NULL;
+ for (unsigned i = 0; i < m_num_file_slots; ++i)
+ {
+ file_cache_slot *c = &m_file_slots[i];
+ if (c->get_file_path () && !strcmp (c->get_file_path (), file_path))
+ {
+ c->inc_use_count ();
+ r = c;
+ }
+ }
+
+ if (r)
+ r->inc_use_count ();
+
+ return r;
+}
+
+/* Purge any mention of FILENAME from the cache of files used for
+ printing source code. For use in selftests when working
+ with tempfiles. */
+
+void
+file_cache::forcibly_evict_file (const char *file_path)
+{
+ gcc_assert (file_path);
+
+ file_cache_slot *r = lookup_file (file_path);
+ if (!r)
+ /* Not found. */
+ return;
+
+ r->evict ();
+}
+
+/* Determine if FILE_PATH missing a trailing newline on its final line.
+ Only valid to call once all of the file has been loaded, by
+ requesting a line number beyond the end of the file. */
+
+bool
+file_cache::missing_trailing_newline_p (const char *file_path)
+{
+ gcc_assert (file_path);
+
+ file_cache_slot *r = lookup_or_add_file (file_path);
+ return r->missing_trailing_newline_p ();
+}
+
+void
+file_cache::add_buffered_content (const char *file_path,
+ const char *buffer,
+ size_t sz)
+{
+ gcc_assert (file_path);
+
+ file_cache_slot *r = lookup_file (file_path);
+ if (!r)
+ {
+ unsigned highest_use_count = 0;
+ r = evicted_cache_tab_entry (&highest_use_count);
+ if (!r->create (m_input_context, file_path, nullptr, highest_use_count))
+ return;
+ }
+
+ r->set_content (buffer, sz);
+}
+
+void
+file_cache_slot::evict ()
+{
+ free (m_file_path);
+ m_file_path = NULL;
+ if (m_fp)
+ fclose (m_fp);
+ m_error = false;
+ m_fp = NULL;
+ m_nb_read = 0;
+ m_line_start_idx = 0;
+ m_line_num = 0;
+ m_line_record.truncate (0);
+ m_line_recent_first = 0;
+ m_line_recent_last = 0;
+ m_use_count = 0;
+ m_missing_trailing_newline = true;
+}
+
+/* Return the file cache that has been less used, recently, or the
+ first empty one. If HIGHEST_USE_COUNT is non-null,
+ *HIGHEST_USE_COUNT is set to the highest use count of the entries
+ in the cache table. */
+
+file_cache_slot*
+file_cache::evicted_cache_tab_entry (unsigned *highest_use_count)
+{
+ file_cache_slot *to_evict = &m_file_slots[0];
+ unsigned huc = to_evict->get_use_count ();
+ for (unsigned i = 1; i < m_num_file_slots; ++i)
+ {
+ file_cache_slot *c = &m_file_slots[i];
+ bool c_is_empty = (c->get_file_path () == NULL);
+
+ if (c->get_use_count () < to_evict->get_use_count ()
+ || (to_evict->get_file_path () && c_is_empty))
+ /* We evict C because it's either an entry with a lower use
+ count or one that is empty. */
+ to_evict = c;
+
+ if (huc < c->get_use_count ())
+ huc = c->get_use_count ();
+
+ if (c_is_empty)
+ /* We've reached the end of the cache; subsequent elements are
+ all empty. */
+ break;
+ }
+
+ if (highest_use_count)
+ *highest_use_count = huc;
+
+ return to_evict;
+}
+
+/* Create the cache used for the content of a given file to be
+ accessed by caret diagnostic. This cache is added to an array of
+ cache and can be retrieved by lookup_file_in_cache_tab. This
+ function returns the created cache. Note that only the last
+ m_num_file_slots files are cached.
+
+ This can return nullptr if the FILE_PATH can't be opened for
+ reading, or if the content can't be converted to the input_charset. */
+
+file_cache_slot*
+file_cache::add_file (const char *file_path)
+{
+
+ FILE *fp = fopen (file_path, "r");
+ if (fp == NULL)
+ return NULL;
+
+ unsigned highest_use_count = 0;
+ file_cache_slot *r = evicted_cache_tab_entry (&highest_use_count);
+ if (!r->create (m_input_context, file_path, fp, highest_use_count))
+ return NULL;
+ return r;
+}
+
+/* Get a borrowed char_span to the full content of this file
+ as decoded according to the input charset, encoded as UTF-8. */
+
+char_span
+file_cache_slot::get_full_file_content ()
+{
+ char *line;
+ ssize_t line_len;
+ while (get_next_line (&line, &line_len))
+ {
+ }
+ return char_span (m_data, m_nb_read);
+}
+
+/* Populate this slot for use on FILE_PATH and FP, dropping any
+ existing cached content within it. */
+
+bool
+file_cache_slot::create (const file_cache::input_context &in_context,
+ const char *file_path, FILE *fp,
+ unsigned highest_use_count)
+{
+ m_file_path = file_path ? xstrdup (file_path) : nullptr;
+ if (m_fp)
+ fclose (m_fp);
+ m_error = false;
+ m_fp = fp;
+ if (m_alloc_offset)
+ offset_buffer (-m_alloc_offset);
+ m_nb_read = 0;
+ m_line_start_idx = 0;
+ m_line_num = 0;
+ m_line_recent_first = 0;
+ m_line_recent_last = 0;
+ m_line_record.truncate (0);
+ /* Ensure that this cache entry doesn't get evicted next time
+ add_file_to_cache_tab is called. */
+ m_use_count = ++highest_use_count;
+ m_missing_trailing_newline = true;
+
+
+ /* Check the input configuration to determine if we need to do any
+ transformations, such as charset conversion or BOM skipping. */
+ if (const char *input_charset = in_context.ccb (file_path))
+ {
+ /* Need a full-blown conversion of the input charset. */
+ fclose (m_fp);
+ m_fp = NULL;
+ const cpp_converted_source cs
+ = cpp_get_converted_source (file_path, input_charset);
+ if (!cs.data)
+ return false;
+ if (m_data)
+ XDELETEVEC (m_data);
+ m_data = cs.data;
+ m_nb_read = m_size = cs.len;
+ m_alloc_offset = cs.data - cs.to_free;
+ }
+ else if (in_context.should_skip_bom)
+ {
+ if (read_data ())
+ {
+ const int offset = cpp_check_utf8_bom (m_data, m_nb_read);
+ offset_buffer (offset);
+ m_nb_read -= offset;
+ }
+ }
+
+ return true;
+}
+
+void
+file_cache_slot::set_content (const char *buf, size_t sz)
+{
+ m_data = (char *)xmalloc (sz);
+ memcpy (m_data, buf, sz);
+ m_nb_read = m_size = sz;
+ m_alloc_offset = 0;
+
+ if (m_fp)
+ {
+ fclose (m_fp);
+ m_fp = nullptr;
+ }
+}
+
+/* file_cache's ctor. */
+
+file_cache::file_cache ()
+: m_num_file_slots (16), m_file_slots (new file_cache_slot[m_num_file_slots])
+{
+ initialize_input_context (nullptr, false);
+}
+
+/* file_cache's dtor. */
+
+file_cache::~file_cache ()
+{
+ delete[] m_file_slots;
+}
+
+void
+file_cache::dump (FILE *out, int indent) const
+{
+ for (size_t i = 0; i < m_num_file_slots; ++i)
+ {
+ fprintf (out, "%*sslot[%i]:\n", indent, "", (int)i);
+ m_file_slots[i].dump (out, indent + 2);
+ }
+}
+
+void
+file_cache::dump () const
+{
+ dump (stderr, 0);
+}
+
+/* Lookup the cache used for the content of a given file accessed by
+ caret diagnostic. If no cached file was found, create a new cache
+ for this file, add it to the array of cached file and return
+ it.
+
+ This can return nullptr on a cache miss if FILE_PATH can't be opened for
+ reading, or if the content can't be converted to the input_charset. */
+
+file_cache_slot*
+file_cache::lookup_or_add_file (const char *file_path)
+{
+ file_cache_slot *r = lookup_file (file_path);
+ if (r == NULL)
+ r = add_file (file_path);
+ return r;
+}
+
+/* Default constructor for a cache of file used by caret
+ diagnostic. */
+
+file_cache_slot::file_cache_slot ()
+: m_use_count (0), m_file_path (NULL), m_fp (NULL), m_error (false), m_data (0),
+ m_alloc_offset (0), m_size (0), m_nb_read (0), m_line_start_idx (0),
+ m_line_num (0), m_missing_trailing_newline (true),
+ m_line_recent_last (0), m_line_recent_first (0)
+{
+ m_line_record.create (0);
+ m_line_recent.create (1U << recent_cached_lines_shift);
+ for (int i = 0; i < 1 << recent_cached_lines_shift; i++)
+ m_line_recent.quick_push (file_cache_slot::line_info (0, 0, 0));
+}
+
+/* Destructor for a cache of file used by caret diagnostic. */
+
+file_cache_slot::~file_cache_slot ()
+{
+ free (m_file_path);
+ if (m_fp)
+ {
+ fclose (m_fp);
+ m_fp = NULL;
+ }
+ if (m_data)
+ {
+ offset_buffer (-m_alloc_offset);
+ XDELETEVEC (m_data);
+ m_data = 0;
+ }
+ m_line_record.release ();
+ m_line_recent.release ();
+}
+
+void
+file_cache_slot::dump (FILE *out, int indent) const
+{
+ if (!m_file_path)
+ {
+ fprintf (out, "%*s(unused)\n", indent, "");
+ return;
+ }
+ fprintf (out, "%*sfile_path: %s\n", indent, "", m_file_path);
+ fprintf (out, "%*sfp: %p\n", indent, "", (void *)m_fp);
+ fprintf (out, "%*sneeds_read_p: %i\n", indent, "", (int)needs_read_p ());
+ fprintf (out, "%*sneeds_grow_p: %i\n", indent, "", (int)needs_grow_p ());
+ fprintf (out, "%*suse_count: %i\n", indent, "", m_use_count);
+ fprintf (out, "%*ssize: %zi\n", indent, "", m_size);
+ fprintf (out, "%*snb_read: %zi\n", indent, "", m_nb_read);
+ fprintf (out, "%*sstart_line_idx: %zi\n", indent, "", m_line_start_idx);
+ fprintf (out, "%*sline_num: %zi\n", indent, "", m_line_num);
+ fprintf (out, "%*smissing_trailing_newline: %i\n",
+ indent, "", (int)m_missing_trailing_newline);
+ fprintf (out, "%*sline records (%i):\n",
+ indent, "", m_line_record.length ());
+ int idx = 0;
+ for (auto &line : m_line_record)
+ fprintf (out, "%*s[%i]: line %zi: byte offsets: %zi-%zi\n",
+ indent + 2, "",
+ idx++, line.line_num, line.start_pos, line.end_pos);
+}
+
+/* Returns TRUE iff the cache would need to be filled with data coming
+ from the file. That is, either the cache is empty or full or the
+ current line is empty. Note that if the cache is full, it would
+ need to be extended and filled again. */
+
+bool
+file_cache_slot::needs_read_p () const
+{
+ return m_fp && (m_nb_read == 0
+ || m_nb_read == m_size
+ || (m_line_start_idx >= m_nb_read - 1));
+}
+
+/* Return TRUE iff the cache is full and thus needs to be
+ extended. */
+
+bool
+file_cache_slot::needs_grow_p () const
+{
+ return m_nb_read == m_size;
+}
+
+/* Grow the cache if it needs to be extended. */
+
+void
+file_cache_slot::maybe_grow ()
+{
+ if (!needs_grow_p ())
+ return;
+
+ if (!m_data)
+ {
+ gcc_assert (m_size == 0 && m_alloc_offset == 0);
+ m_size = buffer_size;
+ m_data = XNEWVEC (char, m_size);
+ }
+ else
+ {
+ const int offset = m_alloc_offset;
+ offset_buffer (-offset);
+ m_size *= 2;
+ m_data = XRESIZEVEC (char, m_data, m_size);
+ offset_buffer (offset);
+ }
+}
+
+/* Read more data into the cache. Extends the cache if need be.
+ Returns TRUE iff new data could be read. */
+
+bool
+file_cache_slot::read_data ()
+{
+ if (feof (m_fp) || ferror (m_fp))
+ return false;
+
+ maybe_grow ();
+
+ char * from = m_data + m_nb_read;
+ size_t to_read = m_size - m_nb_read;
+ size_t nb_read = fread (from, 1, to_read, m_fp);
+
+ if (ferror (m_fp))
+ {
+ m_error = true;
+ return false;
+ }
+
+ m_nb_read += nb_read;
+ return !!nb_read;
+}
+
+/* Read new data iff the cache needs to be filled with more data
+ coming from the file FP. Return TRUE iff the cache was filled with
+ mode data. */
+
+bool
+file_cache_slot::maybe_read_data ()
+{
+ if (!needs_read_p ())
+ return false;
+ return read_data ();
+}
+
+/* Helper function for file_cache_slot::get_next_line (), to find the end of
+ the next line. Returns with the memchr convention, i.e. nullptr if a line
+ terminator was not found. We need to determine line endings in the same
+ manner that libcpp does: any of \n, \r\n, or \r is a line ending. */
+
+static const char *
+find_end_of_line (const char *s, size_t len)
+{
+ for (const auto end = s + len; s != end; ++s)
+ {
+ if (*s == '\n')
+ return s;
+ if (*s == '\r')
+ {
+ const auto next = s + 1;
+ if (next == end)
+ {
+ /* Don't find the line ending if \r is the very last character
+ in the buffer; we do not know if it's the end of the file or
+ just the end of what has been read so far, and we wouldn't
+ want to break in the middle of what's actually a \r\n
+ sequence. Instead, we will handle the case of a file ending
+ in a \r later. */
+ break;
+ }
+ return (*next == '\n' ? next : s);
+ }
+ }
+ return nullptr;
+}
+
+/* Read a new line from file FP, using C as a cache for the data
+ coming from the file. Upon successful completion, *LINE is set to
+ the beginning of the line found. *LINE points directly in the
+ line cache and is only valid until the next call of get_next_line.
+ *LINE_LEN is set to the length of the line. Note that the line
+ does not contain any terminal delimiter. This function returns
+ true if some data was read or process from the cache, false
+ otherwise. Note that subsequent calls to get_next_line might
+ make the content of *LINE invalid. */
+
+bool
+file_cache_slot::get_next_line (char **line, ssize_t *line_len)
+{
+ /* Fill the cache with data to process. */
+ maybe_read_data ();
+
+ size_t remaining_size = m_nb_read - m_line_start_idx;
+ if (remaining_size == 0)
+ /* There is no more data to process. */
+ return false;
+
+ const char *line_start = m_data + m_line_start_idx;
+
+ const char *next_line_start = NULL;
+ size_t len = 0;
+ const char *line_end = find_end_of_line (line_start, remaining_size);
+ if (line_end == NULL)
+ {
+ /* We haven't found an end-of-line delimiter in the cache.
+ Fill the cache with more data from the file and look again. */
+ while (maybe_read_data ())
+ {
+ line_start = m_data + m_line_start_idx;
+ remaining_size = m_nb_read - m_line_start_idx;
+ line_end = find_end_of_line (line_start, remaining_size);
+ if (line_end != NULL)
+ {
+ next_line_start = line_end + 1;
+ break;
+ }
+ }
+ if (line_end == NULL)
+ {
+ /* We've loaded all the file into the cache and still no
+ terminator. Let's say the line ends up at one byte past the
+ end of the file. This is to stay consistent with the case
+ of when the line ends up with a terminator and line_end points to
+ that. That consistency is useful below in the len calculation.
+
+ If the file ends in a \r, we didn't identify it as a line
+ terminator above, so do that now instead. */
+ line_end = m_data + m_nb_read;
+ if (m_nb_read && line_end[-1] == '\r')
+ {
+ --line_end;
+ m_missing_trailing_newline = false;
+ }
+ else
+ m_missing_trailing_newline = true;
+ }
+ else
+ m_missing_trailing_newline = false;
+ }
+ else
+ {
+ next_line_start = line_end + 1;
+ m_missing_trailing_newline = false;
+ }
+
+ if (m_error)
+ return false;
+
+ /* At this point, we've found the end of the of line. It either points to
+ the line terminator or to one byte after the last byte of the file. */
+ gcc_assert (line_end != NULL);
+
+ len = line_end - line_start;
+
+ if (m_line_start_idx < m_nb_read)
+ *line = const_cast<char *> (line_start);
+
+ ++m_line_num;
+
+ /* Now update our line record so that re-reading lines from the
+ before m_line_start_idx is faster. */
+ size_t rlen = m_line_record.length ();
+ /* Only update when beyond the previously cached region. */
+ if (rlen == 0 || m_line_record[rlen - 1].line_num < m_line_num)
+ {
+ size_t spacing
+ = (rlen >= 2
+ ? (m_line_record[rlen - 1].line_num
+ - m_line_record[rlen - 2].line_num) : 1);
+ size_t delta
+ = rlen >= 1 ? m_line_num - m_line_record[rlen - 1].line_num : 1;
+
+ size_t max_size = line_record_size;
+ /* One anchor per hundred input lines. */
+ if (max_size == 0)
+ max_size = m_line_num / 100;
+
+ /* If we're too far beyond drop half of the lines to rebalance. */
+ if (rlen == max_size && delta >= spacing * 2)
+ {
+ size_t j = 0;
+ for (size_t i = 1; i < rlen; i += 2)
+ m_line_record[j++] = m_line_record[i];
+ m_line_record.truncate (j);
+ rlen = j;
+ spacing *= 2;
+ }
+
+ if (rlen < max_size && delta >= spacing)
+ {
+ file_cache_slot::line_info li (m_line_num, m_line_start_idx,
+ line_end - m_data);
+ m_line_record.safe_push (li);
+ }
+ }
+
+ /* Cache recent tail lines separately for fast access. This assumes
+ most accesses do not skip backwards. */
+ if (m_line_recent_last == m_line_recent_first
+ || m_line_recent[m_line_recent_last].line_num == m_line_num - 1)
+ {
+ size_t mask = ((size_t) 1 << recent_cached_lines_shift) - 1;
+ m_line_recent_last = (m_line_recent_last + 1) & mask;
+ if (m_line_recent_last == m_line_recent_first)
+ m_line_recent_first = (m_line_recent_first + 1) & mask;
+ m_line_recent[m_line_recent_last]
+ = file_cache_slot::line_info (m_line_num, m_line_start_idx,
+ line_end - m_data);
+ }
+
+ /* Update m_line_start_idx so that it points to the next line to be
+ read. */
+ if (next_line_start)
+ m_line_start_idx = next_line_start - m_data;
+ else
+ /* We didn't find any terminal '\n'. Let's consider that the end
+ of line is the end of the data in the cache. The next
+ invocation of get_next_line will either read more data from the
+ underlying file or return false early because we've reached the
+ end of the file. */
+ m_line_start_idx = m_nb_read;
+
+ *line_len = len;
+
+ return true;
+}
+
+/* Consume the next bytes coming from the cache (or from its
+ underlying file if there are remaining unread bytes in the file)
+ until we reach the next end-of-line (or end-of-file). There is no
+ copying from the cache involved. Return TRUE upon successful
+ completion. */
+
+bool
+file_cache_slot::goto_next_line ()
+{
+ char *l;
+ ssize_t len;
+
+ return get_next_line (&l, &len);
+}
+
+/* Read an arbitrary line number LINE_NUM from the file cached in C.
+ If the line was read successfully, *LINE points to the beginning
+ of the line in the file cache and *LINE_LEN is the length of the
+ line. *LINE is not nul-terminated, but may contain zero bytes.
+ *LINE is only valid until the next call of read_line_num.
+ This function returns bool if a line was read. */
+
+bool
+file_cache_slot::read_line_num (size_t line_num,
+ char ** line, ssize_t *line_len)
+{
+ gcc_assert (line_num > 0);
+
+ /* Is the line in the recent line cache?
+ This assumes the main file processing is only using
+ a single contiguous cursor with only temporary excursions. */
+ if (m_line_recent_first != m_line_recent_last
+ && m_line_recent[m_line_recent_first].line_num <= line_num
+ && m_line_recent[m_line_recent_last].line_num >= line_num)
+ {
+ line_info &last = m_line_recent[m_line_recent_last];
+ size_t mask = (1U << recent_cached_lines_shift) - 1;
+ size_t idx = (m_line_recent_last - (last.line_num - line_num)) & mask;
+ line_info &recent = m_line_recent[idx];
+ gcc_assert (recent.line_num == line_num);
+ *line = m_data + recent.start_pos;
+ *line_len = recent.end_pos - recent.start_pos;
+ return true;
+ }
+
+ if (line_num <= m_line_num)
+ {
+ line_info l (line_num, 0, 0);
+ int i = m_line_record.lower_bound (l, line_info::less_than);
+ if (i == 0)
+ {
+ m_line_start_idx = 0;
+ m_line_num = 0;
+ }
+ else if (m_line_record[i - 1].line_num == line_num)
+ {
+ /* We have the start/end of the line. */
+ *line = m_data + m_line_record[i - 1].start_pos;
+ *line_len = m_line_record[i - 1].end_pos - m_line_record[i - 1].start_pos;
+ return true;
+ }
+ else
+ {
+ gcc_assert (m_line_record[i - 1].line_num < m_line_num);
+ m_line_start_idx = m_line_record[i - 1].start_pos;
+ m_line_num = m_line_record[i - 1].line_num - 1;
+ }
+ }
+
+ /* Let's walk from line m_line_num up to line_num - 1, without
+ copying any line. */
+ while (m_line_num < line_num - 1)
+ if (!goto_next_line ())
+ return false;
+
+ /* The line we want is the next one. Let's read it. */
+ return get_next_line (line, line_len);
+}
+
+/* Return the physical source line that corresponds to FILE_PATH/LINE.
+ The line is not nul-terminated. The returned pointer is only
+ valid until the next call of location_get_source_line.
+ Note that the line can contain several null characters,
+ so the returned value's length has the actual length of the line.
+ If the function fails, a NULL char_span is returned. */
+
+char_span
+file_cache::get_source_line (const char *file_path, int line)
+{
+ char *buffer = NULL;
+ ssize_t len;
+
+ if (line == 0)
+ return char_span (NULL, 0);
+
+ if (file_path == NULL)
+ return char_span (NULL, 0);
+
+ file_cache_slot *c = lookup_or_add_file (file_path);
+ if (c == NULL)
+ return char_span (NULL, 0);
+
+ bool read = c->read_line_num (line, &buffer, &len);
+ if (!read)
+ return char_span (NULL, 0);
+
+ return char_span (buffer, len);
+}
+
+char_span
+file_cache::get_source_file_content (const char *file_path)
+{
+ file_cache_slot *c = lookup_or_add_file (file_path);
+ if (c == nullptr)
+ return char_span (nullptr, 0);
+ return c->get_full_file_content ();
+}
+
+#if CHECKING_P
+
+namespace selftest {
+
+ using temp_source_file = ::selftest::temp_source_file;
+
+/* Verify reading of a specific line LINENUM in TMP, FC. */
+
+static void
+check_line (temp_source_file &tmp, file_cache &fc, int linenum)
+{
+ char_span line = fc.get_source_line (tmp.get_filename (), linenum);
+ int n;
+ const char *b = line.get_buffer ();
+ size_t l = line.length ();
+ char buf[5];
+ ASSERT_LT (l, 5);
+ memcpy (buf, b, l);
+ buf[l] = '\0';
+ ASSERT_TRUE (sscanf (buf, "%d", &n) == 1);
+ ASSERT_EQ (n, linenum);
+}
+
+/* Test file cache replacement. */
+
+static void
+test_replacement ()
+{
+ const int maxline = 1000;
+
+ char *vec = XNEWVEC (char, maxline * 5);
+ char *p = vec;
+ int i;
+ for (i = 1; i <= maxline; i++)
+ p += sprintf (p, "%d\n", i);
+
+ temp_source_file tmp (SELFTEST_LOCATION, ".txt", vec);
+ free (vec);
+ file_cache fc;
+
+ for (i = 2; i <= maxline; i++)
+ {
+ check_line (tmp, fc, i);
+ check_line (tmp, fc, i - 1);
+ if (i >= 10)
+ check_line (tmp, fc, i - 9);
+ if (i >= 350) /* Exceed the look behind cache. */
+ check_line (tmp, fc, i - 300);
+ }
+ for (i = 5; i <= maxline; i += 100)
+ check_line (tmp, fc, i);
+ for (i = 1; i <= maxline; i++)
+ check_line (tmp, fc, i);
+}
+
+/* Verify reading of input files (e.g. for caret-based diagnostics). */
+
+static void
+test_reading_source_line ()
+{
+ /* Create a tempfile and write some text to it. */
+ temp_source_file tmp (SELFTEST_LOCATION, ".txt",
+ "01234567890123456789\n"
+ "This is the test text\n"
+ "This is the 3rd line");
+ file_cache fc;
+
+ /* Read back a specific line from the tempfile. */
+ char_span source_line = fc.get_source_line (tmp.get_filename (), 3);
+ ASSERT_TRUE (source_line);
+ ASSERT_TRUE (source_line.get_buffer () != NULL);
+ ASSERT_EQ (20, source_line.length ());
+ ASSERT_TRUE (!strncmp ("This is the 3rd line",
+ source_line.get_buffer (), source_line.length ()));
+
+ source_line = fc.get_source_line (tmp.get_filename (), 2);
+ ASSERT_TRUE (source_line);
+ ASSERT_TRUE (source_line.get_buffer () != NULL);
+ ASSERT_EQ (21, source_line.length ());
+ ASSERT_TRUE (!strncmp ("This is the test text",
+ source_line.get_buffer (), source_line.length ()));
+
+ source_line = fc.get_source_line (tmp.get_filename (), 4);
+ ASSERT_FALSE (source_line);
+ ASSERT_TRUE (source_line.get_buffer () == NULL);
+}
+
+/* Verify reading from buffers (e.g. for sarif-replay). */
+
+static void
+test_reading_source_buffer ()
+{
+ const char *text = ("01234567890123456789\n"
+ "This is the test text\n"
+ "This is the 3rd line");
+ const char *filename = "foo.txt";
+ file_cache fc;
+ fc.add_buffered_content (filename, text, strlen (text));
+
+ /* Read back a specific line from the tempfile. */
+ char_span source_line = fc.get_source_line (filename, 3);
+ ASSERT_TRUE (source_line);
+ ASSERT_TRUE (source_line.get_buffer () != NULL);
+ ASSERT_EQ (20, source_line.length ());
+ ASSERT_TRUE (!strncmp ("This is the 3rd line",
+ source_line.get_buffer (), source_line.length ()));
+
+ source_line = fc.get_source_line (filename, 2);
+ ASSERT_TRUE (source_line);
+ ASSERT_TRUE (source_line.get_buffer () != NULL);
+ ASSERT_EQ (21, source_line.length ());
+ ASSERT_TRUE (!strncmp ("This is the test text",
+ source_line.get_buffer (), source_line.length ()));
+
+ source_line = fc.get_source_line (filename, 4);
+ ASSERT_FALSE (source_line);
+ ASSERT_TRUE (source_line.get_buffer () == NULL);
+}
+
+/* Run all of the selftests within this file. */
+
+void
+file_cache_cc_tests ()
+{
+ test_reading_source_line ();
+ test_reading_source_buffer ();
+ test_replacement ();
+}
+
+} // namespace selftest
+
+#endif /* CHECKING_P */
+
+} // namespace diagnostics
diff --git a/gcc/diagnostics/file-cache.h b/gcc/diagnostics/file-cache.h
new file mode 100644
index 0000000..832a960
--- /dev/null
+++ b/gcc/diagnostics/file-cache.h
@@ -0,0 +1,125 @@
+/* Caching input files for use by diagnostics.
+ Copyright (C) 2004-2025 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/>. */
+
+#ifndef GCC_DIAGNOSTICS_FILE_CACHE_H
+#define GCC_DIAGNOSTICS_FILE_CACHE_H
+
+namespace diagnostics {
+
+/* A class capturing the bounds of a buffer, to allow for run-time
+ bounds-checking in a checked build. */
+
+class char_span
+{
+ public:
+ char_span (const char *ptr, size_t n_elts) : m_ptr (ptr), m_n_elts (n_elts) {}
+
+ /* Test for a non-NULL pointer. */
+ operator bool() const { return m_ptr; }
+
+ /* Get length, not including any 0-terminator (which may not be,
+ in fact, present). */
+ size_t length () const { return m_n_elts; }
+
+ const char *get_buffer () const { return m_ptr; }
+
+ char operator[] (int idx) const
+ {
+ gcc_assert (idx >= 0);
+ gcc_assert ((size_t)idx < m_n_elts);
+ return m_ptr[idx];
+ }
+
+ char_span subspan (int offset, int n_elts) const
+ {
+ gcc_assert (offset >= 0);
+ gcc_assert (offset < (int)m_n_elts);
+ gcc_assert (n_elts >= 0);
+ gcc_assert (offset + n_elts <= (int)m_n_elts);
+ return char_span (m_ptr + offset, n_elts);
+ }
+
+ char *xstrdup () const
+ {
+ return ::xstrndup (m_ptr, m_n_elts);
+ }
+
+ private:
+ const char *m_ptr;
+ size_t m_n_elts;
+};
+
+/* Forward decl of slot within file_cache, so that the definition doesn't
+ need to be in this header. */
+class file_cache_slot;
+
+/* A cache of source files for use when emitting diagnostics
+ (and in a few places in the C/C++ frontends).
+
+ Results are only valid until the next call to the cache, as
+ slots can be evicted.
+
+ Filenames are stored by pointer, and so must outlive the cache
+ instance. */
+
+class file_cache
+{
+ public:
+ file_cache ();
+ ~file_cache ();
+
+ void dump (FILE *out, int indent) const;
+ void DEBUG_FUNCTION dump () const;
+
+ file_cache_slot *lookup_or_add_file (const char *file_path);
+ void forcibly_evict_file (const char *file_path);
+
+ /* See comments in diagnostic.h about the input conversion context. */
+ struct input_context
+ {
+ diagnostic_input_charset_callback ccb;
+ bool should_skip_bom;
+ };
+ void initialize_input_context (diagnostic_input_charset_callback ccb,
+ bool should_skip_bom);
+
+ char_span get_source_file_content (const char *file_path);
+ char_span get_source_line (const char *file_path, int line);
+ bool missing_trailing_newline_p (const char *file_path);
+
+ void add_buffered_content (const char *file_path,
+ const char *buffer,
+ size_t sz);
+
+ void tune (size_t num_file_slots, size_t lines);
+
+ private:
+ file_cache_slot *evicted_cache_tab_entry (unsigned *highest_use_count);
+ file_cache_slot *add_file (const char *file_path);
+ file_cache_slot *lookup_file (const char *file_path);
+
+ private:
+ size_t m_num_file_slots;
+ file_cache_slot *m_file_slots;
+ input_context m_input_context;
+};
+
+} // namespace diagnostics
+
+#endif // #ifndef GCC_DIAGNOSTICS_FILE_CACHE_H
diff --git a/gcc/diagnostic-format-html.cc b/gcc/diagnostics/html-sink.cc
index becac39..07e7187 100644
--- a/gcc/diagnostic-format-html.cc
+++ b/gcc/diagnostics/html-sink.cc
@@ -25,29 +25,31 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
-#include "diagnostic-metadata.h"
-#include "diagnostic-format.h"
-#include "diagnostic-format-html.h"
-#include "diagnostic-format-text.h"
-#include "diagnostic-format-sarif.h"
-#include "diagnostic-output-file.h"
-#include "diagnostic-buffer.h"
-#include "diagnostic-path.h"
-#include "diagnostic-client-data-hooks.h"
+#include "diagnostics/metadata.h"
+#include "diagnostics/sink.h"
+#include "diagnostics/html-sink.h"
+#include "diagnostics/text-sink.h"
+#include "diagnostics/sarif-sink.h"
+#include "diagnostics/output-file.h"
+#include "diagnostics/buffering.h"
+#include "diagnostics/paths.h"
+#include "diagnostics/client-data-hooks.h"
#include "selftest.h"
-#include "selftest-diagnostic.h"
+#include "diagnostics/selftest-context.h"
#include "pretty-print-format-impl.h"
#include "pretty-print-urlifier.h"
-#include "edit-context.h"
+#include "diagnostics/changes.h"
#include "intl.h"
#include "xml.h"
#include "xml-printer.h"
-#include "diagnostic-digraphs.h"
-#include "diagnostic-state-graphs.h"
+#include "diagnostics/digraphs.h"
+#include "diagnostics/state-graphs.h"
#include "graphviz.h"
#include "json.h"
#include "selftest-xml.h"
+namespace diagnostics {
+
// struct html_generation_options
html_generation_options::html_generation_options ()
@@ -63,19 +65,19 @@ class html_builder;
/* Concrete buffering implementation subclass for HTML output. */
-class diagnostic_html_format_buffer : public diagnostic_per_format_buffer
+class html_sink_buffer : public per_sink_buffer
{
public:
friend class html_builder;
- friend class html_output_format;
+ friend class html_sink;
- diagnostic_html_format_buffer (html_builder &builder)
+ html_sink_buffer (html_builder &builder)
: m_builder (builder)
{}
void dump (FILE *out, int indent) const final override;
bool empty_p () const final override;
- void move_to (diagnostic_per_format_buffer &dest) final override;
+ void move_to (per_sink_buffer &dest) final override;
void clear () final override;
void flush () final override;
@@ -107,9 +109,9 @@ private:
class html_builder
{
public:
- friend class diagnostic_html_format_buffer;
+ friend class html_sink_buffer;
- html_builder (diagnostic_context &context,
+ html_builder (context &dc,
pretty_printer &pp,
const line_maps *line_maps,
const html_generation_options &html_gen_opts);
@@ -118,10 +120,10 @@ public:
set_main_input_filename (const char *name);
void on_report_diagnostic (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind,
- diagnostic_html_format_buffer *buffer);
- void emit_diagram (const diagnostic_diagram &diagram);
- void emit_global_graph (const diagnostics::digraphs::lazy_digraph &);
+ enum kind orig_diag_kind,
+ html_sink_buffer *buffer);
+ void emit_diagram (const diagram &d);
+ void emit_global_graph (const lazily_created<digraphs::digraph> &);
void end_group ();
@@ -140,7 +142,7 @@ public:
}
std::unique_ptr<xml::element>
- make_element_for_metadata (const diagnostic_metadata &metadata);
+ make_element_for_metadata (const metadata &);
std::unique_ptr<xml::element>
make_element_for_patch (const diagnostic_info &diagnostic);
@@ -151,7 +153,7 @@ public:
}
std::unique_ptr<xml::node>
- maybe_make_state_diagram (const diagnostic_event &event);
+ maybe_make_state_diagram (const paths::event &event);
private:
void
@@ -159,7 +161,7 @@ private:
std::unique_ptr<xml::element>
make_element_for_diagnostic (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind,
+ enum kind orig_diag_kind,
bool alert);
std::unique_ptr<xml::element>
@@ -177,14 +179,14 @@ private:
pop_nesting_level ();
void
- add_graph (const diagnostics::digraphs::digraph &dg,
+ add_graph (const digraphs::digraph &dg,
xml::element &parent_element);
- diagnostic_context &m_context;
+ context &m_context;
pretty_printer *m_printer;
const line_maps *m_line_maps;
html_generation_options m_html_gen_opts;
- const logical_location_manager *m_logical_loc_mgr;
+ const logical_locations::manager *m_logical_loc_mgr;
std::unique_ptr<xml::document> m_document;
xml::element *m_head_element;
@@ -195,7 +197,7 @@ private:
std::vector<xml::element *> m_cur_nesting_levels;
int m_next_diag_id; // for handing out unique IDs
json::array m_ui_focus_ids;
- logical_location m_last_logical_location;
+ logical_locations::key m_last_logical_location;
location_t m_last_location;
expanded_location m_last_expanded_location;
};
@@ -216,12 +218,12 @@ make_span (std::string class_)
return span;
}
-/* class diagnostic_html_format_buffer : public diagnostic_per_format_buffer. */
+/* class html_sink_buffer : public per_sink_buffer. */
void
-diagnostic_html_format_buffer::dump (FILE *out, int indent) const
+html_sink_buffer::dump (FILE *out, int indent) const
{
- fprintf (out, "%*sdiagnostic_html_format_buffer:\n", indent, "");
+ fprintf (out, "%*shtml_sink_buffer:\n", indent, "");
int idx = 0;
for (auto &result : m_results)
{
@@ -233,29 +235,29 @@ diagnostic_html_format_buffer::dump (FILE *out, int indent) const
}
bool
-diagnostic_html_format_buffer::empty_p () const
+html_sink_buffer::empty_p () const
{
return m_results.empty ();
}
void
-diagnostic_html_format_buffer::move_to (diagnostic_per_format_buffer &base)
+html_sink_buffer::move_to (per_sink_buffer &base)
{
- diagnostic_html_format_buffer &dest
- = static_cast<diagnostic_html_format_buffer &> (base);
+ html_sink_buffer &dest
+ = static_cast<html_sink_buffer &> (base);
for (auto &&result : m_results)
dest.m_results.push_back (std::move (result));
m_results.clear ();
}
void
-diagnostic_html_format_buffer::clear ()
+html_sink_buffer::clear ()
{
m_results.clear ();
}
void
-diagnostic_html_format_buffer::flush ()
+html_sink_buffer::flush ()
{
for (auto &&result : m_results)
m_builder.m_diagnostics_element->add_child (std::move (result));
@@ -399,11 +401,11 @@ struct html_doctypedecl : public xml::doctypedecl
/* html_builder's ctor. */
-html_builder::html_builder (diagnostic_context &context,
+html_builder::html_builder (context &dc,
pretty_printer &pp,
const line_maps *line_maps,
const html_generation_options &html_gen_opts)
-: m_context (context),
+: m_context (dc),
m_printer (&pp),
m_line_maps (line_maps),
m_html_gen_opts (html_gen_opts),
@@ -418,7 +420,7 @@ html_builder::html_builder (diagnostic_context &context,
{
gcc_assert (m_line_maps);
- if (auto client_data_hooks = context.get_client_data_hooks ())
+ if (auto client_data_hooks = dc.get_client_data_hooks ())
m_logical_loc_mgr = client_data_hooks->get_logical_location_manager ();
m_document = std::make_unique<xml::document> ();
@@ -494,10 +496,10 @@ html_builder::add_stylesheet (std::string url)
void
html_builder::on_report_diagnostic (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind,
- diagnostic_html_format_buffer *buffer)
+ enum kind orig_diag_kind,
+ html_sink_buffer *buffer)
{
- if (diagnostic.kind == DK_ICE || diagnostic.kind == DK_ICE_NOBT)
+ if (diagnostic.m_kind == kind::ice || diagnostic.m_kind == kind::ice_nobt)
{
/* Print a header for the remaining output to stderr, and
return, attempting to print the usual ICE messages to
@@ -512,7 +514,7 @@ html_builder::on_report_diagnostic (const diagnostic_info &diagnostic,
if (m_cur_diagnostic_element && nesting_level > 0)
alert = false;
if (!m_cur_diagnostic_element)
- m_last_logical_location = logical_location ();
+ m_last_logical_location = logical_locations::key ();
auto diag_element
= make_element_for_diagnostic (diagnostic, orig_diag_kind, alert);
if (buffer)
@@ -605,7 +607,7 @@ print_pre_source (xml::printer &xp, const char *text)
}
std::unique_ptr<xml::node>
-html_builder::maybe_make_state_diagram (const diagnostic_event &event)
+html_builder::maybe_make_state_diagram (const paths::event &event)
{
if (!m_html_gen_opts.m_show_state_diagrams)
return nullptr;
@@ -622,8 +624,7 @@ html_builder::maybe_make_state_diagram (const diagnostic_event &event)
return nullptr;
// Convert it to .dot AST
- auto dot_graph
- = diagnostics::state_graphs::make_dot_graph (*state_graph,
+ auto dot_graph = state_graphs::make_dot_graph (*state_graph,
*m_logical_loc_mgr);
gcc_assert (dot_graph);
@@ -664,7 +665,7 @@ class html_path_label_writer : public html_label_writer
public:
html_path_label_writer (xml::printer &xp,
html_builder &builder,
- const diagnostic_path &path,
+ const paths::path &path,
const std::string &event_id_prefix)
: m_xp (xp),
m_html_builder (builder),
@@ -685,7 +686,7 @@ public:
void end_label () final override
{
- const diagnostic_event &event
+ const paths::event &event
= m_path.get_event (m_curr_event_id.zero_based ());
if (auto state_doc = m_html_builder.maybe_make_state_diagram (event))
{
@@ -713,31 +714,31 @@ private:
xml::printer &m_xp;
html_builder &m_html_builder;
- const diagnostic_path &m_path;
+ const paths::path &m_path;
const std::string &m_event_id_prefix;
int m_next_event_idx;
- diagnostic_event_id_t m_curr_event_id;
+ paths::event_id_t m_curr_event_id;
};
/* See https://pf3.patternfly.org/v3/pattern-library/widgets/#alerts */
static const char *
-get_pf_class_for_alert_div (diagnostic_t diag_kind)
+get_pf_class_for_alert_div (enum kind diag_kind)
{
switch (diag_kind)
{
- case DK_DEBUG:
- case DK_NOTE:
+ case kind::debug:
+ case kind::note:
return "alert alert-info";
- case DK_ANACHRONISM:
- case DK_WARNING:
+ case kind::anachronism:
+ case kind::warning:
return "alert alert-warning";
- case DK_ERROR:
- case DK_SORRY:
- case DK_ICE:
- case DK_ICE_NOBT:
- case DK_FATAL:
+ case kind::error:
+ case kind::sorry:
+ case kind::ice:
+ case kind::ice_nobt:
+ case kind::fatal:
return "alert alert-danger";
default:
@@ -746,23 +747,23 @@ get_pf_class_for_alert_div (diagnostic_t diag_kind)
}
static const char *
-get_pf_class_for_alert_icon (diagnostic_t diag_kind)
+get_pf_class_for_alert_icon (enum kind diag_kind)
{
switch (diag_kind)
{
- case DK_DEBUG:
- case DK_NOTE:
+ case kind::debug:
+ case kind::note:
return "pficon pficon-info";
- case DK_ANACHRONISM:
- case DK_WARNING:
+ case kind::anachronism:
+ case kind::warning:
return "pficon pficon-warning-triangle-o";
- case DK_ERROR:
- case DK_SORRY:
- case DK_ICE:
- case DK_ICE_NOBT:
- case DK_FATAL:
+ case kind::error:
+ case kind::sorry:
+ case kind::ice:
+ case kind::ice_nobt:
+ case kind::fatal:
return "pficon pficon-error-circle-o";
default:
@@ -771,57 +772,57 @@ get_pf_class_for_alert_icon (diagnostic_t diag_kind)
}
static const char *
-get_label_for_logical_location_kind (enum logical_location_kind kind)
+get_label_for_logical_location_kind (enum logical_locations::kind kind)
{
switch (kind)
{
default:
gcc_unreachable ();
- case logical_location_kind::unknown:
+ case logical_locations::kind::unknown:
return nullptr;
/* Kinds within executable code. */
- case logical_location_kind::function:
+ case logical_locations::kind::function:
return "Function";
- case logical_location_kind::member:
+ case logical_locations::kind::member:
return "Member";
- case logical_location_kind::module_:
+ case logical_locations::kind::module_:
return "Module";
- case logical_location_kind::namespace_:
+ case logical_locations::kind::namespace_:
return "Namespace";
- case logical_location_kind::type:
+ case logical_locations::kind::type:
return "Type";
- case logical_location_kind::return_type:
+ case logical_locations::kind::return_type:
return "Return type";
- case logical_location_kind::parameter:
+ case logical_locations::kind::parameter:
return "Parameter";
- case logical_location_kind::variable:
+ case logical_locations::kind::variable:
return "Variable";
/* Kinds within XML or HTML documents. */
- case logical_location_kind::element:
+ case logical_locations::kind::element:
return "Element";
- case logical_location_kind::attribute:
+ case logical_locations::kind::attribute:
return "Attribute";
- case logical_location_kind::text:
+ case logical_locations::kind::text:
return "Text";
- case logical_location_kind::comment:
+ case logical_locations::kind::comment:
return "Comment";
- case logical_location_kind::processing_instruction:
+ case logical_locations::kind::processing_instruction:
return "Processing Instruction";
- case logical_location_kind::dtd:
+ case logical_locations::kind::dtd:
return "DTD";
- case logical_location_kind::declaration:
+ case logical_locations::kind::declaration:
return "Declaration";
/* Kinds within JSON documents. */
- case logical_location_kind::object:
+ case logical_locations::kind::object:
return "Object";
- case logical_location_kind::array:
+ case logical_locations::kind::array:
return "Array";
- case logical_location_kind::property:
+ case logical_locations::kind::property:
return "Property";
- case logical_location_kind::value:
+ case logical_locations::kind::value:
return "Value";
}
}
@@ -945,7 +946,7 @@ private:
std::unique_ptr<xml::element>
html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind,
+ enum kind orig_diag_kind,
bool alert)
{
const int diag_idx = m_next_diag_id++;
@@ -969,7 +970,7 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
diag_element->set_attr ("id", diag_id);
if (alert)
diag_element->set_attr ("class",
- get_pf_class_for_alert_div (diagnostic.kind));
+ get_pf_class_for_alert_div (diagnostic.m_kind));
xml::printer xp (*diag_element.get ());
const size_t depth_within_alert_div = 1;
@@ -979,7 +980,7 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
if (alert)
{
xp.push_tag_with_class ("span",
- get_pf_class_for_alert_icon (diagnostic.kind),
+ get_pf_class_for_alert_icon (diagnostic.m_kind),
true);
xp.add_text (" ");
xp.pop_tag ("span");
@@ -1003,7 +1004,7 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
if (show_severity)
{
xp.push_tag ("strong");
- xp.add_text (_(get_diagnostic_kind_text (diagnostic.kind)));
+ xp.add_text (_(get_text_for_kind (diagnostic.m_kind)));
xp.pop_tag ("strong");
xp.add_text (" ");
}
@@ -1016,21 +1017,21 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
pp_clear_output_area (m_printer);
// Add any metadata as a suffix to the message
- if (diagnostic.metadata)
+ if (diagnostic.m_metadata)
{
xp.add_text (" ");
- xp.append (make_element_for_metadata (*diagnostic.metadata));
+ xp.append (make_element_for_metadata (*diagnostic.m_metadata));
}
// Add any option as a suffix to the message
label_text option_text = label_text::take
- (m_context.make_option_name (diagnostic.option_id,
- orig_diag_kind, diagnostic.kind));
+ (m_context.make_option_name (diagnostic.m_option_id,
+ orig_diag_kind, diagnostic.m_kind));
if (option_text.get ())
{
label_text option_url = label_text::take
- (m_context.make_option_url (diagnostic.option_id));
+ (m_context.make_option_url (diagnostic.m_option_id));
xp.add_text (" ");
auto option_span = make_span ("gcc-option");
@@ -1062,7 +1063,7 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
if (auto logical_loc = client_data_hooks->get_current_logical_location ())
if (logical_loc != m_last_logical_location)
{
- enum logical_location_kind kind
+ enum logical_locations::kind kind
= m_logical_loc_mgr->get_kind (logical_loc);;
if (const char *label = get_label_for_logical_location_kind (kind))
if (const char *name_with_scope
@@ -1085,8 +1086,8 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
if (s.line)
{
add_labelled_value (xp, "line", "Line", std::to_string (s.line), false);
- diagnostic_column_policy column_policy (m_context);
- int converted_column = column_policy.converted_column (s);
+ column_policy col_policy (m_context);
+ int converted_column = col_policy.converted_column (s);
if (converted_column >= 0)
add_labelled_value (xp, "column", "Column",
std::to_string (converted_column),
@@ -1101,12 +1102,13 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
// TODO: m_context.m_last_location should be moved into the sink
location_t saved = m_context.m_last_location;
m_context.m_last_location = m_last_location;
- m_context.maybe_show_locus_as_html (*diagnostic.richloc,
- m_context.m_source_printing,
- diagnostic.kind,
- xp,
- nullptr,
- nullptr);
+ m_context.maybe_show_locus_as_html
+ (*diagnostic.m_richloc,
+ m_context.get_source_printing_options (),
+ diagnostic.m_kind,
+ xp,
+ nullptr,
+ nullptr);
m_context.m_last_location = saved;
m_last_location = m_context.m_last_location;
}
@@ -1114,7 +1116,7 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
gcc_assert (xp.get_num_open_tags () == depth_within_alert_div);
/* Execution path. */
- if (auto path = diagnostic.richloc->get_path ())
+ if (auto path = diagnostic.m_richloc->get_path ())
{
xp.push_tag ("div");
xp.set_attr ("id", "execution-path");
@@ -1133,7 +1135,7 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
html_path_label_writer event_label_writer (xp, *this, *path,
event_id_prefix);
- diagnostic_source_print_policy dspp (m_context);
+ source_print_policy dspp (m_context);
print_path_as_html (xp, *path, m_context, &event_label_writer,
dspp);
@@ -1143,10 +1145,10 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
gcc_assert (xp.get_num_open_tags () == depth_within_alert_div);
// Try to display any per-diagnostic graphs
- if (diagnostic.metadata)
- if (auto ldg = diagnostic.metadata->get_lazy_digraphs ())
+ if (diagnostic.m_metadata)
+ if (auto ldg = diagnostic.m_metadata->get_lazy_digraphs ())
{
- auto &digraphs = ldg->get_or_create_digraphs ();
+ auto &digraphs = ldg->get_or_create ();
for (auto &dg : digraphs)
add_graph (*dg, *xp.get_insertion_point ());
}
@@ -1168,9 +1170,9 @@ html_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
std::unique_ptr<xml::element>
html_builder::make_element_for_patch (const diagnostic_info &diagnostic)
{
- edit_context ec (m_context.get_file_cache ());
- ec.add_fixits (diagnostic.richloc);
- if (char *diff = ec.generate_diff (true))
+ changes::change_set edit (m_context.get_file_cache ());
+ edit.add_fixits (diagnostic.m_richloc);
+ if (char *diff = edit.generate_diff (true))
{
if (strlen (diff) > 0)
{
@@ -1208,11 +1210,11 @@ html_builder::make_metadata_element (label_text label,
}
std::unique_ptr<xml::element>
-html_builder::make_element_for_metadata (const diagnostic_metadata &metadata)
+html_builder::make_element_for_metadata (const metadata &m)
{
auto span_metadata = make_span ("gcc-metadata");
- int cwe = metadata.get_cwe ();
+ int cwe = m.get_cwe ();
if (cwe)
{
pretty_printer pp;
@@ -1223,9 +1225,9 @@ html_builder::make_element_for_metadata (const diagnostic_metadata &metadata)
(make_metadata_element (std::move (label), std::move (url)));
}
- for (unsigned idx = 0; idx < metadata.get_num_rules (); ++idx)
+ for (unsigned idx = 0; idx < m.get_num_rules (); ++idx)
{
- auto &rule = metadata.get_rule (idx);
+ auto &rule = m.get_rule (idx);
label_text label = label_text::take (rule.make_description ());
label_text url = label_text::take (rule.make_url ());
span_metadata->add_child
@@ -1235,11 +1237,11 @@ html_builder::make_element_for_metadata (const diagnostic_metadata &metadata)
return span_metadata;
}
-/* Implementation of diagnostic_context::m_diagrams.m_emission_cb
+/* Implementation of diagnostics::context::m_diagrams.m_emission_cb
for HTML output. */
void
-html_builder::emit_diagram (const diagnostic_diagram &/*diagram*/)
+html_builder::emit_diagram (const diagram &)
{
/* We must be within the emission of a top-level diagnostic. */
gcc_assert (m_cur_diagnostic_element);
@@ -1248,7 +1250,7 @@ html_builder::emit_diagram (const diagnostic_diagram &/*diagram*/)
}
void
-html_builder::add_graph (const diagnostics::digraphs::digraph &dg,
+html_builder::add_graph (const digraphs::digraph &dg,
xml::element &parent_element)
{
if (auto dot_graph = dg.make_dot_graph ())
@@ -1269,9 +1271,9 @@ html_builder::add_graph (const diagnostics::digraphs::digraph &dg,
}
void
-html_builder::emit_global_graph (const diagnostics::digraphs::lazy_digraph &ldg)
+html_builder::emit_global_graph (const lazily_created<digraphs::digraph> &ldg)
{
- auto &dg = ldg.get_or_create_digraph ();
+ auto &dg = ldg.get_or_create ();
gcc_assert (m_body_element);
add_graph (dg, *m_body_element);
}
@@ -1312,10 +1314,10 @@ html_builder::flush_to_file (FILE *outf)
fprintf (outf, "\n");
}
-class html_output_format : public diagnostic_output_format
+class html_sink : public sink
{
public:
- ~html_output_format ()
+ ~html_sink ()
{
/* Any diagnostics should have been handled by now.
If not, then something's gone wrong with diagnostic
@@ -1327,8 +1329,8 @@ public:
void dump (FILE *out, int indent) const override
{
- fprintf (out, "%*shtml_output_format\n", indent, "");
- diagnostic_output_format::dump (out, indent);
+ fprintf (out, "%*shtml_sink\n", indent, "");
+ sink::dump (out, indent);
}
void
@@ -1337,15 +1339,15 @@ public:
m_builder.set_main_input_filename (name);
}
- std::unique_ptr<diagnostic_per_format_buffer>
- make_per_format_buffer () final override
+ std::unique_ptr<per_sink_buffer>
+ make_per_sink_buffer () final override
{
- return std::make_unique<diagnostic_html_format_buffer> (m_builder);
+ return std::make_unique<html_sink_buffer> (m_builder);
}
- void set_buffer (diagnostic_per_format_buffer *base_buffer) final override
+ void set_buffer (per_sink_buffer *base_buffer) final override
{
- diagnostic_html_format_buffer *buffer
- = static_cast<diagnostic_html_format_buffer *> (base_buffer);
+ html_sink_buffer *buffer
+ = static_cast<html_sink_buffer *> (base_buffer);
m_buffer = buffer;
}
@@ -1359,13 +1361,13 @@ public:
}
void
on_report_diagnostic (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind) final override
+ enum kind orig_diag_kind) final override
{
m_builder.on_report_diagnostic (diagnostic, orig_diag_kind, m_buffer);
}
- void on_diagram (const diagnostic_diagram &diagram) final override
+ void on_diagram (const diagram &d) final override
{
- m_builder.emit_diagram (diagram);
+ m_builder.emit_diagram (d);
}
void after_diagnostic (const diagnostic_info &) final override
{
@@ -1390,7 +1392,8 @@ public:
}
void
- report_global_digraph (const diagnostics::digraphs::lazy_digraph &ldg) final override
+ report_global_digraph (const lazily_created<digraphs::digraph> &ldg)
+ final override
{
m_builder.emit_global_graph (ldg);
}
@@ -1403,41 +1406,41 @@ public:
html_builder &get_builder () { return m_builder; }
protected:
- html_output_format (diagnostic_context &context,
- const line_maps *line_maps,
- const html_generation_options &html_gen_opts)
- : diagnostic_output_format (context),
- m_builder (context, *get_printer (), line_maps, html_gen_opts),
+ html_sink (context &dc,
+ const line_maps *line_maps,
+ const html_generation_options &html_gen_opts)
+ : sink (dc),
+ m_builder (dc, *get_printer (), line_maps, html_gen_opts),
m_buffer (nullptr)
{}
html_builder m_builder;
- diagnostic_html_format_buffer *m_buffer;
+ html_sink_buffer *m_buffer;
};
-class html_file_output_format : public html_output_format
+class html_file_sink : public html_sink
{
public:
- html_file_output_format (diagnostic_context &context,
- const line_maps *line_maps,
- const html_generation_options &html_gen_opts,
- diagnostic_output_file output_file)
- : html_output_format (context, line_maps, html_gen_opts),
- m_output_file (std::move (output_file))
+ html_file_sink (context &dc,
+ const line_maps *line_maps,
+ const html_generation_options &html_gen_opts,
+ output_file output_file_)
+ : html_sink (dc, line_maps, html_gen_opts),
+ m_output_file (std::move (output_file_))
{
gcc_assert (m_output_file.get_open_file ());
gcc_assert (m_output_file.get_filename ());
}
- ~html_file_output_format ()
+ ~html_file_sink ()
{
m_builder.flush_to_file (m_output_file.get_open_file ());
}
void dump (FILE *out, int indent) const override
{
- fprintf (out, "%*shtml_file_output_format: %s\n",
+ fprintf (out, "%*shtml_file_sink: %s\n",
indent, "",
m_output_file.get_filename ());
- diagnostic_output_format::dump (out, indent);
+ sink::dump (out, indent);
}
bool machine_readable_stderr_p () const final override
{
@@ -1445,26 +1448,26 @@ public:
}
private:
- diagnostic_output_file m_output_file;
+ output_file m_output_file;
};
/* Attempt to open BASE_FILE_NAME.html for writing.
- Return a non-null diagnostic_output_file,
- or return a null diagnostic_output_file and complain to CONTEXT
+ Return a non-null output_file,
+ or return a null output_file and complain to DC
using LINE_MAPS. */
-diagnostic_output_file
-diagnostic_output_format_open_html_file (diagnostic_context &context,
- line_maps *line_maps,
- const char *base_file_name)
+output_file
+open_html_output_file (context &dc,
+ line_maps *line_maps,
+ const char *base_file_name)
{
if (!base_file_name)
{
rich_location richloc (line_maps, UNKNOWN_LOCATION);
- context.emit_diagnostic_with_group
- (DK_ERROR, richloc, nullptr, 0,
+ dc.emit_diagnostic_with_group
+ (kind::error, richloc, nullptr, 0,
"unable to determine filename for HTML output");
- return diagnostic_output_file ();
+ return output_file ();
}
label_text filename = label_text::take (concat (base_file_name,
@@ -1474,26 +1477,26 @@ diagnostic_output_format_open_html_file (diagnostic_context &context,
if (!outf)
{
rich_location richloc (line_maps, UNKNOWN_LOCATION);
- context.emit_diagnostic_with_group
- (DK_ERROR, richloc, nullptr, 0,
+ dc.emit_diagnostic_with_group
+ (kind::error, richloc, nullptr, 0,
"unable to open %qs for HTML output: %m",
filename.get ());
- return diagnostic_output_file ();
+ return output_file ();
}
- return diagnostic_output_file (outf, true, std::move (filename));
+ return output_file (outf, true, std::move (filename));
}
-std::unique_ptr<diagnostic_output_format>
-make_html_sink (diagnostic_context &context,
+std::unique_ptr<sink>
+make_html_sink (context &dc,
const line_maps &line_maps,
const html_generation_options &html_gen_opts,
- diagnostic_output_file output_file)
+ output_file output_file_)
{
auto sink
- = std::make_unique<html_file_output_format> (context,
- &line_maps,
- html_gen_opts,
- std::move (output_file));
+ = std::make_unique<html_file_sink> (dc,
+ &line_maps,
+ html_gen_opts,
+ std::move (output_file_));
sink->update_printer ();
return sink;
}
@@ -1550,7 +1553,7 @@ test_token_printer ()
{
token_printer_test t;
- diagnostic_event_id_t event_id (0);
+ paths::event_id_t event_id (0);
pp_printf (&t.m_pp, "foo %@ bar", &event_id);
ASSERT_XML_PRINT_EQ
(t.m_top_element,
@@ -1558,26 +1561,26 @@ test_token_printer ()
}
}
-/* A subclass of html_output_format for writing selftests.
+/* A subclass of html_sink for writing selftests.
The XML output is cached internally, rather than written
out to a file. */
-class test_html_diagnostic_context : public test_diagnostic_context
+class test_html_context : public test_context
{
public:
- test_html_diagnostic_context ()
+ test_html_context ()
{
html_generation_options html_gen_opts;
html_gen_opts.m_css = false;
html_gen_opts.m_javascript = false;
- auto sink = std::make_unique<html_buffered_output_format> (*this,
- line_table,
- html_gen_opts);
+ auto sink = std::make_unique<html_buffered_sink> (*this,
+ line_table,
+ html_gen_opts);
sink->update_printer ();
sink->set_main_input_filename ("(main input filename)");
m_format = sink.get (); // borrowed
- set_output_format (std::move (sink));
+ set_sink (std::move (sink));
}
const xml::document &get_document () const
@@ -1591,13 +1594,13 @@ public:
}
private:
- class html_buffered_output_format : public html_output_format
+ class html_buffered_sink : public html_sink
{
public:
- html_buffered_output_format (diagnostic_context &context,
- const line_maps *line_maps,
- const html_generation_options &html_gen_opts)
- : html_output_format (context, line_maps, html_gen_opts)
+ html_buffered_sink (context &dc,
+ const line_maps *line_maps,
+ const html_generation_options &html_gen_opts)
+ : html_sink (dc, line_maps, html_gen_opts)
{
}
bool machine_readable_stderr_p () const final override
@@ -1606,20 +1609,20 @@ private:
}
};
- html_output_format *m_format; // borrowed
+ html_sink *m_format; // borrowed
};
/* Test of reporting a diagnostic at UNKNOWN_LOCATION to a
- diagnostic_context and examining the generated XML document.
+ diagnostics::context and examining the generated XML document.
Verify various basic properties. */
static void
test_simple_log ()
{
- test_html_diagnostic_context dc;
+ test_html_context dc;
rich_location richloc (line_table, UNKNOWN_LOCATION);
- dc.report (DK_ERROR, richloc, nullptr, 0, "this is a test: %qs", "foo");
+ dc.report (kind::error, richloc, nullptr, 0, "this is a test: %qs", "foo");
const xml::document &doc = dc.get_document ();
@@ -1647,13 +1650,13 @@ test_simple_log ()
static void
test_metadata ()
{
- test_html_diagnostic_context dc;
+ test_html_context dc;
html_builder &b = dc.get_builder ();
{
- diagnostic_metadata metadata;
- metadata.add_cwe (415);
- auto element = b.make_element_for_metadata (metadata);
+ metadata m;
+ m.add_cwe (415);
+ auto element = b.make_element_for_metadata (m);
ASSERT_XML_PRINT_EQ
(*element,
"<span class=\"gcc-metadata\">"
@@ -1668,11 +1671,11 @@ test_metadata ()
}
{
- diagnostic_metadata metadata;
- diagnostic_metadata::precanned_rule rule ("MISC-42",
- "http://example.com");
- metadata.add_rule (rule);
- auto element = b.make_element_for_metadata (metadata);
+ metadata m;
+ metadata::precanned_rule rule ("MISC-42",
+ "http://example.com");
+ m.add_rule (rule);
+ auto element = b.make_element_for_metadata (m);
ASSERT_XML_PRINT_EQ
(*element,
"<span class=\"gcc-metadata\">"
@@ -1690,14 +1693,15 @@ test_metadata ()
/* Run all of the selftests within this file. */
void
-diagnostic_format_html_cc_tests ()
+html_sink_cc_tests ()
{
- auto_fix_quotes fix_quotes;
+ ::selftest::auto_fix_quotes fix_quotes;
test_token_printer ();
test_simple_log ();
test_metadata ();
}
} // namespace selftest
+} // namespace diagnostics
#endif /* CHECKING_P */
diff --git a/gcc/diagnostic-format-html.h b/gcc/diagnostics/html-sink.h
index 537ba54..d86bde8 100644
--- a/gcc/diagnostic-format-html.h
+++ b/gcc/diagnostics/html-sink.h
@@ -18,11 +18,13 @@ 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_DIAGNOSTIC_FORMAT_HTML_H
-#define GCC_DIAGNOSTIC_FORMAT_HTML_H
+#ifndef GCC_DIAGNOSTICS_HTML_SINK_H
+#define GCC_DIAGNOSTICS_HTML_SINK_H
-#include "diagnostic-format.h"
-#include "diagnostic-output-file.h"
+#include "diagnostics/sink.h"
+#include "diagnostics/output-file.h"
+
+namespace diagnostics {
struct html_generation_options
{
@@ -43,22 +45,24 @@ struct html_generation_options
bool m_show_state_diagrams_dot_src;
};
-extern diagnostic_output_file
-diagnostic_output_format_open_html_file (diagnostic_context &context,
- line_maps *line_maps,
- const char *base_file_name);
+extern diagnostics::output_file
+open_html_output_file (context &dc,
+ line_maps *line_maps,
+ const char *base_file_name);
-extern std::unique_ptr<diagnostic_output_format>
-make_html_sink (diagnostic_context &context,
+extern std::unique_ptr<sink>
+make_html_sink (context &dc,
const line_maps &line_maps,
const html_generation_options &html_gen_opts,
- diagnostic_output_file output_file);
+ output_file output_file_);
extern void
print_path_as_html (xml::printer &xp,
- const diagnostic_path &path,
- diagnostic_context &dc,
+ const paths::path &path,
+ context &dc,
html_label_writer *event_label_writer,
- const diagnostic_source_print_policy &dspp);
+ const source_print_policy &dspp);
+
+} // namespace diagnostics
-#endif /* ! GCC_DIAGNOSTIC_FORMAT_HTML_H */
+#endif /* ! GCC_DIAGNOSTICS_HTML_SINK_H */
diff --git a/gcc/diagnostic.def b/gcc/diagnostics/kinds.def
index ab2185c..2a0a0a6 100644
--- a/gcc/diagnostic.def
+++ b/gcc/diagnostics/kinds.def
@@ -16,40 +16,40 @@ 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/>. */
-/* DK_UNSPECIFIED must be first so it has a value of zero. We never
+/* kind::unspecified must be first so it has a value of zero. We never
assign this kind to an actual diagnostic, we only use this in
variables that can hold a kind, to mean they have yet to have a
kind specified. I.e. they're uninitialized. Within the diagnostic
machinery, this kind also means "don't change the existing kind",
meaning "no change is specified". */
-DEFINE_DIAGNOSTIC_KIND (DK_UNSPECIFIED, "", NULL)
+DEFINE_DIAGNOSTIC_KIND (unspecified, "", NULL)
-/* If a diagnostic is set to DK_IGNORED, it won't get reported at all.
+/* If a diagnostic is set to kind::ignored, it won't get reported at all.
This is used by the diagnostic machinery when it wants to disable a
diagnostic without disabling the option which causes it. */
-DEFINE_DIAGNOSTIC_KIND (DK_IGNORED, "", NULL)
+DEFINE_DIAGNOSTIC_KIND (ignored, "", NULL)
/* The remainder are real diagnostic types. */
-DEFINE_DIAGNOSTIC_KIND (DK_FATAL, "fatal error: ", "error")
-DEFINE_DIAGNOSTIC_KIND (DK_ICE, "internal compiler error: ", "error")
-DEFINE_DIAGNOSTIC_KIND (DK_ERROR, "error: ", "error")
-DEFINE_DIAGNOSTIC_KIND (DK_SORRY, "sorry, unimplemented: ", "error")
-DEFINE_DIAGNOSTIC_KIND (DK_WARNING, "warning: ", "warning")
-DEFINE_DIAGNOSTIC_KIND (DK_ANACHRONISM, "anachronism: ", "warning")
-DEFINE_DIAGNOSTIC_KIND (DK_NOTE, "note: ", "note")
-DEFINE_DIAGNOSTIC_KIND (DK_DEBUG, "debug: ", "note")
+DEFINE_DIAGNOSTIC_KIND (fatal, "fatal error: ", "error")
+DEFINE_DIAGNOSTIC_KIND (ice, "internal compiler error: ", "error")
+DEFINE_DIAGNOSTIC_KIND (error, "error: ", "error")
+DEFINE_DIAGNOSTIC_KIND (sorry, "sorry, unimplemented: ", "error")
+DEFINE_DIAGNOSTIC_KIND (warning, "warning: ", "warning")
+DEFINE_DIAGNOSTIC_KIND (anachronism, "anachronism: ", "warning")
+DEFINE_DIAGNOSTIC_KIND (note, "note: ", "note")
+DEFINE_DIAGNOSTIC_KIND (debug, "debug: ", "note")
/* For use when using the diagnostic_show_locus machinery to show
a range of events within a path. */
-DEFINE_DIAGNOSTIC_KIND (DK_DIAGNOSTIC_PATH, "path: ", "path")
+DEFINE_DIAGNOSTIC_KIND (path, "path: ", "path")
-/* These two would be re-classified as DK_WARNING or DK_ERROR, so the
+/* These two would be re-classified as kind::warning or kind::error, so the
prefix does not matter. */
-DEFINE_DIAGNOSTIC_KIND (DK_PEDWARN, "pedwarn: ", NULL)
-DEFINE_DIAGNOSTIC_KIND (DK_PERMERROR, "permerror: ", NULL)
-/* This one is just for counting DK_WARNING promoted to DK_ERROR
+DEFINE_DIAGNOSTIC_KIND (pedwarn, "pedwarn: ", NULL)
+DEFINE_DIAGNOSTIC_KIND (permerror, "permerror: ", NULL)
+/* This one is just for counting kind::warning promoted to kind::error
due to -Werror and -Werror=warning. */
-DEFINE_DIAGNOSTIC_KIND (DK_WERROR, "error: ", NULL)
-/* This is like DK_ICE, but backtrace is not printed. Used in the driver
+DEFINE_DIAGNOSTIC_KIND (werror, "error: ", NULL)
+/* This is like kind::ICE, but backtrace is not printed. Used in the driver
when reporting fatal signal in the compiler. */
-DEFINE_DIAGNOSTIC_KIND (DK_ICE_NOBT, "internal compiler error: ", "error")
+DEFINE_DIAGNOSTIC_KIND (ice_nobt, "internal compiler error: ", "error")
diff --git a/gcc/diagnostics/kinds.h b/gcc/diagnostics/kinds.h
new file mode 100644
index 0000000..7b4a168
--- /dev/null
+++ b/gcc/diagnostics/kinds.h
@@ -0,0 +1,45 @@
+/* An enum used to discriminate severities of diagnostics.
+ Copyright (C) 1998-2025 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/>. */
+
+#ifndef GCC_DIAGNOSTICS_KINDS_H
+#define GCC_DIAGNOSTICS_KINDS_H
+
+namespace diagnostics {
+
+/* Constants used to discriminate diagnostics. */
+enum class kind
+{
+#define DEFINE_DIAGNOSTIC_KIND(K, msgid, C) K,
+#include "diagnostics/kinds.def"
+#undef DEFINE_DIAGNOSTIC_KIND
+ last_diagnostic_kind,
+ /* This is used for tagging pragma pops in the diagnostic
+ classification history chain. */
+ pop,
+ /* This is used internally to note that a diagnostic is enabled
+ without mandating any specific type. */
+ any
+};
+
+extern const char *get_text_for_kind (enum diagnostics::kind);
+extern const char *get_color_for_kind (enum diagnostics::kind);
+
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_KINDS_H */
diff --git a/gcc/lazy-diagnostic-path.cc b/gcc/diagnostics/lazy-paths.cc
index 34743e3..4934651 100644
--- a/gcc/lazy-diagnostic-path.cc
+++ b/gcc/diagnostics/lazy-paths.cc
@@ -23,60 +23,58 @@ along with GCC; see the file COPYING3. If not see
#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
-#include "tree.h"
-#include "version.h"
-#include "intl.h"
#include "diagnostic.h"
-#include "lazy-diagnostic-path.h"
+#include "diagnostics/lazy-paths.h"
#include "selftest.h"
-#include "selftest-diagnostic.h"
-#include "simple-diagnostic-path.h"
-#include "gcc-rich-location.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/selftest-context.h"
+#include "diagnostics/selftest-paths.h"
+#include "diagnostics/text-sink.h"
-/* class lazy_diagnostic_path : public diagnostic_path. */
+using namespace diagnostics::paths;
-/* Implementation of diagnostic_path vfuncs in terms of a lazily-generated
+/* class lazy_path : public path. */
+
+/* Implementation of path vfuncs in terms of a lazily-generated
path. */
unsigned
-lazy_diagnostic_path::num_events () const
+lazy_path::num_events () const
{
lazily_generate_path ();
return m_inner_path->num_events ();
}
-const diagnostic_event &
-lazy_diagnostic_path::get_event (int idx) const
+const event &
+lazy_path::get_event (int idx) const
{
lazily_generate_path ();
return m_inner_path->get_event (idx);
}
unsigned
-lazy_diagnostic_path::num_threads () const
+lazy_path::num_threads () const
{
lazily_generate_path ();
return m_inner_path->num_threads ();
}
-const diagnostic_thread &
-lazy_diagnostic_path::get_thread (diagnostic_thread_id_t idx) const
+const thread &
+lazy_path::get_thread (thread_id_t idx) const
{
lazily_generate_path ();
return m_inner_path->get_thread (idx);
}
bool
-lazy_diagnostic_path::same_function_p (int event_idx_a,
- int event_idx_b) const
+lazy_path::same_function_p (int event_idx_a,
+ int event_idx_b) const
{
lazily_generate_path ();
return m_inner_path->same_function_p (event_idx_a, event_idx_b);
}
void
-lazy_diagnostic_path::lazily_generate_path () const
+lazy_path::lazily_generate_path () const
{
if (!m_inner_path)
m_inner_path = make_inner_path ();
@@ -85,30 +83,30 @@ lazy_diagnostic_path::lazily_generate_path () const
#if CHECKING_P
+namespace diagnostics {
namespace selftest {
-class test_lazy_path : public lazy_diagnostic_path
+using auto_fix_quotes = ::selftest::auto_fix_quotes;
+
+class test_lazy_path : public lazy_path
{
public:
test_lazy_path (pretty_printer &pp)
- : lazy_diagnostic_path (m_logical_loc_mgr),
+ : lazy_path (m_logical_loc_mgr),
m_pp (pp)
{
}
- std::unique_ptr<diagnostic_path> make_inner_path () const final override
+ std::unique_ptr<path> make_inner_path () const final override
{
- tree fntype_void_void
- = build_function_type_array (void_type_node, 0, nullptr);
- tree fndecl_foo = build_fn_decl ("foo", fntype_void_void);
auto path
- = std::make_unique<simple_diagnostic_path> (m_logical_loc_mgr,
- &m_pp);
- path->add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "first %qs", "free");
- path->add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "double %qs", "free");
+ = std::make_unique<paths::selftest::test_path> (m_logical_loc_mgr,
+ &m_pp);
+ path->add_event (UNKNOWN_LOCATION, "foo", 0, "first %qs", "free");
+ path->add_event (UNKNOWN_LOCATION, "foo", 0, "double %qs", "free");
return path;
}
private:
- const tree_logical_location_manager m_logical_loc_mgr;
+ mutable logical_locations::selftest::test_manager m_logical_loc_mgr;
pretty_printer &m_pp;
};
@@ -127,26 +125,26 @@ test_intraprocedural_path (pretty_printer *event_pp)
"double `free'");
}
-/* Implementation of diagnostic_option_manager for which all
+/* Implementation of diagnostics::option_manager for which all
options are disabled, for use in selftests.
- Note that this is *not* called for diagnostic_option_id (0), which
+ Note that this is *not* called for option_id (0), which
means "always warn" */
-class all_warnings_disabled : public diagnostic_option_manager
+class all_warnings_disabled : public diagnostics::option_manager
{
public:
- int option_enabled_p (diagnostic_option_id) const final override
+ int option_enabled_p (diagnostics::option_id) const final override
{
/* Treat all options as disabled. */
return 0;
}
- char *make_option_name (diagnostic_option_id,
- diagnostic_t,
- diagnostic_t) const final override
+ char *make_option_name (diagnostics::option_id,
+ enum kind,
+ enum kind) const final override
{
return nullptr;
}
- char *make_option_url (diagnostic_option_id) const final override
+ char *make_option_url (diagnostics::option_id) const final override
{
return nullptr;
}
@@ -155,10 +153,10 @@ public:
static void
test_emission (pretty_printer *event_pp)
{
- struct test_rich_location : public gcc_rich_location
+ struct test_rich_location : public rich_location
{
test_rich_location (pretty_printer &event_pp)
- : gcc_rich_location (UNKNOWN_LOCATION),
+ : rich_location (line_table, UNKNOWN_LOCATION),
m_path (event_pp)
{
set_path (&m_path);
@@ -169,16 +167,16 @@ test_emission (pretty_printer *event_pp)
/* Verify that we don't bother generating the inner path if the warning
is skipped. */
{
- test_diagnostic_context dc;
+ test_context dc;
dc.set_option_manager (std::make_unique<all_warnings_disabled> (), 0);
test_rich_location rich_loc (*event_pp);
ASSERT_FALSE (rich_loc.m_path.generated_p ());
- diagnostic_option_id option_id (42); // has to be non-zero
+ diagnostics::option_id opt_id (42); // has to be non-zero
bool emitted
- = dc.emit_diagnostic_with_group (DK_WARNING, rich_loc, nullptr,
- option_id,
+ = dc.emit_diagnostic_with_group (kind::warning, rich_loc, nullptr,
+ opt_id,
"this warning should be skipped");
ASSERT_FALSE (emitted);
ASSERT_FALSE (rich_loc.m_path.generated_p ());
@@ -187,23 +185,23 @@ test_emission (pretty_printer *event_pp)
/* Verify that we *do* generate the inner path for a diagnostic that
is emitted, such as an error. */
{
- test_diagnostic_context dc;
+ test_context dc;
test_rich_location rich_loc (*event_pp);
ASSERT_FALSE (rich_loc.m_path.generated_p ());
bool emitted
- = dc.emit_diagnostic_with_group (DK_ERROR, rich_loc, nullptr, 0,
+ = dc.emit_diagnostic_with_group (kind::error, rich_loc, nullptr, 0,
"this is a test");
ASSERT_TRUE (emitted);
ASSERT_TRUE (rich_loc.m_path.generated_p ());
/* Verify that the path works as expected. */
dc.set_path_format (DPF_INLINE_EVENTS);
- diagnostic_text_output_format sink (dc);
- pp_buffer (sink.get_printer ())->m_flush_p = false;
- sink.print_path (rich_loc.m_path);
- ASSERT_STREQ (pp_formatted_text (sink.get_printer ()),
+ diagnostics::text_sink sink_ (dc);
+ pp_buffer (sink_.get_printer ())->m_flush_p = false;
+ sink_.print_path (rich_loc.m_path);
+ ASSERT_STREQ (pp_formatted_text (sink_.get_printer ()),
" `foo': event 1\n"
" (1): first `free'\n"
" `foo': event 2\n"
@@ -214,7 +212,7 @@ test_emission (pretty_printer *event_pp)
/* Run all of the selftests within this file. */
void
-lazy_diagnostic_path_cc_tests ()
+lazy_paths_cc_tests ()
{
/* In a few places we use the global dc's printer to determine
colorization so ensure this off during the tests. */
@@ -232,6 +230,7 @@ lazy_diagnostic_path_cc_tests ()
pp_show_color (global_pp) = saved_show_color;
}
-} // namespace selftest
+} // namespace diagnostics::selftest
+} // namespace diagnostics
#endif /* #if CHECKING_P */
diff --git a/gcc/lazy-diagnostic-path.h b/gcc/diagnostics/lazy-paths.h
index 9609cab..01b921b 100644
--- a/gcc/lazy-diagnostic-path.h
+++ b/gcc/diagnostics/lazy-paths.h
@@ -18,13 +18,16 @@ 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_LAZY_DIAGNOSTIC_PATH_H
-#define GCC_LAZY_DIAGNOSTIC_PATH_H
+#ifndef GCC_DIAGNOSTICS_LAZY_PATHS_H
+#define GCC_DIAGNOSTICS_LAZY_PATHS_H
-#include "diagnostic-path.h"
+#include "diagnostics/paths.h"
-/* An implementation of diagnostic_path which has a trivial ctor
- and lazily creates another diagnostic_path the first time the path
+namespace diagnostics {
+namespace paths {
+
+/* An implementation of diagnostics::paths::path which has a trivial ctor
+ and lazily creates another path the first time the path
is queried, deferring to this inner path for all queries.
Use this to avoid expensive path creation logic when creating
@@ -32,16 +35,16 @@ along with GCC; see the file COPYING3. If not see
is actually used by a diagnostic, and thus avoided for warnings that
are disabled. */
-class lazy_diagnostic_path : public diagnostic_path
+class lazy_path : public path
{
public:
- virtual ~lazy_diagnostic_path () {}
+ virtual ~lazy_path () {}
unsigned num_events () const final override;
- const diagnostic_event & get_event (int idx) const final override;
+ const event & get_event (int idx) const final override;
unsigned num_threads () const final override;
- const diagnostic_thread &
- get_thread (diagnostic_thread_id_t) const final override;
+ const thread &
+ get_thread (thread_id_t) const final override;
bool
same_function_p (int event_idx_a,
int event_idx_b) const final override;
@@ -49,16 +52,19 @@ class lazy_diagnostic_path : public diagnostic_path
bool generated_p () const { return m_inner_path != nullptr; }
protected:
- lazy_diagnostic_path (const logical_location_manager &logical_loc_mgr)
- : diagnostic_path (logical_loc_mgr)
+ lazy_path (const logical_locations::manager &logical_loc_mgr)
+ : path (logical_loc_mgr)
{
}
private:
void lazily_generate_path () const;
- virtual std::unique_ptr<diagnostic_path> make_inner_path () const = 0;
+ virtual std::unique_ptr<path> make_inner_path () const = 0;
- mutable std::unique_ptr<diagnostic_path> m_inner_path;
+ mutable std::unique_ptr<path> m_inner_path;
};
-#endif /* ! GCC_LAZY_DIAGNOSTIC_PATH_H */
+} // namespace paths
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_LAZY_PATHS_H */
diff --git a/gcc/logical-location.h b/gcc/diagnostics/logical-locations.h
index 3522934..b52a9b4 100644
--- a/gcc/logical-location.h
+++ b/gcc/diagnostics/logical-locations.h
@@ -18,18 +18,21 @@ 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_LOGICAL_LOCATION_H
-#define GCC_LOGICAL_LOCATION_H
+#ifndef GCC_DIAGNOSTICS_LOGICAL_LOCATIONS_H
+#define GCC_DIAGNOSTICS_LOGICAL_LOCATIONS_H
#include "label-text.h"
+namespace diagnostics {
+namespace logical_locations {
+
/* An enum for discriminating between different kinds of logical location
for a diagnostic.
Roughly corresponds to logicalLocation's "kind" property in SARIF v2.1.0
(section 3.33.7). */
-enum class logical_location_kind
+enum class kind
{
unknown,
@@ -68,78 +71,84 @@ enum class logical_location_kind
libgdiagnostics internals), and without requiring heap allocation of an
interface class when emitting a diagnostic.
- To do this, we split the implementation into logical_location, which is
- a wrapper around a (const void *), and logical_location_manager which
+ To do this, we split the implementation into logical_locations::key, which is
+ a wrapper around a (const void *), and logical_locations::manager which
is provided by the client and has vfunc hooks for interpreting
- logical_location instances.
+ key instances.
- Every logical_location is associated with a logical_location_manager and
- only has meaning in relation to that manager.
+ Every logical_locations::key is associated with a logical_locations::manager
+ and only has meaning in relation to that manager.
- A "nullptr" within a logical_location means "no logical location".
+ A "nullptr" within a key means "no logical location".
See tree-logical-location.h for concrete subclasses relating to trees,
where the pointer is a const_tree.
- See selftest-logical-location.h for a concrete subclass for selftests. */
+ See diagnostics/selftest-logical-locations.h for a concrete subclass for
+ selftests. */
-/* Abstract base class for giving meaning to logical_location values.
- Typically there will just be one client-provided instance, of a
- client-specific subclass. */
+/* Extrinsic state for identifying a specific logical location.
+ This will be our logical location type.
+ This only makes sense with respect to a specific manager.
+ e.g. for a tree-based one it's a wrapper around "tree".
+
+ "nullptr" means "no logical location".
+
+ Note that there is no integration with GCC's garbage collector and thus
+ keys can't be long-lived. */
-class logical_location_manager
+class key
{
public:
- /* Extrinsic state for identifying a specific logical location.
- This will be our logical_location type.
- This only makes sense with respect to a specific manager.
- e.g. for a tree-based one it's a wrapper around "tree".
- "nullptr" means "no logical location". */
- class key
+ key () : m_ptr (nullptr) {}
+
+ static key from_ptr (const void *ptr)
{
- public:
- key () : m_ptr (nullptr) {}
+ return key (ptr);
+ }
- static key from_ptr (const void *ptr)
- {
- return key (ptr);
- }
+ operator bool () const
+ {
+ return m_ptr != nullptr;
+ }
- operator bool () const
- {
- return m_ptr != nullptr;
- }
+ template <typename T>
+ T cast_to () const { return static_cast<T> (m_ptr); }
- template <typename T>
- T cast_to () const { return static_cast<T> (m_ptr); }
+ bool
+ operator== (const key &other) const
+ {
+ return m_ptr == other.m_ptr;
+ }
- bool
- operator== (const key &other) const
- {
- return m_ptr == other.m_ptr;
- }
+ bool
+ operator!= (const key &other) const
+ {
+ return m_ptr != other.m_ptr;
+ }
- bool
- operator!= (const key &other) const
- {
- return m_ptr != other.m_ptr;
- }
+ bool
+ operator< (const key &other) const
+ {
+ return m_ptr < other.m_ptr;
+ }
- bool
- operator< (const key &other) const
- {
- return m_ptr < other.m_ptr;
- }
+private:
+ explicit key (const void *ptr) : m_ptr (ptr) {}
- private:
- explicit key (const void *ptr) : m_ptr (ptr) {}
+ const void *m_ptr;
+};
- const void *m_ptr;
- };
+/* Abstract base class for giving meaning to keys.
+ Typically there will just be one client-provided instance, of a
+ client-specific subclass. */
- virtual ~logical_location_manager () {}
+class manager
+{
+public:
+ virtual ~manager () {}
- /* vfuncs for interpreting logical_location values. */
+ /* vfuncs for interpreting keys. */
/* Get a string (or NULL) for K suitable for use by the SARIF logicalLocation
"name" property (SARIF v2.1.0 section 3.33.4). */
@@ -154,7 +163,7 @@ public:
virtual const char *get_internal_name (key k) const = 0;
/* Get what kind of SARIF logicalLocation K is (if any). */
- virtual enum logical_location_kind get_kind (key k) const = 0;
+ virtual enum kind get_kind (key k) const = 0;
/* Get a string for location K in a form suitable for path output. */
virtual label_text get_name_for_path_output (key k) const = 0;
@@ -165,11 +174,7 @@ public:
bool function_p (key k) const;
};
-/* A logical location is a key for a given logical_location_manager.
-
- Note that there is no integration with GCC's garbage collector and thus
- logical_location instances can't be long-lived. */
-
-typedef logical_location_manager::key logical_location;
+} // namespace diagnostics::logical_locations
+} // namespace diagnostics
-#endif /* GCC_LOGICAL_LOCATION_H. */
+#endif /* GCC_DIAGNOSTICS_LOGICAL_LOCATIONS_H. */
diff --git a/gcc/diagnostic-macro-unwinding.cc b/gcc/diagnostics/macro-unwinding.cc
index aa1b816..66bad1c 100644
--- a/gcc/diagnostic-macro-unwinding.cc
+++ b/gcc/diagnostics/macro-unwinding.cc
@@ -22,10 +22,12 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "tree.h"
#include "diagnostic.h"
-#include "diagnostic-macro-unwinding.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/macro-unwinding.h"
+#include "diagnostics/text-sink.h"
#include "intl.h"
+namespace diagnostics {
+
/* This is a pair made of a location and the line map it originated
from. It's used in the maybe_unwind_expanded_macro_loc function
below. */
@@ -73,7 +75,7 @@ struct loc_map_pair
function. */
void
-maybe_unwind_expanded_macro_loc (diagnostic_text_output_format &text_output,
+maybe_unwind_expanded_macro_loc (text_sink &text_output,
location_t where)
{
const struct line_map *map;
@@ -215,8 +217,11 @@ maybe_unwind_expanded_macro_loc (diagnostic_text_output_format &text_output,
that is similar to what is done for function call stacks, or
template instantiation contexts. */
void
-virt_loc_aware_diagnostic_finalizer (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic)
+virt_loc_aware_text_finalizer (text_sink &text_output,
+ const diagnostic_info *diagnostic)
{
- maybe_unwind_expanded_macro_loc (text_output, diagnostic_location (diagnostic));
+ maybe_unwind_expanded_macro_loc (text_output,
+ diagnostic_location (diagnostic));
}
+
+} // namespace diagnostics
diff --git a/gcc/diagnostic-macro-unwinding.h b/gcc/diagnostics/macro-unwinding.h
index ef1e55d..1f28d58 100644
--- a/gcc/diagnostic-macro-unwinding.h
+++ b/gcc/diagnostics/macro-unwinding.h
@@ -17,13 +17,17 @@ 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_DIAGNOSTIC_MACRO_UNWINDING_H
-#define GCC_DIAGNOSTIC_MACRO_UNWINDING_H
+#ifndef GCC_DIAGNOSTICS_MACRO_UNWINDING_H
+#define GCC_DIAGNOSTICS_MACRO_UNWINDING_H
-void virt_loc_aware_diagnostic_finalizer (diagnostic_text_output_format &,
- const diagnostic_info *);
+namespace diagnostics {
-extern void maybe_unwind_expanded_macro_loc (diagnostic_text_output_format &,
+extern void virt_loc_aware_text_finalizer (text_sink &,
+ const diagnostic_info *);
+
+extern void maybe_unwind_expanded_macro_loc (text_sink &,
location_t where);
-#endif /* ! GCC_DIAGNOSTIC_MACRO_UNWINDING_H */
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_MACRO_UNWINDING_H */
diff --git a/gcc/diagnostic-metadata.h b/gcc/diagnostics/metadata.h
index f6ea7dc..c28f982 100644
--- a/gcc/diagnostic-metadata.h
+++ b/gcc/diagnostics/metadata.h
@@ -18,16 +18,15 @@ 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_DIAGNOSTIC_METADATA_H
-#define GCC_DIAGNOSTIC_METADATA_H
+#ifndef GCC_DIAGNOSTICS_METADATA_H
+#define GCC_DIAGNOSTICS_METADATA_H
-class sarif_object;
+#include "lazily-created.h"
namespace diagnostics {
- namespace digraphs {
- class lazy_digraphs;
- } // namespace digraphs
-} // namespace diagnostics
+
+ class sarif_object;
+ namespace digraphs { class digraph; }
/* A bundle of additional metadata that can be associated with a
diagnostic.
@@ -38,9 +37,12 @@ namespace diagnostics {
Additionally, this provides a place to associate a diagnostic
with zero or more directed graphs. */
-class diagnostic_metadata
+class metadata
{
public:
+ using lazy_digraphs
+ = lazily_created<std::vector<std::unique_ptr<digraphs::digraph>>>;
+
/* Abstract base class for referencing a rule that has been violated,
such as within a coding standard, or within a specification. */
class rule
@@ -73,8 +75,8 @@ class diagnostic_metadata
const char *m_url;
};
- diagnostic_metadata () : m_cwe (0), m_lazy_digraphs (nullptr) {}
- virtual ~diagnostic_metadata () {}
+ metadata () : m_cwe (0), m_lazy_digraphs (nullptr) {}
+ virtual ~metadata () {}
/* Hook for SARIF output to allow for adding diagnostic-specific
properties to the result object's property bag. */
@@ -97,12 +99,12 @@ class diagnostic_metadata
const rule &get_rule (unsigned idx) const { return *(m_rules[idx]); }
void
- set_lazy_digraphs (const diagnostics::digraphs::lazy_digraphs *lazy_digraphs)
+ set_lazy_digraphs (const lazy_digraphs *lazy_digraphs_)
{
- m_lazy_digraphs = lazy_digraphs;
+ m_lazy_digraphs = lazy_digraphs_;
}
- const diagnostics::digraphs::lazy_digraphs *
+ const lazy_digraphs *
get_lazy_digraphs () const
{
return m_lazy_digraphs;
@@ -114,7 +116,9 @@ class diagnostic_metadata
/* An optional way to create directed graphs associated with the
diagnostic, for the sinks that support this (e.g. SARIF). */
- const diagnostics::digraphs::lazy_digraphs *m_lazy_digraphs;
+ const lazy_digraphs *m_lazy_digraphs;
};
-#endif /* ! GCC_DIAGNOSTIC_METADATA_H */
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_METADATA_H */
diff --git a/gcc/diagnostics/option-classifier.cc b/gcc/diagnostics/option-classifier.cc
new file mode 100644
index 0000000..f98fd55
--- /dev/null
+++ b/gcc/diagnostics/option-classifier.cc
@@ -0,0 +1,222 @@
+/* Stacks of set of classifications of diagnostics.
+ Copyright (C) 1999-2025 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"
+#include "system.h"
+#include "coretypes.h"
+#include "version.h"
+#include "diagnostic.h"
+
+namespace diagnostics {
+
+void
+option_classifier::init (int n_opts)
+{
+ m_n_opts = n_opts;
+ m_classify_diagnostic = XNEWVEC (enum kind, n_opts);
+ for (int i = 0; i < n_opts; i++)
+ m_classify_diagnostic[i] = kind::unspecified;
+ m_push_list = vNULL;
+ m_classification_history = vNULL;
+}
+
+void
+option_classifier::fini ()
+{
+ XDELETEVEC (m_classify_diagnostic);
+ m_classify_diagnostic = nullptr;
+ m_classification_history.release ();
+ m_push_list.release ();
+}
+
+/* Save the diagnostics::option_classifier state to F for PCH
+ output. Returns 0 on success, -1 on error. */
+
+int
+option_classifier::pch_save (FILE *f)
+{
+ unsigned int lengths[2] = { m_classification_history.length (),
+ m_push_list.length () };
+ if (fwrite (lengths, sizeof (lengths), 1, f) != 1
+ || (lengths[0]
+ && fwrite (m_classification_history.address (),
+ sizeof (classification_change_t),
+ lengths[0], f) != lengths[0])
+ || (lengths[1]
+ && fwrite (m_push_list.address (), sizeof (int),
+ lengths[1], f) != lengths[1]))
+ return -1;
+ return 0;
+}
+
+/* Read the diagnostics::option_classifier state from F for PCH
+ read. Returns 0 on success, -1 on error. */
+
+int
+option_classifier::pch_restore (FILE *f)
+{
+ unsigned int lengths[2];
+ if (fread (lengths, sizeof (lengths), 1, f) != 1)
+ return -1;
+ gcc_checking_assert (m_classification_history.is_empty ());
+ gcc_checking_assert (m_push_list.is_empty ());
+ m_classification_history.safe_grow (lengths[0]);
+ m_push_list.safe_grow (lengths[1]);
+ if ((lengths[0]
+ && fread (m_classification_history.address (),
+ sizeof (classification_change_t),
+ lengths[0], f) != lengths[0])
+ || (lengths[1]
+ && fread (m_push_list.address (), sizeof (int),
+ lengths[1], f) != lengths[1]))
+ return -1;
+ return 0;
+}
+
+/* Save all diagnostic classifications in a stack. */
+
+void
+option_classifier::push ()
+{
+ m_push_list.safe_push (m_classification_history.length ());
+}
+
+/* Restore the topmost classification set off the stack. If the stack
+ is empty, revert to the state based on command line parameters. */
+
+void
+option_classifier::pop (location_t where)
+{
+ int jump_to;
+
+ if (!m_push_list.is_empty ())
+ jump_to = m_push_list.pop ();
+ else
+ jump_to = 0;
+
+ classification_change_t v = { where, jump_to, kind::pop };
+ m_classification_history.safe_push (v);
+}
+
+/* Interface to specify diagnostic kind overrides. Returns the
+ previous setting, or kind::unspecified if the parameters are out of
+ range. If OPTION_ID is zero, the new setting is for all the
+ diagnostics. */
+
+enum kind
+option_classifier::classify_diagnostic (const context *dc,
+ option_id opt_id,
+ enum kind new_kind,
+ location_t where)
+{
+ enum kind old_kind;
+
+ if (opt_id.m_idx < 0
+ || opt_id.m_idx >= m_n_opts
+ || new_kind >= kind::last_diagnostic_kind)
+ return kind::unspecified;
+
+ old_kind = m_classify_diagnostic[opt_id.m_idx];
+
+ /* Handle pragmas separately, since we need to keep track of *where*
+ the pragmas were. */
+ if (where != UNKNOWN_LOCATION)
+ {
+ unsigned i;
+
+ /* Record the command-line status, so we can reset it back on kind::pop. */
+ if (old_kind == kind::unspecified)
+ {
+ old_kind = (!dc->option_enabled_p (opt_id)
+ ? kind::ignored : kind::any);
+ m_classify_diagnostic[opt_id.m_idx] = old_kind;
+ }
+
+ classification_change_t *p;
+ FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
+ if (p->option == opt_id.m_idx)
+ {
+ old_kind = p->kind;
+ break;
+ }
+
+ classification_change_t v
+ = { where, opt_id.m_idx, new_kind };
+ m_classification_history.safe_push (v);
+ }
+ else
+ m_classify_diagnostic[opt_id.m_idx] = new_kind;
+
+ return old_kind;
+}
+
+/* Update the kind of DIAGNOSTIC based on its location(s), including
+ any of those in its inlining stack, relative to any
+ #pragma GCC diagnostic
+ directives recorded within this object.
+
+ Return the new kind of DIAGNOSTIC if it was updated, or kind::unspecified
+ otherwise. */
+
+enum kind
+option_classifier::
+update_effective_level_from_pragmas (diagnostic_info *diagnostic) const
+{
+ if (m_classification_history.is_empty ())
+ return kind::unspecified;
+
+ /* Iterate over the locations, checking the diagnostic disposition
+ for the diagnostic at each. If it's explicitly set as opposed
+ to unspecified, update the disposition for this instance of
+ the diagnostic and return it. */
+ for (location_t loc: diagnostic->m_iinfo.m_ilocs)
+ {
+ /* FIXME: Stupid search. Optimize later. */
+ unsigned int i;
+ classification_change_t *p;
+ FOR_EACH_VEC_ELT_REVERSE (m_classification_history, i, p)
+ {
+ location_t pragloc = p->location;
+ if (!linemap_location_before_p (line_table, pragloc, loc))
+ continue;
+
+ if (p->kind == kind::pop)
+ {
+ /* Move on to the next region. */
+ i = p->option;
+ continue;
+ }
+
+ option_id opt_id = p->option;
+ /* The option 0 is for all the diagnostics. */
+ if (opt_id == 0 || opt_id == diagnostic->m_option_id)
+ {
+ enum kind kind = p->kind;
+ if (kind != diagnostics::kind::unspecified)
+ diagnostic->m_kind = kind;
+ return kind;
+ }
+ }
+ }
+
+ return kind::unspecified;
+}
+
+} // namespace diagnostics
diff --git a/gcc/diagnostics/option-classifier.h b/gcc/diagnostics/option-classifier.h
new file mode 100644
index 0000000..3b16c74
--- /dev/null
+++ b/gcc/diagnostics/option-classifier.h
@@ -0,0 +1,110 @@
+/* Stacks of set of classifications of diagnostics.
+ Copyright (C) 2000-2025 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/>. */
+
+#ifndef GCC_DIAGNOSTICS_OPTION_CLASSIFIER_H
+#define GCC_DIAGNOSTICS_OPTION_CLASSIFIER_H
+
+namespace diagnostics {
+
+/* Forward declarations. */
+class context;
+
+/* A stack of sets of classifications: each entry in the stack is
+ a mapping from option index to diagnostic severity that can be changed
+ via pragmas. The stack can be pushed and popped. */
+
+class option_classifier
+{
+public:
+ void init (int n_opts);
+ void fini ();
+
+ /* Save all diagnostic classifications in a stack. */
+ void push ();
+
+ /* Restore the topmost classification set off the stack. If the stack
+ is empty, revert to the state based on command line parameters. */
+ void pop (location_t where);
+
+ bool option_unspecified_p (option_id opt_id) const
+ {
+ return get_current_override (opt_id) == kind::unspecified;
+ }
+
+ enum kind get_current_override (option_id opt_id) const
+ {
+ gcc_assert (opt_id.m_idx < m_n_opts);
+ return m_classify_diagnostic[opt_id.m_idx];
+ }
+
+ enum kind
+ classify_diagnostic (const context *context,
+ option_id opt_id,
+ enum kind new_kind,
+ location_t where);
+
+ enum kind
+ update_effective_level_from_pragmas (diagnostic_info *diagnostic) const;
+
+ int pch_save (FILE *);
+ int pch_restore (FILE *);
+
+private:
+ /* Each time a diagnostic's classification is changed with a pragma,
+ we record the change and the location of the change in an array of
+ these structs. */
+ struct classification_change_t
+ {
+ location_t location;
+
+ /* For kind::pop, this is the index of the corresponding push (as stored
+ in m_push_list).
+ Otherwise, this is an option index. */
+ int option;
+
+ enum kind kind;
+ };
+
+ int m_n_opts;
+
+ /* For each option index that can be passed to warning() et al
+ (OPT_* from options.h when using this code with the core GCC
+ options), this array may contain a new kind that the diagnostic
+ should be changed to before reporting, or kind::unspecified to leave
+ it as the reported kind, or kind::ignored to not report it at
+ all. */
+ enum kind *m_classify_diagnostic;
+
+ /* History of all changes to the classifications above. This list
+ is stored in location-order, so we can search it, either
+ binary-wise or end-to-front, to find the most recent
+ classification for a given diagnostic, given the location of the
+ diagnostic. */
+ vec<classification_change_t> m_classification_history;
+
+ /* For context::get_classification_history, declared later. */
+ friend class context;
+
+ /* For pragma push/pop. */
+ vec<int> m_push_list;
+};
+
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_OPTION_CLASSIFIER_H */
diff --git a/gcc/diagnostics/option-id.h b/gcc/diagnostics/option-id.h
new file mode 100644
index 0000000..4132775
--- /dev/null
+++ b/gcc/diagnostics/option-id.h
@@ -0,0 +1,49 @@
+/* Declaration of struct diagnostics::option_id.
+ Copyright (C) 2024-2025 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_DIAGNOSTICS_OPTION_ID_H
+#define GCC_DIAGNOSTICS_OPTION_ID_H
+
+namespace diagnostics {
+
+/* A class to use for the ID of an option that controls
+ a particular diagnostic.
+ This is just a wrapper around "int", but better documents
+ the intent of the code. */
+
+struct option_id
+{
+ option_id () : m_idx (0) {}
+
+ option_id (int idx) : m_idx (idx) {}
+ /* Ideally we'd take an enum opt_code here, but we don't
+ want to depend on its decl. */
+
+ bool operator== (option_id other) const
+ {
+ return m_idx == other.m_idx;
+ }
+
+ int m_idx;
+};
+
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_OPTION_ID_H */
diff --git a/gcc/diagnostic-output-file.h b/gcc/diagnostics/output-file.h
index a0b2e1b..f936387 100644
--- a/gcc/diagnostic-output-file.h
+++ b/gcc/diagnostics/output-file.h
@@ -18,22 +18,24 @@ 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_DIAGNOSTIC_OUTPUT_FILE_H
-#define GCC_DIAGNOSTIC_OUTPUT_FILE_H
+#ifndef GCC_DIAGNOSTICS_OUTPUT_FILE_H
+#define GCC_DIAGNOSTICS_OUTPUT_FILE_H
+
+namespace diagnostics {
/* RAII class for wrapping a FILE * that could be borrowed or owned,
along with the underlying filename. */
-class diagnostic_output_file
+class output_file
{
public:
- diagnostic_output_file ()
+ output_file ()
: m_outf (nullptr),
m_owned (false),
m_filename ()
{
}
- diagnostic_output_file (FILE *outf, bool owned, label_text filename)
+ output_file (FILE *outf, bool owned, label_text filename)
: m_outf (outf),
m_owned (owned),
m_filename (std::move (filename))
@@ -42,7 +44,7 @@ public:
if (m_owned)
gcc_assert (m_outf);
}
- ~diagnostic_output_file ()
+ ~output_file ()
{
if (m_owned)
{
@@ -50,8 +52,8 @@ public:
fclose (m_outf);
}
}
- diagnostic_output_file (const diagnostic_output_file &other) = delete;
- diagnostic_output_file (diagnostic_output_file &&other)
+ output_file (const output_file &other) = delete;
+ output_file (output_file &&other)
: m_outf (other.m_outf),
m_owned (other.m_owned),
m_filename (std::move (other.m_filename))
@@ -63,10 +65,10 @@ public:
if (m_owned)
gcc_assert (m_outf);
}
- diagnostic_output_file &
- operator= (const diagnostic_output_file &other) = delete;
- diagnostic_output_file &
- operator= (diagnostic_output_file &&other)
+ output_file &
+ operator= (const output_file &other) = delete;
+ output_file &
+ operator= (output_file &&other)
{
if (m_owned)
{
@@ -91,8 +93,8 @@ public:
FILE *get_open_file () const { return m_outf; }
const char *get_filename () const { return m_filename.get (); }
- static diagnostic_output_file
- try_to_open (diagnostic_context &context,
+ static output_file
+ try_to_open (context &dc,
line_maps *line_maps,
const char *base_file_name,
const char *extension,
@@ -104,4 +106,6 @@ private:
label_text m_filename;
};
-#endif /* ! GCC_DIAGNOSTIC_OUTPUT_FILE_H */
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_OUTPUT_FILE_H */
diff --git a/gcc/diagnostic-output-spec.cc b/gcc/diagnostics/output-spec.cc
index 4fa3176..08128a9 100644
--- a/gcc/diagnostic-output-spec.cc
+++ b/gcc/diagnostics/output-spec.cc
@@ -32,20 +32,21 @@ along with GCC; see the file COPYING3. If not see
#include "version.h"
#include "intl.h"
#include "diagnostic.h"
-#include "diagnostic-color.h"
-#include "diagnostic-format.h"
-#include "diagnostic-format-html.h"
-#include "diagnostic-format-text.h"
-#include "diagnostic-format-sarif.h"
+#include "diagnostics/color.h"
+#include "diagnostics/sink.h"
+#include "diagnostics/html-sink.h"
+#include "diagnostics/text-sink.h"
+#include "diagnostics/sarif-sink.h"
#include "selftest.h"
-#include "selftest-diagnostic.h"
+#include "diagnostics/selftest-context.h"
#include "pretty-print-markup.h"
-#include "diagnostic-output-spec.h"
+#include "diagnostics/output-spec.h"
/* A namespace for handling the DSL of the arguments of
-fdiagnostics-add-output= and -fdiagnostics-set-output=. */
-namespace diagnostics_output_spec {
+namespace diagnostics {
+namespace output_spec {
/* Decls. */
@@ -56,7 +57,7 @@ struct scheme_name_and_params
};
/* Class for parsing the arguments of -fdiagnostics-add-output= and
- -fdiagnostics-set-output=, and making diagnostic_output_format
+ -fdiagnostics-set-output=, and making sink
instances (or issuing errors). */
class output_factory
@@ -72,9 +73,9 @@ public:
const std::string &get_scheme_name () const { return m_scheme_name; }
- virtual std::unique_ptr<diagnostic_output_format>
+ virtual std::unique_ptr<sink>
make_sink (const context &ctxt,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *unparsed_arg,
const scheme_name_and_params &parsed_arg) const = 0;
@@ -145,9 +146,9 @@ public:
output_factory ();
- std::unique_ptr<diagnostic_output_format>
+ std::unique_ptr<sink>
make_sink (const context &ctxt,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *unparsed_arg,
const scheme_name_and_params &parsed_arg);
@@ -162,9 +163,9 @@ class text_scheme_handler : public output_factory::scheme_handler
public:
text_scheme_handler () : scheme_handler ("text") {}
- std::unique_ptr<diagnostic_output_format>
+ std::unique_ptr<sink>
make_sink (const context &ctxt,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *unparsed_arg,
const scheme_name_and_params &parsed_arg) const final override;
};
@@ -174,9 +175,9 @@ class sarif_scheme_handler : public output_factory::scheme_handler
public:
sarif_scheme_handler () : scheme_handler ("sarif") {}
- std::unique_ptr<diagnostic_output_format>
+ std::unique_ptr<sink>
make_sink (const context &ctxt,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *unparsed_arg,
const scheme_name_and_params &parsed_arg) const final override;
@@ -194,9 +195,9 @@ class html_scheme_handler : public output_factory::scheme_handler
public:
html_scheme_handler () : scheme_handler ("experimental-html") {}
- std::unique_ptr<diagnostic_output_format>
+ std::unique_ptr<sink>
make_sink (const context &ctxt,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *unparsed_arg,
const scheme_name_and_params &parsed_arg) const final override;
};
@@ -241,16 +242,16 @@ context::report_missing_key (const char *unparsed_arg,
get_option_name (), scheme_name.c_str (), key.c_str (), metavar);
}
-diagnostic_output_file
+output_file
context::open_output_file (label_text &&filename) const
{
FILE *outf = fopen (filename.get (), "w");
if (!outf)
{
report_error ("unable to open %qs: %m", filename.get ());
- return diagnostic_output_file (nullptr, false, std::move (filename));
+ return output_file (nullptr, false, std::move (filename));
}
- return diagnostic_output_file (outf, true, std::move (filename));
+ return output_file (outf, true, std::move (filename));
}
static std::unique_ptr<scheme_name_and_params>
@@ -303,15 +304,15 @@ parse (const context &ctxt, const char *unparsed_arg)
return std::make_unique<scheme_name_and_params> (std::move (result));
}
-std::unique_ptr<diagnostic_output_format>
+std::unique_ptr<sink>
context::parse_and_make_sink (const char *unparsed_arg,
- diagnostic_context &dc)
+ diagnostics::context &dc)
{
- auto parsed_arg = diagnostics_output_spec::parse (*this, unparsed_arg);
+ auto parsed_arg = parse (*this, unparsed_arg);
if (!parsed_arg)
return nullptr;
- diagnostics_output_spec::output_factory factory;
+ output_factory factory;
return factory.make_sink (*this, dc, unparsed_arg, *parsed_arg);
}
@@ -335,9 +336,9 @@ output_factory::get_scheme_handler (const std::string &scheme_name)
return nullptr;
}
-std::unique_ptr<diagnostic_output_format>
+std::unique_ptr<sink>
output_factory::make_sink (const context &ctxt,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *unparsed_arg,
const scheme_name_and_params &parsed_arg)
{
@@ -360,9 +361,9 @@ output_factory::make_sink (const context &ctxt,
/* class text_scheme_handler : public output_factory::scheme_handler. */
-std::unique_ptr<diagnostic_output_format>
+std::unique_ptr<sink>
text_scheme_handler::make_sink (const context &ctxt,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *unparsed_arg,
const scheme_name_and_params &parsed_arg) const
{
@@ -412,7 +413,7 @@ text_scheme_handler::make_sink (const context &ctxt,
return nullptr;
}
- auto sink = std::make_unique<diagnostic_text_output_format> (dc);
+ auto sink = std::make_unique<diagnostics::text_sink> (dc);
sink->set_show_nesting (show_nesting);
sink->set_show_locations_in_nesting (show_locations_in_nesting);
sink->set_show_nesting_levels (show_levels);
@@ -421,9 +422,9 @@ text_scheme_handler::make_sink (const context &ctxt,
/* class sarif_scheme_handler : public output_factory::scheme_handler. */
-std::unique_ptr<diagnostic_output_format>
+std::unique_ptr<sink>
sarif_scheme_handler::make_sink (const context &ctxt,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *unparsed_arg,
const scheme_name_and_params &parsed_arg) const
{
@@ -488,9 +489,9 @@ sarif_scheme_handler::make_sink (const context &ctxt,
return nullptr;
}
- diagnostic_output_file output_file;
+ output_file output_file_;
if (filename.get ())
- output_file = ctxt.open_output_file (std::move (filename));
+ output_file_ = ctxt.open_output_file (std::move (filename));
else
// Default filename
{
@@ -503,14 +504,13 @@ sarif_scheme_handler::make_sink (const context &ctxt,
"FILENAME");
return nullptr;
}
- output_file
- = diagnostic_output_format_open_sarif_file
- (dc,
- ctxt.get_affected_location_mgr (),
- basename,
- serialization_kind);
+ output_file_
+ = open_sarif_output_file (dc,
+ ctxt.get_affected_location_mgr (),
+ basename,
+ serialization_kind);
}
- if (!output_file)
+ if (!output_file_)
return nullptr;
auto sarif_gen_opts = make_sarif_gen_opts (version, state_graph);
@@ -521,7 +521,7 @@ sarif_scheme_handler::make_sink (const context &ctxt,
*ctxt.get_affected_location_mgr (),
std::move (serialization_obj),
sarif_gen_opts,
- std::move (output_file));
+ std::move (output_file_));
return sink;
}
@@ -551,9 +551,9 @@ make_sarif_serialization_object (enum sarif_serialization_kind kind)
/* class html_scheme_handler : public output_factory::scheme_handler. */
-std::unique_ptr<diagnostic_output_format>
+std::unique_ptr<sink>
html_scheme_handler::make_sink (const context &ctxt,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *unparsed_arg,
const scheme_name_and_params &parsed_arg) const
{
@@ -621,9 +621,9 @@ html_scheme_handler::make_sink (const context &ctxt,
return nullptr;
}
- diagnostic_output_file output_file;
+ output_file output_file_;
if (filename.get ())
- output_file = ctxt.open_output_file (std::move (filename));
+ output_file_ = ctxt.open_output_file (std::move (filename));
else
// Default filename
{
@@ -636,13 +636,13 @@ html_scheme_handler::make_sink (const context &ctxt,
"FILENAME");
return nullptr;
}
- output_file
- = diagnostic_output_format_open_html_file
+ output_file_
+ = open_html_output_file
(dc,
ctxt.get_affected_location_mgr (),
basename);
}
- if (!output_file)
+ if (!output_file_)
return nullptr;
html_generation_options html_gen_opts;
@@ -655,16 +655,18 @@ html_scheme_handler::make_sink (const context &ctxt,
auto sink = make_html_sink (dc,
*ctxt.get_affected_location_mgr (),
html_gen_opts,
- std::move (output_file));
+ std::move (output_file_));
return sink;
}
-} // namespace diagnostics_output_spec
+} // namespace output_spec
#if CHECKING_P
namespace selftest {
+using auto_fix_quotes = ::selftest::auto_fix_quotes;
+
/* RAII class to temporarily override "progname" to the
string "PROGNAME". */
@@ -688,18 +690,18 @@ private:
struct parser_test
{
- class test_spec_context : public diagnostics_output_spec::gcc_spec_context
+ class test_spec_context : public diagnostics::output_spec::dc_spec_context
{
public:
- test_spec_context (diagnostic_context &dc,
+ test_spec_context (diagnostics::context &dc,
line_maps *location_mgr,
location_t loc,
const char *option_name)
- : gcc_spec_context (dc,
- location_mgr,
- location_mgr,
- loc,
- option_name)
+ : dc_spec_context (dc,
+ location_mgr,
+ location_mgr,
+ loc,
+ option_name)
{
}
@@ -713,15 +715,15 @@ struct parser_test
parser_test ()
: m_dc (),
m_ctxt (m_dc, line_table, UNKNOWN_LOCATION, "-fOPTION="),
- m_fmt (m_dc.get_output_format (0))
+ m_fmt (m_dc.get_sink (0))
{
pp_buffer (m_fmt.get_printer ())->m_flush_p = false;
}
- std::unique_ptr<diagnostics_output_spec::scheme_name_and_params>
+ std::unique_ptr<diagnostics::output_spec::scheme_name_and_params>
parse (const char *unparsed_arg)
{
- return diagnostics_output_spec::parse (m_ctxt, unparsed_arg);
+ return diagnostics::output_spec::parse (m_ctxt, unparsed_arg);
}
bool execution_failed_p () const
@@ -736,9 +738,9 @@ struct parser_test
}
private:
- test_diagnostic_context m_dc;
+ diagnostics::selftest::test_context m_dc;
test_spec_context m_ctxt;
- diagnostic_output_format &m_fmt;
+ diagnostics::sink &m_fmt;
};
/* Selftests. */
@@ -838,12 +840,12 @@ test_output_arg_parsing ()
/* Run all of the selftests within this file. */
void
-diagnostic_output_spec_cc_tests ()
+output_spec_cc_tests ()
{
test_output_arg_parsing ();
}
-} // namespace selftest
-
+} // namespace diagnostics::selftest
+} // namespace diagnostics
#endif /* #if CHECKING_P */
diff --git a/gcc/diagnostic-output-spec.h b/gcc/diagnostics/output-spec.h
index e02cdfe..c84d237 100644
--- a/gcc/diagnostic-output-spec.h
+++ b/gcc/diagnostics/output-spec.h
@@ -18,13 +18,14 @@ 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_DIAGNOSTIC_OUTPUT_SPEC_H
-#define GCC_DIAGNOSTIC_OUTPUT_SPEC_H
+#ifndef GCC_DIAGNOSTICS_OUTPUT_SPEC_H
+#define GCC_DIAGNOSTICS_OUTPUT_SPEC_H
-#include "diagnostic-format.h"
-#include "diagnostic-output-file.h"
+#include "diagnostics/sink.h"
+#include "diagnostics/output-file.h"
-namespace diagnostics_output_spec {
+namespace diagnostics {
+namespace output_spec {
/* An abstract base class for handling the DSL of -fdiagnostics-add-output=
and -fdiagnostics-set-output=. */
@@ -32,9 +33,9 @@ namespace diagnostics_output_spec {
class context
{
public:
- std::unique_ptr<diagnostic_output_format>
+ std::unique_ptr<sink>
parse_and_make_sink (const char *,
- diagnostic_context &dc);
+ diagnostics::context &dc);
void
report_error (const char *gmsgid, ...) const
@@ -52,7 +53,7 @@ class context
const std::string &scheme_name,
const char *metavar) const;
- diagnostic_output_file
+ output_file
open_output_file (label_text &&filename) const;
const char *
@@ -81,16 +82,16 @@ protected:
line_maps *m_affected_location_mgr;
};
-/* A subclass that implements reporting errors via a diagnostic_context. */
+/* A subclass that implements reporting errors via a diagnostics::context. */
-struct gcc_spec_context : public diagnostics_output_spec::context
+struct dc_spec_context : public output_spec::context
{
public:
- gcc_spec_context (diagnostic_context &dc,
- line_maps *affected_location_mgr,
- line_maps *control_location_mgr,
- location_t loc,
- const char *option_name)
+ dc_spec_context (diagnostics::context &dc,
+ line_maps *affected_location_mgr,
+ line_maps *control_location_mgr,
+ location_t loc,
+ const char *option_name)
: context (option_name, affected_location_mgr),
m_dc (dc),
m_control_location_mgr (control_location_mgr),
@@ -102,15 +103,16 @@ public:
{
m_dc.begin_group ();
rich_location richloc (m_control_location_mgr, m_loc);
- m_dc.diagnostic_impl (&richloc, nullptr, -1, gmsgid, ap, DK_ERROR);
+ m_dc.diagnostic_impl (&richloc, nullptr, -1, gmsgid, ap, kind::error);
m_dc.end_group ();
}
- diagnostic_context &m_dc;
+ diagnostics::context &m_dc;
line_maps *m_control_location_mgr;
location_t m_loc;
};
-} // namespace diagnostics_output_spec
+} // namespace output_spec
+} // namespace diagnostics
-#endif
+#endif // #ifndef GCC_DIAGNOSTICS_OUTPUT_SPEC_H
diff --git a/gcc/diagnostic-path-output.cc b/gcc/diagnostics/paths-output.cc
index 439fd33..a3ac9a0 100644
--- a/gcc/diagnostic-path-output.cc
+++ b/gcc/diagnostics/paths-output.cc
@@ -26,20 +26,20 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
-#include "diagnostic-macro-unwinding.h"
+#include "diagnostics/macro-unwinding.h"
#include "intl.h"
-#include "diagnostic-path.h"
+#include "diagnostics/paths.h"
#include "gcc-rich-location.h"
-#include "diagnostic-color.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-label-effects.h"
+#include "diagnostics/color.h"
+#include "diagnostics/event-id.h"
+#include "diagnostics/source-printing-effects.h"
#include "pretty-print-markup.h"
#include "selftest.h"
-#include "selftest-diagnostic.h"
-#include "selftest-diagnostic-path.h"
+#include "diagnostics/selftest-context.h"
+#include "diagnostics/selftest-paths.h"
#include "text-art/theme.h"
-#include "diagnostic-format-text.h"
-#include "diagnostic-format-html.h"
+#include "diagnostics/text-sink.h"
+#include "diagnostics/html-sink.h"
#include "xml.h"
#include "xml-printer.h"
@@ -54,17 +54,20 @@ along with GCC; see the file COPYING3. If not see
namespace {
+using namespace diagnostics;
+using namespace diagnostics::paths;
+
/* A bundle of state for printing a path. */
class path_print_policy
{
public:
- path_print_policy (const diagnostic_text_output_format &text_output)
+ path_print_policy (const diagnostics::text_sink &text_output)
: m_source_policy (text_output.get_context ())
{
}
- path_print_policy (const diagnostic_context &dc)
+ path_print_policy (const diagnostics::context &dc)
: m_source_policy (dc)
{
}
@@ -75,26 +78,26 @@ public:
return m_source_policy.get_diagram_theme ();
}
- const diagnostic_source_print_policy &
+ const diagnostics::source_print_policy &
get_source_policy () const { return m_source_policy; }
private:
- diagnostic_source_print_policy m_source_policy;
+ diagnostics::source_print_policy m_source_policy;
};
/* Subclass of range_label for showing a particular event
- when showing a consecutive run of events within a diagnostic_path as
+ when showing a consecutive run of events within a diagnostic path as
labelled ranges within one gcc_rich_location. */
class path_label : public range_label
{
public:
- path_label (const diagnostic_path &path,
+ path_label (const path &path_,
const pretty_printer &ref_pp,
unsigned start_idx,
bool colorize,
bool allow_emojis)
- : m_path (path),
+ : m_path (path_),
m_ref_pp (ref_pp),
m_start_idx (start_idx), m_effects (*this),
m_colorize (colorize), m_allow_emojis (allow_emojis)
@@ -103,18 +106,17 @@ class path_label : public range_label
label_text get_text (unsigned range_idx) const final override
{
unsigned event_idx = m_start_idx + range_idx;
- const diagnostic_event &event = m_path.get_event (event_idx);
+ const event &ev = m_path.get_event (event_idx);
- const diagnostic_event::meaning meaning (event.get_meaning ());
+ const event::meaning meaning (ev.get_meaning ());
auto pp = m_ref_pp.clone ();
pp_show_color (pp.get ()) = m_colorize;
- diagnostic_event_id_t event_id (event_idx);
-
+ event_id_t event_id (event_idx);
pp_printf (pp.get (), "%@", &event_id);
pp_space (pp.get ());
- if (meaning.m_verb == diagnostic_event::verb::danger
+ if (meaning.m_verb == event::verb::danger
&& m_allow_emojis)
{
pp_unicode_character (pp.get (), 0x26A0); /* U+26A0 WARNING SIGN. */
@@ -128,14 +130,15 @@ class path_label : public range_label
pp_string (pp.get (), " ");
}
- event.print_desc (*pp.get ());
+ ev.print_desc (*pp.get ());
label_text result
= label_text::take (xstrdup (pp_formatted_text (pp.get ())));
return result;
}
- const label_effects *get_effects (unsigned /*range_idx*/) const final override
+ const diagnostics::label_effects *
+ get_effects (unsigned /*range_idx*/) const final override
{
return &m_effects;
}
@@ -150,28 +153,28 @@ class path_label : public range_label
}
bool has_in_edge (unsigned range_idx) const final override
{
- if (const diagnostic_event *prev_event
+ if (const event *prev_event
= m_path_label.get_prev_event (range_idx))
return prev_event->connect_to_next_event_p ();
return false;
}
bool has_out_edge (unsigned range_idx) const final override
{
- const diagnostic_event &event = m_path_label.get_event (range_idx);
- return event.connect_to_next_event_p ();
+ const event &ev = m_path_label.get_event (range_idx);
+ return ev.connect_to_next_event_p ();
}
private:
const path_label &m_path_label;
};
- const diagnostic_event &get_event (unsigned range_idx) const
+ const event &get_event (unsigned range_idx) const
{
unsigned event_idx = m_start_idx + range_idx;
return m_path.get_event (event_idx);
}
- const diagnostic_event *get_prev_event (unsigned range_idx) const
+ const event *get_prev_event (unsigned range_idx) const
{
if (m_start_idx + range_idx == 0)
return nullptr;
@@ -179,7 +182,7 @@ class path_label : public range_label
return &m_path.get_event (event_idx);
}
- const diagnostic_path &m_path;
+ const path &m_path;
const pretty_printer &m_ref_pp;
unsigned m_start_idx;
path_label_effects m_effects;
@@ -188,20 +191,20 @@ class path_label : public range_label
};
/* Return true if E1 and E2 can be consolidated into the same run of events
- when printing a diagnostic_path. */
+ when printing a diagnostic path. */
static bool
-can_consolidate_events (const diagnostic_path &path,
- const diagnostic_event &e1,
+can_consolidate_events (const path &p,
+ const event &e1,
unsigned ev1_idx,
- const diagnostic_event &e2,
+ const event &e2,
unsigned ev2_idx,
bool check_locations)
{
if (e1.get_thread_id () != e2.get_thread_id ())
return false;
- if (!path.same_function_p (ev1_idx, ev2_idx))
+ if (!p.same_function_p (ev1_idx, ev2_idx))
return false;
if (e1.get_stack_depth () != e2.get_stack_depth ())
@@ -231,16 +234,16 @@ struct event_range;
struct path_summary;
class thread_event_printer;
-/* A bundle of information about all of the events in a diagnostic_path
+/* A bundle of information about all of the events in a diagnostic path
relating to a specific path, for use by path_summary. */
class per_thread_summary
{
public:
- per_thread_summary (const diagnostic_path &path,
- const logical_location_manager &logical_loc_mgr,
+ per_thread_summary (const path &path_,
+ const logical_locations::manager &logical_loc_mgr,
label_text name, unsigned swimlane_idx)
- : m_path (path),
+ : m_path (path_),
m_logical_loc_mgr (logical_loc_mgr),
m_name (std::move (name)),
m_swimlane_idx (swimlane_idx),
@@ -267,8 +270,8 @@ private:
friend class thread_event_printer;
friend struct event_range;
- const diagnostic_path &m_path;
- const logical_location_manager &m_logical_loc_mgr;
+ const path &m_path;
+ const logical_locations::manager &m_logical_loc_mgr;
const label_text m_name;
@@ -279,7 +282,7 @@ private:
// The event ranges specific to this thread:
auto_vec<event_range *> m_event_ranges;
- const diagnostic_event *m_last_event;
+ const event *m_last_event;
int m_min_depth;
int m_max_depth;
@@ -291,7 +294,7 @@ private:
struct stack_frame
{
stack_frame (std::unique_ptr<stack_frame> parent,
- logical_location logical_loc,
+ logical_locations::key logical_loc,
int stack_depth)
: m_parent (std::move (parent)),
m_logical_loc (logical_loc),
@@ -299,7 +302,7 @@ struct stack_frame
{}
std::unique_ptr<stack_frame> m_parent;
- logical_location m_logical_loc;
+ logical_locations::key m_logical_loc;
const int m_stack_depth;
};
@@ -309,9 +312,9 @@ struct stack_frame
static std::unique_ptr<stack_frame>
begin_html_stack_frame (xml::printer &xp,
std::unique_ptr<stack_frame> parent,
- logical_location logical_loc,
+ logical_locations::key logical_loc,
int stack_depth,
- const logical_location_manager *logical_loc_mgr)
+ const logical_locations::manager *logical_loc_mgr)
{
if (logical_loc)
{
@@ -398,7 +401,7 @@ emit_svg_arrow (xml::printer &xp, int old_depth, int new_depth)
xp.add_raw (pp_formatted_text (pp));
}
-/* A range of consecutive events within a diagnostic_path, all within the
+/* A range of consecutive events within a diagnostic path, all within the
same thread, and with the same fndecl and stack_depth, and which are suitable
to print with a single call to diagnostic_show_locus. */
struct event_range
@@ -423,7 +426,7 @@ struct event_range
the events already on this source line, *and* a new event at COLUMN. */
bool
can_add_label_for_event_p (bool has_in_edge,
- const diagnostic_event *prev_event,
+ const event *prev_event,
bool has_out_edge,
int column) const
{
@@ -488,20 +491,20 @@ struct event_range
int m_max_label_source_column;
};
- event_range (const diagnostic_path &path,
+ event_range (const path &path_,
const pretty_printer &ref_pp,
unsigned start_idx,
- const diagnostic_event &initial_event,
+ const event &initial_event,
per_thread_summary &t,
bool show_event_links,
bool colorize_labels,
bool allow_emojis)
- : m_path (path),
+ : m_path (path_),
m_initial_event (initial_event),
m_logical_loc (initial_event.get_logical_location ()),
m_stack_depth (initial_event.get_stack_depth ()),
m_start_idx (start_idx), m_end_idx (start_idx),
- m_path_label (path, ref_pp,
+ m_path_label (path_, ref_pp,
start_idx, colorize_labels, allow_emojis),
m_richloc (initial_event.get_location (), &m_path_label, nullptr),
m_thread_id (initial_event.get_thread_id ()),
@@ -516,7 +519,7 @@ struct event_range
per_source_line_info &source_line_info
= get_per_source_line_info (exploc.line);
- const diagnostic_event *prev_thread_event = t.m_last_event;
+ const event *prev_thread_event = t.m_last_event;
const bool has_in_edge
= (prev_thread_event
? prev_thread_event->connect_to_next_event_p ()
@@ -540,7 +543,7 @@ struct event_range
}
bool maybe_add_event (const path_print_policy &policy,
- const diagnostic_event &new_ev,
+ const event &new_ev,
unsigned new_ev_idx,
bool check_rich_locations)
{
@@ -557,7 +560,7 @@ struct event_range
(line_table, new_ev.get_location (), LOCATION_ASPECT_CARET);
per_source_line_info &source_line_info
= get_per_source_line_info (exploc.line);
- const diagnostic_event *prev_event = nullptr;
+ const event *prev_event = nullptr;
if (new_ev_idx > 0)
prev_event = &m_path.get_event (new_ev_idx - 1);
const bool has_in_edge = (prev_event
@@ -591,24 +594,24 @@ struct event_range
call to diagnostic_show_locus. */
void print_as_text (pretty_printer &pp,
- diagnostic_text_output_format &text_output,
- diagnostic_source_effect_info *effect_info)
+ diagnostics::text_sink &text_output,
+ diagnostics::source_effect_info *effect_info)
{
location_t initial_loc = m_initial_event.get_location ();
- diagnostic_context &dc = text_output.get_context ();
+ diagnostics::context &dc = text_output.get_context ();
/* Emit a span indicating the filename (and line/column) if the
line has changed relative to the last call to
diagnostic_show_locus. */
- if (dc.m_source_printing.enabled)
+ if (dc.get_source_printing_options ().enabled)
{
expanded_location exploc
= linemap_client_expand_location_to_spelling_point
(line_table, initial_loc, LOCATION_ASPECT_CARET);
if (exploc.file != LOCATION_FILE (dc.m_last_location))
{
- diagnostic_location_print_policy loc_policy (text_output);
+ diagnostics::location_print_policy loc_policy (text_output);
loc_policy.print_text_span_start (dc, pp, exploc);
}
}
@@ -624,7 +627,7 @@ struct event_range
{
for (unsigned i = m_start_idx; i <= m_end_idx; i++)
{
- const diagnostic_event &iter_event = m_path.get_event (i);
+ const event &iter_event = m_path.get_event (i);
diagnostic_event_id_t event_id (i);
pp_printf (&pp, " %@: ", &event_id);
iter_event.print_desc (pp);
@@ -635,7 +638,7 @@ struct event_range
/* Call diagnostic_show_locus to show the events using labels. */
diagnostic_show_locus (&dc, text_output.get_source_printing_options (),
- &m_richloc, DK_DIAGNOSTIC_PATH, &pp,
+ &m_richloc, diagnostics::kind::path, &pp,
effect_info);
/* If we have a macro expansion, show the expansion to the user. */
@@ -650,8 +653,8 @@ struct event_range
call to diagnostic_show_locus_as_html. */
void print_as_html (xml::printer &xp,
- diagnostic_context &dc,
- diagnostic_source_effect_info *effect_info,
+ diagnostics::context &dc,
+ diagnostics::source_effect_info *effect_info,
html_label_writer *event_label_writer)
{
location_t initial_loc = m_initial_event.get_location ();
@@ -659,14 +662,14 @@ struct event_range
/* Emit a span indicating the filename (and line/column) if the
line has changed relative to the last call to
diagnostic_show_locus. */
- if (dc.m_source_printing.enabled)
+ if (dc.get_source_printing_options ().enabled)
{
expanded_location exploc
= linemap_client_expand_location_to_spelling_point
(line_table, initial_loc, LOCATION_ASPECT_CARET);
if (exploc.file != LOCATION_FILE (dc.m_last_location))
{
- diagnostic_location_print_policy loc_policy (dc);
+ diagnostics::location_print_policy loc_policy (dc);
loc_policy.print_html_span_start (dc, xp, exploc);
}
}
@@ -682,7 +685,7 @@ struct event_range
{
for (unsigned i = m_start_idx; i <= m_end_idx; i++)
{
- const diagnostic_event &iter_event = m_path.get_event (i);
+ const event &iter_event = m_path.get_event (i);
diagnostic_event_id_t event_id (i);
pretty_printer pp;
pp_printf (&pp, " %@: ", &event_id);
@@ -698,29 +701,29 @@ struct event_range
/* Call diagnostic_show_locus_as_html to show the source,
showing events using labels. */
- diagnostic_show_locus_as_html (&dc, dc.m_source_printing,
- &m_richloc, DK_DIAGNOSTIC_PATH, xp,
+ diagnostic_show_locus_as_html (&dc, dc.get_source_printing_options (),
+ &m_richloc, diagnostics::kind::path, xp,
effect_info, event_label_writer);
// TODO: show macro expansions
}
- const diagnostic_path &m_path;
- const diagnostic_event &m_initial_event;
- logical_location m_logical_loc;
+ const path &m_path;
+ const event &m_initial_event;
+ logical_locations::key m_logical_loc;
int m_stack_depth;
unsigned m_start_idx;
unsigned m_end_idx;
path_label m_path_label;
gcc_rich_location m_richloc;
- diagnostic_thread_id_t m_thread_id;
+ thread_id_t m_thread_id;
per_thread_summary &m_per_thread_summary;
hash_map<int_hash<int, -1, -2>,
per_source_line_info> m_source_line_info_map;
bool m_show_event_links;
};
-/* A struct for grouping together the events in a diagnostic_path into
+/* A struct for grouping together the events in a path into
ranges of events, partitioned by thread and by stack frame (i.e. by fndecl
and stack depth). */
@@ -728,19 +731,19 @@ struct path_summary
{
path_summary (const path_print_policy &policy,
const pretty_printer &ref_pp,
- const diagnostic_path &path,
+ const path &path_,
bool check_rich_locations,
bool colorize = false,
bool show_event_links = true);
- const logical_location_manager &get_logical_location_manager () const
+ const logical_locations::manager &get_logical_location_manager () const
{
return m_logical_loc_mgr;
}
unsigned get_num_ranges () const { return m_ranges.length (); }
bool multithreaded_p () const { return m_per_thread_summary.length () > 1; }
- const per_thread_summary &get_events_for_thread_id (diagnostic_thread_id_t tid)
+ const per_thread_summary &get_events_for_thread_id (thread_id_t tid)
{
per_thread_summary **slot = m_thread_id_to_events.get (tid);
gcc_assert (slot);
@@ -748,23 +751,23 @@ struct path_summary
return **slot;
}
- const logical_location_manager &m_logical_loc_mgr;
+ const logical_locations::manager &m_logical_loc_mgr;
auto_delete_vec <event_range> m_ranges;
auto_delete_vec <per_thread_summary> m_per_thread_summary;
- hash_map<int_hash<diagnostic_thread_id_t, -1, -2>,
+ hash_map<int_hash<thread_id_t, -1, -2>,
per_thread_summary *> m_thread_id_to_events;
private:
per_thread_summary &
- get_or_create_events_for_thread_id (const diagnostic_path &path,
- diagnostic_thread_id_t tid)
+ get_or_create_events_for_thread_id (const path &path_,
+ thread_id_t tid)
{
if (per_thread_summary **slot = m_thread_id_to_events.get (tid))
return **slot;
- const diagnostic_thread &thread = path.get_thread (tid);
+ const thread &thread = path_.get_thread (tid);
per_thread_summary *pts
- = new per_thread_summary (path,
+ = new per_thread_summary (path_,
m_logical_loc_mgr,
thread.get_name (false),
m_per_thread_summary.length ());
@@ -798,40 +801,40 @@ per_thread_summary::interprocedural_p () const
path_summary::path_summary (const path_print_policy &policy,
const pretty_printer &ref_pp,
- const diagnostic_path &path,
+ const path &path_,
bool check_rich_locations,
bool colorize,
bool show_event_links)
-: m_logical_loc_mgr (path.get_logical_location_manager ())
+: m_logical_loc_mgr (path_.get_logical_location_manager ())
{
- const unsigned num_events = path.num_events ();
+ const unsigned num_events = path_.num_events ();
event_range *cur_event_range = nullptr;
for (unsigned idx = 0; idx < num_events; idx++)
{
- const diagnostic_event &event = path.get_event (idx);
- const diagnostic_thread_id_t thread_id = event.get_thread_id ();
+ const event &ev = path_.get_event (idx);
+ const thread_id_t thread_id = ev.get_thread_id ();
per_thread_summary &pts
- = get_or_create_events_for_thread_id (path, thread_id);
+ = get_or_create_events_for_thread_id (path_, thread_id);
- pts.update_depth_limits (event.get_stack_depth ());
+ pts.update_depth_limits (ev.get_stack_depth ());
if (cur_event_range)
if (cur_event_range->maybe_add_event (policy,
- event,
+ ev,
idx, check_rich_locations))
continue;
auto theme = policy.get_diagram_theme ();
const bool allow_emojis = theme ? theme->emojis_p () : false;
- cur_event_range = new event_range (path, ref_pp,
- idx, event, pts,
+ cur_event_range = new event_range (path_, ref_pp,
+ idx, ev, pts,
show_event_links,
colorize,
allow_emojis);
m_ranges.safe_push (cur_event_range);
pts.m_event_ranges.safe_push (cur_event_range);
- pts.m_last_event = &event;
+ pts.m_last_event = &ev;
}
}
@@ -881,11 +884,11 @@ public:
}
void
- print_swimlane_for_event_range_as_text (diagnostic_text_output_format &text_output,
+ print_swimlane_for_event_range_as_text (diagnostics::text_sink &text_output,
pretty_printer *pp,
- const logical_location_manager &logical_loc_mgr,
+ const logical_locations::manager &logical_loc_mgr,
event_range *range,
- diagnostic_source_effect_info *effect_info)
+ diagnostics::source_effect_info *effect_info)
{
gcc_assert (pp);
const char *const line_color = "path";
@@ -1041,11 +1044,11 @@ public:
}
void
- print_swimlane_for_event_range_as_html (diagnostic_context &dc,
+ print_swimlane_for_event_range_as_html (diagnostics::context &dc,
xml::printer &xp,
html_label_writer *event_label_writer,
event_range *range,
- diagnostic_source_effect_info *effect_info)
+ diagnostics::source_effect_info *effect_info)
{
range->print_as_html (xp, dc, effect_info, event_label_writer);
m_num_printed++;
@@ -1107,7 +1110,7 @@ private:
static void
print_path_summary_as_text (const path_summary &ps,
- diagnostic_text_output_format &text_output,
+ diagnostics::text_sink &text_output,
bool show_depths)
{
pretty_printer *const pp = text_output.get_printer ();
@@ -1135,7 +1138,7 @@ print_path_summary_as_text (const path_summary &ps,
thread_event_printer &tep = thread_event_printers[swimlane_idx];
/* Wire up any trailing out-edge from previous range to leading in-edge
of this range. */
- diagnostic_source_effect_info effect_info;
+ diagnostics::source_effect_info effect_info;
effect_info.m_leading_in_edge_column = last_out_edge_column;
tep.print_swimlane_for_event_range_as_text
(text_output, pp,
@@ -1149,7 +1152,7 @@ print_path_summary_as_text (const path_summary &ps,
static void
print_path_summary_as_html (const path_summary &ps,
- diagnostic_context &dc,
+ diagnostics::context &dc,
xml::printer &xp,
html_label_writer *event_label_writer,
bool show_depths)
@@ -1158,7 +1161,7 @@ print_path_summary_as_html (const path_summary &ps,
for (auto t : ps.m_per_thread_summary)
thread_event_printers.push_back (thread_event_printer (*t, show_depths));
- const logical_location_manager *logical_loc_mgr
+ const logical_locations::manager *logical_loc_mgr
= dc.get_logical_location_manager ();
xp.push_tag_with_class ("div", "event-ranges", false);
@@ -1173,7 +1176,7 @@ print_path_summary_as_html (const path_summary &ps,
const int swimlane_idx
= range->m_per_thread_summary.get_swimlane_index ();
- const logical_location this_logical_loc = range->m_logical_loc;
+ const logical_locations::key this_logical_loc = range->m_logical_loc;
const int this_depth = range->m_stack_depth;
if (curr_frame)
{
@@ -1261,7 +1264,7 @@ print_path_summary_as_html (const path_summary &ps,
thread_event_printer &tep = thread_event_printers[swimlane_idx];
/* Wire up any trailing out-edge from previous range to leading in-edge
of this range. */
- diagnostic_source_effect_info effect_info;
+ diagnostics::source_effect_info effect_info;
effect_info.m_leading_in_edge_column = last_out_edge_column;
tep.print_swimlane_for_event_range_as_html (dc, xp, event_label_writer,
range, &effect_info);
@@ -1284,8 +1287,8 @@ print_path_summary_as_html (const path_summary &ps,
class element_event_desc : public pp_element
{
public:
- element_event_desc (const diagnostic_event &event)
- : m_event (event)
+ element_event_desc (const event &event_)
+ : m_event (event_)
{
}
@@ -1297,15 +1300,15 @@ public:
}
private:
- const diagnostic_event &m_event;
+ const event &m_event;
};
/* Print PATH according to the context's path_format. */
void
-diagnostic_text_output_format::print_path (const diagnostic_path &path)
+diagnostics::text_sink::print_path (const path &path_)
{
- const unsigned num_events = path.num_events ();
+ const unsigned num_events = path_.num_events ();
switch (get_context ().get_path_format ())
{
@@ -1316,36 +1319,36 @@ diagnostic_text_output_format::print_path (const diagnostic_path &path)
case DPF_SEPARATE_EVENTS:
{
/* A note per event. */
- auto &logical_loc_mgr = path.get_logical_location_manager ();
+ auto &logical_loc_mgr = path_.get_logical_location_manager ();
for (unsigned i = 0; i < num_events; i++)
{
- const diagnostic_event &event = path.get_event (i);
- element_event_desc e_event_desc (event);
+ const event &ev = path_.get_event (i);
+ element_event_desc e_event_desc (ev);
diagnostic_event_id_t event_id (i);
if (get_context ().show_path_depths_p ())
{
- int stack_depth = event.get_stack_depth ();
+ int stack_depth = ev.get_stack_depth ();
/* -fdiagnostics-path-format=separate-events doesn't print
fndecl information, so with -fdiagnostics-show-path-depths
print the fndecls too, if any. */
- if (logical_location logical_loc
- = event.get_logical_location ())
+ if (logical_locations::key logical_loc
+ = ev.get_logical_location ())
{
label_text name
(logical_loc_mgr.get_name_for_path_output (logical_loc));
- inform (event.get_location (),
+ inform (ev.get_location (),
"%@ %e (fndecl %qs, depth %i)",
&event_id, &e_event_desc,
name.get (), stack_depth);
}
else
- inform (event.get_location (),
+ inform (ev.get_location (),
"%@ %e (depth %i)",
&event_id, &e_event_desc,
stack_depth);
}
else
- inform (event.get_location (),
+ inform (ev.get_location (),
"%@ %e", &event_id, &e_event_desc);
}
}
@@ -1361,7 +1364,7 @@ diagnostic_text_output_format::print_path (const diagnostic_path &path)
const bool show_event_links = m_source_printing.show_event_links_p;
path_summary summary (policy,
*pp,
- path,
+ path_,
check_rich_locations,
colorize,
show_event_links);
@@ -1376,25 +1379,25 @@ diagnostic_text_output_format::print_path (const diagnostic_path &path)
}
}
-/* Print PATH as HTML to XP, using DC and DSPP for settings.
+/* Print PATH_ as HTML to XP, using DC and DSPP for settings.
If non-null, use EVENT_LABEL_WRITER when writing events. */
void
-print_path_as_html (xml::printer &xp,
- const diagnostic_path &path,
- diagnostic_context &dc,
- html_label_writer *event_label_writer,
- const diagnostic_source_print_policy &dspp)
+diagnostics::print_path_as_html (xml::printer &xp,
+ const path &path_,
+ context &dc,
+ html_label_writer *event_label_writer,
+ const source_print_policy &dspp)
{
path_print_policy policy (dc);
const bool check_rich_locations = true;
const bool colorize = false;
- const diagnostic_source_printing_options &source_printing_opts
+ const source_printing_options &source_printing_opts
= dspp.get_options ();
const bool show_event_links = source_printing_opts.show_event_links_p;
path_summary summary (policy,
*dc.get_reference_printer (),
- path,
+ path_,
check_rich_locations,
colorize,
show_event_links);
@@ -1404,18 +1407,27 @@ print_path_as_html (xml::printer &xp,
#if CHECKING_P
+namespace diagnostics {
+namespace paths {
namespace selftest {
-/* Return true iff all events in PATH have locations for which column data
+using location = ::selftest::location;
+using line_table_case = ::selftest::line_table_case;
+using line_table_test = ::selftest::line_table_test;
+using temp_source_file = ::selftest::temp_source_file;
+
+using test_context = diagnostics::selftest::test_context;
+
+/* Return true iff all events in PATH_ have locations for which column data
is available, so that selftests that require precise string output can
bail out for awkward line_table cases. */
static bool
-path_events_have_column_data_p (const diagnostic_path &path)
+path_events_have_column_data_p (const path &path_)
{
- for (unsigned idx = 0; idx < path.num_events (); idx++)
+ for (unsigned idx = 0; idx < path_.num_events (); idx++)
{
- location_t event_loc = path.get_event (idx).get_location ();
+ location_t event_loc = path_.get_event (idx).get_location ();
if (line_table->get_pure_location (event_loc)
> LINE_MAP_MAX_LOCATION_WITH_COLS)
return false;
@@ -1432,11 +1444,12 @@ path_events_have_column_data_p (const diagnostic_path &path)
static void
test_empty_path (pretty_printer *event_pp)
{
- test_diagnostic_path path (event_pp);
+ logical_locations::selftest::test_manager logical_loc_mgr;
+ test_path path (logical_loc_mgr, event_pp);
ASSERT_FALSE (path.interprocedural_p ());
- test_diagnostic_context dc;
- diagnostic_text_output_format text_output (dc);
+ test_context dc;
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, false);
ASSERT_EQ (summary.get_num_ranges (), 0);
@@ -1451,15 +1464,16 @@ test_empty_path (pretty_printer *event_pp)
static void
test_intraprocedural_path (pretty_printer *event_pp)
{
- test_diagnostic_path path (event_pp);
+ logical_locations::selftest::test_manager logical_loc_mgr;
+ test_path path (logical_loc_mgr, event_pp);
const char *const funcname = "foo";
path.add_event (UNKNOWN_LOCATION, funcname, 0, "first %qs", "free");
path.add_event (UNKNOWN_LOCATION, funcname, 0, "double %qs", "free");
ASSERT_FALSE (path.interprocedural_p ());
- test_diagnostic_context dc;
- diagnostic_text_output_format text_output (dc);
+ selftest::test_context dc;
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, false, false, false);
ASSERT_EQ (summary.get_num_ranges (), 1);
@@ -1476,7 +1490,8 @@ test_intraprocedural_path (pretty_printer *event_pp)
static void
test_interprocedural_path_1 (pretty_printer *event_pp)
{
- test_diagnostic_path path (event_pp);
+ logical_locations::selftest::test_manager logical_loc_mgr;
+ test_path path (logical_loc_mgr, event_pp);
path.add_entry ("test", 0);
path.add_call ("test", 0, "make_boxed_int");
path.add_call ("make_boxed_int", 1, "wrapped_malloc");
@@ -1495,8 +1510,8 @@ test_interprocedural_path_1 (pretty_printer *event_pp)
ASSERT_TRUE (path.interprocedural_p ());
{
- test_diagnostic_context dc;
- diagnostic_text_output_format text_output (dc, nullptr, false);
+ selftest::test_context dc;
+ text_sink text_output (dc, nullptr, false);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, false);
ASSERT_EQ (summary.get_num_ranges (), 9);
@@ -1556,9 +1571,9 @@ test_interprocedural_path_1 (pretty_printer *event_pp)
pp_formatted_text (text_output.get_printer ()));
}
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE);
- diagnostic_text_output_format text_output (dc);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, false);
print_path_summary_as_text (summary, text_output, true);
@@ -1623,7 +1638,8 @@ test_interprocedural_path_1 (pretty_printer *event_pp)
static void
test_interprocedural_path_2 (pretty_printer *event_pp)
{
- test_diagnostic_path path (event_pp);
+ logical_locations::selftest::test_manager logical_loc_mgr;
+ test_path path (logical_loc_mgr, event_pp);
path.add_entry ("foo", 0);
path.add_call ("foo", 0, "bar");
path.add_call ("bar", 1, "baz");
@@ -1634,8 +1650,8 @@ test_interprocedural_path_2 (pretty_printer *event_pp)
ASSERT_TRUE (path.interprocedural_p ());
{
- test_diagnostic_context dc;
- diagnostic_text_output_format text_output (dc);
+ selftest::test_context dc;
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, false);
ASSERT_EQ (summary.get_num_ranges (), 5);
@@ -1670,9 +1686,9 @@ test_interprocedural_path_2 (pretty_printer *event_pp)
pp_formatted_text (text_output.get_printer ()));
}
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE);
- diagnostic_text_output_format text_output (dc);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, false);
print_path_summary_as_text (summary, text_output, true);
@@ -1707,12 +1723,13 @@ test_interprocedural_path_2 (pretty_printer *event_pp)
}
/* Verify that print_path_summary is sane in the face of a recursive
- diagnostic_path. */
+ diagnostic path. */
static void
test_recursion (pretty_printer *event_pp)
{
- test_diagnostic_path path (event_pp);
+ logical_locations::selftest::test_manager logical_loc_mgr;
+ test_path path (logical_loc_mgr, event_pp);
path.add_entry ("factorial", 0);
for (int depth = 0; depth < 3; depth++)
path.add_call ("factorial", depth, "factorial");
@@ -1721,10 +1738,10 @@ test_recursion (pretty_printer *event_pp)
ASSERT_TRUE (path.interprocedural_p ());
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
- diagnostic_text_output_format text_output (dc);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, false);
ASSERT_EQ (summary.get_num_ranges (), 4);
@@ -1753,10 +1770,10 @@ test_recursion (pretty_printer *event_pp)
pp_formatted_text (text_output.get_printer ()));
}
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE);
- diagnostic_text_output_format text_output (dc);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, false);
print_path_summary_as_text (summary, text_output, true);
@@ -1789,7 +1806,7 @@ test_recursion (pretty_printer *event_pp)
class control_flow_test
{
public:
- control_flow_test (const location &loc,
+ control_flow_test (const selftest::location &loc,
const line_table_case &case_,
const char *content)
: m_tmp_file (loc, ".c", content,
@@ -1858,7 +1875,8 @@ test_control_flow_1 (const line_table_case &case_,
const location_t conditional = t.get_line_and_column (3, 7);
const location_t cfg_dest = t.get_line_and_column (5, 10);
- test_diagnostic_path path (event_pp);
+ logical_locations::selftest::test_manager logical_loc_mgr;
+ test_path path (logical_loc_mgr, event_pp);
path.add_event (conditional, nullptr, 0,
"following %qs branch (when %qs is NULL)...",
"false", "p");
@@ -1875,10 +1893,10 @@ test_control_flow_1 (const line_table_case &case_,
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
- dc.m_source_printing.show_event_links_p = true;
- diagnostic_text_output_format text_output (dc);
+ dc.show_event_links (true);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, true);
print_path_summary_as_text (summary, text_output, false);
@@ -1901,10 +1919,10 @@ test_control_flow_1 (const line_table_case &case_,
pp_formatted_text (text_output.get_printer ()));
}
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
- dc.m_source_printing.show_event_links_p = false;
- diagnostic_text_output_format text_output (dc);
+ dc.show_event_links (false);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, true);
print_path_summary_as_text (summary, text_output, false);
@@ -1924,11 +1942,11 @@ test_control_flow_1 (const line_table_case &case_,
pp_formatted_text (text_output.get_printer ()));
}
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
- dc.m_source_printing.show_line_numbers_p = true;
- dc.m_source_printing.show_event_links_p = true;
- diagnostic_text_output_format text_output (dc);
+ dc.show_line_numbers (true);
+ dc.show_event_links (true);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, true);
print_path_summary_as_text (summary, text_output, false);
@@ -1951,11 +1969,11 @@ test_control_flow_1 (const line_table_case &case_,
pp_formatted_text (text_output.get_printer ()));
}
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
- dc.m_source_printing.show_line_numbers_p = true;
- dc.m_source_printing.show_event_links_p = false;
- diagnostic_text_output_format text_output (dc);
+ dc.show_line_numbers (true);
+ dc.show_event_links (false);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, true);
print_path_summary_as_text (summary, text_output, false);
@@ -1975,10 +1993,10 @@ test_control_flow_1 (const line_table_case &case_,
pp_formatted_text (text_output.get_printer ()));
}
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE);
- dc.m_source_printing.show_event_links_p = true;
- diagnostic_text_output_format text_output (dc);
+ dc.show_event_links (true);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, true);
print_path_summary_as_text (summary, text_output, false);
@@ -2001,11 +2019,11 @@ test_control_flow_1 (const line_table_case &case_,
pp_formatted_text (text_output.get_printer ()));
}
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE);
- dc.m_source_printing.show_event_links_p = true;
- dc.m_source_printing.show_line_numbers_p = true;
- diagnostic_text_output_format text_output (dc);
+ dc.show_event_links (true);
+ dc.show_line_numbers (true);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, true);
print_path_summary_as_text (summary, text_output, false);
@@ -2055,7 +2073,8 @@ test_control_flow_2 (const line_table_case &case_,
const location_t loop_body_start = t.get_line_and_columns (5, 12, 17);
const location_t loop_body_end = t.get_line_and_columns (5, 5, 9, 17);
- test_diagnostic_path path (event_pp);
+ logical_locations::selftest::test_manager logical_loc_mgr;
+ test_path path (logical_loc_mgr, event_pp);
path.add_event (iter_test, nullptr, 0, "infinite loop here");
path.add_event (iter_test, nullptr, 0, "looping from here...");
@@ -2072,11 +2091,11 @@ test_control_flow_2 (const line_table_case &case_,
return;
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
- dc.m_source_printing.show_event_links_p = true;
- dc.m_source_printing.show_line_numbers_p = true;
- diagnostic_text_output_format text_output (dc);
+ dc.show_event_links (true);
+ dc.show_line_numbers (true);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, true);
print_path_summary_as_text (summary, text_output, false);
@@ -2142,7 +2161,8 @@ test_control_flow_3 (const line_table_case &case_,
const location_t iter_test = t.get_line_and_column (3, 19);
const location_t iter_next = t.get_line_and_columns (3, 22, 24);
- test_diagnostic_path path (event_pp);
+ logical_locations::selftest::test_manager logical_loc_mgr;
+ test_path path (logical_loc_mgr, event_pp);
path.add_event (iter_test, nullptr, 0, "infinite loop here");
path.add_event (iter_test, nullptr, 0, "looping from here...");
@@ -2159,11 +2179,11 @@ test_control_flow_3 (const line_table_case &case_,
return;
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
- dc.m_source_printing.show_event_links_p = true;
- dc.m_source_printing.show_line_numbers_p = true;
- diagnostic_text_output_format text_output (dc);
+ dc.show_event_links (true);
+ dc.show_line_numbers (true);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, true);
print_path_summary_as_text (summary, text_output, false);
@@ -2208,7 +2228,8 @@ assert_cfg_edge_path_streq (const location &loc,
const location_t dst_loc,
const char *expected_str)
{
- test_diagnostic_path path (event_pp);
+ logical_locations::selftest::test_manager logical_loc_mgr;
+ test_path path (logical_loc_mgr, event_pp);
path.add_event (src_loc, nullptr, 0, "from here...");
path.connect_to_next_event ();
@@ -2217,11 +2238,11 @@ assert_cfg_edge_path_streq (const location &loc,
if (!path_events_have_column_data_p (path))
return;
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
- dc.m_source_printing.show_event_links_p = true;
- dc.m_source_printing.show_line_numbers_p = true;
- diagnostic_text_output_format text_output (dc);
+ dc.show_event_links (true);
+ dc.show_line_numbers (true);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, true);
print_path_summary_as_text (summary, text_output, false);
@@ -2512,7 +2533,8 @@ test_control_flow_5 (const line_table_case &case_,
control_flow_test t (SELFTEST_LOCATION, case_, content);
- test_diagnostic_path path (event_pp);
+ logical_locations::selftest::test_manager logical_loc_mgr;
+ test_path path (logical_loc_mgr, event_pp);
/* (1) */
path.add_event (t.get_line_and_column (1, 6), nullptr, 0,
"following %qs branch (when %qs is non-NULL)...",
@@ -2541,11 +2563,11 @@ test_control_flow_5 (const line_table_case &case_,
return;
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
- dc.m_source_printing.show_event_links_p = true;
- dc.m_source_printing.show_line_numbers_p = true;
- diagnostic_text_output_format text_output (dc);
+ dc.show_event_links (true);
+ dc.show_line_numbers (true);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, true);
print_path_summary_as_text (summary, text_output, false);
@@ -2601,7 +2623,8 @@ test_control_flow_6 (const line_table_case &case_,
control_flow_test t (SELFTEST_LOCATION, case_, content);
- test_diagnostic_path path (event_pp);
+ logical_locations::selftest::test_manager logical_loc_mgr;
+ test_path path (logical_loc_mgr, event_pp);
/* (1) */
path.add_event (t.get_line_and_columns (6, 25, 35), nullptr, 0,
"allocated here");
@@ -2630,11 +2653,11 @@ test_control_flow_6 (const line_table_case &case_,
return;
{
- test_diagnostic_context dc;
+ selftest::test_context dc;
dc.set_text_art_charset (DIAGNOSTICS_TEXT_ART_CHARSET_ASCII);
- dc.m_source_printing.show_event_links_p = true;
- dc.m_source_printing.show_line_numbers_p = true;
- diagnostic_text_output_format text_output (dc);
+ dc.show_event_links (true);
+ dc.show_line_numbers (true);
+ text_sink text_output (dc);
path_print_policy policy (text_output);
path_summary summary (policy, *event_pp, path, true);
print_path_summary_as_text (summary, text_output, false);
@@ -2687,24 +2710,30 @@ control_flow_tests (const line_table_case &case_)
test_control_flow_6 (case_, &pp);
}
+} // namespace diagnostics::paths::selftest
+} // namespace diagnostics::paths
+
+namespace selftest { // diagnostics::selftest
+
/* Run all of the selftests within this file. */
void
-diagnostic_path_output_cc_tests ()
+paths_output_cc_tests ()
{
pretty_printer pp;
pp_show_color (&pp) = false;
- auto_fix_quotes fix_quotes;
- test_empty_path (&pp);
- test_intraprocedural_path (&pp);
- test_interprocedural_path_1 (&pp);
- test_interprocedural_path_2 (&pp);
- test_recursion (&pp);
- for_each_line_table_case (control_flow_tests);
+ ::selftest::auto_fix_quotes fix_quotes;
+ diagnostics::paths::selftest::test_empty_path (&pp);
+ diagnostics::paths::selftest::test_intraprocedural_path (&pp);
+ diagnostics::paths::selftest::test_interprocedural_path_1 (&pp);
+ diagnostics::paths::selftest::test_interprocedural_path_2 (&pp);
+ diagnostics::paths::selftest::test_recursion (&pp);
+ for_each_line_table_case (diagnostics::paths::selftest::control_flow_tests);
}
-} // namespace selftest
+} // namespace diagnostics::selftest
+} // namespace diagnostics
#if __GNUC__ >= 10
# pragma GCC diagnostic pop
diff --git a/gcc/diagnostic-path.cc b/gcc/diagnostics/paths.cc
index 1ae87b7..bc769c4 100644
--- a/gcc/diagnostic-path.cc
+++ b/gcc/diagnostics/paths.cc
@@ -26,8 +26,8 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
-#include "diagnostic-path.h"
-#include "diagnostic-state-graphs.h"
+#include "diagnostics/paths.h"
+#include "diagnostics/state-graphs.h"
/* Disable warnings about missing quoting in GCC diagnostics for the print
calls below. */
@@ -36,12 +36,15 @@ along with GCC; see the file COPYING3. If not see
# pragma GCC diagnostic ignored "-Wformat-diag"
#endif
-/* class diagnostic_event. */
+using namespace diagnostics;
+using namespace diagnostics::paths;
-/* struct diagnostic_event::meaning. */
+/* class diagnostics::paths::event. */
+
+/* struct event::meaning. */
void
-diagnostic_event::meaning::dump_to_pp (pretty_printer *pp) const
+event::meaning::dump_to_pp (pretty_printer *pp) const
{
bool need_comma = false;
pp_character (pp, '{');
@@ -71,7 +74,7 @@ diagnostic_event::meaning::dump_to_pp (pretty_printer *pp) const
threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
const char *
-diagnostic_event::meaning::maybe_get_verb_str (enum verb v)
+event::meaning::maybe_get_verb_str (enum verb v)
{
switch (v)
{
@@ -102,7 +105,7 @@ diagnostic_event::meaning::maybe_get_verb_str (enum verb v)
threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
const char *
-diagnostic_event::meaning::maybe_get_noun_str (enum noun n)
+event::meaning::maybe_get_noun_str (enum noun n)
{
switch (n)
{
@@ -129,7 +132,7 @@ diagnostic_event::meaning::maybe_get_noun_str (enum noun n)
threadFlowLocation "kinds" property (SARIF v2.1.0 section 3.38.8). */
const char *
-diagnostic_event::meaning::maybe_get_property_str (enum property p)
+event::meaning::maybe_get_property_str (enum property p)
{
switch (p)
{
@@ -148,7 +151,7 @@ diagnostic_event::meaning::maybe_get_property_str (enum property p)
(for debugging/logging purposes). */
label_text
-diagnostic_event::get_desc (pretty_printer &ref_pp) const
+event::get_desc (pretty_printer &ref_pp) const
{
auto pp = ref_pp.clone ();
pp_show_color (pp.get ()) = false;
@@ -156,31 +159,31 @@ diagnostic_event::get_desc (pretty_printer &ref_pp) const
return label_text::take (xstrdup (pp_formatted_text (pp.get ())));
}
-// Base implementation of diagnostic_event::maybe_make_diagnostic_state_graph
+// Base implementation of event::maybe_make_diagnostic_state_graph
-std::unique_ptr<diagnostics::digraphs::digraph>
-diagnostic_event::maybe_make_diagnostic_state_graph (bool) const
+std::unique_ptr<digraphs::digraph>
+event::maybe_make_diagnostic_state_graph (bool) const
{
// Don't attempt to make a state graph:
return nullptr;
}
-/* class diagnostic_path. */
+/* class diagnostics::paths::path. */
-/* Subroutine of diagnostic_path::interprocedural_p.
+/* Subroutine of path::interprocedural_p.
Look for the first event in this path that is within a function
i.e. has a non-null logical location for which function_p is true.
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
+path::get_first_event_in_a_function (unsigned *out_idx) const
{
const unsigned num = num_events ();
for (unsigned i = 0; i < num; i++)
{
- const diagnostic_event &event = get_event (i);
- if (logical_location logical_loc = event.get_logical_location ())
+ const event &event = get_event (i);
+ if (logical_locations::key logical_loc = event.get_logical_location ())
if (m_logical_loc_mgr.function_p (logical_loc))
{
*out_idx = i;
@@ -194,14 +197,14 @@ diagnostic_path::get_first_event_in_a_function (unsigned *out_idx) const
function, or false if it is purely intraprocedural. */
bool
-diagnostic_path::interprocedural_p () const
+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);
+ const event &first_fn_event = get_event (first_fn_event_idx);
int first_fn_stack_depth = first_fn_event.get_stack_depth ();
const unsigned num = num_events ();
@@ -218,10 +221,10 @@ diagnostic_path::interprocedural_p () const
/* Print PATH by emitting a dummy "note" associated with it. */
DEBUG_FUNCTION
-void debug (diagnostic_path *path)
+void debug (path *p)
{
rich_location richloc (line_table, UNKNOWN_LOCATION);
- richloc.set_path (path);
+ richloc.set_path (p);
inform (&richloc, "debug path");
}
diff --git a/gcc/diagnostic-path.h b/gcc/diagnostics/paths.h
index ca2628e..d30c420 100644
--- a/gcc/diagnostic-path.h
+++ b/gcc/diagnostics/paths.h
@@ -18,25 +18,28 @@ 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_DIAGNOSTIC_PATH_H
-#define GCC_DIAGNOSTIC_PATH_H
+#ifndef GCC_DIAGNOSTICS_PATHS_H
+#define GCC_DIAGNOSTICS_PATHS_H
#include "diagnostic.h" /* for ATTRIBUTE_GCC_DIAG. */
-#include "diagnostic-event-id.h"
-#include "logical-location.h"
-
-namespace xml { class document; }
-
-class sarif_builder;
-class sarif_object;
+#include "diagnostics/event-id.h"
+#include "diagnostics/logical-locations.h"
namespace diagnostics {
-namespace digraphs {
- class digraph;
-} // namespace digraphs
+ namespace digraphs {
+ class digraph;
+ } // namespace digraphs
+ namespace logical_locations {
+ class manager;
+ } // logical_locations
+ class sarif_builder;
+ class sarif_object;
} //namespace diagnostics
-/* A diagnostic_path is an optional additional piece of metadata associated
+namespace diagnostics {
+namespace paths {
+
+/* A diagnostics::paths::path is an optional additional piece of metadata associated
with a diagnostic (via its rich_location).
It describes a sequence of events predicted by the compiler that
@@ -74,9 +77,9 @@ namespace digraphs {
/* Abstract base classes, describing events within a path, and the paths
themselves. */
-/* One event within a diagnostic_path. */
+/* One event within a path. */
-class diagnostic_event
+class event
{
public:
/* Enums for giving a sense of what this event means.
@@ -148,7 +151,7 @@ class diagnostic_event
enum property m_property;
};
- virtual ~diagnostic_event () {}
+ virtual ~event () {}
virtual location_t get_location () const = 0;
@@ -160,7 +163,7 @@ class diagnostic_event
virtual void print_desc (pretty_printer &pp) const = 0;
/* Get a logical location for this event, or null if there is none. */
- virtual logical_location get_logical_location () const = 0;
+ virtual logical_locations::key get_logical_location () const = 0;
virtual meaning get_meaning () const = 0;
@@ -168,7 +171,7 @@ class diagnostic_event
next event (e.g. to highlight control flow). */
virtual bool connect_to_next_event_p () const = 0;
- virtual diagnostic_thread_id_t get_thread_id () const = 0;
+ virtual thread_id_t get_thread_id () const = 0;
/* Hook for SARIF output to allow for adding diagnostic-specific
properties to the threadFlowLocation object's property bag. */
@@ -180,35 +183,35 @@ class diagnostic_event
/* Hook for capturing state at this event, potentially for visualizing
in HTML output, or for adding to SARIF. */
- virtual std::unique_ptr<diagnostics::digraphs::digraph>
+ virtual std::unique_ptr<digraphs::digraph>
maybe_make_diagnostic_state_graph (bool debug) const;
label_text get_desc (pretty_printer &ref_pp) const;
};
/* Abstract base class representing a thread of execution within
- a diagnostic_path.
- Each diagnostic_event is associated with one thread.
- Typically there is just one thread per diagnostic_path. */
+ a diagnostics::paths::path.
+ Each event is associated with one thread.
+ Typically there is just one thread per diagnostics::paths::path. */
-class diagnostic_thread
+class thread
{
public:
- virtual ~diagnostic_thread () {}
+ virtual ~thread () {}
virtual label_text get_name (bool can_colorize) const = 0;
};
/* Abstract base class for getting at a sequence of events. */
-class diagnostic_path
+class path
{
public:
- virtual ~diagnostic_path () {}
+ virtual ~path () {}
virtual unsigned num_events () const = 0;
- virtual const diagnostic_event & get_event (int idx) const = 0;
+ virtual const event & get_event (int idx) const = 0;
virtual unsigned num_threads () const = 0;
- virtual const diagnostic_thread &
- get_thread (diagnostic_thread_id_t) const = 0;
+ virtual const thread &
+ get_thread (thread_id_t) const = 0;
/* Return true iff the two events are both within the same function,
or both outside of any function. */
@@ -219,13 +222,13 @@ class diagnostic_path
bool interprocedural_p () const;
bool multithreaded_p () const;
- const logical_location_manager &get_logical_location_manager () const
+ const logical_locations::manager &get_logical_location_manager () const
{
return m_logical_loc_mgr;
}
protected:
- diagnostic_path (const logical_location_manager &logical_loc_mgr)
+ path (const logical_locations::manager &logical_loc_mgr)
: m_logical_loc_mgr (logical_loc_mgr)
{
}
@@ -233,12 +236,15 @@ protected:
private:
bool get_first_event_in_a_function (unsigned *out_idx) const;
- const logical_location_manager &m_logical_loc_mgr;
+ const logical_locations::manager &m_logical_loc_mgr;
};
+} // namespace paths
+} // namespace diagnostics
+
/* Concrete subclasses of the above can be found in
simple-diagnostic-path.h. */
-extern void debug (diagnostic_path *path);
+extern void debug (diagnostics::paths::path *path);
-#endif /* ! GCC_DIAGNOSTIC_PATH_H */
+#endif /* ! GCC_DIAGNOSTICS_PATHS_H */
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostics/sarif-sink.cc
index d20ca86..05c0a8e 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostics/sarif-sink.cc
@@ -27,25 +27,25 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
-#include "diagnostic-metadata.h"
-#include "diagnostic-digraphs.h"
-#include "diagnostic-state-graphs.h"
-#include "diagnostic-path.h"
-#include "diagnostic-format.h"
-#include "diagnostic-buffer.h"
+#include "diagnostics/metadata.h"
+#include "diagnostics/digraphs.h"
+#include "diagnostics/state-graphs.h"
+#include "diagnostics/paths.h"
+#include "diagnostics/sink.h"
+#include "diagnostics/buffering.h"
#include "json.h"
#include "cpplib.h"
-#include "logical-location.h"
-#include "diagnostic-client-data-hooks.h"
-#include "diagnostic-diagram.h"
+#include "diagnostics/logical-locations.h"
+#include "diagnostics/client-data-hooks.h"
+#include "diagnostics/diagram.h"
#include "text-art/canvas.h"
-#include "diagnostic-format-sarif.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/sarif-sink.h"
+#include "diagnostics/text-sink.h"
#include "ordered-hash-map.h"
#include "sbitmap.h"
#include "selftest.h"
-#include "selftest-diagnostic.h"
-#include "selftest-diagnostic-show-locus.h"
+#include "diagnostics/selftest-context.h"
+#include "diagnostics/selftest-source-printing.h"
#include "selftest-json.h"
#include "text-range-label.h"
#include "pretty-print-format-impl.h"
@@ -54,6 +54,8 @@ along with GCC; see the file COPYING3. If not see
#include "backtrace.h"
#include "xml.h"
+namespace diagnostics {
+
/* A json::array where the values are "unique" as per
SARIF v2.1.0 section 3.7.3 ("Array properties with unique values"). */
@@ -450,9 +452,9 @@ public:
void
on_nested_diagnostic (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind,
+ enum kind orig_diag_kind,
sarif_builder &builder);
- void on_diagram (const diagnostic_diagram &diagram,
+ void on_diagram (const diagram &d,
sarif_builder &builder);
private:
@@ -532,22 +534,22 @@ public:
unsigned get_index_within_parent () const { return m_idx_within_parent; }
sarif_thread_flow &
- get_or_append_thread_flow (const diagnostic_thread &thread,
- diagnostic_thread_id_t thread_id);
+ get_or_append_thread_flow (const paths::thread &thread,
+ paths::thread_id_t thread_id);
sarif_thread_flow &
- get_thread_flow (diagnostic_thread_id_t thread_id);
+ get_thread_flow (paths::thread_id_t thread_id);
void add_location (sarif_thread_flow_location &);
sarif_thread_flow_location &
- get_thread_flow_loc_obj (diagnostic_event_id_t event_id) const;
+ get_thread_flow_loc_obj (paths::event_id_t event_id) const;
private:
sarif_result &m_parent;
const unsigned m_idx_within_parent;
- hash_map<int_hash<diagnostic_thread_id_t, -1, -2>,
+ hash_map<int_hash<paths::thread_id_t, -1, -2>,
sarif_thread_flow *> m_thread_id_map; // borrowed ptr
json::array *m_thread_flows_arr; // borrowed
@@ -563,7 +565,7 @@ class sarif_thread_flow : public sarif_object
{
public:
sarif_thread_flow (sarif_code_flow &parent,
- const diagnostic_thread &thread,
+ const paths::thread &thread,
unsigned idx_within_parent);
sarif_code_flow &get_parent () const { return m_parent; }
@@ -660,20 +662,20 @@ public:
render (const sarif_builder &builder) const = 0;
};
-/* Concrete buffering implementation subclass for JSON output. */
+/* Concrete buffering implementation subclass for SARIF output. */
-class diagnostic_sarif_format_buffer : public diagnostic_per_format_buffer
+class sarif_sink_buffer : public per_sink_buffer
{
public:
- friend class sarif_output_format;
+ friend class sarif_sink;
- diagnostic_sarif_format_buffer (sarif_builder &builder)
+ sarif_sink_buffer (sarif_builder &builder)
: m_builder (builder)
{}
void dump (FILE *out, int indent) const final override;
bool empty_p () const final override;
- void move_to (diagnostic_per_format_buffer &dest) final override;
+ void move_to (per_sink_buffer &dest) final override;
void clear () final override;
void flush () final override;
@@ -743,15 +745,15 @@ sarif_serialization_format_json::write_to_file (FILE *outf,
- doesn't capture -Werror cleanly
- doesn't capture inlining information (can SARIF handle this?)
- doesn't capture macro expansion information (can SARIF handle this?).
- - doesn't capture any diagnostic_metadata::rules associated with
+ - doesn't capture any diagnostics::metadata::rules associated with
a diagnostic. */
class sarif_builder
{
public:
- friend class diagnostic_sarif_format_buffer;
+ friend class sarif_sink_buffer;
- sarif_builder (diagnostic_context &context,
+ sarif_builder (diagnostics::context &dc,
pretty_printer &printer,
const line_maps *line_maps,
std::unique_ptr<sarif_serialization_format> serialization_format,
@@ -763,7 +765,7 @@ public:
m_printer = &printer;
}
- const logical_location_manager *
+ const logical_locations::manager *
get_logical_location_manager () const
{
return m_logical_loc_mgr;
@@ -773,13 +775,13 @@ public:
set_main_input_filename (const char *name);
void on_report_diagnostic (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind,
- diagnostic_sarif_format_buffer *buffer);
- void emit_diagram (const diagnostic_diagram &diagram);
+ enum kind orig_diag_kind,
+ sarif_sink_buffer *buffer);
+ void emit_diagram (const diagram &d);
void end_group ();
void
- report_global_digraph (const diagnostics::digraphs::lazy_digraph &);
+ report_global_digraph (const lazily_created<digraphs::digraph> &);
std::unique_ptr<sarif_result> take_current_result ()
{
@@ -796,7 +798,7 @@ public:
std::unique_ptr<sarif_location>
make_location_object (sarif_location_manager *loc_mgr,
const rich_location &rich_loc,
- logical_location logical_loc,
+ logical_locations::key logical_loc,
enum diagnostic_artifact_role role);
std::unique_ptr<sarif_location>
make_location_object (sarif_location_manager &loc_mgr,
@@ -805,7 +807,7 @@ public:
std::unique_ptr<sarif_message>
make_message_object (const char *msg) const;
std::unique_ptr<sarif_message>
- make_message_object_for_diagram (const diagnostic_diagram &diagram);
+ make_message_object_for_diagram (const diagram &d);
std::unique_ptr<sarif_artifact_content>
maybe_make_artifact_content_object (const char *filename) const;
@@ -818,7 +820,7 @@ public:
return m_current_code_flow;
}
- diagnostic_context &get_context () const { return m_context; }
+ diagnostics::context &get_context () const { return m_context; }
pretty_printer *get_printer () const { return m_printer; }
token_printer &get_token_printer () { return m_token_printer; }
enum sarif_version get_version () const { return m_sarif_gen_opts.m_version; }
@@ -834,7 +836,7 @@ public:
const sarif_generation_options &get_opts () const { return m_sarif_gen_opts; }
std::unique_ptr<sarif_logical_location>
- make_minimal_sarif_logical_location (logical_location);
+ make_minimal_sarif_logical_location (logical_locations::key);
private:
class sarif_token_printer : public token_printer
@@ -852,7 +854,7 @@ private:
std::unique_ptr<sarif_result>
make_result_object (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind,
+ enum kind orig_diag_kind,
unsigned idx_within_parent);
void
add_any_include_chain (sarif_location_manager &loc_mgr,
@@ -860,22 +862,22 @@ private:
location_t where);
void
set_any_logical_locs_arr (sarif_location &location_obj,
- logical_location logical_loc);
+ logical_locations::key logical_loc);
std::unique_ptr<sarif_location>
make_location_object (sarif_location_manager &loc_mgr,
- const diagnostic_event &event,
+ const paths::event &event,
enum diagnostic_artifact_role role);
std::unique_ptr<sarif_code_flow>
make_code_flow_object (sarif_result &result,
unsigned idx_within_parent,
- const diagnostic_path &path);
+ const paths::path &path);
void
populate_thread_flow_location_object (sarif_result &result,
sarif_thread_flow_location &thread_flow_loc_obj,
- const diagnostic_event &event,
+ const paths::event &event,
int event_execution_idx);
std::unique_ptr<json::array>
- maybe_make_kinds_array (diagnostic_event::meaning m) const;
+ maybe_make_kinds_array (paths::event::meaning m) const;
std::unique_ptr<sarif_physical_location>
maybe_make_physical_location_object (location_t loc,
enum diagnostic_artifact_role role,
@@ -895,7 +897,7 @@ private:
make_region_object_for_hint (const fixit_hint &hint) const;
int
- ensure_sarif_logical_location_for (logical_location k);
+ ensure_sarif_logical_location_for (logical_locations::key k);
std::unique_ptr<sarif_multiformat_message_string>
make_multiformat_message_string (const char *msg) const;
@@ -916,7 +918,7 @@ private:
make_tool_component_reference_object_for_cwe () const;
std::unique_ptr<sarif_reporting_descriptor>
make_reporting_descriptor_object_for_warning (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind,
+ enum kind orig_diag_kind,
const char *option_text);
std::unique_ptr<sarif_reporting_descriptor>
make_reporting_descriptor_object_for_cwe_id (int cwe_id) const;
@@ -948,12 +950,12 @@ private:
std::unique_ptr<json::object>
make_stack_from_backtrace ();
- diagnostic_context &m_context;
+ diagnostics::context &m_context;
pretty_printer *m_printer;
const line_maps *m_line_maps;
sarif_token_printer m_token_printer;
- const logical_location_manager *m_logical_loc_mgr;
+ const logical_locations::manager *m_logical_loc_mgr;
/* The JSON object for the invocation object. */
std::unique_ptr<sarif_invocation> m_invocation_obj;
@@ -1060,10 +1062,10 @@ sarif_invocation::add_notification_for_ice (const diagnostic_info &diagnostic,
void
sarif_invocation::prepare_to_flush (sarif_builder &builder)
{
- const diagnostic_context &context = builder.get_context ();
+ const context &dc = builder.get_context ();
/* "executionSuccessful" property (SARIF v2.1.0 section 3.20.14). */
- if (context.execution_failed_p ())
+ if (dc.execution_failed_p ())
m_success = false;
set_bool ("executionSuccessful", m_success);
@@ -1072,7 +1074,7 @@ sarif_invocation::prepare_to_flush (sarif_builder &builder)
/* Call client hook, allowing it to create a custom property bag for
this object (SARIF v2.1.0 section 3.8) e.g. for recording time vars. */
- if (auto client_data_hooks = context.get_client_data_hooks ())
+ if (auto client_data_hooks = dc.get_client_data_hooks ())
client_data_hooks->add_sarif_invocation_properties (*this);
// "endTimeUtc" property (SARIF v2.1.0 section 3.20.8);
@@ -1305,15 +1307,15 @@ sarif_location_manager::process_worklist_item (sarif_builder &builder,
void
sarif_result::on_nested_diagnostic (const diagnostic_info &diagnostic,
- diagnostic_t /*orig_diag_kind*/,
+ enum kind /*orig_diag_kind*/,
sarif_builder &builder)
{
/* We don't yet generate meaningful logical locations for notes;
sometimes these will related to current_function_decl, but
often they won't. */
auto location_obj
- = builder.make_location_object (this, *diagnostic.richloc,
- logical_location (),
+ = builder.make_location_object (this, *diagnostic.m_richloc,
+ logical_locations::key (),
diagnostic_artifact_role::result_file);
auto message_obj
= builder.make_message_object (pp_formatted_text (builder.get_printer ()));
@@ -1336,11 +1338,11 @@ sarif_result::on_nested_diagnostic (const diagnostic_info &diagnostic,
(SARIF v2.1.0 section 3.28.5). */
void
-sarif_result::on_diagram (const diagnostic_diagram &diagram,
+sarif_result::on_diagram (const diagram &d,
sarif_builder &builder)
{
auto location_obj = std::make_unique<sarif_location> ();
- auto message_obj = builder.make_message_object_for_diagram (diagram);
+ auto message_obj = builder.make_message_object_for_diagram (d);
location_obj->set<sarif_message> ("message", std::move (message_obj));
add_related_location (std::move (location_obj), builder);
@@ -1572,8 +1574,8 @@ sarif_code_flow::sarif_code_flow (sarif_result &parent,
}
sarif_thread_flow &
-sarif_code_flow::get_or_append_thread_flow (const diagnostic_thread &thread,
- diagnostic_thread_id_t thread_id)
+sarif_code_flow::get_or_append_thread_flow (const paths::thread &thread,
+ paths::thread_id_t thread_id)
{
sarif_thread_flow **slot = m_thread_id_map.get (thread_id);
if (slot)
@@ -1589,7 +1591,7 @@ sarif_code_flow::get_or_append_thread_flow (const diagnostic_thread &thread,
}
sarif_thread_flow &
-sarif_code_flow::get_thread_flow (diagnostic_thread_id_t thread_id)
+sarif_code_flow::get_thread_flow (paths::thread_id_t thread_id)
{
sarif_thread_flow **slot = m_thread_id_map.get (thread_id);
gcc_assert (slot); // it must already have one
@@ -1603,7 +1605,7 @@ sarif_code_flow::add_location (sarif_thread_flow_location &tfl_obj)
}
sarif_thread_flow_location &
-sarif_code_flow::get_thread_flow_loc_obj (diagnostic_event_id_t event_id) const
+sarif_code_flow::get_thread_flow_loc_obj (paths::event_id_t event_id) const
{
gcc_assert (event_id.known_p ());
gcc_assert ((size_t)event_id.zero_based () < m_all_tfl_objs.size ());
@@ -1615,7 +1617,7 @@ sarif_code_flow::get_thread_flow_loc_obj (diagnostic_event_id_t event_id) const
/* class sarif_thread_flow : public sarif_object. */
sarif_thread_flow::sarif_thread_flow (sarif_code_flow &parent,
- const diagnostic_thread &thread,
+ const paths::thread &thread,
unsigned idx_within_parent)
: m_parent (parent),
m_idx_within_parent (idx_within_parent)
@@ -1650,19 +1652,19 @@ sarif_thread_flow::add_location ()
/* sarif_builder's ctor. */
-sarif_builder::sarif_builder (diagnostic_context &context,
+sarif_builder::sarif_builder (diagnostics::context &dc,
pretty_printer &printer,
const line_maps *line_maps,
std::unique_ptr<sarif_serialization_format> serialization_format,
const sarif_generation_options &sarif_gen_opts)
-: m_context (context),
+: m_context (dc),
m_printer (&printer),
m_line_maps (line_maps),
m_token_printer (*this),
m_logical_loc_mgr (nullptr),
m_invocation_obj
(std::make_unique<sarif_invocation> (*this,
- context.get_original_argv ())),
+ dc.get_original_argv ())),
m_results_array (new json::array ()),
m_cur_group_result (nullptr),
m_seen_any_relative_paths (false),
@@ -1672,7 +1674,7 @@ sarif_builder::sarif_builder (diagnostic_context &context,
(std::make_unique<sarif_array_of_unique<sarif_logical_location>> ()),
m_run_graphs
(std::make_unique<sarif_array_of_unique<sarif_graph>> ()),
- m_tabstop (context.m_tabstop),
+ m_tabstop (dc.m_tabstop),
m_serialization_format (std::move (serialization_format)),
m_sarif_gen_opts (sarif_gen_opts),
m_next_result_idx (0),
@@ -1681,7 +1683,7 @@ sarif_builder::sarif_builder (diagnostic_context &context,
gcc_assert (m_line_maps);
gcc_assert (m_serialization_format);
- if (auto client_data_hooks = context.get_client_data_hooks ())
+ if (auto client_data_hooks = dc.get_client_data_hooks ())
m_logical_loc_mgr = client_data_hooks->get_logical_location_manager ();
}
@@ -1734,10 +1736,10 @@ bt_callback (void *data, uintptr_t pc, const char *filename, int lineno,
if (filename == nullptr && function == nullptr)
return 0;
- /* Skip functions in diagnostic.cc or diagnostic-global-context.cc. */
+ /* Skip functions in context.cc or diagnostic-global-context.cc. */
if (closure->m_frames_arr->size () == 0
&& filename != nullptr
- && (strcmp (lbasename (filename), "diagnostic.cc") == 0
+ && (strcmp (lbasename (filename), "context.cc") == 0
|| strcmp (lbasename (filename),
"diagnostic-global-context.cc") == 0))
return 0;
@@ -1838,12 +1840,12 @@ sarif_builder::set_main_input_filename (const char *name)
void
sarif_builder::on_report_diagnostic (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind,
- diagnostic_sarif_format_buffer *buffer)
+ enum kind orig_diag_kind,
+ sarif_sink_buffer *buffer)
{
pp_output_formatted_text (m_printer, m_context.get_urlifier ());
- if (diagnostic.kind == DK_ICE || diagnostic.kind == DK_ICE_NOBT)
+ if (diagnostic.m_kind == kind::ice || diagnostic.m_kind == kind::ice_nobt)
{
std::unique_ptr<json::object> stack = make_stack_from_backtrace ();
m_invocation_obj->add_notification_for_ice (diagnostic, *this,
@@ -1881,15 +1883,15 @@ sarif_builder::on_report_diagnostic (const diagnostic_info &diagnostic,
}
}
-/* Implementation of diagnostic_context::m_diagrams.m_emission_cb
+/* Implementation of diagnostics::context::m_diagrams.m_emission_cb
for SARIF output. */
void
-sarif_builder::emit_diagram (const diagnostic_diagram &diagram)
+sarif_builder::emit_diagram (const diagram &d)
{
/* We must be within the emission of a top-level diagnostic. */
gcc_assert (m_cur_group_result);
- m_cur_group_result->on_diagram (diagram, *this);
+ m_cur_group_result->on_diagram (d, *this);
}
/* Implementation of "end_group_cb" for SARIF output. */
@@ -1906,9 +1908,9 @@ sarif_builder::end_group ()
void
sarif_builder::
-report_global_digraph (const diagnostics::digraphs::lazy_digraph &ldg)
+report_global_digraph (const lazily_created<digraphs::digraph> &ldg)
{
- auto &dg = ldg.get_or_create_digraph ();
+ auto &dg = ldg.get_or_create ();
/* Presumably the location manager must be nullptr; see
https://github.com/oasis-tcs/sarif-spec/issues/712 */
@@ -1947,16 +1949,16 @@ sarif_builder::flush_to_file (FILE *outf)
Return nullptr if there isn't one. */
static const char *
-maybe_get_sarif_level (diagnostic_t diag_kind)
+maybe_get_sarif_level (enum kind diag_kind)
{
switch (diag_kind)
{
- case DK_WARNING:
+ case kind::warning:
return "warning";
- case DK_ERROR:
+ case kind::error:
return "error";
- case DK_NOTE:
- case DK_ANACHRONISM:
+ case kind::note:
+ case kind::anachronism:
return "note";
default:
return nullptr;
@@ -1968,10 +1970,10 @@ maybe_get_sarif_level (diagnostic_t diag_kind)
have anything better to use. */
static char *
-make_rule_id_for_diagnostic_kind (diagnostic_t diag_kind)
+make_rule_id_for_diagnostic_kind (enum kind diag_kind)
{
/* Lose the trailing ": ". */
- const char *kind_text = get_diagnostic_kind_text (diag_kind);
+ const char *kind_text = get_text_for_kind (diag_kind);
size_t len = strlen (kind_text);
gcc_assert (len > 2);
gcc_assert (kind_text[len - 2] == ':');
@@ -1985,7 +1987,7 @@ make_rule_id_for_diagnostic_kind (diagnostic_t diag_kind)
std::unique_ptr<sarif_result>
sarif_builder::make_result_object (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind,
+ enum kind orig_diag_kind,
unsigned idx_within_parent)
{
auto result_obj = std::make_unique<sarif_result> (idx_within_parent);
@@ -1993,8 +1995,8 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
/* "ruleId" property (SARIF v2.1.0 section 3.27.5). */
/* Ideally we'd have an option_name for these. */
if (char *option_text
- = m_context.make_option_name (diagnostic.option_id,
- orig_diag_kind, diagnostic.kind))
+ = m_context.make_option_name (diagnostic.m_option_id,
+ orig_diag_kind, diagnostic.m_kind))
{
/* Lazily create reportingDescriptor objects for and add to m_rules_arr.
Set ruleId referencing them. */
@@ -2024,10 +2026,10 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
free (rule_id);
}
- if (diagnostic.metadata)
+ if (diagnostic.m_metadata)
{
/* "taxa" property (SARIF v2.1.0 section 3.27.8). */
- if (int cwe_id = diagnostic.metadata->get_cwe ())
+ if (int cwe_id = diagnostic.m_metadata->get_cwe ())
{
auto taxa_arr = std::make_unique<json::array> ();
taxa_arr->append<sarif_reporting_descriptor_reference>
@@ -2035,13 +2037,13 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
result_obj->set<json::array> ("taxa", std::move (taxa_arr));
}
- diagnostic.metadata->maybe_add_sarif_properties (*result_obj);
+ diagnostic.m_metadata->maybe_add_sarif_properties (*result_obj);
- /* We don't yet support diagnostic_metadata::rule. */
+ /* We don't yet support diagnostics::metadata::rule. */
}
/* "level" property (SARIF v2.1.0 section 3.27.10). */
- if (const char *sarif_level = maybe_get_sarif_level (diagnostic.kind))
+ if (const char *sarif_level = maybe_get_sarif_level (diagnostic.m_kind))
result_obj->set_string ("level", sarif_level);
/* "message" property (SARIF v2.1.0 section 3.27.11). */
@@ -2058,7 +2060,7 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
diagnostic_artifact_role::result_file));
/* "codeFlows" property (SARIF v2.1.0 section 3.27.18). */
- if (const diagnostic_path *path = diagnostic.richloc->get_path ())
+ if (const paths::path *path = diagnostic.m_richloc->get_path ())
{
auto code_flows_arr = std::make_unique<json::array> ();
const unsigned code_flow_index = 0;
@@ -2070,10 +2072,10 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
}
// "graphs" property (SARIF v2.1.0 section 3.27.19). */
- if (diagnostic.metadata)
- if (auto ldg = diagnostic.metadata->get_lazy_digraphs ())
+ if (diagnostic.m_metadata)
+ if (auto ldg = diagnostic.m_metadata->get_lazy_digraphs ())
{
- auto &digraphs = ldg->get_or_create_digraphs ();
+ auto &digraphs = ldg->get_or_create ();
auto graphs_arr = std::make_unique<json::array> ();
for (auto &iter : digraphs)
graphs_arr->append (make_sarif_graph (*iter, this,
@@ -2087,7 +2089,7 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
group. */
/* "fixes" property (SARIF v2.1.0 section 3.27.30). */
- const rich_location *richloc = diagnostic.richloc;
+ const rich_location *richloc = diagnostic.m_richloc;
if (richloc->get_num_fixit_hints ())
{
auto fix_arr = std::make_unique<json::array> ();
@@ -2104,7 +2106,7 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
std::unique_ptr<sarif_reporting_descriptor>
sarif_builder::
make_reporting_descriptor_object_for_warning (const diagnostic_info &diagnostic,
- diagnostic_t /*orig_diag_kind*/,
+ enum kind /*orig_diag_kind*/,
const char *option_text)
{
auto reporting_desc = std::make_unique<sarif_reporting_descriptor> ();
@@ -2116,7 +2118,7 @@ make_reporting_descriptor_object_for_warning (const diagnostic_info &diagnostic,
it seems redundant compared to "id". */
/* "helpUri" property (SARIF v2.1.0 section 3.49.12). */
- if (char *option_url = m_context.make_option_url (diagnostic.option_id))
+ if (char *option_url = m_context.make_option_url (diagnostic.m_option_id))
{
reporting_desc->set_string ("helpUri", option_url);
free (option_url);
@@ -2204,12 +2206,12 @@ sarif_builder::make_locations_arr (sarif_location_manager &loc_mgr,
enum diagnostic_artifact_role role)
{
auto locations_arr = std::make_unique<json::array> ();
- logical_location logical_loc;
+ logical_locations::key logical_loc;
if (auto client_data_hooks = m_context.get_client_data_hooks ())
logical_loc = client_data_hooks->get_current_logical_location ();
auto location_obj
- = make_location_object (&loc_mgr, *diagnostic.richloc, logical_loc, role);
+ = make_location_object (&loc_mgr, *diagnostic.m_richloc, logical_loc, role);
/* Don't add entirely empty location objects to the array. */
if (!location_obj->is_empty ())
locations_arr->append<sarif_location> (std::move (location_obj));
@@ -2224,7 +2226,7 @@ sarif_builder::make_locations_arr (sarif_location_manager &loc_mgr,
void
sarif_builder::
set_any_logical_locs_arr (sarif_location &location_obj,
- logical_location logical_loc)
+ logical_locations::key logical_loc)
{
if (!logical_loc)
return;
@@ -2250,7 +2252,7 @@ set_any_logical_locs_arr (sarif_location &location_obj,
std::unique_ptr<sarif_location>
sarif_builder::make_location_object (sarif_location_manager *loc_mgr,
const rich_location &rich_loc,
- logical_location logical_loc,
+ logical_locations::key logical_loc,
enum diagnostic_artifact_role role)
{
class escape_nonascii_renderer : public content_renderer
@@ -2265,21 +2267,22 @@ sarif_builder::make_location_object (sarif_location_manager *loc_mgr,
std::unique_ptr<sarif_multiformat_message_string>
render (const sarif_builder &builder) const final override
{
- diagnostic_context dc;
+ diagnostics::context dc;
diagnostic_initialize (&dc, 0);
- dc.m_source_printing.enabled = true;
- dc.m_source_printing.colorize_source_p = false;
- dc.m_source_printing.show_labels_p = true;
- dc.m_source_printing.show_line_numbers_p = true;
+ auto &source_printing_opts = dc.get_source_printing_options ();
+ source_printing_opts.enabled = true;
+ source_printing_opts.colorize_source_p = false;
+ source_printing_opts.show_labels_p = true;
+ source_printing_opts.show_line_numbers_p = true;
rich_location my_rich_loc (m_richloc);
my_rich_loc.set_escape_on_output (true);
- diagnostic_source_print_policy source_policy (dc);
+ source_print_policy source_policy (dc);
dc.set_escape_format (m_escape_format);
- diagnostic_text_output_format text_output (dc);
+ text_sink text_output (dc);
source_policy.print (*text_output.get_printer (),
- my_rich_loc, DK_ERROR, nullptr);
+ my_rich_loc, kind::error, nullptr);
const char *buf = pp_formatted_text (text_output.get_printer ());
std::unique_ptr<sarif_multiformat_message_string> result
@@ -2376,7 +2379,7 @@ sarif_builder::make_location_object (sarif_location_manager *loc_mgr,
/* If WHERE was #included from somewhere, add a worklist item
to LOC_MGR to lazily add a location for the #include location,
and relationships between it and the LOCATION_OBJ.
- Compare with diagnostic_context::report_current_module, but rather
+ Compare with diagnostics::context::report_current_module, but rather
than iterating the current chain, we add the next edge and iterate
in the worklist, so that edges are only added once. */
@@ -2428,11 +2431,11 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
}
/* Make a "location" object (SARIF v2.1.0 section 3.28) for EVENT
- within a diagnostic_path. */
+ within a paths::path. */
std::unique_ptr<sarif_location>
sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
- const diagnostic_event &event,
+ const paths::event &event,
enum diagnostic_artifact_role role)
{
auto location_obj = std::make_unique<sarif_location> ();
@@ -2445,7 +2448,7 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
std::move (phs_loc_obj));
/* "logicalLocations" property (SARIF v2.1.0 section 3.28.4). */
- logical_location logical_loc = event.get_logical_location ();
+ logical_locations::key logical_loc = event.get_logical_location ();
set_any_logical_locs_arr (*location_obj, logical_loc);
/* "message" property (SARIF v2.1.0 section 3.28.5). */
@@ -2766,57 +2769,59 @@ sarif_builder::make_region_object_for_hint (const fixit_hint &hint) const
Return nullptr if unknown. */
static const char *
-maybe_get_sarif_kind (enum logical_location_kind kind)
+maybe_get_sarif_kind (enum logical_locations::kind kind)
{
+ using namespace logical_locations;
+
switch (kind)
{
default:
gcc_unreachable ();
- case logical_location_kind::unknown:
+ case logical_locations::kind::unknown:
return nullptr;
/* Kinds within executable code. */
- case logical_location_kind::function:
+ case logical_locations::kind::function:
return "function";
- case logical_location_kind::member:
+ case logical_locations::kind::member:
return "member";
- case logical_location_kind::module_:
+ case logical_locations::kind::module_:
return "module";
- case logical_location_kind::namespace_:
+ case logical_locations::kind::namespace_:
return "namespace";
- case logical_location_kind::type:
+ case logical_locations::kind::type:
return "type";
- case logical_location_kind::return_type:
+ case logical_locations::kind::return_type:
return "returnType";
- case logical_location_kind::parameter:
+ case logical_locations::kind::parameter:
return "parameter";
- case logical_location_kind::variable:
+ case logical_locations::kind::variable:
return "variable";
/* Kinds within XML or HTML documents. */
- case logical_location_kind::element:
+ case logical_locations::kind::element:
return "element";
- case logical_location_kind::attribute:
+ case logical_locations::kind::attribute:
return "attribute";
- case logical_location_kind::text:
+ case logical_locations::kind::text:
return "text";
- case logical_location_kind::comment:
+ case logical_locations::kind::comment:
return "comment";
- case logical_location_kind::processing_instruction:
+ case logical_locations::kind::processing_instruction:
return "processingInstruction";
- case logical_location_kind::dtd:
+ case logical_locations::kind::dtd:
return "dtd";
- case logical_location_kind::declaration:
+ case logical_locations::kind::declaration:
return "declaration";
/* Kinds within JSON documents. */
- case logical_location_kind::object:
+ case logical_locations::kind::object:
return "object";
- case logical_location_kind::array:
+ case logical_locations::kind::array:
return "array";
- case logical_location_kind::property:
+ case logical_locations::kind::property:
return "property";
- case logical_location_kind::value:
+ case logical_locations::kind::value:
return "value";
}
}
@@ -2828,7 +2833,7 @@ maybe_get_sarif_kind (enum logical_location_kind kind)
void
sarif_property_bag::set_logical_location (const char *property_name,
sarif_builder &builder,
- logical_location logical_loc)
+ logical_locations::key logical_loc)
{
set<sarif_logical_location>
(property_name,
@@ -2836,7 +2841,7 @@ sarif_property_bag::set_logical_location (const char *property_name,
}
static void
-copy_any_property_bag (const diagnostics::digraphs::object &input_obj,
+copy_any_property_bag (const digraphs::object &input_obj,
sarif_object &output_obj)
{
if (input_obj.get_property_bag ())
@@ -2853,7 +2858,7 @@ copy_any_property_bag (const diagnostics::digraphs::object &input_obj,
}
std::unique_ptr<sarif_graph>
-make_sarif_graph (const diagnostics::digraphs::digraph &g,
+make_sarif_graph (const digraphs::digraph &g,
sarif_builder *builder,
sarif_location_manager *sarif_location_mgr)
{
@@ -2887,7 +2892,7 @@ make_sarif_graph (const diagnostics::digraphs::digraph &g,
}
std::unique_ptr<sarif_node>
-make_sarif_node (const diagnostics::digraphs::node &n,
+make_sarif_node (const digraphs::node &n,
sarif_builder *builder,
sarif_location_manager *sarif_location_mgr)
{
@@ -2936,7 +2941,7 @@ make_sarif_node (const diagnostics::digraphs::node &n,
}
std::unique_ptr<sarif_edge>
-make_sarif_edge (const diagnostics::digraphs::edge &e,
+make_sarif_edge (const digraphs::edge &e,
sarif_builder *builder)
{
auto result = std::make_unique<sarif_edge> ();
@@ -2965,7 +2970,7 @@ void
sarif_property_bag::set_graph (const char *property_name,
sarif_builder &builder,
sarif_location_manager *sarif_location_mgr,
- const diagnostics::digraphs::digraph &g)
+ const digraphs::digraph &g)
{
set<sarif_graph> (property_name,
make_sarif_graph (g, &builder, sarif_location_mgr));
@@ -2977,7 +2982,7 @@ sarif_property_bag::set_graph (const char *property_name,
int
sarif_builder::
-ensure_sarif_logical_location_for (logical_location k)
+ensure_sarif_logical_location_for (logical_locations::key k)
{
gcc_assert (m_logical_loc_mgr);
@@ -2995,7 +3000,7 @@ ensure_sarif_logical_location_for (logical_location k)
sarif_logical_loc->set_string ("decoratedName", internal_name);
/* "kind" property (SARIF v2.1.0 section 3.33.7). */
- enum logical_location_kind kind = m_logical_loc_mgr->get_kind (k);
+ enum logical_locations::kind kind = m_logical_loc_mgr->get_kind (k);
if (const char *sarif_kind_str = maybe_get_sarif_kind (kind))
sarif_logical_loc->set_string ("kind", sarif_kind_str);
@@ -3021,7 +3026,7 @@ ensure_sarif_logical_location_for (logical_location k)
std::unique_ptr<sarif_logical_location>
sarif_builder::
-make_minimal_sarif_logical_location (logical_location logical_loc)
+make_minimal_sarif_logical_location (logical_locations::key logical_loc)
{
gcc_assert (m_logical_loc_mgr);
@@ -3046,7 +3051,7 @@ make_minimal_sarif_logical_location (logical_location logical_loc)
label_text
make_sarif_url_for_event (const sarif_code_flow *code_flow,
- diagnostic_event_id_t event_id)
+ paths::event_id_t event_id)
{
gcc_assert (event_id.known_p ());
@@ -3080,7 +3085,7 @@ make_sarif_url_for_event (const sarif_code_flow *code_flow,
std::unique_ptr<sarif_code_flow>
sarif_builder::make_code_flow_object (sarif_result &result,
unsigned idx_within_parent,
- const diagnostic_path &path)
+ const paths::path &path)
{
auto code_flow_obj
= std::make_unique <sarif_code_flow> (result, idx_within_parent);
@@ -3092,8 +3097,8 @@ sarif_builder::make_code_flow_object (sarif_result &result,
SARIF file. */
for (unsigned i = 0; i < path.num_events (); i++)
{
- const diagnostic_event &event = path.get_event (i);
- const diagnostic_thread_id_t thread_id = event.get_thread_id ();
+ const paths::event &event = path.get_event (i);
+ const paths::thread_id_t thread_id = event.get_thread_id ();
sarif_thread_flow &thread_flow_obj
= code_flow_obj->get_or_append_thread_flow (path.get_thread (thread_id),
@@ -3105,7 +3110,7 @@ sarif_builder::make_code_flow_object (sarif_result &result,
m_current_code_flow = code_flow_obj.get ();
for (unsigned i = 0; i < path.num_events (); i++)
{
- const diagnostic_event &event = path.get_event (i);
+ const paths::event &event = path.get_event (i);
sarif_thread_flow_location &thread_flow_loc_obj
= code_flow_obj->get_thread_flow_loc_obj (i);
populate_thread_flow_location_object (result,
@@ -3125,10 +3130,10 @@ void
sarif_builder::
populate_thread_flow_location_object (sarif_result &result,
sarif_thread_flow_location &tfl_obj,
- const diagnostic_event &ev,
+ const paths::event &ev,
int event_execution_idx)
{
- /* Give diagnostic_event subclasses a chance to add custom properties
+ /* Give paths::event subclasses a chance to add custom properties
via a property bag. */
ev.maybe_add_sarif_properties (*this, tfl_obj);
@@ -3137,7 +3142,7 @@ populate_thread_flow_location_object (sarif_result &result,
{
sarif_property_bag &props = tfl_obj.get_or_create_properties ();
-#define PROPERTY_PREFIX "gcc/diagnostic_event/"
+#define PROPERTY_PREFIX "gcc/diagnostics/paths/event/"
props.set_graph (PROPERTY_PREFIX "state_graph",
*this,
/* Use RESULT for any related locations in the graph's
@@ -3156,7 +3161,7 @@ populate_thread_flow_location_object (sarif_result &result,
make_location_object (result, ev, diagnostic_artifact_role::traced_file));
/* "kinds" property (SARIF v2.1.0 section 3.38.8). */
- diagnostic_event::meaning m = ev.get_meaning ();
+ paths::event::meaning m = ev.get_meaning ();
if (auto kinds_arr = maybe_make_kinds_array (m))
tfl_obj.set<json::array> ("kinds", std::move (kinds_arr));
@@ -3179,22 +3184,25 @@ populate_thread_flow_location_object (sarif_result &result,
Otherwise, return nullptr. */
std::unique_ptr<json::array>
-sarif_builder::maybe_make_kinds_array (diagnostic_event::meaning m) const
+sarif_builder::
+maybe_make_kinds_array (paths::event::meaning m) const
{
- if (m.m_verb == diagnostic_event::verb::unknown
- && m.m_noun == diagnostic_event::noun::unknown
- && m.m_property == diagnostic_event::property::unknown)
+ using namespace paths;
+
+ if (m.m_verb == event::verb::unknown
+ && m.m_noun == event::noun::unknown
+ && m.m_property == event::property::unknown)
return nullptr;
auto kinds_arr = std::make_unique<json::array> ();
if (const char *verb_str
- = diagnostic_event::meaning::maybe_get_verb_str (m.m_verb))
+ = event::meaning::maybe_get_verb_str (m.m_verb))
kinds_arr->append_string (verb_str);
if (const char *noun_str
- = diagnostic_event::meaning::maybe_get_noun_str (m.m_noun))
+ = event::meaning::maybe_get_noun_str (m.m_noun))
kinds_arr->append_string (noun_str);
if (const char *property_str
- = diagnostic_event::meaning::maybe_get_property_str (m.m_property))
+ = event::meaning::maybe_get_property_str (m.m_property))
kinds_arr->append_string (property_str);
return kinds_arr;
}
@@ -3245,18 +3253,18 @@ sarif_builder::make_message_object (const char *msg) const
return message_obj;
}
-/* Make a "message" object (SARIF v2.1.0 section 3.11) for DIAGRAM.
+/* Make a "message" object (SARIF v2.1.0 section 3.11) for D.
We emit the diagram as a code block within the Markdown part
of the message. */
std::unique_ptr<sarif_message>
-sarif_builder::make_message_object_for_diagram (const diagnostic_diagram &diagram)
+sarif_builder::make_message_object_for_diagram (const diagram &d)
{
auto message_obj = std::make_unique<sarif_message> ();
/* "text" property (SARIF v2.1.0 section 3.11.8). */
set_string_property_escaping_braces (*message_obj,
- "text", diagram.get_alt_text ());
+ "text", d.get_alt_text ());
pretty_printer *const pp = m_printer;
char *saved_prefix = pp_take_prefix (pp);
@@ -3265,7 +3273,7 @@ sarif_builder::make_message_object_for_diagram (const diagnostic_diagram &diagra
/* "To produce a code block in Markdown, simply indent every line of
the block by at least 4 spaces or 1 tab."
Here we use 4 spaces. */
- diagram.get_canvas ().print_to_pp (pp, " ");
+ d.get_canvas ().print_to_pp (pp, " ");
pp_set_prefix (pp, saved_prefix);
/* "markdown" property (SARIF v2.1.0 section 3.11.9). */
@@ -3438,7 +3446,8 @@ sarif_builder::make_tool_object ()
class my_plugin_visitor : public client_version_info :: plugin_visitor
{
public:
- void on_plugin (const diagnostic_client_plugin_info &p) final override
+ void
+ on_plugin (const client_plugin_info &p) final override
{
/* Create a "toolComponent" object (SARIF v2.1.0 section 3.19)
for the plugin. */
@@ -3789,12 +3798,12 @@ sarif_builder::make_artifact_content_object (const char *text) const
return content_obj;
}
-/* class diagnostic_sarif_format_buffer : public diagnostic_per_format_buffer. */
+/* class sarif_sink_buffer : public per_sink_buffer. */
void
-diagnostic_sarif_format_buffer::dump (FILE *out, int indent) const
+sarif_sink_buffer::dump (FILE *out, int indent) const
{
- fprintf (out, "%*sdiagnostic_sarif_format_buffer:\n", indent, "");
+ fprintf (out, "%*ssarif_sink_buffer:\n", indent, "");
int idx = 0;
for (auto &result : m_results)
{
@@ -3806,29 +3815,29 @@ diagnostic_sarif_format_buffer::dump (FILE *out, int indent) const
}
bool
-diagnostic_sarif_format_buffer::empty_p () const
+sarif_sink_buffer::empty_p () const
{
return m_results.empty ();
}
void
-diagnostic_sarif_format_buffer::move_to (diagnostic_per_format_buffer &base)
+sarif_sink_buffer::move_to (per_sink_buffer &base)
{
- diagnostic_sarif_format_buffer &dest
- = static_cast<diagnostic_sarif_format_buffer &> (base);
+ sarif_sink_buffer &dest
+ = static_cast<sarif_sink_buffer &> (base);
for (auto &&result : m_results)
dest.m_results.push_back (std::move (result));
m_results.clear ();
}
void
-diagnostic_sarif_format_buffer::clear ()
+sarif_sink_buffer::clear ()
{
m_results.clear ();
}
void
-diagnostic_sarif_format_buffer::flush ()
+sarif_sink_buffer::flush ()
{
for (auto &&result : m_results)
{
@@ -3838,10 +3847,10 @@ diagnostic_sarif_format_buffer::flush ()
m_results.clear ();
}
-class sarif_output_format : public diagnostic_output_format
+class sarif_sink : public sink
{
public:
- ~sarif_output_format ()
+ ~sarif_sink ()
{
/* Any sarifResult objects should have been handled by now.
If not, then something's gone wrong with diagnostic
@@ -3853,8 +3862,8 @@ public:
void dump (FILE *out, int indent) const override
{
- fprintf (out, "%*ssarif_output_format\n", indent, "");
- diagnostic_output_format::dump (out, indent);
+ fprintf (out, "%*ssarif_sink\n", indent, "");
+ sink::dump (out, indent);
}
void
@@ -3863,15 +3872,15 @@ public:
m_builder.set_main_input_filename (name);
}
- std::unique_ptr<diagnostic_per_format_buffer>
- make_per_format_buffer () final override
+ std::unique_ptr<per_sink_buffer>
+ make_per_sink_buffer () final override
{
- return std::make_unique<diagnostic_sarif_format_buffer> (m_builder);
+ return std::make_unique<sarif_sink_buffer> (m_builder);
}
- void set_buffer (diagnostic_per_format_buffer *base_buffer) final override
+ void set_buffer (per_sink_buffer *base_buffer) final override
{
- diagnostic_sarif_format_buffer *buffer
- = static_cast<diagnostic_sarif_format_buffer *> (base_buffer);
+ sarif_sink_buffer *buffer
+ = static_cast<sarif_sink_buffer *> (base_buffer);
m_buffer = buffer;
}
@@ -3907,13 +3916,13 @@ public:
}
void
on_report_diagnostic (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind) final override
+ enum kind orig_diag_kind) final override
{
m_builder.on_report_diagnostic (diagnostic, orig_diag_kind, m_buffer);
}
- void on_diagram (const diagnostic_diagram &diagram) final override
+ void on_diagram (const diagram &d) final override
{
- m_builder.emit_diagram (diagram);
+ m_builder.emit_diagram (d);
}
void after_diagnostic (const diagnostic_info &) final override
{
@@ -3921,9 +3930,10 @@ public:
}
void
- report_global_digraph (const diagnostics::digraphs::lazy_digraph &lazy_digraph) final override
+ report_global_digraph (const lazily_created<digraphs::digraph> &ldg)
+ final override
{
- m_builder.report_global_digraph (lazy_digraph);
+ m_builder.report_global_digraph (ldg);
}
sarif_builder &get_builder () { return m_builder; }
@@ -3932,34 +3942,34 @@ public:
sarif_result &get_result (size_t idx) { return m_builder.get_result (idx); }
protected:
- sarif_output_format (diagnostic_context &context,
- const line_maps *line_maps,
- std::unique_ptr<sarif_serialization_format> serialization_format,
- const sarif_generation_options &sarif_gen_opts)
- : diagnostic_output_format (context),
- m_builder (context, *get_printer (), line_maps,
+ sarif_sink (context &dc,
+ const line_maps *line_maps,
+ std::unique_ptr<sarif_serialization_format> serialization_format,
+ const sarif_generation_options &sarif_gen_opts)
+ : sink (dc),
+ m_builder (dc, *get_printer (), line_maps,
std::move (serialization_format), sarif_gen_opts),
m_buffer (nullptr)
{}
sarif_builder m_builder;
- diagnostic_sarif_format_buffer *m_buffer;
+ sarif_sink_buffer *m_buffer;
};
-class sarif_stream_output_format : public sarif_output_format
+class sarif_stream_sink : public sarif_sink
{
public:
- sarif_stream_output_format (diagnostic_context &context,
- const line_maps *line_maps,
- std::unique_ptr<sarif_serialization_format> serialization_format,
- const sarif_generation_options &sarif_gen_opts,
- FILE *stream)
- : sarif_output_format (context, line_maps,
- std::move (serialization_format), sarif_gen_opts),
+ sarif_stream_sink (context &dc,
+ const line_maps *line_maps,
+ std::unique_ptr<sarif_serialization_format> serialization_format,
+ const sarif_generation_options &sarif_gen_opts,
+ FILE *stream)
+ : sarif_sink (dc, line_maps,
+ std::move (serialization_format), sarif_gen_opts),
m_stream (stream)
{
}
- ~sarif_stream_output_format ()
+ ~sarif_stream_sink ()
{
m_builder.flush_to_file (m_stream);
}
@@ -3971,31 +3981,32 @@ private:
FILE *m_stream;
};
-class sarif_file_output_format : public sarif_output_format
+class sarif_file_sink : public sarif_sink
{
public:
- sarif_file_output_format (diagnostic_context &context,
- const line_maps *line_maps,
- std::unique_ptr<sarif_serialization_format> serialization_format,
- const sarif_generation_options &sarif_gen_opts,
- diagnostic_output_file output_file)
- : sarif_output_format (context, line_maps,
- std::move (serialization_format), sarif_gen_opts),
- m_output_file (std::move (output_file))
+ sarif_file_sink (context &dc,
+ const line_maps *line_maps,
+ std::unique_ptr<sarif_serialization_format> serialization_format,
+ const sarif_generation_options &sarif_gen_opts,
+ output_file output_file_)
+ : sarif_sink (dc, line_maps,
+ std::move (serialization_format),
+ sarif_gen_opts),
+ m_output_file (std::move (output_file_))
{
gcc_assert (m_output_file.get_open_file ());
gcc_assert (m_output_file.get_filename ());
}
- ~sarif_file_output_format ()
+ ~sarif_file_sink ()
{
m_builder.flush_to_file (m_output_file.get_open_file ());
}
void dump (FILE *out, int indent) const override
{
- fprintf (out, "%*ssarif_file_output_format: %s\n",
+ fprintf (out, "%*ssarif_file_sink: %s\n",
indent, "",
m_output_file.get_filename ());
- diagnostic_output_format::dump (out, indent);
+ sink::dump (out, indent);
}
bool machine_readable_stderr_p () const final override
{
@@ -4003,7 +4014,7 @@ public:
}
private:
- diagnostic_output_file m_output_file;
+ output_file m_output_file;
};
/* Print the start of an embedded link to PP, as per 3.11.6. */
@@ -4126,52 +4137,52 @@ sarif_builder::sarif_token_printer::print_tokens (pretty_printer *pp,
to a file).
Return a reference to *FMT. */
-static diagnostic_output_format &
-diagnostic_output_format_init_sarif (diagnostic_context &context,
- std::unique_ptr<sarif_output_format> fmt)
+static sink &
+init_sarif_sink (context &dc,
+ std::unique_ptr<sarif_sink> fmt)
{
gcc_assert (fmt);
- diagnostic_output_format &out = *fmt;
+ sink &out = *fmt;
fmt->update_printer ();
- context.set_output_format (std::move (fmt));
+ dc.set_sink (std::move (fmt));
return out;
}
-/* Populate CONTEXT in preparation for SARIF output to stderr.
+/* Populate DC in preparation for SARIF output to stderr.
Return a reference to the new sink. */
-diagnostic_output_format &
-diagnostic_output_format_init_sarif_stderr (diagnostic_context &context,
- const line_maps *line_maps,
- bool formatted)
+sink &
+init_sarif_stderr (context &dc,
+ const line_maps *line_maps,
+ bool formatted)
{
gcc_assert (line_maps);
const sarif_generation_options sarif_gen_opts;
auto serialization
= std::make_unique<sarif_serialization_format_json> (formatted);
- return diagnostic_output_format_init_sarif
- (context,
- std::make_unique<sarif_stream_output_format> (context,
- line_maps,
- std::move (serialization),
- sarif_gen_opts,
- stderr));
+ return init_sarif_sink
+ (dc,
+ std::make_unique<sarif_stream_sink> (dc,
+ line_maps,
+ std::move (serialization),
+ sarif_gen_opts,
+ stderr));
}
/* Attempt to open "BASE_FILE_NAME""EXTENSION" for writing.
- Return a non-null diagnostic_output_file,
- or return a null diagnostic_output_file and complain to CONTEXT
+ Return a non-null output_file,
+ or return a null output_file and complain to DC
using LINE_MAPS. */
-diagnostic_output_file
-diagnostic_output_file::try_to_open (diagnostic_context &context,
- line_maps *line_maps,
- const char *base_file_name,
- const char *extension,
- bool is_binary)
+output_file
+output_file::try_to_open (context &dc,
+ line_maps *line_maps,
+ const char *base_file_name,
+ const char *extension,
+ bool is_binary)
{
gcc_assert (extension);
gcc_assert (extension[0] == '.');
@@ -4179,10 +4190,10 @@ diagnostic_output_file::try_to_open (diagnostic_context &context,
if (!base_file_name)
{
rich_location richloc (line_maps, UNKNOWN_LOCATION);
- context.emit_diagnostic_with_group
- (DK_ERROR, richloc, nullptr, 0,
+ dc.emit_diagnostic_with_group
+ (kind::error, richloc, nullptr, 0,
"unable to determine filename for SARIF output");
- return diagnostic_output_file ();
+ return output_file ();
}
label_text filename = label_text::take (concat (base_file_name,
@@ -4192,25 +4203,25 @@ diagnostic_output_file::try_to_open (diagnostic_context &context,
if (!outf)
{
rich_location richloc (line_maps, UNKNOWN_LOCATION);
- context.emit_diagnostic_with_group
- (DK_ERROR, richloc, nullptr, 0,
+ dc.emit_diagnostic_with_group
+ (kind::error, richloc, nullptr, 0,
"unable to open %qs for diagnostic output: %m",
filename.get ());
- return diagnostic_output_file ();
+ return output_file ();
}
- return diagnostic_output_file (outf, true, std::move (filename));
+ return output_file (outf, true, std::move (filename));
}
/* Attempt to open BASE_FILE_NAME.sarif for writing JSON.
- Return a non-null diagnostic_output_file,
- or return a null diagnostic_output_file and complain to CONTEXT
+ Return a non-null output_file,
+ or return a null output_file and complain to DC
using LINE_MAPS. */
-diagnostic_output_file
-diagnostic_output_format_open_sarif_file (diagnostic_context &context,
- line_maps *line_maps,
- const char *base_file_name,
- enum sarif_serialization_kind serialization_kind)
+output_file
+open_sarif_output_file (context &dc,
+ line_maps *line_maps,
+ const char *base_file_name,
+ enum sarif_serialization_kind serialization_kind)
{
const char *suffix;
bool is_binary;
@@ -4224,78 +4235,78 @@ diagnostic_output_format_open_sarif_file (diagnostic_context &context,
break;
}
- return diagnostic_output_file::try_to_open (context,
- line_maps,
- base_file_name,
- suffix,
- is_binary);
+ return output_file::try_to_open (dc,
+ line_maps,
+ base_file_name,
+ suffix,
+ is_binary);
}
-/* Populate CONTEXT in preparation for SARIF output to a file named
+/* Populate DC in preparation for SARIF output to a file named
BASE_FILE_NAME.sarif.
Return a reference to the new sink. */
-diagnostic_output_format &
-diagnostic_output_format_init_sarif_file (diagnostic_context &context,
- line_maps *line_maps,
- bool formatted,
- const char *base_file_name)
+sink &
+init_sarif_file (context &dc,
+ line_maps *line_maps,
+ bool formatted,
+ const char *base_file_name)
{
gcc_assert (line_maps);
- diagnostic_output_file output_file
- = diagnostic_output_format_open_sarif_file (context,
- line_maps,
- base_file_name,
- sarif_serialization_kind::json);
+ output_file output_file_
+ = open_sarif_output_file (dc,
+ line_maps,
+ base_file_name,
+ sarif_serialization_kind::json);
auto serialization
= std::make_unique<sarif_serialization_format_json> (formatted);
const sarif_generation_options sarif_gen_opts;
- return diagnostic_output_format_init_sarif
- (context,
- std::make_unique<sarif_file_output_format> (context,
- line_maps,
- std::move (serialization),
- sarif_gen_opts,
- std::move (output_file)));
+ return init_sarif_sink
+ (dc,
+ std::make_unique<sarif_file_sink> (dc,
+ line_maps,
+ std::move (serialization),
+ sarif_gen_opts,
+ std::move (output_file_)));
}
-/* Populate CONTEXT in preparation for SARIF output to STREAM.
+/* Populate DC in preparation for SARIF output to STREAM.
Return a reference to the new sink. */
-diagnostic_output_format &
-diagnostic_output_format_init_sarif_stream (diagnostic_context &context,
- const line_maps *line_maps,
- bool formatted,
- FILE *stream)
+sink &
+init_sarif_stream (context &dc,
+ const line_maps *line_maps,
+ bool formatted,
+ FILE *stream)
{
gcc_assert (line_maps);
const sarif_generation_options sarif_gen_opts;
auto serialization
= std::make_unique<sarif_serialization_format_json> (formatted);
- return diagnostic_output_format_init_sarif
- (context,
- std::make_unique<sarif_stream_output_format> (context,
- line_maps,
- std::move (serialization),
- sarif_gen_opts,
- stream));
+ return init_sarif_sink
+ (dc,
+ std::make_unique<sarif_stream_sink> (dc,
+ line_maps,
+ std::move (serialization),
+ sarif_gen_opts,
+ stream));
}
-std::unique_ptr<diagnostic_output_format>
-make_sarif_sink (diagnostic_context &context,
+std::unique_ptr<sink>
+make_sarif_sink (context &dc,
const line_maps &line_maps,
std::unique_ptr<sarif_serialization_format> serialization,
const sarif_generation_options &sarif_gen_opts,
- diagnostic_output_file output_file)
+ output_file output_file_)
{
auto sink
- = std::make_unique<sarif_file_output_format> (context,
- &line_maps,
- std::move (serialization),
- sarif_gen_opts,
- std::move (output_file));
+ = std::make_unique<sarif_file_sink> (dc,
+ &line_maps,
+ std::move (serialization),
+ sarif_gen_opts,
+ std::move (output_file_));
sink->update_printer ();
return sink;
}
@@ -4312,6 +4323,9 @@ sarif_generation_options::sarif_generation_options ()
namespace selftest {
+using auto_fix_quotes = ::selftest::auto_fix_quotes;
+using line_table_case = ::selftest::line_table_case;
+
static void
test_sarif_array_of_unique_1 ()
{
@@ -4382,45 +4396,44 @@ test_sarif_array_of_unique_2 ()
ASSERT_JSON_INT_PROPERTY_EQ (arr[1], "index", 1);
}
-/* A subclass of sarif_output_format for writing selftests.
+/* A subclass of sarif_sink for writing selftests.
The JSON output is cached internally, rather than written
out to a file. */
-class test_sarif_diagnostic_context : public test_diagnostic_context
+class test_sarif_diagnostic_context : public test_context
{
public:
test_sarif_diagnostic_context (const char *main_input_filename,
const sarif_generation_options &sarif_gen_opts)
{
- auto format = std::make_unique<buffered_output_format> (*this,
- line_table,
- true,
- sarif_gen_opts);
- m_format = format.get (); // borrowed
- diagnostic_output_format_init_sarif (*this, std::move (format));
- m_format->set_main_input_filename (main_input_filename);
+ auto sink_ = std::make_unique<buffered_sink> (*this,
+ line_table,
+ true,
+ sarif_gen_opts);
+ m_sink = sink_.get (); // borrowed
+ init_sarif_sink (*this, std::move (sink_));
+ m_sink->set_main_input_filename (main_input_filename);
}
std::unique_ptr<sarif_log> flush_to_object ()
{
- return m_format->flush_to_object ();
+ return m_sink->flush_to_object ();
}
- size_t num_results () const { return m_format->num_results (); }
- sarif_result &get_result (size_t idx) { return m_format->get_result (idx); }
+ size_t num_results () const { return m_sink->num_results (); }
+ sarif_result &get_result (size_t idx) { return m_sink->get_result (idx); }
private:
- class buffered_output_format : public sarif_output_format
+ class buffered_sink : public sarif_sink
{
public:
- buffered_output_format (diagnostic_context &context,
- const line_maps *line_maps,
- bool formatted,
- const sarif_generation_options &sarif_gen_opts)
- : sarif_output_format (context, line_maps,
- std::make_unique<sarif_serialization_format_json>
- (formatted),
- sarif_gen_opts)
+ buffered_sink (context &dc,
+ const line_maps *line_maps,
+ bool formatted,
+ const sarif_generation_options &sarif_gen_opts)
+ : sarif_sink (dc, line_maps,
+ std::make_unique<sarif_serialization_format_json> (formatted),
+ sarif_gen_opts)
{
}
bool machine_readable_stderr_p () const final override
@@ -4433,7 +4446,7 @@ private:
}
};
- buffered_output_format *m_format; // borrowed
+ buffered_sink *m_sink; // borrowed
};
/* Test making a sarif_location for a complex rich_location
@@ -4441,16 +4454,16 @@ private:
static void
test_make_location_object (const sarif_generation_options &sarif_gen_opts,
- const line_table_case &case_)
+ const ::selftest::line_table_case &case_)
{
- diagnostic_show_locus_fixture_one_liner_utf8 f (case_);
+ source_printing_fixture_one_liner_utf8 f (case_);
location_t line_end = linemap_position_for_column (line_table, 31);
/* Don't attempt to run the tests if column data might be unavailable. */
if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
return;
- test_diagnostic_context dc;
+ test_context dc;
pretty_printer pp;
sarif_builder builder
(dc, pp, line_table,
@@ -4486,7 +4499,7 @@ test_make_location_object (const sarif_generation_options &sarif_gen_opts,
std::unique_ptr<sarif_location> location_obj
= builder.make_location_object
- (&result, richloc, logical_location (),
+ (&result, richloc, logical_locations::key (),
diagnostic_artifact_role::analysis_target);
ASSERT_NE (location_obj, nullptr);
@@ -4563,7 +4576,7 @@ test_make_location_object (const sarif_generation_options &sarif_gen_opts,
}
/* Test of reporting a diagnostic at UNKNOWN_LOCATION to a
- diagnostic_context and examining the generated sarif_log.
+ diagnostics::context and examining the generated sarif_log.
Verify various basic properties. */
static void
@@ -4572,7 +4585,7 @@ test_simple_log (const sarif_generation_options &sarif_gen_opts)
test_sarif_diagnostic_context dc ("MAIN_INPUT_FILENAME", sarif_gen_opts);
rich_location richloc (line_table, UNKNOWN_LOCATION);
- dc.report (DK_ERROR, richloc, nullptr, 0, "this is a test: %i", 42);
+ dc.report (kind::error, richloc, nullptr, 0, "this is a test: %i", 42);
auto log_ptr = dc.flush_to_object ();
@@ -4694,7 +4707,7 @@ test_simple_log_2 (const sarif_generation_options &sarif_gen_opts,
/* 000000000111111
123456789012345. */
= "unsinged int i;\n";
- diagnostic_show_locus_fixture f (case_, content);
+ source_printing_fixture f (case_, content);
location_t line_end = linemap_position_for_column (line_table, 31);
/* Don't attempt to run the tests if column data might be unavailable. */
@@ -4709,7 +4722,7 @@ test_simple_log_2 (const sarif_generation_options &sarif_gen_opts,
linemap_position_for_column (line_table, 8));
rich_location richloc (line_table, typo_loc);
- dc.report (DK_ERROR, richloc, nullptr, 0,
+ dc.report (kind::error, richloc, nullptr, 0,
"did you misspell %qs again?",
"unsigned");
@@ -4837,7 +4850,7 @@ test_message_with_embedded_link (const sarif_generation_options &sarif_gen_opts)
{
test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
rich_location richloc (line_table, UNKNOWN_LOCATION);
- dc.report (DK_ERROR, richloc, nullptr, 0,
+ dc.report (kind::error, richloc, nullptr, 0,
"before %{text%} after",
"http://example.com");
std::unique_ptr<sarif_log> log = dc.flush_to_object ();
@@ -4860,7 +4873,7 @@ test_message_with_embedded_link (const sarif_generation_options &sarif_gen_opts)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-diag"
#endif
- dc.report (DK_ERROR, richloc, nullptr, 0,
+ dc.report (kind::error, richloc, nullptr, 0,
"Prohibited term used in %{para[0]\\spans[2]%}.",
"1");
#if __GNUC__ >= 10
@@ -4894,7 +4907,7 @@ test_message_with_embedded_link (const sarif_generation_options &sarif_gen_opts)
test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
dc.push_owned_urlifier (std::make_unique<test_urlifier> ());
rich_location richloc (line_table, UNKNOWN_LOCATION);
- dc.report (DK_ERROR, richloc, nullptr, 0,
+ dc.report (kind::error, richloc, nullptr, 0,
"foo %<-foption%> %<unrecognized%> bar");
std::unique_ptr<sarif_log> log = dc.flush_to_object ();
@@ -4915,7 +4928,7 @@ test_message_with_braces (const sarif_generation_options &sarif_gen_opts)
{
test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
rich_location richloc (line_table, UNKNOWN_LOCATION);
- dc.report (DK_ERROR, richloc, nullptr, 0,
+ dc.report (kind::error, richloc, nullptr, 0,
"open brace: %qs close brace: %qs",
"{", "}");
std::unique_ptr<sarif_log> log = dc.flush_to_object ();
@@ -4932,26 +4945,26 @@ test_buffering (const sarif_generation_options &sarif_gen_opts)
{
test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
- diagnostic_buffer buf_a (dc);
- diagnostic_buffer buf_b (dc);
+ diagnostics::buffer buf_a (dc);
+ diagnostics::buffer buf_b (dc);
rich_location rich_loc (line_table, UNKNOWN_LOCATION);
- ASSERT_EQ (dc.diagnostic_count (DK_ERROR), 0);
- ASSERT_EQ (buf_a.diagnostic_count (DK_ERROR), 0);
- ASSERT_EQ (buf_b.diagnostic_count (DK_ERROR), 0);
+ ASSERT_EQ (dc.diagnostic_count (kind::error), 0);
+ ASSERT_EQ (buf_a.diagnostic_count (kind::error), 0);
+ ASSERT_EQ (buf_b.diagnostic_count (kind::error), 0);
ASSERT_EQ (dc.num_results (), 0);
ASSERT_TRUE (buf_a.empty_p ());
ASSERT_TRUE (buf_b.empty_p ());
/* Unbuffered diagnostic. */
{
- dc.report (DK_ERROR, rich_loc, nullptr, 0,
+ dc.report (kind::error, rich_loc, nullptr, 0,
"message 1");
- ASSERT_EQ (dc.diagnostic_count (DK_ERROR), 1);
- ASSERT_EQ (buf_a.diagnostic_count (DK_ERROR), 0);
- ASSERT_EQ (buf_b.diagnostic_count (DK_ERROR), 0);
+ ASSERT_EQ (dc.diagnostic_count (kind::error), 1);
+ ASSERT_EQ (buf_a.diagnostic_count (kind::error), 0);
+ ASSERT_EQ (buf_b.diagnostic_count (kind::error), 0);
ASSERT_EQ (dc.num_results (), 1);
sarif_result &result_obj = dc.get_result (0);
auto message_obj = get_message_from_result (result_obj);
@@ -4964,11 +4977,11 @@ test_buffering (const sarif_generation_options &sarif_gen_opts)
/* Buffer diagnostic into buffer A. */
{
dc.set_diagnostic_buffer (&buf_a);
- dc.report (DK_ERROR, rich_loc, nullptr, 0,
+ dc.report (kind::error, rich_loc, nullptr, 0,
"message in buffer a");
- ASSERT_EQ (dc.diagnostic_count (DK_ERROR), 1);
- ASSERT_EQ (buf_a.diagnostic_count (DK_ERROR), 1);
- ASSERT_EQ (buf_b.diagnostic_count (DK_ERROR), 0);
+ ASSERT_EQ (dc.diagnostic_count (kind::error), 1);
+ ASSERT_EQ (buf_a.diagnostic_count (kind::error), 1);
+ ASSERT_EQ (buf_b.diagnostic_count (kind::error), 0);
ASSERT_EQ (dc.num_results (), 1);
ASSERT_FALSE (buf_a.empty_p ());
ASSERT_TRUE (buf_b.empty_p ());
@@ -4977,11 +4990,11 @@ test_buffering (const sarif_generation_options &sarif_gen_opts)
/* Buffer diagnostic into buffer B. */
{
dc.set_diagnostic_buffer (&buf_b);
- dc.report (DK_ERROR, rich_loc, nullptr, 0,
+ dc.report (kind::error, rich_loc, nullptr, 0,
"message in buffer b");
- ASSERT_EQ (dc.diagnostic_count (DK_ERROR), 1);
- ASSERT_EQ (buf_a.diagnostic_count (DK_ERROR), 1);
- ASSERT_EQ (buf_b.diagnostic_count (DK_ERROR), 1);
+ ASSERT_EQ (dc.diagnostic_count (kind::error), 1);
+ ASSERT_EQ (buf_a.diagnostic_count (kind::error), 1);
+ ASSERT_EQ (buf_b.diagnostic_count (kind::error), 1);
ASSERT_EQ (dc.num_results (), 1);
ASSERT_FALSE (buf_a.empty_p ());
ASSERT_FALSE (buf_b.empty_p ());
@@ -4990,9 +5003,9 @@ test_buffering (const sarif_generation_options &sarif_gen_opts)
/* Flush buffer B to dc. */
{
dc.flush_diagnostic_buffer (buf_b);
- ASSERT_EQ (dc.diagnostic_count (DK_ERROR), 2);
- ASSERT_EQ (buf_a.diagnostic_count (DK_ERROR), 1);
- ASSERT_EQ (buf_b.diagnostic_count (DK_ERROR), 0);
+ ASSERT_EQ (dc.diagnostic_count (kind::error), 2);
+ ASSERT_EQ (buf_a.diagnostic_count (kind::error), 1);
+ ASSERT_EQ (buf_b.diagnostic_count (kind::error), 0);
ASSERT_EQ (dc.num_results (), 2);
sarif_result &result_1_obj = dc.get_result (1);
auto message_1_obj = get_message_from_result (result_1_obj);
@@ -5005,9 +5018,9 @@ test_buffering (const sarif_generation_options &sarif_gen_opts)
/* Clear buffer A. */
{
dc.clear_diagnostic_buffer (buf_a);
- ASSERT_EQ (dc.diagnostic_count (DK_ERROR), 2);
- ASSERT_EQ (buf_a.diagnostic_count (DK_ERROR), 0);
- ASSERT_EQ (buf_b.diagnostic_count (DK_ERROR), 0);
+ ASSERT_EQ (dc.diagnostic_count (kind::error), 2);
+ ASSERT_EQ (buf_a.diagnostic_count (kind::error), 0);
+ ASSERT_EQ (buf_b.diagnostic_count (kind::error), 0);
ASSERT_EQ (dc.num_results (), 2);
ASSERT_TRUE (buf_a.empty_p ());
ASSERT_TRUE (buf_b.empty_p ());
@@ -5044,7 +5057,7 @@ run_line_table_case_tests_per_version (const line_table_case &case_)
/* Run all of the selftests within this file. */
void
-diagnostic_format_sarif_cc_tests ()
+sarif_sink_cc_tests ()
{
test_sarif_array_of_unique_1 ();
test_sarif_array_of_unique_2 ();
@@ -5058,6 +5071,7 @@ diagnostic_format_sarif_cc_tests ()
for_each_line_table_case (run_line_table_case_tests_per_version);
}
-} // namespace selftest
+} // namespace diagnostics::selftest
+} // namespace diagnostics
#endif /* CHECKING_P */
diff --git a/gcc/diagnostic-format-sarif.h b/gcc/diagnostics/sarif-sink.h
index 60657c6..9f8a73f 100644
--- a/gcc/diagnostic-format-sarif.h
+++ b/gcc/diagnostics/sarif-sink.h
@@ -18,13 +18,21 @@ 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_DIAGNOSTIC_FORMAT_SARIF_H
-#define GCC_DIAGNOSTIC_FORMAT_SARIF_H
+#ifndef GCC_DIAGNOSTICS_SARIF_SINK_H
+#define GCC_DIAGNOSTICS_SARIF_SINK_H
#include "json.h"
-#include "diagnostic-format.h"
-#include "diagnostic-output-file.h"
-#include "logical-location.h"
+#include "diagnostics/sink.h"
+#include "diagnostics/output-file.h"
+#include "diagnostics/logical-locations.h"
+
+namespace diagnostics {
+
+namespace digraphs {
+ class digraph;
+ class node;
+ class edge;
+}
/* Enum for choosing what format to serializing the generated SARIF into. */
@@ -35,26 +43,26 @@ enum class sarif_serialization_kind
num_values
};
-extern diagnostic_output_file
-diagnostic_output_format_open_sarif_file (diagnostic_context &context,
- line_maps *line_maps,
- const char *base_file_name,
- enum sarif_serialization_kind serialization_kind);
-
-extern diagnostic_output_format &
-diagnostic_output_format_init_sarif_stderr (diagnostic_context &context,
- const line_maps *line_maps,
- bool formatted);
-extern diagnostic_output_format &
-diagnostic_output_format_init_sarif_file (diagnostic_context &context,
- line_maps *line_maps,
- bool formatted,
- const char *base_file_name);
-extern diagnostic_output_format &
-diagnostic_output_format_init_sarif_stream (diagnostic_context &context,
- const line_maps *line_maps,
- bool formatted,
- FILE *stream);
+extern output_file
+open_sarif_output_file (context &dc,
+ line_maps *line_maps,
+ const char *base_file_name,
+ enum sarif_serialization_kind serialization_kind);
+
+extern sink &
+init_sarif_stderr (context &dc,
+ const line_maps *line_maps,
+ bool formatted);
+extern sink &
+init_sarif_file (context &dc,
+ line_maps *line_maps,
+ bool formatted,
+ const char *base_file_name);
+extern sink &
+init_sarif_stream (context &dc,
+ const line_maps *line_maps,
+ bool formatted,
+ FILE *stream);
/* Abstract base class for handling JSON output vs other kinds of
serialization of the json tree. */
@@ -104,23 +112,16 @@ struct sarif_generation_options
bool m_state_graph;
};
-extern std::unique_ptr<diagnostic_output_format>
-make_sarif_sink (diagnostic_context &context,
+extern std::unique_ptr<sink>
+make_sarif_sink (context &dc,
const line_maps &line_maps,
std::unique_ptr<sarif_serialization_format> serialization_format,
const sarif_generation_options &sarif_gen_opts,
- diagnostic_output_file output_file);
+ output_file output_file_);
class sarif_builder;
class sarif_location_manager;
-namespace diagnostics {
-namespace digraphs {
- class digraph;
- class node;
- class edge;
-}}
-
/* Concrete subclass of json::object for SARIF property bags
(SARIF v2.1.0 section 3.8). */
@@ -129,11 +130,11 @@ class sarif_property_bag : public json::object
public:
void set_logical_location (const char *property_name,
sarif_builder &,
- logical_location logical_loc);
+ logical_locations::key logical_loc);
void set_graph (const char *property_name,
sarif_builder &,
sarif_location_manager *sarif_location_mgr,
- const diagnostics::digraphs::digraph &g);
+ const digraphs::digraph &g);
};
/* Concrete subclass of json::object for SARIF objects that can
@@ -170,17 +171,19 @@ class sarif_edge : public sarif_object
};
extern std::unique_ptr<sarif_graph>
-make_sarif_graph (const diagnostics::digraphs::digraph &g,
+make_sarif_graph (const digraphs::digraph &g,
sarif_builder *builder,
sarif_location_manager *sarif_location_mgr);
extern std::unique_ptr<sarif_node>
-make_sarif_node (const diagnostics::digraphs::node &n,
+make_sarif_node (const digraphs::node &n,
sarif_builder *builder,
sarif_location_manager *sarif_location_mgr);
extern std::unique_ptr<sarif_edge>
-make_sarif_edge (const diagnostics::digraphs::edge &e,
+make_sarif_edge (const digraphs::edge &e,
sarif_builder *builder);
-#endif /* ! GCC_DIAGNOSTIC_FORMAT_SARIF_H */
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_SARIF_SINK_H */
diff --git a/gcc/selftest-diagnostic.cc b/gcc/diagnostics/selftest-context.cc
index eeee2eb..2b6dd0b 100644
--- a/gcc/selftest-diagnostic.cc
+++ b/gcc/diagnostics/selftest-context.cc
@@ -21,61 +21,65 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
-#include "diagnostic-format.h"
+#include "diagnostics/sink.h"
#include "selftest.h"
-#include "selftest-diagnostic.h"
+#include "diagnostics/selftest-context.h"
/* The selftest code should entirely disappear in a production
configuration, hence we guard all of it with #if CHECKING_P. */
#if CHECKING_P
+namespace diagnostics {
namespace selftest {
-/* Implementation of class selftest::test_diagnostic_context. */
+/* Implementation of class diagnostics::selftest::test_context. */
-test_diagnostic_context::test_diagnostic_context ()
+test_context::test_context ()
{
diagnostic_initialize (this, 0);
pp_show_color (get_reference_printer ()) = false;
- m_source_printing.enabled = true;
- m_source_printing.show_labels_p = true;
+
+ auto &source_printing_opts = get_source_printing_options ();
+ source_printing_opts.enabled = true;
+ source_printing_opts.show_labels_p = true;
m_show_column = true;
- diagnostic_start_span (this) = start_span_cb;
- m_source_printing.min_margin_width = 6;
- m_source_printing.max_width = 80;
- pp_buffer (get_output_format (0).get_printer ())->m_flush_p = false;
+ start_span (this) = start_span_cb;
+ source_printing_opts.min_margin_width = 6;
+ source_printing_opts.max_width = 80;
+ pp_buffer (get_sink (0).get_printer ())->m_flush_p = false;
}
-test_diagnostic_context::~test_diagnostic_context ()
+test_context::~test_context ()
{
diagnostic_finish (this);
}
-/* Implementation of diagnostic_start_span_fn, hiding the
+/* Implementation of diagnostics::start_span_fn, hiding the
real filename (to avoid printing the names of tempfiles). */
void
-test_diagnostic_context::
-start_span_cb (const diagnostic_location_print_policy &loc_policy,
- to_text &sink,
+test_context::
+start_span_cb (const location_print_policy &loc_policy,
+ to_text &html_or_text,
expanded_location exploc)
{
exploc.file = "FILENAME";
- default_diagnostic_start_span_fn<to_text> (loc_policy, sink, exploc);
+ default_start_span_fn<to_text>
+ (loc_policy, html_or_text, exploc);
}
bool
-test_diagnostic_context::report (diagnostic_t kind,
- rich_location &richloc,
- const diagnostic_metadata *metadata,
- diagnostic_option_id option,
- const char * fmt, ...)
+test_context::report (enum kind kind,
+ rich_location &richloc,
+ const metadata *metadata_,
+ option_id opt_id,
+ const char * fmt, ...)
{
va_list ap;
va_start (ap, fmt);
begin_group ();
- bool result = diagnostic_impl (&richloc, metadata, option, fmt, &ap, kind);
+ bool result = diagnostic_impl (&richloc, metadata_, opt_id, fmt, &ap, kind);
end_group ();
va_end (ap);
return result;
@@ -85,15 +89,16 @@ test_diagnostic_context::report (diagnostic_t kind,
Return the text buffer from the printer. */
const char *
-test_diagnostic_context::test_show_locus (rich_location &richloc)
+test_context::test_show_locus (rich_location &richloc)
{
pretty_printer *pp = get_reference_printer ();
gcc_assert (pp);
- diagnostic_source_print_policy source_policy (*this);
- source_policy.print (*pp, richloc, DK_ERROR, nullptr);
+ source_print_policy source_policy (*this);
+ source_policy.print (*pp, richloc, kind::error, nullptr);
return pp_formatted_text (pp);
}
} // namespace selftest
+} // namespace diagnostics
#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-diagnostic.h b/gcc/diagnostics/selftest-context.h
index 4a43310..cfba997 100644
--- a/gcc/selftest-diagnostic.h
+++ b/gcc/diagnostics/selftest-context.h
@@ -17,29 +17,30 @@ 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_SELFTEST_DIAGNOSTIC_H
-#define GCC_SELFTEST_DIAGNOSTIC_H
+#ifndef GCC_DIAGNOSTICS_SELFTEST_CONTEXT_H
+#define GCC_DIAGNOSTICS_SELFTEST_CONTEXT_H
/* The selftest code should entirely disappear in a production
configuration, hence we guard all of it with #if CHECKING_P. */
#if CHECKING_P
+namespace diagnostics {
namespace selftest {
-/* Convenience subclass of diagnostic_context for testing
+/* Convenience subclass of diagnostics::context for testing
the diagnostic subsystem. */
-class test_diagnostic_context : public diagnostic_context
+class test_context : public context
{
public:
- test_diagnostic_context ();
- ~test_diagnostic_context ();
+ test_context ();
+ ~test_context ();
- /* Implementation of diagnostic_start_span_fn, hiding the
+ /* Implementation of diagnostics::start_span_fn, hiding the
real filename (to avoid printing the names of tempfiles). */
static void
- start_span_cb (const diagnostic_location_print_policy &,
+ start_span_cb (const location_print_policy &,
to_text &sink,
expanded_location exploc);
@@ -47,17 +48,46 @@ class test_diagnostic_context : public diagnostic_context
should only be called on a context that uses a non-standard formatter
that e.g. gathers the results in memory, rather than emits to stderr. */
bool
- report (diagnostic_t kind,
+ report (enum kind kind,
rich_location &richloc,
- const diagnostic_metadata *metadata,
- diagnostic_option_id option,
+ const metadata *,
+ option_id opt_id,
const char * fmt, ...) ATTRIBUTE_GCC_DIAG(6,7);
const char *test_show_locus (rich_location &richloc);
+
+ /* Setters for the context's source_printing_options
+ for use in selftests. */
+ void colorize_source (bool val)
+ {
+ get_source_printing_options ().colorize_source_p = val;
+ }
+ void show_labels (bool val)
+ {
+ get_source_printing_options ().show_labels_p = val;
+ }
+ void show_line_numbers (bool val)
+ {
+ get_source_printing_options ().show_line_numbers_p = val;
+ }
+ void show_ruler (bool val)
+ {
+ get_source_printing_options ().show_ruler_p = val;
+ }
+ void show_event_links (bool val)
+ {
+ get_source_printing_options ().show_event_links_p = val;
+ }
+ void set_caret_char (unsigned idx, char ch)
+ {
+ gcc_assert (idx < rich_location::STATICALLY_ALLOCATED_RANGES);
+ get_source_printing_options ().caret_chars[idx] = ch;
+ }
};
} // namespace selftest
+} // namespace diagnostics
#endif /* #if CHECKING_P */
-#endif /* GCC_SELFTEST_DIAGNOSTIC_H */
+#endif /* GCC_DIAGNOSTICS_SELFTEST_CONTEXT_H */
diff --git a/gcc/selftest-logical-location.cc b/gcc/diagnostics/selftest-logical-locations.cc
index 63b9fb4..8ba4233 100644
--- a/gcc/selftest-logical-location.cc
+++ b/gcc/diagnostics/selftest-logical-locations.cc
@@ -1,4 +1,4 @@
-/* Concrete subclass of logical_location for use in selftests.
+/* Concrete subclass of logical_locations::manager for use in selftests.
Copyright (C) 2024-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -22,22 +22,24 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "selftest.h"
-#include "selftest-logical-location.h"
+#include "diagnostics/selftest-logical-locations.h"
#if CHECKING_P
+namespace diagnostics {
+namespace logical_locations {
namespace selftest {
-/* class test_logical_location_manager : public logical_location_manager. */
+/* class test_manager : public manager. */
-test_logical_location_manager::~test_logical_location_manager ()
+test_manager::~test_manager ()
{
for (auto iter : m_name_to_item_map)
delete iter.second;
}
const char *
-test_logical_location_manager::get_short_name (key k) const
+test_manager::get_short_name (key k) const
{
auto item = item_from_key (k);
if (!item)
@@ -46,43 +48,43 @@ test_logical_location_manager::get_short_name (key k) const
}
const char *
-test_logical_location_manager::get_name_with_scope (key k) const
+test_manager::get_name_with_scope (key k) const
{
auto item = item_from_key (k);
return item->m_name;
}
const char *
-test_logical_location_manager::get_internal_name (key k) const
+test_manager::get_internal_name (key k) const
{
auto item = item_from_key (k);
return item->m_name;
}
-enum logical_location_kind
-test_logical_location_manager::get_kind (key k) const
+enum diagnostics::logical_locations::kind
+test_manager::get_kind (key k) const
{
auto item = item_from_key (k);
return item->m_kind;
}
label_text
-test_logical_location_manager::get_name_for_path_output (key k) const
+test_manager::get_name_for_path_output (key k) const
{
auto item = item_from_key (k);
return label_text::borrow (item->m_name);
}
-logical_location
-test_logical_location_manager::
+diagnostics::logical_locations::key
+test_manager::
logical_location_from_funcname (const char *funcname)
{
const item *i = item_from_funcname (funcname);
return key::from_ptr (i);
}
-const test_logical_location_manager::item *
-test_logical_location_manager::item_from_funcname (const char *funcname)
+const test_manager::item *
+test_manager::item_from_funcname (const char *funcname)
{
if (!funcname)
return nullptr;
@@ -90,7 +92,7 @@ test_logical_location_manager::item_from_funcname (const char *funcname)
if (item **slot = m_name_to_item_map.get (funcname))
return *slot;
- item *i = new item (logical_location_kind::function, funcname);
+ item *i = new item (kind::function, funcname);
m_name_to_item_map.put (funcname, i);
return i;
}
@@ -98,14 +100,14 @@ test_logical_location_manager::item_from_funcname (const char *funcname)
/* Run all of the selftests within this file. */
void
-selftest_logical_location_cc_tests ()
+selftest_logical_locations_cc_tests ()
{
- test_logical_location_manager mgr;
+ test_manager mgr;
ASSERT_FALSE (mgr.logical_location_from_funcname (nullptr));
- logical_location loc_foo = mgr.logical_location_from_funcname ("foo");
- logical_location loc_bar = mgr.logical_location_from_funcname ("bar");
+ key loc_foo = mgr.logical_location_from_funcname ("foo");
+ key loc_bar = mgr.logical_location_from_funcname ("bar");
ASSERT_NE (loc_foo, loc_bar);
@@ -113,6 +115,8 @@ selftest_logical_location_cc_tests ()
ASSERT_STREQ (mgr.get_short_name (loc_bar), "bar");
}
-} // namespace selftest
+} // namespace diagnostics::logical_locations::selftest
+} // namespace diagnostics::logical_locations
+} // namespace diagnostics
#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-logical-location.h b/gcc/diagnostics/selftest-logical-locations.h
index d9bf38f..c14a282 100644
--- a/gcc/selftest-logical-location.h
+++ b/gcc/diagnostics/selftest-logical-locations.h
@@ -1,4 +1,4 @@
-/* Concrete subclass of logical_location for use in selftests.
+/* Concrete subclass of logical_locations::manager for use in selftests.
Copyright (C) 2024-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -18,56 +18,58 @@ 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_SELFTEST_LOGICAL_LOCATION_H
-#define GCC_SELFTEST_LOGICAL_LOCATION_H
+#ifndef GCC_DIAGNOSTICS_SELFTEST_LOGICAL_LOCATIONS_H
+#define GCC_DIAGNOSTICS_SELFTEST_LOGICAL_LOCATIONS_H
-#include "logical-location.h"
+#include "diagnostics/logical-locations.h"
/* The selftest code should entirely disappear in a production
configuration, hence we guard all of it with #if CHECKING_P. */
#if CHECKING_P
+namespace diagnostics {
+namespace logical_locations {
namespace selftest {
-/* Concrete subclass of logical_location_manager for use in selftests. */
+/* Concrete subclass of logical_locations::manager for use in selftests. */
-class test_logical_location_manager : public logical_location_manager
+class test_manager : public manager
{
public:
- ~test_logical_location_manager ();
+ ~test_manager ();
const char *get_short_name (key) const final override;
const char *get_name_with_scope (key) const final override;
const char *get_internal_name (key) const final override;
- enum logical_location_kind get_kind (key) const final override;
+ kind get_kind (key) const final override;
label_text get_name_for_path_output (key) const final override;
key get_parent (key) const final override
{
return key ();
}
- logical_location
+ key
logical_location_from_funcname (const char *funcname);
private:
struct item
{
- item (enum logical_location_kind kind,
+ item (kind kind_,
const char *name)
- : m_kind (kind),
+ : m_kind (kind_),
m_name (name)
{
}
- enum logical_location_kind m_kind;
+ kind m_kind;
const char *m_name;
};
const item *
item_from_funcname (const char *funcname);
- static const item *item_from_key (logical_location k)
+ static const item *item_from_key (key k)
{
return k.cast_to<const item *> ();
}
@@ -75,9 +77,10 @@ private:
hash_map<nofree_string_hash, item *> m_name_to_item_map;
};
-} // namespace selftest
+} // namespace diagnostics::logical_locations::selftest
+} // namespace diagnostics::logical_locations::
+} // namespace diagnostics
#endif /* #if CHECKING_P */
-
-#endif /* GCC_SELFTEST_LOGICAL_LOCATION_H. */
+#endif /* GCC_DIAGNOSTICS_SELFTEST_LOGICAL_LOCATIONS_H. */
diff --git a/gcc/selftest-diagnostic-path.cc b/gcc/diagnostics/selftest-paths.cc
index 04372e7..56ce7ff 100644
--- a/gcc/selftest-diagnostic-path.cc
+++ b/gcc/diagnostics/selftest-paths.cc
@@ -24,66 +24,69 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "version.h"
-#include "demangle.h"
-#include "backtrace.h"
#include "diagnostic.h"
-#include "selftest-diagnostic-path.h"
+#include "diagnostics/selftest-paths.h"
#if CHECKING_P
+namespace diagnostics {
+namespace paths {
namespace selftest {
-/* class test_diagnostic_path : public diagnostic_path. */
+/* class test_path : public diagnostics::paths::path. */
-test_diagnostic_path::test_diagnostic_path (pretty_printer *event_pp)
-: diagnostic_path (m_test_logical_loc_mgr),
+test_path::
+test_path (logical_locations::selftest::test_manager &logical_loc_mgr,
+ pretty_printer *event_pp)
+: path (logical_loc_mgr),
+ m_test_logical_loc_mgr (logical_loc_mgr),
m_event_pp (event_pp)
{
add_thread ("main");
}
-/* Implementation of diagnostic_path::num_events vfunc for
- test_diagnostic_path: simply get the number of events in the vec. */
+/* Implementation of path::num_events vfunc for
+ test_path: simply get the number of events in the vec. */
unsigned
-test_diagnostic_path::num_events () const
+test_path::num_events () const
{
return m_events.length ();
}
-/* Implementation of diagnostic_path::get_event vfunc for
- test_diagnostic_path: simply return the event in the vec. */
+/* Implementation of path::get_event vfunc for
+ test_path: simply return the event in the vec. */
-const diagnostic_event &
-test_diagnostic_path::get_event (int idx) const
+const event &
+test_path::get_event (int idx) const
{
return *m_events[idx];
}
unsigned
-test_diagnostic_path::num_threads () const
+test_path::num_threads () const
{
return m_threads.length ();
}
-const diagnostic_thread &
-test_diagnostic_path::get_thread (diagnostic_thread_id_t idx) const
+const thread &
+test_path::get_thread (thread_id_t idx) const
{
return *m_threads[idx];
}
bool
-test_diagnostic_path::same_function_p (int event_idx_a,
- int event_idx_b) const
+test_path::same_function_p (int event_idx_a,
+ int event_idx_b) const
{
return (m_events[event_idx_a]->get_logical_location ()
== m_events[event_idx_b]->get_logical_location ());
}
-diagnostic_thread_id_t
-test_diagnostic_path::add_thread (const char *name)
+thread_id_t
+test_path::add_thread (const char *name)
{
- m_threads.safe_push (new test_diagnostic_thread (name));
+ m_threads.safe_push (new test_thread (name));
return m_threads.length () - 1;
}
@@ -95,11 +98,11 @@ test_diagnostic_path::add_thread (const char *name)
Return the id of the new event. */
-diagnostic_event_id_t
-test_diagnostic_path::add_event (location_t loc,
- const char *funcname,
- int depth,
- const char *fmt, ...)
+event_id_t
+test_path::add_event (location_t loc,
+ const char *funcname,
+ int depth,
+ const char *fmt, ...)
{
pretty_printer *pp = m_event_pp;
pp_clear_output_area (pp);
@@ -117,24 +120,24 @@ test_diagnostic_path::add_event (location_t loc,
va_end (ap);
- test_diagnostic_event *new_event
- = new test_diagnostic_event (loc,
- logical_location_from_funcname (funcname),
- depth,
- pp_formatted_text (pp));
+ test_event *new_event
+ = new test_event (loc,
+ logical_location_from_funcname (funcname),
+ depth,
+ pp_formatted_text (pp));
m_events.safe_push (new_event);
pp_clear_output_area (pp);
- return diagnostic_event_id_t (m_events.length () - 1);
+ return event_id_t (m_events.length () - 1);
}
-diagnostic_event_id_t
-test_diagnostic_path::add_thread_event (diagnostic_thread_id_t thread_id,
- location_t loc,
- const char *funcname,
- int depth,
- const char *fmt, ...)
+event_id_t
+test_path::add_thread_event (thread_id_t thread_id,
+ location_t loc,
+ const char *funcname,
+ int depth,
+ const char *fmt, ...)
{
pretty_printer *pp = m_event_pp;
pp_clear_output_area (pp);
@@ -153,52 +156,52 @@ test_diagnostic_path::add_thread_event (diagnostic_thread_id_t thread_id,
va_end (ap);
- test_diagnostic_event *new_event
- = new test_diagnostic_event (loc,
- logical_location_from_funcname (funcname),
- depth,
- pp_formatted_text (pp),
- thread_id);
+ test_event *new_event
+ = new test_event (loc,
+ logical_location_from_funcname (funcname),
+ depth,
+ pp_formatted_text (pp),
+ thread_id);
m_events.safe_push (new_event);
pp_clear_output_area (pp);
- return diagnostic_event_id_t (m_events.length () - 1);
+ return event_id_t (m_events.length () - 1);
}
/* Mark the most recent event on this path (which must exist) as being
connected to the next one to be added. */
void
-test_diagnostic_path::connect_to_next_event ()
+test_path::connect_to_next_event ()
{
gcc_assert (m_events.length () > 0);
m_events[m_events.length () - 1]->connect_to_next_event ();
}
void
-test_diagnostic_path::add_entry (const char *callee_name,
- int stack_depth,
- diagnostic_thread_id_t thread_id)
+test_path::add_entry (const char *callee_name,
+ int stack_depth,
+ thread_id_t thread_id)
{
add_thread_event (thread_id, UNKNOWN_LOCATION, callee_name, stack_depth,
"entering %qs", callee_name);
}
void
-test_diagnostic_path::add_return (const char *caller_name,
- int stack_depth,
- diagnostic_thread_id_t thread_id)
+test_path::add_return (const char *caller_name,
+ int stack_depth,
+ thread_id_t thread_id)
{
add_thread_event (thread_id, UNKNOWN_LOCATION, caller_name, stack_depth,
"returning to %qs", caller_name);
}
void
-test_diagnostic_path::add_call (const char *caller_name,
- int caller_stack_depth,
- const char *callee_name,
- diagnostic_thread_id_t thread_id)
+test_path::add_call (const char *caller_name,
+ int caller_stack_depth,
+ const char *callee_name,
+ thread_id_t thread_id)
{
add_thread_event (thread_id, UNKNOWN_LOCATION,
caller_name, caller_stack_depth,
@@ -206,22 +209,22 @@ test_diagnostic_path::add_call (const char *caller_name,
add_entry (callee_name, caller_stack_depth + 1, thread_id);
}
-logical_location
-test_diagnostic_path::logical_location_from_funcname (const char *funcname)
+logical_locations::key
+test_path::logical_location_from_funcname (const char *funcname)
{
return m_test_logical_loc_mgr.logical_location_from_funcname (funcname);
}
-/* struct test_diagnostic_event. */
+/* struct test_event. */
-/* test_diagnostic_event's ctor. */
+/* test_event's ctor. */
-test_diagnostic_event::
-test_diagnostic_event (location_t loc,
- logical_location logical_loc,
- int depth,
- const char *desc,
- diagnostic_thread_id_t thread_id)
+test_event::
+test_event (location_t loc,
+ logical_location logical_loc,
+ int depth,
+ const char *desc,
+ thread_id_t thread_id)
: m_loc (loc),
m_logical_loc (logical_loc),
m_depth (depth), m_desc (xstrdup (desc)),
@@ -230,13 +233,15 @@ test_diagnostic_event (location_t loc,
{
}
-/* test_diagnostic_event's dtor. */
+/* test_event's dtor. */
-test_diagnostic_event::~test_diagnostic_event ()
+test_event::~test_event ()
{
free (m_desc);
}
-} // namespace selftest
+} // namespace diagnostics::paths::selftest
+} // namespace diagnostics::paths
+} // namespace diagnostics
#endif /* #if CHECKING_P */
diff --git a/gcc/selftest-diagnostic-path.h b/gcc/diagnostics/selftest-paths.h
index 8829943..fe628f6 100644
--- a/gcc/selftest-diagnostic-path.h
+++ b/gcc/diagnostics/selftest-paths.h
@@ -18,17 +18,19 @@ 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_SELFTEST_DIAGNOSTIC_PATH_H
-#define GCC_SELFTEST_DIAGNOSTIC_PATH_H
+#ifndef GCC_DIAGNOSTICS_SELFTEST_PATHS_H
+#define GCC_DIAGNOSTICS_SELFTEST_PATHS_H
-#include "diagnostic-path.h"
-#include "selftest-logical-location.h"
+#include "diagnostics/paths.h"
+#include "diagnostics/selftest-logical-locations.h"
/* The selftest code should entirely disappear in a production
configuration, hence we guard all of it with #if CHECKING_P. */
#if CHECKING_P
+namespace diagnostics {
+namespace paths {
namespace selftest {
/* Concrete subclasses of the abstract base classes
@@ -36,17 +38,20 @@ namespace selftest {
This code should have no dependency on "tree". */
-/* An implementation of diagnostic_event. */
+/* An implementation of diagnostics::paths::event. */
-class test_diagnostic_event : public diagnostic_event
+class test_event : public event
{
public:
- test_diagnostic_event (location_t loc,
- logical_location logical_loc,
- int depth,
- const char *desc,
- diagnostic_thread_id_t thread_id = 0);
- ~test_diagnostic_event ();
+ using logical_location = logical_locations::key;
+ using thread_id_t = paths::thread_id_t;
+
+ test_event (location_t loc,
+ logical_location logical_loc,
+ int depth,
+ const char *desc,
+ thread_id_t thread_id = 0);
+ ~test_event ();
location_t get_location () const final override { return m_loc; }
int get_stack_depth () const final override { return m_depth; }
@@ -66,7 +71,7 @@ class test_diagnostic_event : public diagnostic_event
{
return m_connected_to_next_event;
}
- diagnostic_thread_id_t get_thread_id () const final override
+ thread_id_t get_thread_id () const final override
{
return m_thread_id;
}
@@ -82,15 +87,15 @@ class test_diagnostic_event : public diagnostic_event
int m_depth;
char *m_desc; // has been formatted; doesn't get i18n-ed
bool m_connected_to_next_event;
- diagnostic_thread_id_t m_thread_id;
+ thread_id_t m_thread_id;
};
-/* A simple implementation of diagnostic_thread. */
+/* A simple implementation of diagnostics::paths::thread. */
-class test_diagnostic_thread : public diagnostic_thread
+class test_thread : public thread
{
public:
- test_diagnostic_thread (const char *name) : m_name (name) {}
+ test_thread (const char *name) : m_name (name) {}
label_text get_name (bool) const final override
{
return label_text::borrow (m_name);
@@ -100,33 +105,34 @@ private:
const char *m_name; // has been i18n-ed and formatted
};
-/* A concrete subclass of diagnostic_path for implementing selftests
- - a vector of test_diagnostic_event instances
+/* A concrete subclass of diagnostics::paths::path for implementing selftests
+ - a vector of test_event instances
- adds member functions for adding test event
- does no translation of its events
- has no dependency on "tree". */
-class test_diagnostic_path : public diagnostic_path
+class test_path : public path
{
public:
- test_diagnostic_path (pretty_printer *event_pp);
+ test_path (logical_locations::selftest::test_manager &logical_loc_mgr,
+ pretty_printer *event_pp);
unsigned num_events () const final override;
- const diagnostic_event & get_event (int idx) const final override;
+ const event & get_event (int idx) const final override;
unsigned num_threads () const final override;
- const diagnostic_thread &
- get_thread (diagnostic_thread_id_t) const final override;
+ const thread &
+ get_thread (thread_id_t) const final override;
bool
same_function_p (int event_idx_a,
int event_idx_b) const final override;
- diagnostic_thread_id_t add_thread (const char *name);
+ thread_id_t add_thread (const char *name);
- diagnostic_event_id_t add_event (location_t loc, const char *funcname, int depth,
- const char *fmt, ...)
+ event_id_t add_event (location_t loc, const char *funcname, int depth,
+ const char *fmt, ...)
ATTRIBUTE_GCC_DIAG(5,6);
- diagnostic_event_id_t
- add_thread_event (diagnostic_thread_id_t thread_id,
+ event_id_t
+ add_thread_event (thread_id_t thread_id,
location_t loc, const char *funcname, int depth,
const char *fmt, ...)
ATTRIBUTE_GCC_DIAG(6,7);
@@ -134,28 +140,30 @@ class test_diagnostic_path : public diagnostic_path
void connect_to_next_event ();
void add_entry (const char *callee_name, int stack_depth,
- diagnostic_thread_id_t thread_id = 0);
+ thread_id_t thread_id = 0);
void add_return (const char *caller_name, int stack_depth,
- diagnostic_thread_id_t thread_id = 0);
+ thread_id_t thread_id = 0);
void add_call (const char *caller_name,
int caller_stack_depth,
const char *callee_name,
- diagnostic_thread_id_t thread_id = 0);
+ thread_id_t thread_id = 0);
private:
- logical_location
+ logical_locations::key
logical_location_from_funcname (const char *funcname);
- test_logical_location_manager m_test_logical_loc_mgr;
- auto_delete_vec<test_diagnostic_thread> m_threads;
- auto_delete_vec<test_diagnostic_event> m_events;
+ logical_locations::selftest::test_manager &m_test_logical_loc_mgr;
+ auto_delete_vec<test_thread> m_threads;
+ auto_delete_vec<test_event> m_events;
/* (for use by add_event). */
pretty_printer *m_event_pp;
};
-} // namespace selftest
+} // namespace diagnostics::paths::selftest
+} // namespace diagnostics::paths
+} // namespace diagnostics
#endif /* #if CHECKING_P */
-#endif /* ! GCC_SELFTEST_DIAGNOSTIC_PATH_H */
+#endif /* ! GCC_DIAGNOSTICS_SELFTEST_PATHS_H */
diff --git a/gcc/selftest-diagnostic-show-locus.h b/gcc/diagnostics/selftest-source-printing.h
index 37a18b2..451c120 100644
--- a/gcc/selftest-diagnostic-show-locus.h
+++ b/gcc/diagnostics/selftest-source-printing.h
@@ -17,16 +17,18 @@ 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_SELFTEST_DIAGNOSTIC_SHOW_LOCUS_H
-#define GCC_SELFTEST_DIAGNOSTIC_SHOW_LOCUS_H
+#ifndef GCC_DIAGNOSTICS_SELFTEST_SOURCE_PRINTING_H
+#define GCC_DIAGNOSTICS_SELFTEST_SOURCE_PRINTING_H
#include "selftest.h"
+#include "diagnostics/file-cache.h"
/* The selftest code should entirely disappear in a production
configuration, hence we guard all of it with #if CHECKING_P. */
#if CHECKING_P
+namespace diagnostics {
namespace selftest {
/* RAII class for use in selftests involving diagnostic_show_locus.
@@ -37,10 +39,10 @@ namespace selftest {
push a line_map starting at the first line of the temporary file
- provide a file_cache. */
-struct diagnostic_show_locus_fixture
+struct source_printing_fixture
{
- diagnostic_show_locus_fixture (const line_table_case &case_,
- const char *content);
+ source_printing_fixture (const ::selftest::line_table_case &case_,
+ const char *content);
const char *get_filename () const
{
@@ -48,8 +50,8 @@ struct diagnostic_show_locus_fixture
}
const char *m_content;
- temp_source_file m_tmp_source_file;
- line_table_test m_ltt;
+ ::selftest::temp_source_file m_tmp_source_file;
+ ::selftest::line_table_test m_ltt;
file_cache m_fc;
};
@@ -69,14 +71,15 @@ struct diagnostic_show_locus_fixture
Here SS represents the two display columns for the U+1F602 emoji and
P represents the one display column for the U+03C0 pi symbol. */
-struct diagnostic_show_locus_fixture_one_liner_utf8
- : public diagnostic_show_locus_fixture
+struct source_printing_fixture_one_liner_utf8
+ : public source_printing_fixture
{
- diagnostic_show_locus_fixture_one_liner_utf8 (const line_table_case &case_);
+ source_printing_fixture_one_liner_utf8 (const ::selftest::line_table_case &case_);
};
-} // namespace selftest
+} // namespace diagnostics::selftest
+} // namespace diagnostics
#endif /* #if CHECKING_P */
-#endif /* GCC_SELFTEST_DIAGNOSTIC_SHOW_LOCUS_H */
+#endif /* GCC_DIAGNOSTICS_SELFTEST_SOURCE_PRINTING_H */
diff --git a/gcc/diagnostic-format.h b/gcc/diagnostics/sink.h
index a4c776c..ac4e0fb64 100644
--- a/gcc/diagnostic-format.h
+++ b/gcc/diagnostics/sink.h
@@ -18,21 +18,23 @@ 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_DIAGNOSTIC_FORMAT_H
-#define GCC_DIAGNOSTIC_FORMAT_H
+#ifndef GCC_DIAGNOSTICS_SINK_H
+#define GCC_DIAGNOSTICS_SINK_H
#include "diagnostic.h"
-class diagnostic_per_format_buffer;
+namespace diagnostics {
+
+class per_sink_buffer;
/* Abstract base class for a particular output format for diagnostics;
each value of -fdiagnostics-output-format= will have its own
implementation. */
-class diagnostic_output_format
+class sink
{
public:
- virtual ~diagnostic_output_format () {}
+ virtual ~sink () {}
virtual void dump (FILE *out, int indent) const;
@@ -40,16 +42,16 @@ public:
e.g. for titles of HTML, for SARIF's artifact metadata. */
virtual void set_main_input_filename (const char *) {}
- /* Vfunc for making an appropriate diagnostic_per_format_buffer
+ /* Vfunc for making an appropriate per_sink_buffer
subclass for this format. */
- virtual std::unique_ptr<diagnostic_per_format_buffer>
- make_per_format_buffer () = 0;
+ virtual std::unique_ptr<per_sink_buffer>
+ make_per_sink_buffer () = 0;
- /* Vfunc to be called when call a diagnostic_buffer is set on
- a diagnostic_context, to update this format. The per_format_buffer
- will be one created by make_per_format_buffer above and thus be
+ /* Vfunc to be called when call a diagnostics::buffer is set on
+ a diagnostics::context, to update this format. The per_sink_buffer
+ will be one created by make_per_sink_buffer above and thus be
of the correct subclass. */
- virtual void set_buffer (diagnostic_per_format_buffer *) = 0;
+ virtual void set_buffer (per_sink_buffer *) = 0;
virtual void on_begin_group () = 0;
virtual void on_end_group () = 0;
@@ -57,25 +59,25 @@ public:
/* Vfunc with responsibility for phase 3 of formatting the message
and "printing" the result. */
virtual void on_report_diagnostic (const diagnostic_info &,
- diagnostic_t orig_diag_kind) = 0;
+ enum kind orig_diag_kind) = 0;
virtual void on_report_verbatim (text_info &);
- virtual void on_diagram (const diagnostic_diagram &diagram) = 0;
+ virtual void on_diagram (const diagram &diag) = 0;
virtual void after_diagnostic (const diagnostic_info &) = 0;
virtual bool machine_readable_stderr_p () const = 0;
virtual bool follows_reference_printer_p () const = 0;
- /* Vfunc called when the diagnostic_context changes its
+ /* Vfunc called when the diagnostics::context changes its
reference printer (either to a new subclass of pretty_printer
or when color/url options change).
Subclasses should update their m_printer accordingly. */
virtual void update_printer () = 0;
virtual void
- report_global_digraph (const diagnostics::digraphs::lazy_digraph &) = 0;
+ report_global_digraph (const lazily_created<digraphs::digraph> &) = 0;
- diagnostic_context &get_context () const { return m_context; }
+ context &get_context () const { return m_context; }
pretty_printer *get_printer () const { return m_printer.get (); }
text_art::theme *get_diagram_theme () const
@@ -86,21 +88,23 @@ public:
void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
protected:
- diagnostic_output_format (diagnostic_context &context)
- : m_context (context),
- m_printer (context.clone_printer ())
+ sink (context &dc)
+ : m_context (dc),
+ m_printer (dc.clone_printer ())
{}
protected:
- diagnostic_context &m_context;
+ context &m_context;
std::unique_ptr<pretty_printer> m_printer;
};
extern void
-diagnostic_output_format_init (diagnostic_context &,
- const char *main_input_filename_,
- const char *base_file_name,
- enum diagnostics_output_format,
- bool json_formatting);
+output_format_init (context &,
+ const char *main_input_filename_,
+ const char *base_file_name,
+ enum diagnostics_output_format,
+ bool json_formatting);
+
+} // namespace diagnostics
-#endif /* ! GCC_DIAGNOSTIC_FORMAT_H */
+#endif /* ! GCC_DIAGNOSTICS_SINK_H */
diff --git a/gcc/diagnostic-label-effects.h b/gcc/diagnostics/source-printing-effects.h
index 1d877b0d..3c4b1bd 100644
--- a/gcc/diagnostic-label-effects.h
+++ b/gcc/diagnostics/source-printing-effects.h
@@ -18,8 +18,10 @@ 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_DIAGNOSTIC_LABEL_EFFECTS_H
-#define GCC_DIAGNOSTIC_LABEL_EFFECTS_H
+#ifndef GCC_DIAGNOSTICS_SOURCE_PRINTING_EFFECTS_H
+#define GCC_DIAGNOSTICS_SOURCE_PRINTING_EFFECTS_H
+
+namespace diagnostics {
/* Abstract base class for describing special effects when printing
a label when quoting source code. */
@@ -37,10 +39,10 @@ public:
/* A class to hold state when quoting a run of lines of source code. */
-class diagnostic_source_effect_info
+class source_effect_info
{
public:
- diagnostic_source_effect_info ()
+ source_effect_info ()
: m_leading_in_edge_column (-1),
m_trailing_out_edge_column (-1)
{
@@ -55,4 +57,6 @@ public:
int m_trailing_out_edge_column;
};
-#endif /* GCC_DIAGNOSTIC_LABEL_EFFECTS_H */
+} // namespace diagnostics
+
+#endif /* GCC_DIAGNOSTICS_SOURCE_PRINTING_EFFECTS_H */
diff --git a/gcc/diagnostic-show-locus.cc b/gcc/diagnostics/source-printing.cc
index da7637c..94b1c2d 100644
--- a/gcc/diagnostic-show-locus.cc
+++ b/gcc/diagnostics/source-printing.cc
@@ -25,20 +25,19 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "version.h"
-#include "demangle.h"
#include "intl.h"
-#include "backtrace.h"
#include "diagnostic.h"
-#include "diagnostic-color.h"
+#include "diagnostics/color.h"
#include "gcc-rich-location.h"
#include "text-range-label.h"
#include "selftest.h"
-#include "selftest-diagnostic.h"
-#include "selftest-diagnostic-show-locus.h"
+#include "diagnostics/selftest-context.h"
+#include "diagnostics/selftest-source-printing.h"
#include "cpplib.h"
#include "text-art/types.h"
#include "text-art/theme.h"
-#include "diagnostic-label-effects.h"
+#include "diagnostics/source-printing-effects.h"
+#include "diagnostics/file-cache.h"
#include "xml.h"
#include "xml-printer.h"
@@ -96,7 +95,7 @@ class colorizer
public:
colorizer (pretty_printer &pp,
const rich_location &richloc,
- diagnostic_t diagnostic_kind);
+ enum diagnostics::kind diagnostic_kind);
~colorizer ();
void set_range (int range_idx)
@@ -116,7 +115,7 @@ class colorizer
two colors for the secondary locations.
But if we're printing a run of events in a diagnostic path, that
makes no sense, so print all of them with the same colorization. */
- if (m_diagnostic_kind == DK_DIAGNOSTIC_PATH)
+ if (m_diagnostic_kind == diagnostics::kind::path)
set_state (0);
else
set_state (range_idx);
@@ -141,7 +140,7 @@ class colorizer
pretty_printer &m_pp;
const rich_location &m_richloc;
- diagnostic_t m_diagnostic_kind;
+ enum diagnostics::kind m_diagnostic_kind;
int m_current_state;
const char *m_range1;
const char *m_range2;
@@ -203,7 +202,7 @@ enum column_unit {
class exploc_with_display_col : public expanded_location
{
public:
- exploc_with_display_col (file_cache &fc,
+ exploc_with_display_col (diagnostics::file_cache &fc,
const expanded_location &exploc,
const cpp_char_column_policy &policy,
enum location_aspect aspect)
@@ -375,9 +374,9 @@ struct char_display_policy : public cpp_char_column_policy
public:
char_display_policy (int tabstop,
int (*width_cb) (cppchar_t c),
- void (*print_text_cb) (to_text &sink,
+ void (*print_text_cb) (diagnostics::to_text &text_out,
const cpp_decoded_char &cp),
- void (*print_html_cb) (to_html &sink,
+ void (*print_html_cb) (diagnostics::to_html &html_out,
const cpp_decoded_char &cp))
: cpp_char_column_policy (tabstop, width_cb),
m_print_text_cb (print_text_cb),
@@ -385,21 +384,23 @@ struct char_display_policy : public cpp_char_column_policy
{
}
- void (*m_print_text_cb) (to_text &sink,
+ void (*m_print_text_cb) (diagnostics::to_text &text_out,
const cpp_decoded_char &cp);
- void (*m_print_html_cb) (to_html &sink,
+ void (*m_print_html_cb) (diagnostics::to_html &html_out,
const cpp_decoded_char &cp);
};
-template <typename Sink> class layout_printer;
+template <typename TextOrHtml> class layout_printer;
} // anonymous namespace
+namespace diagnostics {
+
/* This code is written generically to write either:
- text, to a pretty_printer, potentially with colorization codes, or
- html, to an xml::printer, with nested HTML tags.
- This is handled via a "Sink" template, which is either to_text
+ This is handled via a "TextOrHtml" template, which is either to_text
or to_html. */
/* Writing text output. */
@@ -519,8 +520,8 @@ struct to_text
}
void
- invoke_start_span_fn (const diagnostic_source_print_policy &source_policy,
- const diagnostic_location_print_policy &loc_policy,
+ invoke_start_span_fn (const source_print_policy &source_policy,
+ const location_print_policy &loc_policy,
const expanded_location &exploc)
{
source_policy.get_text_start_span_fn () (loc_policy, *this, exploc);
@@ -548,8 +549,8 @@ struct to_html
struct auto_check_tag_nesting : public xml::auto_check_tag_nesting
{
public:
- auto_check_tag_nesting (to_html &sink)
- : xml::auto_check_tag_nesting (sink.m_xp)
+ auto_check_tag_nesting (to_html &out)
+ : xml::auto_check_tag_nesting (out.m_xp)
{
}
};
@@ -654,8 +655,8 @@ struct to_html
}
void
- invoke_start_span_fn (const diagnostic_source_print_policy &source_policy,
- const diagnostic_location_print_policy &loc_policy,
+ invoke_start_span_fn (const source_print_policy &source_policy,
+ const location_print_policy &loc_policy,
const expanded_location &exploc)
{
source_policy.get_html_start_span_fn () (loc_policy, *this, exploc);
@@ -687,66 +688,67 @@ private:
};
void
-diagnostic_location_print_policy::
-print_text_span_start (const diagnostic_context &dc,
+location_print_policy::
+print_text_span_start (const diagnostics::context &dc,
pretty_printer &pp,
const expanded_location &exploc)
{
- to_text sink (pp, nullptr);
- diagnostic_source_print_policy source_policy (dc);
- source_policy.get_text_start_span_fn () (*this, sink, exploc);
+ to_text out (pp, nullptr);
+ source_print_policy source_policy (dc);
+ source_policy.get_text_start_span_fn () (*this, out, exploc);
}
void
-diagnostic_location_print_policy::
-print_html_span_start (const diagnostic_context &dc,
+location_print_policy::
+print_html_span_start (const diagnostics::context &dc,
xml::printer &xp,
const expanded_location &exploc)
{
- to_html sink (xp, nullptr, nullptr);
- diagnostic_source_print_policy source_policy (dc);
- source_policy.get_html_start_span_fn () (*this, sink, exploc);
+ to_html out (xp, nullptr, nullptr);
+ source_print_policy source_policy (dc);
+ source_policy.get_html_start_span_fn () (*this, out, exploc);
}
pretty_printer *
-get_printer (to_text &sink)
+get_printer (to_text &out)
{
- return &sink.m_pp;
+ return &out.m_pp;
}
template<>
void
-default_diagnostic_start_span_fn<to_text> (const diagnostic_location_print_policy &loc_policy,
- to_text &sink,
- expanded_location exploc)
+default_start_span_fn<to_text> (const location_print_policy &loc_policy,
+ to_text &out,
+ expanded_location exploc)
{
- const diagnostic_column_policy &column_policy
- = loc_policy.get_column_policy ();
+ const column_policy &column_policy_ = loc_policy.get_column_policy ();
label_text text
- = column_policy.get_location_text (exploc,
- loc_policy.show_column_p (),
- pp_show_color (&sink.m_pp));
- pp_string (&sink.m_pp, text.get ());
- pp_newline (&sink.m_pp);
+ = column_policy_.get_location_text (exploc,
+ loc_policy.show_column_p (),
+ pp_show_color (&out.m_pp));
+ pp_string (&out.m_pp, text.get ());
+ pp_newline (&out.m_pp);
}
template<>
void
-default_diagnostic_start_span_fn<to_html> (const diagnostic_location_print_policy &loc_policy,
- to_html &sink,
- expanded_location exploc)
+default_start_span_fn<to_html> (const location_print_policy &loc_policy,
+ to_html &out,
+ expanded_location exploc)
{
- const diagnostic_column_policy &column_policy
+ const column_policy &column_policy_
= loc_policy.get_column_policy ();
label_text text
- = column_policy.get_location_text (exploc,
- loc_policy.show_column_p (),
- false);
- sink.m_xp.push_tag_with_class ("span", "location", true);
- sink.m_xp.add_text (text.get ());
- sink.m_xp.pop_tag ("span");
+ = column_policy_.get_location_text (exploc,
+ loc_policy.show_column_p (),
+ false);
+ out.m_xp.push_tag_with_class ("span", "location", true);
+ out.m_xp.add_text (text.get ());
+ out.m_xp.pop_tag ("span");
}
+} // namespace diagnostics
+
namespace {
/* A class to control the overall layout when printing a diagnostic.
@@ -761,12 +763,12 @@ namespace {
class layout
{
public:
- friend class layout_printer<to_text>;
- friend class layout_printer<to_html>;
+ friend class layout_printer<diagnostics::to_text>;
+ friend class layout_printer<diagnostics::to_html>;
- layout (const diagnostic_source_print_policy &source_policy,
+ layout (const diagnostics::source_print_policy &source_policy,
const rich_location &richloc,
- diagnostic_source_effect_info *effect_info = nullptr);
+ diagnostics::source_effect_info *effect_info = nullptr);
bool maybe_add_location_range (const location_range *loc_range,
unsigned original_idx,
@@ -811,12 +813,12 @@ class layout
private:
bool compatible_locations_p (location_t loc_a, location_t loc_b) const;
- const diagnostic_source_printing_options &m_options;
+ const diagnostics::source_printing_options &m_options;
const line_maps *m_line_table;
- file_cache &m_file_cache;
+ diagnostics::file_cache &m_file_cache;
const text_art::ascii_theme m_fallback_theme;
const text_art::theme &m_theme;
- diagnostic_source_effect_info *m_effect_info;
+ diagnostics::source_effect_info *m_effect_info;
char_display_policy m_char_policy;
location_t m_primary_loc;
exploc_with_display_col m_exploc;
@@ -838,19 +840,19 @@ enum class margin_kind
};
/* A bundle of state for printing a particular layout
- to a particular Sink (either to_text or to_html). */
-template <typename Sink>
+ to a particular TextOrHtml (either to_text or to_html). */
+template <typename TextOrHtml>
class layout_printer
{
public:
- layout_printer (Sink &sink,
+ layout_printer (TextOrHtml &text_or_html,
const layout &layout,
bool is_diagnostic_path);
- void print (const diagnostic_source_print_policy &source_policy);
+ void print (const diagnostics::source_print_policy &source_policy);
private:
- const diagnostic_source_printing_options &
+ const diagnostics::source_printing_options &
get_options () const { return m_layout.m_options; }
const text_art::theme &
@@ -880,7 +882,7 @@ private:
void set_outside_range ();
private:
- Sink &m_sink;
+ TextOrHtml &m_text_or_html;
const layout &m_layout;
bool m_is_diagnostic_path;
@@ -944,7 +946,7 @@ private:
colorizer::colorizer (pretty_printer &pp,
const rich_location &richloc,
- diagnostic_t diagnostic_kind) :
+ enum diagnostics::kind diagnostic_kind) :
m_pp (pp),
m_richloc (richloc),
m_diagnostic_kind (diagnostic_kind),
@@ -1022,7 +1024,7 @@ colorizer::begin_state (int state)
pp_string
(&m_pp,
colorize_start (pp_show_color (&m_pp),
- diagnostic_get_color_for_kind (m_diagnostic_kind)));
+ get_color_for_kind (m_diagnostic_kind)));
break;
case 1:
@@ -1206,7 +1208,8 @@ layout_range::has_in_edge () const
{
if (!m_label)
return false;
- const label_effects *effects = m_label->get_effects (m_original_idx);
+ const diagnostics::label_effects *effects
+ = m_label->get_effects (m_original_idx);
if (!effects)
return false;
@@ -1220,7 +1223,8 @@ layout_range::has_out_edge () const
{
if (!m_label)
return false;
- const label_effects *effects = m_label->get_effects (m_original_idx);
+ const diagnostics::label_effects *effects
+ = m_label->get_effects (m_original_idx);
if (!effects)
return false;
@@ -1247,7 +1251,7 @@ static cpp_char_column_policy def_policy ()
e.g. in test_diagnostic_show_locus_one_liner_utf8(). */
static layout_range
-make_range (file_cache &fc,
+make_range (diagnostics::file_cache &fc,
int start_line, int start_col, int end_line, int end_col)
{
const expanded_location start_exploc
@@ -1276,7 +1280,7 @@ make_range (file_cache &fc,
static void
test_layout_range_for_single_point ()
{
- file_cache fc;
+ diagnostics::file_cache fc;
layout_range point = make_range (fc, 7, 10, 7, 10);
/* Tests for layout_range::contains_point. */
@@ -1313,7 +1317,7 @@ test_layout_range_for_single_point ()
static void
test_layout_range_for_single_line ()
{
- file_cache fc;
+ diagnostics::file_cache fc;
layout_range example_a = make_range (fc, 2, 22, 2, 38);
/* Tests for layout_range::contains_point. */
@@ -1356,7 +1360,7 @@ test_layout_range_for_single_line ()
static void
test_layout_range_for_multiple_lines ()
{
- file_cache fc;
+ diagnostics::file_cache fc;
layout_range example_b = make_range (fc, 3, 14, 5, 8);
/* Tests for layout_range::contains_point. */
@@ -1567,9 +1571,9 @@ fixit_cmp (const void *p_a, const void *p_b)
/* Callback for char_display_policy::m_print_cb for printing source chars
when not escaping the source. */
-template <class Sink>
+template <class TextOrHtml>
static void
-default_print_decoded_ch (Sink &sink,
+default_print_decoded_ch (TextOrHtml &text_or_html,
const cpp_decoded_char &decoded_ch)
{
for (const char *ptr = decoded_ch.m_start_byte;
@@ -1577,11 +1581,11 @@ default_print_decoded_ch (Sink &sink,
{
if (*ptr == '\0' || *ptr == '\r')
{
- sink.add_space ();
+ text_or_html.add_space ();
continue;
}
- sink.add_utf8_byte (*ptr);
+ text_or_html.add_utf8_byte (*ptr);
}
}
@@ -1609,9 +1613,9 @@ escape_as_bytes_width (cppchar_t ch)
/* Callback for char_display_policy::m_print_cb for printing source chars
when escaping with DIAGNOSTICS_ESCAPE_FORMAT_BYTES. */
-template <typename Sink>
+template <typename TextOrHtml>
static void
-escape_as_bytes_print (Sink &sink,
+escape_as_bytes_print (TextOrHtml &text_or_html,
const cpp_decoded_char &decoded_ch)
{
if (!decoded_ch.m_valid_ch)
@@ -1621,14 +1625,14 @@ escape_as_bytes_print (Sink &sink,
{
char buf[16];
sprintf (buf, "<%02x>", (unsigned char)*iter);
- sink.add_text (buf);
+ text_or_html.add_text (buf);
}
return;
}
cppchar_t ch = decoded_ch.m_ch;
if (ch < 0x80 && ISPRINT (ch))
- sink.add_character (ch);
+ text_or_html.add_character (ch);
else
{
for (const char *iter = decoded_ch.m_start_byte;
@@ -1636,7 +1640,7 @@ escape_as_bytes_print (Sink &sink,
{
char buf[16];
sprintf (buf, "<%02x>", (unsigned char)*iter);
- sink.add_text (buf);
+ text_or_html.add_text (buf);
}
}
}
@@ -1666,40 +1670,40 @@ escape_as_unicode_width (cppchar_t ch)
/* Callback for char_display_policy::m_print_cb for printing source chars
when escaping with DIAGNOSTICS_ESCAPE_FORMAT_UNICODE. */
-template <typename Sink>
+template <typename TextOrHtml>
static void
-escape_as_unicode_print (Sink &sink,
+escape_as_unicode_print (TextOrHtml &text_or_html,
const cpp_decoded_char &decoded_ch)
{
if (!decoded_ch.m_valid_ch)
{
- escape_as_bytes_print<Sink> (sink, decoded_ch);
+ escape_as_bytes_print<TextOrHtml> (text_or_html, decoded_ch);
return;
}
cppchar_t ch = decoded_ch.m_ch;
if (ch < 0x80 && ISPRINT (ch))
- sink.add_character (ch);
+ text_or_html.add_character (ch);
else
{
char buf[16];
sprintf (buf, "<U+%04X>", ch);
- sink.add_text (buf);
+ text_or_html.add_text (buf);
}
}
/* Populate a char_display_policy based on SOURCE_POLICY and RICHLOC. */
static char_display_policy
-make_char_policy (const diagnostic_source_print_policy &source_policy,
+make_char_policy (const diagnostics::source_print_policy &source_policy,
const rich_location &richloc)
{
/* The default is to not escape non-ASCII bytes. */
char_display_policy result
(source_policy.get_column_policy ().get_tabstop (),
cpp_wcwidth,
- default_print_decoded_ch<to_text>,
- default_print_decoded_ch<to_html>);
+ default_print_decoded_ch<diagnostics::to_text>,
+ default_print_decoded_ch<diagnostics::to_html>);
/* If the diagnostic suggests escaping non-ASCII bytes, then
use policy from user-supplied options. */
@@ -1712,13 +1716,15 @@ make_char_policy (const diagnostic_source_print_policy &source_policy,
gcc_unreachable ();
case DIAGNOSTICS_ESCAPE_FORMAT_UNICODE:
result.m_width_cb = escape_as_unicode_width;
- result.m_print_text_cb = escape_as_unicode_print<to_text>;
- result.m_print_html_cb = escape_as_unicode_print<to_html>;
+ result.m_print_text_cb
+ = escape_as_unicode_print<diagnostics::to_text>;
+ result.m_print_html_cb
+ = escape_as_unicode_print<diagnostics::to_html>;
break;
case DIAGNOSTICS_ESCAPE_FORMAT_BYTES:
result.m_width_cb = escape_as_bytes_width;
- result.m_print_text_cb = escape_as_bytes_print<to_text>;
- result.m_print_html_cb = escape_as_bytes_print<to_html>;
+ result.m_print_text_cb = escape_as_bytes_print<diagnostics::to_text>;
+ result.m_print_html_cb = escape_as_bytes_print<diagnostics::to_html>;
break;
}
}
@@ -1735,11 +1741,11 @@ make_char_policy (const diagnostic_source_print_policy &source_policy,
Determine the range of lines that we will print, splitting them
up into an ordered list of disjoint spans of contiguous line numbers.
Determine m_x_offset_display, to ensure that the primary caret
- will fit within the max_width provided by the diagnostic_context. */
+ will fit within the max_width provided by the diagnostics::context. */
-layout::layout (const diagnostic_source_print_policy &source_policy,
+layout::layout (const diagnostics::source_print_policy &source_policy,
const rich_location &richloc,
- diagnostic_source_effect_info *effect_info)
+ diagnostics::source_effect_info *effect_info)
: m_options (source_policy.get_options ()),
m_line_table (richloc.get_line_table ()),
m_file_cache (source_policy.get_file_cache ()),
@@ -1927,25 +1933,25 @@ layout::will_show_line_p (linenum_type row) const
template<>
void
-layout_printer<to_text>::print_gap_in_line_numbering ()
+layout_printer<diagnostics::to_text>::print_gap_in_line_numbering ()
{
gcc_assert (m_layout.m_options.show_line_numbers_p);
- m_sink.emit_text_prefix ();
+ m_text_or_html.emit_text_prefix ();
for (int i = 0; i < m_layout.get_linenum_width () + 1; i++)
- m_sink.add_character ('.');
+ m_text_or_html.add_character ('.');
- m_sink.add_newline ();
+ m_text_or_html.add_newline ();
}
template<>
void
-layout_printer<to_html>::print_gap_in_line_numbering ()
+layout_printer<diagnostics::to_html>::print_gap_in_line_numbering ()
{
gcc_assert (m_layout.m_options.show_line_numbers_p);
- m_sink.add_raw_html
+ m_text_or_html.add_raw_html
("<tbody class=\"line-span-jump\">\n"
"<tr class=\"line-span-jump-row\">"
"<td class=\"linenum-gap\">[...]</td>"
@@ -2169,7 +2175,7 @@ layout::calculate_linenum_width ()
int highest_line = last_span->m_last_line;
if (highest_line < 0)
highest_line = 0;
- m_linenum_width = num_digits (highest_line);
+ m_linenum_width = diagnostics::num_digits (highest_line);
/* If we're showing jumps in the line-numbering, allow at least 3 chars. */
if (m_line_spans.length () > 1)
m_linenum_width = MAX (m_linenum_width, 3);
@@ -2196,8 +2202,9 @@ layout::calculate_x_offset_display ()
return;
}
- const char_span line = m_file_cache.get_source_line (m_exploc.file,
- m_exploc.line);
+ const diagnostics::char_span line
+ = m_file_cache.get_source_line (m_exploc.file,
+ m_exploc.line);
if (!line)
{
/* Nothing to do, we couldn't find the source line. */
@@ -2264,32 +2271,32 @@ layout::calculate_x_offset_display ()
colorization and tab expansion, this function tracks the line position in
both byte and display column units. */
-template<typename Sink>
+template<typename TextOrHtml>
line_bounds
-layout_printer<Sink>::print_source_line (linenum_type row,
+layout_printer<TextOrHtml>::print_source_line (linenum_type row,
const char *line,
int line_bytes)
{
- m_sink.colorize_text_ensure_normal ();
- m_sink.push_html_tag ("tr", true);
- m_sink.emit_text_prefix ();
+ m_text_or_html.colorize_text_ensure_normal ();
+ m_text_or_html.push_html_tag ("tr", true);
+ m_text_or_html.emit_text_prefix ();
if (m_layout.m_options.show_line_numbers_p)
{
- m_sink.push_html_tag_with_class ("td", "linenum", true);
- int width = num_digits (row);
+ m_text_or_html.push_html_tag_with_class ("td", "linenum", true);
+ int width = diagnostics::num_digits (row);
for (int i = 0; i < m_layout.get_linenum_width () - width; i++)
- m_sink.add_space ();
+ m_text_or_html.add_space ();
char buf[20];
sprintf (buf, "%i", row);
- m_sink.add_text (buf);
- if (Sink::is_text ())
- m_sink.add_text (" |");
- m_sink.pop_html_tag ("td");
+ m_text_or_html.add_text (buf);
+ if (TextOrHtml::is_text ())
+ m_text_or_html.add_text (" |");
+ m_text_or_html.pop_html_tag ("td");
}
- m_sink.push_html_tag_with_class ("td", "left-margin", true);
+ m_text_or_html.push_html_tag_with_class ("td", "left-margin", true);
print_leftmost_column ();
- m_sink.pop_html_tag ("td");
+ m_text_or_html.pop_html_tag ("td");
/* We will stop printing the source line at any trailing whitespace. */
line_bytes = get_line_bytes_without_trailing_whitespace (line,
@@ -2300,7 +2307,7 @@ layout_printer<Sink>::print_source_line (linenum_type row,
tab expansion, and for implementing m_x_offset_display. */
cpp_display_width_computation dw (line, line_bytes, m_layout.m_char_policy);
- m_sink.push_html_tag_with_class ("td", "source", true);
+ m_text_or_html.push_html_tag_with_class ("td", "source", true);
/* Skip the first m_x_offset_display display columns. In case the leading
portion that will be skipped ends with a character with wcwidth > 1, then
@@ -2312,7 +2319,7 @@ layout_printer<Sink>::print_source_line (linenum_type row,
for (int skipped_display_cols
= dw.advance_display_cols (m_layout.m_x_offset_display);
skipped_display_cols > m_layout.m_x_offset_display; --skipped_display_cols)
- m_sink.add_space ();
+ m_text_or_html.add_space ();
/* Print the line and compute the line_bounds. */
line_bounds lbounds;
@@ -2356,7 +2363,7 @@ layout_printer<Sink>::print_source_line (linenum_type row,
/* The returned display width is the number of spaces into which the
tab should be expanded. */
for (int i = 0; i != this_display_width; ++i)
- m_sink.add_space ();
+ m_text_or_html.add_space ();
continue;
}
@@ -2370,7 +2377,7 @@ layout_printer<Sink>::print_source_line (linenum_type row,
}
/* Output the character. */
- m_sink.print_decoded_char (m_layout.m_char_policy, cp);
+ m_text_or_html.print_decoded_char (m_layout.m_char_policy, cp);
c = dw.next_byte ();
}
set_outside_range ();
@@ -2399,9 +2406,9 @@ layout::should_print_annotation_line_p (linenum_type row) const
/* Print the leftmost column after the margin, which is used for showing
links between labels (e.g. for CFG edges in execution paths). */
-template<typename Sink>
+template<typename TextOrHtml>
void
-layout_printer<Sink>::print_leftmost_column ()
+layout_printer<TextOrHtml>::print_leftmost_column ()
{
if (!get_options ().show_event_links_p)
gcc_assert (m_link_lhs_state == link_lhs_state::none);
@@ -2411,33 +2418,33 @@ layout_printer<Sink>::print_leftmost_column ()
default:
gcc_unreachable ();
case link_lhs_state::none:
- m_sink.add_space ();
+ m_text_or_html.add_space ();
break;
case link_lhs_state::rewinding_to_lhs:
{
- m_sink.colorize_text_for_cfg_edge ();
+ m_text_or_html.colorize_text_for_cfg_edge ();
const cppchar_t ch = get_theme ().get_cppchar
(text_art::theme::cell_kind::CFG_FROM_LEFT_TO_DOWN);
- m_sink.add_character (ch);
- m_sink.colorize_text_ensure_normal ();
+ m_text_or_html.add_character (ch);
+ m_text_or_html.colorize_text_ensure_normal ();
}
break;
case link_lhs_state::at_lhs:
{
- m_sink.colorize_text_for_cfg_edge ();
+ m_text_or_html.colorize_text_for_cfg_edge ();
const cppchar_t ch = get_theme ().get_cppchar
(text_art::theme::cell_kind::CFG_DOWN);
- m_sink.add_character (ch);
- m_sink.colorize_text_ensure_normal ();
+ m_text_or_html.add_character (ch);
+ m_text_or_html.colorize_text_ensure_normal ();
}
break;
case link_lhs_state::indenting_to_dest:
{
- m_sink.colorize_text_for_cfg_edge ();
+ m_text_or_html.colorize_text_for_cfg_edge ();
const cppchar_t ch = get_theme ().get_cppchar
(text_art::theme::cell_kind::CFG_FROM_DOWN_TO_RIGHT);
- m_sink.add_character (ch);
- m_sink.colorize_text_ensure_normal ();
+ m_text_or_html.add_character (ch);
+ m_text_or_html.colorize_text_ensure_normal ();
}
break;
}
@@ -2450,16 +2457,16 @@ layout_printer<Sink>::print_leftmost_column ()
After any left margin, print a leftmost column, which is used for
showing links between labels (e.g. for CFG edges in execution paths).
- For text sinks, this also first prints the text prefix.
- For html sinks, this also pushes <tr> and <td> open tags, where the
+ For text output, this also first prints the text prefix.
+ For html output, this also pushes <tr> and <td> open tags, where the
<td> is for the coming annotations. */
-template<typename Sink>
+template<typename TextOrHtml>
void
-layout_printer<Sink>::start_annotation_line (enum margin_kind margin)
+layout_printer<TextOrHtml>::start_annotation_line (enum margin_kind margin)
{
- m_sink.emit_text_prefix ();
- m_sink.push_html_tag ("tr", true);
+ m_text_or_html.emit_text_prefix ();
+ m_text_or_html.push_html_tag ("tr", true);
char margin_char = (margin == margin_kind::insertion
? '+'
@@ -2469,29 +2476,29 @@ layout_printer<Sink>::start_annotation_line (enum margin_kind margin)
{
/* Print the margin. If MARGIN_CHAR != ' ', then print up to 3
of it, right-aligned, padded with spaces. */
- m_sink.push_html_tag_with_class ("td", "linenum", true);
+ m_text_or_html.push_html_tag_with_class ("td", "linenum", true);
int i;
for (i = 0; i < m_layout.m_linenum_width - 3; i++)
- m_sink.add_space ();
+ m_text_or_html.add_space ();
for (; i < m_layout.m_linenum_width; i++)
- m_sink.add_character (margin_char);
- if (Sink::is_text ())
- m_sink.add_text (" |");
- m_sink.pop_html_tag ("td");
+ m_text_or_html.add_character (margin_char);
+ if (TextOrHtml::is_text ())
+ m_text_or_html.add_text (" |");
+ m_text_or_html.pop_html_tag ("td");
}
- m_sink.push_html_tag_with_class ("td", "left-margin", true);
+ m_text_or_html.push_html_tag_with_class ("td", "left-margin", true);
if (margin == margin_kind::insertion)
- m_sink.add_character (margin_char);
+ m_text_or_html.add_character (margin_char);
else
print_leftmost_column ();
- m_sink.pop_html_tag ("td");
+ m_text_or_html.pop_html_tag ("td");
- m_sink.push_html_tag_with_class ("td",
- (margin == margin_kind::ruler
- ? "ruler"
- : "annotation"),
- true);
+ m_text_or_html.push_html_tag_with_class ("td",
+ (margin == margin_kind::ruler
+ ? "ruler"
+ : "annotation"),
+ true);
}
/* End a source or annotation line: text implementation.
@@ -2499,10 +2506,10 @@ layout_printer<Sink>::start_annotation_line (enum margin_kind margin)
template<>
void
-layout_printer<to_text>::end_line ()
+layout_printer<diagnostics::to_text>::end_line ()
{
- m_sink.colorize_text_ensure_normal ();
- m_sink.add_newline ();
+ m_text_or_html.colorize_text_ensure_normal ();
+ m_text_or_html.add_newline ();
}
/* End a source or annotation line: HTML implementation.
@@ -2510,18 +2517,18 @@ layout_printer<to_text>::end_line ()
template<>
void
-layout_printer<to_html>::end_line ()
+layout_printer<diagnostics::to_html>::end_line ()
{
- m_sink.pop_html_tag ("td");
- m_sink.pop_html_tag ("tr");
+ m_text_or_html.pop_html_tag ("td");
+ m_text_or_html.pop_html_tag ("tr");
}
/* Handle the various transitions between being-in-range and
not-being-in-a-range, and between ranges. */
-template<typename Sink>
+template<typename TextOrHtml>
void
-layout_printer<Sink>::set_in_range (int range_idx)
+layout_printer<TextOrHtml>::set_in_range (int range_idx)
{
if (m_was_in_range_p)
{
@@ -2541,9 +2548,9 @@ layout_printer<Sink>::set_in_range (int range_idx)
m_last_range_idx = range_idx;
}
-template<typename Sink>
+template<typename TextOrHtml>
void
-layout_printer<Sink>::set_outside_range ()
+layout_printer<TextOrHtml>::set_outside_range ()
{
if (m_was_in_range_p)
/* transition from "in a range" to "not in a range". */
@@ -2554,9 +2561,9 @@ layout_printer<Sink>::set_outside_range ()
/* Print a line consisting of the caret/underlines for the given
source line. */
-template<typename Sink>
+template<typename TextOrHtml>
void
-layout_printer<Sink>::print_annotation_line (linenum_type row,
+layout_printer<TextOrHtml>::print_annotation_line (linenum_type row,
const line_bounds lbounds)
{
int x_bound = m_layout.get_x_bound_for_row (row,
@@ -2590,15 +2597,15 @@ layout_printer<Sink>::print_annotation_line (linenum_type row,
caret_char = get_options ().caret_chars[state.range_idx];
else
caret_char = '^';
- m_sink.add_character (caret_char);
+ m_text_or_html.add_character (caret_char);
}
else
- m_sink.add_character ('~');
+ m_text_or_html.add_character ('~');
}
else
{
/* Not in a range. */
- m_sink.add_character (' ');
+ m_text_or_html.add_character (' ');
}
}
@@ -2697,54 +2704,54 @@ public:
template<>
void
-layout_printer<to_text>::begin_label (int range_idx,
- bool is_label_text)
+layout_printer<diagnostics::to_text>::begin_label (int range_idx,
+ bool is_label_text)
{
/* Colorize the text, unless it's for labels for events in a
- diagnostic_path. */
+ diagnostic path. */
if (is_label_text && m_is_diagnostic_path)
return;
- gcc_assert (m_sink.m_colorizer);
- m_sink.m_colorizer->set_range (range_idx);
+ gcc_assert (m_text_or_html.m_colorizer);
+ m_text_or_html.m_colorizer->set_range (range_idx);
}
template<>
void
-layout_printer<to_html>::begin_label (int range_idx,
- bool is_label_text)
+layout_printer<diagnostics::to_html>::begin_label (int range_idx,
+ bool is_label_text)
{
- if (is_label_text && m_sink.m_html_label_writer)
- m_sink.m_html_label_writer->begin_label ();
+ if (is_label_text && m_text_or_html.m_html_label_writer)
+ m_text_or_html.m_html_label_writer->begin_label ();
if (const char *highlight_color
- = m_sink.get_highlight_color_for_range_idx (range_idx))
- m_sink.m_xp.push_tag_with_class ("span", highlight_color);
+ = m_text_or_html.get_highlight_color_for_range_idx (range_idx))
+ m_text_or_html.m_xp.push_tag_with_class ("span", highlight_color);
}
template<>
void
-layout_printer<to_text>::end_label (int, bool)
+layout_printer<diagnostics::to_text>::end_label (int, bool)
{
- m_sink.colorize_text_ensure_normal ();
+ m_text_or_html.colorize_text_ensure_normal ();
}
template<>
void
-layout_printer<to_html>::end_label (int range_idx,
- bool is_label_text)
+layout_printer<diagnostics::to_html>::end_label (int range_idx,
+ bool is_label_text)
{
- if (m_sink.get_highlight_color_for_range_idx (range_idx))
- m_sink.m_xp.pop_tag ("span");
+ if (m_text_or_html.get_highlight_color_for_range_idx (range_idx))
+ m_text_or_html.m_xp.pop_tag ("span");
- if (is_label_text && m_sink.m_html_label_writer)
- m_sink.m_html_label_writer->end_label ();
+ if (is_label_text && m_text_or_html.m_html_label_writer)
+ m_text_or_html.m_html_label_writer->end_label ();
}
/* Print any labels in this row. */
-template <typename Sink>
+template <typename TextOrHtml>
void
-layout_printer<Sink>::print_any_labels (linenum_type row)
+layout_printer<TextOrHtml>::print_any_labels (linenum_type row)
{
int i;
auto_vec<line_label> labels;
@@ -2885,20 +2892,20 @@ layout_printer<Sink>::print_any_labels (linenum_type row)
. ^~~~~~~~~~~~~
. this text. */
gcc_assert (get_options ().show_event_links_p);
- m_sink.colorize_text_for_cfg_edge ();
+ m_text_or_html.colorize_text_for_cfg_edge ();
const cppchar_t right= get_theme ().get_cppchar
(text_art::theme::cell_kind::CFG_RIGHT);
while (column < label->m_column - 1)
{
- m_sink.add_character (right);
+ m_text_or_html.add_character (right);
column++;
}
if (column == label->m_column - 1)
{
- m_sink.add_character ('>');
+ m_text_or_html.add_character ('>');
column++;
}
- m_sink.colorize_text_ensure_normal ();
+ m_text_or_html.colorize_text_ensure_normal ();
m_link_lhs_state = link_lhs_state::none;
label_line_with_in_edge = -1;
}
@@ -2907,7 +2914,7 @@ layout_printer<Sink>::print_any_labels (linenum_type row)
gcc_assert (column == label->m_column);
begin_label (label->m_state_idx, true);
- m_sink.add_text (label->m_text.m_buffer);
+ m_text_or_html.add_text (label->m_text.m_buffer);
end_label (label->m_state_idx, true);
column += label->m_display_width;
@@ -2924,13 +2931,13 @@ layout_printer<Sink>::print_any_labels (linenum_type row)
(text_art::theme::cell_kind::CFG_RIGHT);
const cppchar_t from_right_to_down= get_theme ().get_cppchar
(text_art::theme::cell_kind::CFG_FROM_RIGHT_TO_DOWN);
- m_sink.colorize_text_for_cfg_edge ();
- m_sink.add_space ();
- m_sink.add_character (right);
- m_sink.add_character ('>');
- m_sink.add_character (right);
- m_sink.add_character (from_right_to_down);
- m_sink.colorize_text_ensure_normal ();
+ m_text_or_html.colorize_text_for_cfg_edge ();
+ m_text_or_html.add_space ();
+ m_text_or_html.add_character (right);
+ m_text_or_html.add_character ('>');
+ m_text_or_html.add_character (right);
+ m_text_or_html.add_character (from_right_to_down);
+ m_text_or_html.colorize_text_ensure_normal ();
column += 5;
m_link_rhs_column = column - 1;
}
@@ -2940,7 +2947,7 @@ layout_printer<Sink>::print_any_labels (linenum_type row)
gcc_assert (column <= label->m_column);
move_to_column (&column, label->m_column, true);
begin_label (label->m_state_idx, false);
- m_sink.add_character ('|');
+ m_text_or_html.add_character ('|');
end_label (label->m_state_idx, false);
column++;
}
@@ -2951,11 +2958,11 @@ layout_printer<Sink>::print_any_labels (linenum_type row)
if (m_link_rhs_column != -1 && column < m_link_rhs_column)
{
move_to_column (&column, m_link_rhs_column, true);
- m_sink.colorize_text_for_cfg_edge ();
+ m_text_or_html.colorize_text_for_cfg_edge ();
const cppchar_t down= get_theme ().get_cppchar
(text_art::theme::cell_kind::CFG_DOWN);
- m_sink.add_character (down);
- m_sink.colorize_text_ensure_normal ();
+ m_text_or_html.add_character (down);
+ m_text_or_html.colorize_text_ensure_normal ();
}
end_line ();
@@ -2969,10 +2976,10 @@ layout_printer<Sink>::print_any_labels (linenum_type row)
int column = 1 + m_layout.m_x_offset_display;
start_annotation_line (margin_kind::normal);
move_to_column (&column, m_link_rhs_column, true);
- m_sink.colorize_text_for_cfg_edge ();
+ m_text_or_html.colorize_text_for_cfg_edge ();
const cppchar_t down= get_theme ().get_cppchar
(text_art::theme::cell_kind::CFG_DOWN);
- m_sink.add_character (down);
+ m_text_or_html.add_character (down);
end_line ();
}
@@ -2990,9 +2997,9 @@ layout_printer<Sink>::print_any_labels (linenum_type row)
They are printed on lines of their own, before the source line
itself, with a leading '+'. */
-template <typename Sink>
+template <typename TextOrHtml>
void
-layout_printer<Sink>::print_leading_fixits (linenum_type row)
+layout_printer<TextOrHtml>::print_leading_fixits (linenum_type row)
{
for (unsigned int i = 0; i < m_layout.m_fixit_hints.length (); i++)
{
@@ -3012,14 +3019,14 @@ layout_printer<Sink>::print_leading_fixits (linenum_type row)
and the inserted line with "insert" colorization
helps them stand out from each other, and from
the surrounding text. */
- m_sink.colorize_text_ensure_normal ();
+ m_text_or_html.colorize_text_ensure_normal ();
start_annotation_line (margin_kind::insertion);
- m_sink.colorize_text_for_fixit_insert ();
+ m_text_or_html.colorize_text_for_fixit_insert ();
/* Print all but the trailing newline of the fix-it hint.
We have to print the newline separately to avoid
getting additional pp prefixes printed. */
for (size_t i = 0; i < hint->get_length () - 1; i++)
- m_sink.add_character (hint->get_string ()[i]);
+ m_text_or_html.add_character (hint->get_string ()[i]);
end_line ();
}
}
@@ -3154,7 +3161,7 @@ public:
/* Get the range of bytes or display columns that HINT would affect. */
static column_range
-get_affected_range (file_cache &fc,
+get_affected_range (diagnostics::file_cache &fc,
const cpp_char_column_policy &policy,
const fixit_hint *hint, enum column_unit col_unit)
{
@@ -3184,7 +3191,7 @@ get_affected_range (file_cache &fc,
/* Get the range of display columns that would be printed for HINT. */
static column_range
-get_printed_columns (file_cache &fc,
+get_printed_columns (diagnostics::file_cache &fc,
const cpp_char_column_policy &policy,
const fixit_hint *hint)
{
@@ -3246,7 +3253,7 @@ public:
m_display_cols = cpp_display_width (m_text, m_byte_length, m_policy);
}
- void overwrite (int dst_offset, const char_span &src_span)
+ void overwrite (int dst_offset, const diagnostics::char_span &src_span)
{
gcc_assert (dst_offset >= 0);
gcc_assert (dst_offset + src_span.length () < m_alloc_sz);
@@ -3307,7 +3314,7 @@ correction::ensure_terminated ()
class line_corrections
{
public:
- line_corrections (file_cache &fc,
+ line_corrections (diagnostics::file_cache &fc,
const char_display_policy &policy,
const char *filename,
linenum_type row)
@@ -3318,7 +3325,7 @@ public:
void add_hint (const fixit_hint *hint);
- file_cache &m_file_cache;
+ diagnostics::file_cache &m_file_cache;
const char_display_policy &m_policy;
const char *m_filename;
linenum_type m_row;
@@ -3341,9 +3348,12 @@ line_corrections::~line_corrections ()
class source_line
{
public:
- source_line (file_cache &fc, const char *filename, int line);
+ source_line (diagnostics::file_cache &fc, const char *filename, int line);
- char_span as_span () { return char_span (chars, width); }
+ diagnostics::char_span as_span ()
+ {
+ return diagnostics::char_span (chars, width);
+ }
const char *chars;
int width;
@@ -3351,9 +3361,11 @@ public:
/* source_line's ctor. */
-source_line::source_line (file_cache &fc, const char *filename, int line)
+source_line::source_line (diagnostics::file_cache &fc,
+ const char *filename,
+ int line)
{
- char_span span = fc.get_source_line (filename, line);
+ diagnostics::char_span span = fc.get_source_line (filename, line);
chars = span.get_buffer ();
width = span.length ();
}
@@ -3417,9 +3429,10 @@ line_corrections::add_hint (const fixit_hint *hint)
(old_byte_len,
line.as_span ().subspan (between.start - 1,
between.finish + 1 - between.start));
- last_correction->overwrite (old_byte_len + between_byte_len,
- char_span (hint->get_string (),
- hint->get_length ()));
+ last_correction->overwrite
+ (old_byte_len + between_byte_len,
+ diagnostics::char_span (hint->get_string (),
+ hint->get_length ()));
last_correction->m_byte_length = new_byte_len;
last_correction->ensure_terminated ();
last_correction->m_affected_bytes.finish
@@ -3450,11 +3463,11 @@ line_corrections::add_hint (const fixit_hint *hint)
Fix-it hints that insert new lines are handled separately,
in layout::print_leading_fixits. */
-template<typename Sink>
+template<typename TextOrHtml>
void
-layout_printer<Sink>::print_trailing_fixits (linenum_type row)
+layout_printer<TextOrHtml>::print_trailing_fixits (linenum_type row)
{
- typename Sink::auto_check_tag_nesting sentinel (m_sink);
+ typename TextOrHtml::auto_check_tag_nesting sentinel (m_text_or_html);
/* Build a list of correction instances for the line,
potentially consolidating hints (for the sake of readability). */
@@ -3490,9 +3503,9 @@ layout_printer<Sink>::print_trailing_fixits (linenum_type row)
/* This assumes the insertion just affects one line. */
int start_column = c->m_printed_columns.start;
move_to_column (&column, start_column, true);
- m_sink.colorize_text_for_fixit_insert ();
- m_sink.add_text (c->m_text);
- m_sink.colorize_text_ensure_normal ();
+ m_text_or_html.colorize_text_for_fixit_insert ();
+ m_text_or_html.add_text (c->m_text);
+ m_text_or_html.colorize_text_ensure_normal ();
column += c->m_display_cols;
}
else
@@ -3508,10 +3521,10 @@ layout_printer<Sink>::print_trailing_fixits (linenum_type row)
|| c->m_byte_length == 0)
{
move_to_column (&column, start_column, true);
- m_sink.colorize_text_for_fixit_delete ();
+ m_text_or_html.colorize_text_for_fixit_delete ();
for (; column <= finish_column; column++)
- m_sink.add_character ('-');
- m_sink.colorize_text_ensure_normal ();
+ m_text_or_html.add_character ('-');
+ m_text_or_html.colorize_text_ensure_normal ();
}
/* Print the replacement text. REPLACE also covers
removals, so only do this extra work (potentially starting
@@ -3519,9 +3532,9 @@ layout_printer<Sink>::print_trailing_fixits (linenum_type row)
if (c->m_byte_length > 0)
{
move_to_column (&column, start_column, true);
- m_sink.colorize_text_for_fixit_insert ();
- m_sink.add_text (c->m_text);
- m_sink.colorize_text_ensure_normal ();
+ m_text_or_html.colorize_text_for_fixit_insert ();
+ m_text_or_html.add_text (c->m_text);
+ m_text_or_html.colorize_text_ensure_normal ();
column += c->m_display_cols;
}
}
@@ -3627,9 +3640,9 @@ layout::get_x_bound_for_row (linenum_type row, int caret_column,
and updating *COLUMN. If ADD_LEFT_MARGIN, then print the (empty)
left margin after any newline. */
-template<typename Sink>
+template<typename TextOrHtml>
void
-layout_printer<Sink>::move_to_column (int *column,
+layout_printer<TextOrHtml>::move_to_column (int *column,
int dest_column,
bool add_left_margin)
{
@@ -3646,9 +3659,9 @@ layout_printer<Sink>::move_to_column (int *column,
{
/* For debugging column issues, it can be helpful to replace this
add_space call with
- m_sink.add_character ('0' + (*column % 10));
+ m_text_or_html.add_character ('0' + (*column % 10));
to visualize the changing value of "*column". */
- m_sink.add_space ();
+ m_text_or_html.add_space ();
(*column)++;
}
}
@@ -3656,11 +3669,11 @@ layout_printer<Sink>::move_to_column (int *column,
/* For debugging layout issues, render a ruler giving column numbers
(after the 1-column indent). */
-template<typename Sink>
+template<typename TextOrHtml>
void
-layout_printer<Sink>::show_ruler (int max_column)
+layout_printer<TextOrHtml>::show_ruler (int max_column)
{
- m_sink.push_html_tag_with_class("thead", "ruler", false);
+ m_text_or_html.push_html_tag_with_class("thead", "ruler", false);
/* Hundreds. */
if (max_column > 99)
@@ -3670,9 +3683,9 @@ layout_printer<Sink>::show_ruler (int max_column)
column <= max_column;
++column)
if (column % 10 == 0)
- m_sink.add_character ('0' + (column / 100) % 10);
+ m_text_or_html.add_character ('0' + (column / 100) % 10);
else
- m_sink.add_space ();
+ m_text_or_html.add_space ();
end_line ();
}
@@ -3682,9 +3695,9 @@ layout_printer<Sink>::show_ruler (int max_column)
column <= max_column;
++column)
if (column % 10 == 0)
- m_sink.add_character ('0' + (column / 10) % 10);
+ m_text_or_html.add_character ('0' + (column / 10) % 10);
else
- m_sink.add_space ();
+ m_text_or_html.add_space ();
end_line ();
/* Units. */
@@ -3692,23 +3705,23 @@ layout_printer<Sink>::show_ruler (int max_column)
for (int column = 1 + m_layout.m_x_offset_display;
column <= max_column;
++column)
- m_sink.add_character ('0' + (column % 10));
+ m_text_or_html.add_character ('0' + (column % 10));
end_line ();
- m_sink.pop_html_tag("thead"); // thead
+ m_text_or_html.pop_html_tag("thead"); // thead
}
/* Print leading fix-its (for new lines inserted before the source line)
then the source line, followed by an annotation line
consisting of any caret/underlines, then any fixits.
If the source line can't be read, print nothing. */
-template<typename Sink>
+template<typename TextOrHtml>
void
-layout_printer<Sink>::print_line (linenum_type row)
+layout_printer<TextOrHtml>::print_line (linenum_type row)
{
- typename Sink::auto_check_tag_nesting sentinel (m_sink);
+ typename TextOrHtml::auto_check_tag_nesting sentinel (m_text_or_html);
- char_span line
+ diagnostics::char_span line
= m_layout.m_file_cache.get_source_line (m_layout.m_exploc.file, row);
if (!line)
return;
@@ -3730,9 +3743,9 @@ layout_printer<Sink>::print_line (linenum_type row)
showing the link entering at the top right and emerging
at the bottom left. */
-template<typename Sink>
+template<typename TextOrHtml>
void
-layout_printer<Sink>::print_any_right_to_left_edge_lines ()
+layout_printer<TextOrHtml>::print_any_right_to_left_edge_lines ()
{
if (m_link_rhs_column == -1)
/* Can also happen if the out-edge had UNKNOWN_LOCATION. */
@@ -3745,25 +3758,25 @@ layout_printer<Sink>::print_any_right_to_left_edge_lines ()
int column = 1 + m_layout.m_x_offset_display;
move_to_column (&column, m_link_rhs_column, true);
- m_sink.colorize_text_for_cfg_edge ();
+ m_text_or_html.colorize_text_for_cfg_edge ();
const cppchar_t down= get_theme ().get_cppchar
(text_art::theme::cell_kind::CFG_DOWN);
- m_sink.add_character (down);
+ m_text_or_html.add_character (down);
end_line ();
/* Print the line with "┌──────────────────────────────────────────┘". */
m_link_lhs_state = link_lhs_state::rewinding_to_lhs;
start_annotation_line (margin_kind::normal);
- m_sink.colorize_text_for_cfg_edge ();
+ m_text_or_html.colorize_text_for_cfg_edge ();
const cppchar_t left= get_theme ().get_cppchar
(text_art::theme::cell_kind::CFG_LEFT);
for (int column = 1 + m_layout.m_x_offset_display;
column < m_link_rhs_column;
++column)
- m_sink.add_character (left);
+ m_text_or_html.add_character (left);
const cppchar_t from_down_to_left = get_theme ().get_cppchar
(text_art::theme::cell_kind::CFG_FROM_DOWN_TO_LEFT);
- m_sink.add_character (from_down_to_left);
+ m_text_or_html.add_character (from_down_to_left);
end_line ();
/* We now have a link line on the LHS,
@@ -3772,11 +3785,11 @@ layout_printer<Sink>::print_any_right_to_left_edge_lines ()
m_link_rhs_column = -1;
}
-template<typename Sink>
-layout_printer<Sink>::layout_printer (Sink &sink,
+template<typename TextOrHtml>
+layout_printer<TextOrHtml>::layout_printer (TextOrHtml &text_or_html,
const layout &layout,
bool is_diagnostic_path)
-: m_sink (sink),
+: m_text_or_html (text_or_html),
m_layout (layout),
m_is_diagnostic_path (is_diagnostic_path),
m_was_in_range_p (false),
@@ -3801,7 +3814,7 @@ layout_printer<Sink>::layout_printer (Sink &sink,
bool
gcc_rich_location::
-add_location_if_nearby (const diagnostic_source_print_policy &policy,
+add_location_if_nearby (const diagnostics::source_print_policy &policy,
location_t loc,
bool restrict_to_current_line_spans,
const range_label *label)
@@ -3825,27 +3838,29 @@ add_location_if_nearby (const diagnostic_source_print_policy &policy,
bool
gcc_rich_location::
-add_location_if_nearby (const diagnostic_context &dc,
+add_location_if_nearby (const diagnostics::context &dc,
location_t loc,
bool restrict_to_current_line_spans,
const range_label *label)
{
- diagnostic_source_print_policy source_policy (dc,
- dc.m_source_printing);
+ diagnostics::source_print_policy
+ source_policy (dc,
+ dc.get_source_printing_options ());
return add_location_if_nearby (source_policy, loc,
restrict_to_current_line_spans, label);
}
+namespace diagnostics {
-/* As per diagnostic_source_print_policy::print, but don't print anything
+/* As per diagnostics::source_print_policy::print, but don't print anything
if source printing is disabled, or if the location hasn't changed. */
void
-diagnostic_context::maybe_show_locus (const rich_location &richloc,
- const diagnostic_source_printing_options &opts,
- diagnostic_t diagnostic_kind,
- pretty_printer &pp,
- diagnostic_source_effect_info *effects)
+context::maybe_show_locus (const rich_location &richloc,
+ const source_printing_options &opts,
+ enum kind diagnostic_kind,
+ pretty_printer &pp,
+ source_effect_info *effects)
{
const location_t loc = richloc.get_loc ();
/* Do nothing if source-printing has been disabled. */
@@ -3866,7 +3881,7 @@ diagnostic_context::maybe_show_locus (const rich_location &richloc,
m_last_location = loc;
- diagnostic_source_print_policy source_policy (*this, opts);
+ source_print_policy source_policy (*this, opts);
source_policy.print (pp, richloc, diagnostic_kind, effects);
}
@@ -3874,12 +3889,12 @@ diagnostic_context::maybe_show_locus (const rich_location &richloc,
If non-null, use LABEL_WRITER when writing labelled ranges. */
void
-diagnostic_context::maybe_show_locus_as_html (const rich_location &richloc,
- const diagnostic_source_printing_options &opts,
- diagnostic_t diagnostic_kind,
- xml::printer &xp,
- diagnostic_source_effect_info *effects,
- html_label_writer *label_writer)
+context::maybe_show_locus_as_html (const rich_location &richloc,
+ const source_printing_options &opts,
+ enum kind diagnostic_kind,
+ xml::printer &xp,
+ source_effect_info *effects,
+ html_label_writer *label_writer)
{
const location_t loc = richloc.get_loc ();
/* Do nothing if source-printing has been disabled. */
@@ -3900,13 +3915,13 @@ diagnostic_context::maybe_show_locus_as_html (const rich_location &richloc,
m_last_location = loc;
- diagnostic_source_print_policy source_policy (*this, opts);
+ source_print_policy source_policy (*this, opts);
source_policy.print_as_html (xp, richloc, diagnostic_kind, effects,
label_writer);
}
-diagnostic_source_print_policy::
-diagnostic_source_print_policy (const diagnostic_context &dc)
+source_print_policy::
+source_print_policy (const context &dc)
: m_options (dc.m_source_printing),
m_location_policy (dc),
m_text_start_span_cb (dc.m_text_callbacks.m_text_start_span),
@@ -3917,9 +3932,8 @@ diagnostic_source_print_policy (const diagnostic_context &dc)
{
}
-diagnostic_source_print_policy::
-diagnostic_source_print_policy (const diagnostic_context &dc,
- const diagnostic_source_printing_options &opts)
+source_print_policy::source_print_policy (const context &dc,
+ const source_printing_options &opts)
: m_options (opts),
m_location_policy (dc),
m_text_start_span_cb (dc.m_text_callbacks.m_text_start_span),
@@ -3936,17 +3950,16 @@ diagnostic_source_print_policy (const diagnostic_context &dc,
If EFFECTS is non-null, then use and update it. */
void
-diagnostic_source_print_policy::print (pretty_printer &pp,
- const rich_location &richloc,
- diagnostic_t diagnostic_kind,
- diagnostic_source_effect_info *effects)
- const
+source_print_policy::print (pretty_printer &pp,
+ const rich_location &richloc,
+ enum kind diagnostic_kind,
+ source_effect_info *effects) const
{
layout layout (*this, richloc, effects);
colorizer col (pp, richloc, diagnostic_kind);
- to_text sink (pp, col);
- layout_printer<to_text> lp (sink, layout,
- diagnostic_kind == DK_DIAGNOSTIC_PATH);
+ to_text text_or_html (pp, col);
+ layout_printer<to_text> lp (text_or_html, layout,
+ diagnostic_kind == diagnostics::kind::path);
lp.print (*this);
}
@@ -3954,28 +3967,30 @@ diagnostic_source_print_policy::print (pretty_printer &pp,
If non-null, use LABEL_WRITER when writing labelled ranges. */
void
-diagnostic_source_print_policy::print_as_html (xml::printer &xp,
- const rich_location &richloc,
- diagnostic_t diagnostic_kind,
- diagnostic_source_effect_info *effects,
- html_label_writer *label_writer)
- const
+source_print_policy::print_as_html (xml::printer &xp,
+ const rich_location &richloc,
+ enum kind diagnostic_kind,
+ source_effect_info *effects,
+ html_label_writer *label_writer) const
{
layout layout (*this, richloc, effects);
- to_html sink (xp, &richloc, label_writer);
- layout_printer<to_html> lp (sink, layout,
- diagnostic_kind == DK_DIAGNOSTIC_PATH);
+ to_html text_or_html (xp, &richloc, label_writer);
+ layout_printer<to_html> lp (text_or_html, layout,
+ diagnostic_kind == diagnostics::kind::path);
xml::auto_check_tag_nesting sentinel (xp);
lp.print (*this);
}
-template <typename Sink>
+} // namespace diagnostics
+
+template <typename TextOrHtml>
void
-layout_printer<Sink>::print (const diagnostic_source_print_policy &source_policy)
+layout_printer<TextOrHtml>::
+print (const diagnostics::source_print_policy &source_policy)
{
- typename Sink::auto_check_tag_nesting sentinel (m_sink);
+ typename TextOrHtml::auto_check_tag_nesting sentinel (m_text_or_html);
- m_sink.push_html_tag_with_class ("table", "locus", false);
+ m_text_or_html.push_html_tag_with_class ("table", "locus", false);
if (get_options ().show_ruler_p)
show_ruler (m_layout.m_x_offset_display + get_options ().max_width);
@@ -3998,13 +4013,13 @@ layout_printer<Sink>::print (const diagnostic_source_print_policy &source_policy
{
expanded_location exploc
= m_layout.get_expanded_location (line_span);
- const diagnostic_location_print_policy &
+ const diagnostics::location_print_policy &
loc_policy = source_policy.get_location_policy ();
- m_sink.invoke_start_span_fn (source_policy, loc_policy, exploc);
+ m_text_or_html.invoke_start_span_fn (source_policy, loc_policy, exploc);
}
}
- m_sink.push_html_tag_with_class ("tbody", "line-span", false);
+ m_text_or_html.push_html_tag_with_class ("tbody", "line-span", false);
/* Iterate over the lines within this span (using linenum_arith_t to
avoid overflow with 0xffffffff causing an infinite loop). */
@@ -4013,30 +4028,37 @@ layout_printer<Sink>::print (const diagnostic_source_print_policy &source_policy
row <= last_line; row++)
print_line (row);
- m_sink.pop_html_tag ("tbody");
+ m_text_or_html.pop_html_tag ("tbody");
}
if (auto effect_info = m_layout.m_effect_info)
effect_info->m_trailing_out_edge_column = m_link_rhs_column;
- m_sink.pop_html_tag ("table");
+ m_text_or_html.pop_html_tag ("table");
}
#if CHECKING_P
+namespace diagnostics {
namespace selftest {
+using test_context = diagnostics::selftest::test_context;
+
+using line_table_case = ::selftest::line_table_case;
+using line_table_test = ::selftest::line_table_test;
+using temp_source_file = ::selftest::temp_source_file;
+
static std::unique_ptr<xml::node>
make_element_for_locus (const rich_location &rich_loc,
- diagnostic_t kind,
- diagnostic_context &dc)
+ enum kind kind,
+ diagnostics::context &dc)
{
dc.m_last_location = UNKNOWN_LOCATION;
xml::element wrapper ("wrapper", false);
xml::printer xp (wrapper);
dc.maybe_show_locus_as_html (rich_loc,
- dc.m_source_printing,
+ dc.get_source_printing_options (),
kind,
xp,
nullptr,
@@ -4049,8 +4071,8 @@ make_element_for_locus (const rich_location &rich_loc,
static label_text
make_raw_html_for_locus (const rich_location &rich_loc,
- diagnostic_t kind,
- diagnostic_context &dc)
+ enum kind kind,
+ diagnostics::context &dc)
{
auto node = make_element_for_locus (rich_loc, kind, dc);
pretty_printer pp;
@@ -4061,9 +4083,9 @@ make_raw_html_for_locus (const rich_location &rich_loc,
/* Selftests for diagnostic_show_locus. */
-diagnostic_show_locus_fixture::
-diagnostic_show_locus_fixture (const line_table_case &case_,
- const char *content)
+source_printing_fixture::
+source_printing_fixture (const line_table_case &case_,
+ const char *content)
: m_content (content),
m_tmp_source_file (SELFTEST_LOCATION, ".c", content),
m_ltt (case_),
@@ -4076,10 +4098,10 @@ diagnostic_show_locus_fixture (const line_table_case &case_,
/* Populate a char_display_policy based on DC and RICHLOC. */
static char_display_policy
-make_char_policy (const diagnostic_context &dc,
+make_char_policy (const diagnostics::context &dc,
const rich_location &richloc)
{
- diagnostic_source_print_policy source_policy (dc);
+ diagnostics::source_print_policy source_policy (dc);
return ::make_char_policy (source_policy, richloc);
}
@@ -4101,7 +4123,7 @@ test_display_widths ()
/* No escaping. */
{
- test_diagnostic_context dc;
+ test_context dc;
char_display_policy policy (make_char_policy (dc, richloc));
ASSERT_EQ (cpp_display_width (pi, strlen (pi), policy), 1);
ASSERT_EQ (cpp_display_width (emoji, strlen (emoji), policy), 2);
@@ -4112,7 +4134,7 @@ test_display_widths ()
richloc.set_escape_on_output (true);
{
- test_diagnostic_context dc;
+ test_context dc;
dc.set_escape_format (DIAGNOSTICS_ESCAPE_FORMAT_UNICODE);
char_display_policy policy (make_char_policy (dc, richloc));
ASSERT_EQ (cpp_display_width (pi, strlen (pi), policy), 8);
@@ -4124,7 +4146,7 @@ test_display_widths ()
}
{
- test_diagnostic_context dc;
+ test_context dc;
dc.set_escape_format (DIAGNOSTICS_ESCAPE_FORMAT_BYTES);
char_display_policy policy (make_char_policy (dc, richloc));
ASSERT_EQ (cpp_display_width (pi, strlen (pi), policy), 8);
@@ -4149,13 +4171,14 @@ test_offset_impl (int caret_byte_col, int max_width,
int expected_x_offset_display,
int left_margin = test_left_margin)
{
- test_diagnostic_context dc;
- dc.m_source_printing.max_width = max_width;
- /* diagnostic_context::min_margin_width sets the minimum space reserved for
+ test_context dc;
+ auto &source_printing_opts = dc.get_source_printing_options ();
+ source_printing_opts.max_width = max_width;
+ /* min_margin_width sets the minimum space reserved for
the line number plus one space after. */
- dc.m_source_printing.min_margin_width = left_margin - test_linenum_sep + 1;
- dc.m_source_printing.show_line_numbers_p = true;
- diagnostic_source_print_policy source_policy (dc);
+ source_printing_opts.min_margin_width = left_margin - test_linenum_sep + 1;
+ dc.show_line_numbers (true);
+ diagnostics::source_print_policy source_policy (dc);
rich_location richloc (line_table,
linemap_position_for_column (line_table,
caret_byte_col));
@@ -4188,7 +4211,7 @@ test_layout_x_offset_display_utf8 (const line_table_case &case_)
no multibyte characters earlier on the line. */
const int emoji_col = 102;
- diagnostic_show_locus_fixture f (case_, content);
+ source_printing_fixture f (case_, content);
linemap_add (line_table, LC_ENTER, false, f.get_filename (), 1);
@@ -4202,7 +4225,7 @@ test_layout_x_offset_display_utf8 (const line_table_case &case_)
ASSERT_EQ (1, LOCATION_LINE (line_end));
ASSERT_EQ (line_bytes, LOCATION_COLUMN (line_end));
- char_span lspan = f.m_fc.get_source_line (f.get_filename (), 1);
+ diagnostics::char_span lspan = f.m_fc.get_source_line (f.get_filename (), 1);
ASSERT_EQ (line_display_cols,
cpp_display_width (lspan.get_buffer (), lspan.length (),
def_policy ()));
@@ -4265,21 +4288,22 @@ test_layout_x_offset_display_utf8 (const line_table_case &case_)
/* Test that the source line is offset as expected when printed. */
{
- test_diagnostic_context dc;
- dc.m_source_printing.max_width = small_width - 6;
- dc.m_source_printing.min_margin_width
+ test_context dc;
+ auto &source_printing_opts = dc.get_source_printing_options ();
+ source_printing_opts.max_width = small_width - 6;
+ source_printing_opts.min_margin_width
= test_left_margin - test_linenum_sep + 1;
- dc.m_source_printing.show_line_numbers_p = true;
- dc.m_source_printing.show_ruler_p = true;
- diagnostic_source_print_policy policy (dc);
+ dc.show_line_numbers (true);
+ dc.show_ruler (true);
+ diagnostics::source_print_policy policy (dc);
rich_location richloc (line_table,
linemap_position_for_column (line_table,
emoji_col));
layout test_layout (policy, richloc, nullptr);
colorizer col (*dc.get_reference_printer (),
- richloc, DK_ERROR);
- to_text sink (*dc.get_reference_printer (), col);
- layout_printer<to_text> lp (sink, test_layout, false);
+ richloc, diagnostics::kind::error);
+ diagnostics::to_text text_or_html (*dc.get_reference_printer (), col);
+ layout_printer<diagnostics::to_text> lp (text_or_html, test_layout, false);
lp.print (policy);
ASSERT_STREQ (" | 1 \n"
" | 1 \n"
@@ -4295,21 +4319,22 @@ test_layout_x_offset_display_utf8 (const line_table_case &case_)
the first emoji in the middle of the UTF-8 sequence. Check that we replace
it with a padding space in this case. */
{
- test_diagnostic_context dc;
- dc.m_source_printing.max_width = small_width - 5;
- dc.m_source_printing.min_margin_width
+ test_context dc;
+ auto &source_printing_opts = dc.get_source_printing_options ();
+ source_printing_opts.max_width = small_width - 5;
+ source_printing_opts.min_margin_width
= test_left_margin - test_linenum_sep + 1;
- dc.m_source_printing.show_line_numbers_p = true;
- dc.m_source_printing.show_ruler_p = true;
- diagnostic_source_print_policy policy (dc);
+ dc.show_line_numbers (true);
+ dc.show_ruler (true);
+ diagnostics::source_print_policy policy (dc);
rich_location richloc (line_table,
linemap_position_for_column (line_table,
emoji_col + 2));
layout test_layout (dc, richloc, nullptr);
colorizer col (*dc.get_reference_printer (),
- richloc, DK_ERROR);
- to_text sink (*dc.get_reference_printer (), col);
- layout_printer<to_text> lp (sink, test_layout, false);
+ richloc, diagnostics::kind::error);
+ diagnostics::to_text text_or_html (*dc.get_reference_printer (), col);
+ layout_printer<diagnostics::to_text> lp (text_or_html, test_layout, false);
lp.print (policy);
ASSERT_STREQ (" | 1 1 \n"
" | 1 2 \n"
@@ -4354,7 +4379,7 @@ test_layout_x_offset_display_tab (const line_table_case &case_)
ASSERT_EQ (7, extra_width[10]);
temp_source_file tmp (SELFTEST_LOCATION, ".c", content);
- file_cache fc;
+ diagnostics::file_cache fc;
line_table_test ltt (case_);
linemap_add (line_table, LC_ENTER, false, tmp.get_filename (), 1);
@@ -4366,7 +4391,7 @@ test_layout_x_offset_display_tab (const line_table_case &case_)
return;
/* Check that cpp_display_width handles the tabs as expected. */
- char_span lspan = fc.get_source_line (tmp.get_filename (), 1);
+ diagnostics::char_span lspan = fc.get_source_line (tmp.get_filename (), 1);
ASSERT_EQ ('\t', *(lspan.get_buffer () + (tab_col - 1)));
for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
{
@@ -4386,14 +4411,15 @@ test_layout_x_offset_display_tab (const line_table_case &case_)
tab_col + 1));
for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
{
- test_diagnostic_context dc;
+ test_context dc;
dc.m_tabstop = tabstop;
- diagnostic_source_print_policy policy (dc);
+ diagnostics::source_print_policy policy (dc);
layout test_layout (policy, richloc, nullptr);
colorizer col (*dc.get_reference_printer (),
- richloc, DK_ERROR);
- to_text sink (*dc.get_reference_printer (), col);
- layout_printer<to_text> lp (sink, test_layout, false);
+ richloc, diagnostics::kind::error);
+ diagnostics::to_text text_or_html (*dc.get_reference_printer (), col);
+ layout_printer<diagnostics::to_text> lp
+ (text_or_html, test_layout, false);
lp.print (policy);
const char *out = pp_formatted_text (dc.get_reference_printer ());
ASSERT_EQ (nullptr, strchr (out, '\t'));
@@ -4409,19 +4435,21 @@ test_layout_x_offset_display_tab (const line_table_case &case_)
over. */
for (int tabstop = 1; tabstop != num_tabstops; ++tabstop)
{
- test_diagnostic_context dc;
+ test_context dc;
dc.m_tabstop = tabstop;
static const int small_width = 24;
- dc.m_source_printing.max_width = small_width - 4;
- dc.m_source_printing.min_margin_width
+ auto &source_printing_opts = dc.get_source_printing_options ();
+ source_printing_opts.max_width = small_width - 4;
+ source_printing_opts.min_margin_width
= test_left_margin - test_linenum_sep + 1;
- dc.m_source_printing.show_line_numbers_p = true;
- diagnostic_source_print_policy policy (dc);
+ dc.show_line_numbers (true);
+ diagnostics::source_print_policy policy (dc);
layout test_layout (policy, richloc, nullptr);
colorizer col (*dc.get_reference_printer (),
- richloc, DK_ERROR);
- to_text sink (*dc.get_reference_printer (), col);
- layout_printer<to_text> lp (sink, test_layout, false);
+ richloc, diagnostics::kind::error);
+ diagnostics::to_text text_or_html (*dc.get_reference_printer (), col);
+ layout_printer<diagnostics::to_text> lp
+ (text_or_html, test_layout, false);
lp.print (policy);
/* We have arranged things so that two columns will be printed before
@@ -4447,7 +4475,7 @@ test_layout_x_offset_display_tab (const line_table_case &case_)
static void
test_diagnostic_show_locus_unknown_location ()
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, UNKNOWN_LOCATION);
ASSERT_STREQ ("", dc.test_show_locus (richloc));
}
@@ -4467,7 +4495,7 @@ test_diagnostic_show_locus_unknown_location ()
static void
test_one_liner_simple_caret ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t caret = linemap_position_for_column (line_table, 10);
rich_location richloc (line_table, caret);
ASSERT_STREQ (" foo = bar.field;\n"
@@ -4481,7 +4509,7 @@ test_one_liner_simple_caret ()
static void
test_one_liner_no_column ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t caret = linemap_position_for_column (line_table, 0);
rich_location richloc (line_table, caret);
ASSERT_STREQ (" foo = bar.field;\n",
@@ -4493,7 +4521,7 @@ test_one_liner_no_column ()
static void
test_one_liner_caret_and_range ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t caret = linemap_position_for_column (line_table, 10);
location_t start = linemap_position_for_column (line_table, 7);
location_t finish = linemap_position_for_column (line_table, 15);
@@ -4504,8 +4532,8 @@ test_one_liner_caret_and_range ()
dc.test_show_locus (richloc));
{
- test_diagnostic_context dc;
- auto out = make_raw_html_for_locus (richloc, DK_ERROR, dc);
+ test_context dc;
+ auto out = make_raw_html_for_locus (richloc, diagnostics::kind::error, dc);
ASSERT_STREQ
("<table class=\"locus\">\n"
" <tbody class=\"line-span\">\n"
@@ -4516,9 +4544,9 @@ test_one_liner_caret_and_range ()
out.get ());
}
{
- test_diagnostic_context dc;
- dc.m_source_printing.show_line_numbers_p = true;
- auto out = make_raw_html_for_locus (richloc, DK_ERROR, dc);
+ test_context dc;
+ dc.show_line_numbers (true);
+ auto out = make_raw_html_for_locus (richloc, diagnostics::kind::error, dc);
ASSERT_STREQ
("<table class=\"locus\">\n"
" <tbody class=\"line-span\">\n"
@@ -4535,24 +4563,24 @@ test_one_liner_caret_and_range ()
static void
test_one_liner_multiple_carets_and_ranges ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t foo
= make_location (linemap_position_for_column (line_table, 2),
linemap_position_for_column (line_table, 1),
linemap_position_for_column (line_table, 3));
- dc.m_source_printing.caret_chars[0] = 'A';
+ dc.set_caret_char (0, 'A');
location_t bar
= make_location (linemap_position_for_column (line_table, 8),
linemap_position_for_column (line_table, 7),
linemap_position_for_column (line_table, 9));
- dc.m_source_printing.caret_chars[1] = 'B';
+ dc.set_caret_char (1, 'B');
location_t field
= make_location (linemap_position_for_column (line_table, 13),
linemap_position_for_column (line_table, 11),
linemap_position_for_column (line_table, 15));
- dc.m_source_printing.caret_chars[2] = 'C';
+ dc.set_caret_char (2, 'C');
rich_location richloc (line_table, foo);
richloc.add_range (bar, SHOW_RANGE_WITH_CARET);
@@ -4567,7 +4595,7 @@ test_one_liner_multiple_carets_and_ranges ()
static void
test_one_liner_fixit_insert_before ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t caret = linemap_position_for_column (line_table, 7);
rich_location richloc (line_table, caret);
richloc.add_fixit_insert_before ("&");
@@ -4582,7 +4610,7 @@ test_one_liner_fixit_insert_before ()
static void
test_one_liner_fixit_insert_after ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t start = linemap_position_for_column (line_table, 1);
location_t finish = linemap_position_for_column (line_table, 3);
location_t foo = make_location (start, start, finish);
@@ -4609,7 +4637,7 @@ test_one_liner_fixit_remove ()
/* Normal. */
{
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar.field;\n"
" ^~~~~~\n"
" ------\n",
@@ -4618,7 +4646,7 @@ test_one_liner_fixit_remove ()
/* Test of adding a prefix. */
{
- test_diagnostic_context dc;
+ test_context dc;
pp_prefixing_rule (dc.get_reference_printer ()) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
pp_set_prefix (dc.get_reference_printer (), xstrdup ("TEST PREFIX:"));
ASSERT_STREQ ("TEST PREFIX: foo = bar.field;\n"
@@ -4629,9 +4657,10 @@ test_one_liner_fixit_remove ()
/* Normal, with ruler. */
{
- test_diagnostic_context dc;
- dc.m_source_printing.show_ruler_p = true;
- dc.m_source_printing.max_width = 104;
+ test_context dc;
+ auto &source_printing_opts = dc.get_source_printing_options ();
+ dc.show_ruler (true);
+ source_printing_opts.max_width = 104;
ASSERT_STREQ (" 0 0 0 0 0 0 0 0 0 1 \n"
" 1 2 3 4 5 6 7 8 9 0 \n"
" 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234\n"
@@ -4643,9 +4672,10 @@ test_one_liner_fixit_remove ()
/* Test of adding a prefix, with ruler. */
{
- test_diagnostic_context dc;
- dc.m_source_printing.show_ruler_p = true;
- dc.m_source_printing.max_width = 50;
+ test_context dc;
+ auto &source_printing_opts = dc.get_source_printing_options ();
+ dc.show_ruler (true);
+ source_printing_opts.max_width = 50;
pp_prefixing_rule (dc.get_reference_printer ()) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
pp_set_prefix (dc.get_reference_printer (), xstrdup ("TEST PREFIX:"));
ASSERT_STREQ ("TEST PREFIX: 1 2 3 4 5\n"
@@ -4658,10 +4688,11 @@ test_one_liner_fixit_remove ()
/* Test of adding a prefix, with ruler and line numbers. */
{
- test_diagnostic_context dc;
- dc.m_source_printing.show_ruler_p = true;
- dc.m_source_printing.max_width = 50;
- dc.m_source_printing.show_line_numbers_p = true;
+ test_context dc;
+ auto &source_printing_opts = dc.get_source_printing_options ();
+ dc.show_ruler (true);
+ source_printing_opts.max_width = 50;
+ dc.show_line_numbers (true);
pp_prefixing_rule (dc.get_reference_printer ()) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
pp_set_prefix (dc.get_reference_printer (), xstrdup ("TEST PREFIX:"));
ASSERT_STREQ ("TEST PREFIX: | 1 2 3 4 5\n"
@@ -4678,7 +4709,7 @@ test_one_liner_fixit_remove ()
static void
test_one_liner_fixit_replace ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t start = linemap_position_for_column (line_table, 11);
location_t finish = linemap_position_for_column (line_table, 15);
location_t field = make_location (start, start, finish);
@@ -4696,7 +4727,7 @@ test_one_liner_fixit_replace ()
static void
test_one_liner_fixit_replace_non_equal_range ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t equals = linemap_position_for_column (line_table, 5);
location_t start = linemap_position_for_column (line_table, 11);
location_t finish = linemap_position_for_column (line_table, 15);
@@ -4721,7 +4752,7 @@ test_one_liner_fixit_replace_non_equal_range ()
static void
test_one_liner_fixit_replace_equal_secondary_range ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t equals = linemap_position_for_column (line_table, 5);
location_t start = linemap_position_for_column (line_table, 11);
location_t finish = linemap_position_for_column (line_table, 15);
@@ -4762,7 +4793,7 @@ test_one_liner_fixit_validation_adhoc_locations ()
/* It should not have been discarded by the validator. */
ASSERT_EQ (1, richloc.get_num_fixit_hints ());
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar.field;\n"
" ^~~~~~~~~~ "
" "
@@ -4788,7 +4819,7 @@ test_one_liner_fixit_validation_adhoc_locations ()
/* It should not have been discarded by the validator. */
ASSERT_EQ (1, richloc.get_num_fixit_hints ());
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar.field;\n"
" ^~~~~~~~~~ "
" "
@@ -4825,7 +4856,7 @@ test_one_liner_fixit_validation_adhoc_locations ()
/* It should not have been discarded by the validator. */
ASSERT_EQ (1, richloc.get_num_fixit_hints ());
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar.field;\n"
" ^~~~~~~~~~ "
" "
@@ -4849,7 +4880,7 @@ test_one_liner_fixit_validation_adhoc_locations ()
static void
test_one_liner_many_fixits_1 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t equals = linemap_position_for_column (line_table, 5);
rich_location richloc (line_table, equals);
for (int i = 0; i < 19; i++)
@@ -4867,7 +4898,7 @@ test_one_liner_many_fixits_1 ()
static void
test_one_liner_many_fixits_2 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t equals = linemap_position_for_column (line_table, 5);
rich_location richloc (line_table, equals);
for (int i = 0; i < 19; i++)
@@ -4910,7 +4941,7 @@ test_one_liner_labels ()
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
{
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar.field;\n"
" ^~~ ~~~ ~~~~~\n"
" | | |\n"
@@ -4920,8 +4951,8 @@ test_one_liner_labels ()
/* Verify that we can disable label-printing. */
{
- test_diagnostic_context dc;
- dc.m_source_printing.show_labels_p = false;
+ test_context dc;
+ dc.show_labels (false);
ASSERT_STREQ (" foo = bar.field;\n"
" ^~~ ~~~ ~~~~~\n",
dc.test_show_locus (richloc));
@@ -4937,7 +4968,7 @@ test_one_liner_labels ()
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar.field;\n"
" ^~~ ~~~ ~~~~~\n"
" | | |\n"
@@ -4947,9 +4978,10 @@ test_one_liner_labels ()
dc.test_show_locus (richloc));
{
- test_diagnostic_context dc;
- dc.m_source_printing.show_line_numbers_p = true;
- auto out = make_raw_html_for_locus (richloc, DK_ERROR, dc);
+ test_context dc;
+ dc.show_line_numbers (true);
+ auto out
+ = make_raw_html_for_locus (richloc, diagnostics::kind::error, dc);
ASSERT_STREQ
("<table class=\"locus\">\n"
" <tbody class=\"line-span\">\n"
@@ -4975,7 +5007,7 @@ test_one_liner_labels ()
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar.field;\n"
" ^~~ ~~~ ~~~~~\n"
" | | |\n"
@@ -4993,7 +5025,7 @@ test_one_liner_labels ()
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label2);
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar.field;\n"
" ~~~ ~~~ ^~~~~\n"
" | | |\n"
@@ -5011,7 +5043,7 @@ test_one_liner_labels ()
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label2);
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar.field;\n"
" ^~~\n"
" |\n"
@@ -5045,7 +5077,7 @@ test_one_liner_labels ()
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label_1c);
richloc.add_range (foo, SHOW_RANGE_WITHOUT_CARET, &label_2c);
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar.field;\n"
" ~~~ ~~~ ^~~~~\n"
" | | |\n"
@@ -5067,7 +5099,7 @@ test_one_liner_labels ()
text_range_label label (nullptr);
gcc_rich_location richloc (bar, &label, nullptr);
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar.field;\n"
" ^~~\n",
dc.test_show_locus (richloc));
@@ -5087,7 +5119,7 @@ test_diagnostic_show_locus_one_liner (const line_table_case &case_)
....................1234567890123456. */
const char *content = "foo = bar.field;\n";
- diagnostic_show_locus_fixture f (case_, content);
+ source_printing_fixture f (case_, content);
location_t line_end = linemap_position_for_column (line_table, 16);
@@ -5117,7 +5149,7 @@ test_diagnostic_show_locus_one_liner (const line_table_case &case_)
/* Version of all one-liner tests exercising multibyte awareness.
These are all called from test_diagnostic_show_locus_one_liner,
- which uses diagnostic_show_locus_fixture_one_liner_utf8 to create
+ which uses source_printing_fixture_one_liner_utf8 to create
the test file; see the notes in diagnostic-show-locus-selftest.h.
Note: all of the below asserts would be easier to read if we used UTF-8
@@ -5132,7 +5164,7 @@ test_diagnostic_show_locus_one_liner (const line_table_case &case_)
static void
test_one_liner_simple_caret_utf8 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t caret = linemap_position_for_column (line_table, 18);
rich_location richloc (line_table, caret);
ASSERT_STREQ (" \xf0\x9f\x98\x82"
@@ -5148,7 +5180,7 @@ test_one_liner_simple_caret_utf8 ()
static void
test_one_liner_caret_and_range_utf8 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t caret = linemap_position_for_column (line_table, 18);
location_t start = linemap_position_for_column (line_table, 12);
location_t finish = linemap_position_for_column (line_table, 30);
@@ -5168,24 +5200,24 @@ test_one_liner_caret_and_range_utf8 ()
static void
test_one_liner_multiple_carets_and_ranges_utf8 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t foo
= make_location (linemap_position_for_column (line_table, 7),
linemap_position_for_column (line_table, 1),
linemap_position_for_column (line_table, 8));
- dc.m_source_printing.caret_chars[0] = 'A';
+ dc.set_caret_char (0, 'A');
location_t bar
= make_location (linemap_position_for_column (line_table, 16),
linemap_position_for_column (line_table, 12),
linemap_position_for_column (line_table, 17));
- dc.m_source_printing.caret_chars[1] = 'B';
+ dc.set_caret_char (1, 'B');
location_t field
= make_location (linemap_position_for_column (line_table, 26),
linemap_position_for_column (line_table, 19),
linemap_position_for_column (line_table, 30));
- dc.m_source_printing.caret_chars[2] = 'C';
+ dc.set_caret_char (2, 'C');
rich_location richloc (line_table, foo);
richloc.add_range (bar, SHOW_RANGE_WITH_CARET);
richloc.add_range (field, SHOW_RANGE_WITH_CARET);
@@ -5203,7 +5235,7 @@ test_one_liner_multiple_carets_and_ranges_utf8 ()
static void
test_one_liner_fixit_insert_before_utf8 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t caret = linemap_position_for_column (line_table, 12);
rich_location richloc (line_table, caret);
richloc.add_fixit_insert_before ("&");
@@ -5222,7 +5254,7 @@ test_one_liner_fixit_insert_before_utf8 ()
static void
test_one_liner_fixit_insert_after_utf8 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t start = linemap_position_for_column (line_table, 1);
location_t finish = linemap_position_for_column (line_table, 8);
location_t foo = make_location (start, start, finish);
@@ -5243,7 +5275,7 @@ test_one_liner_fixit_insert_after_utf8 ()
static void
test_one_liner_fixit_remove_utf8 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t start = linemap_position_for_column (line_table, 18);
location_t finish = linemap_position_for_column (line_table, 30);
location_t dot = make_location (start, start, finish);
@@ -5264,7 +5296,7 @@ test_one_liner_fixit_remove_utf8 ()
static void
test_one_liner_fixit_replace_utf8 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t start = linemap_position_for_column (line_table, 19);
location_t finish = linemap_position_for_column (line_table, 30);
location_t field = make_location (start, start, finish);
@@ -5287,7 +5319,7 @@ test_one_liner_fixit_replace_utf8 ()
static void
test_one_liner_fixit_replace_non_equal_range_utf8 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t equals = linemap_position_for_column (line_table, 10);
location_t start = linemap_position_for_column (line_table, 19);
location_t finish = linemap_position_for_column (line_table, 30);
@@ -5317,7 +5349,7 @@ test_one_liner_fixit_replace_non_equal_range_utf8 ()
static void
test_one_liner_fixit_replace_equal_secondary_range_utf8 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t equals = linemap_position_for_column (line_table, 10);
location_t start = linemap_position_for_column (line_table, 19);
location_t finish = linemap_position_for_column (line_table, 30);
@@ -5363,7 +5395,7 @@ test_one_liner_fixit_validation_adhoc_locations_utf8 ()
/* It should not have been discarded by the validator. */
ASSERT_EQ (1, richloc.get_num_fixit_hints ());
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" \xf0\x9f\x98\x82"
"_foo = \xcf\x80"
"_bar.\xf0\x9f\x98\x82"
@@ -5393,7 +5425,7 @@ test_one_liner_fixit_validation_adhoc_locations_utf8 ()
/* It should not have been discarded by the validator. */
ASSERT_EQ (1, richloc.get_num_fixit_hints ());
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" \xf0\x9f\x98\x82"
"_foo = \xcf\x80"
"_bar.\xf0\x9f\x98\x82"
@@ -5434,7 +5466,7 @@ test_one_liner_fixit_validation_adhoc_locations_utf8 ()
/* It should not have been discarded by the validator. */
ASSERT_EQ (1, richloc.get_num_fixit_hints ());
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" \xf0\x9f\x98\x82"
"_foo = \xcf\x80"
"_bar.\xf0\x9f\x98\x82"
@@ -5462,7 +5494,7 @@ test_one_liner_fixit_validation_adhoc_locations_utf8 ()
static void
test_one_liner_many_fixits_1_utf8 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t equals = linemap_position_for_column (line_table, 10);
rich_location richloc (line_table, equals);
for (int i = 0; i < 19; i++)
@@ -5485,7 +5517,7 @@ test_one_liner_many_fixits_1_utf8 ()
static void
test_one_liner_many_fixits_2_utf8 ()
{
- test_diagnostic_context dc;
+ test_context dc;
location_t equals = linemap_position_for_column (line_table, 10);
rich_location richloc (line_table, equals);
const int nlocs = 19;
@@ -5546,7 +5578,7 @@ test_one_liner_labels_utf8 ()
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
{
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" \xf0\x9f\x98\x82"
"_foo = \xcf\x80"
"_bar.\xf0\x9f\x98\x82"
@@ -5572,7 +5604,7 @@ test_one_liner_labels_utf8 ()
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" \xf0\x9f\x98\x82"
"_foo = \xcf\x80"
"_bar.\xf0\x9f\x98\x82"
@@ -5596,7 +5628,7 @@ test_one_liner_labels_utf8 ()
richloc.add_range (bar, SHOW_RANGE_WITHOUT_CARET, &label1);
richloc.add_range (field, SHOW_RANGE_WITHOUT_CARET, &label2);
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" \xf0\x9f\x98\x82"
"_foo = \xcf\x80"
"_bar.\xf0\x9f\x98\x82"
@@ -5621,7 +5653,7 @@ test_one_liner_labels_utf8 ()
richloc.set_escape_on_output (true);
{
- test_diagnostic_context dc;
+ test_context dc;
dc.set_escape_format (DIAGNOSTICS_ESCAPE_FORMAT_UNICODE);
ASSERT_STREQ (" <U+1F602>_foo = <U+03C0>_bar.<U+1F602>_field<U+03C0>;\n"
" ^~~~~~~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~\n"
@@ -5632,7 +5664,7 @@ test_one_liner_labels_utf8 ()
dc.test_show_locus (richloc));
}
{
- test_diagnostic_context dc;
+ test_context dc;
dc.set_escape_format (DIAGNOSTICS_ESCAPE_FORMAT_BYTES);
ASSERT_STREQ
(" <f0><9f><98><82>_foo = <cf><80>_bar.<f0><9f><98><82>_field<cf><80>;\n"
@@ -5651,8 +5683,8 @@ test_one_liner_labels_utf8 ()
static void
test_one_liner_colorized_utf8 ()
{
- test_diagnostic_context dc;
- dc.m_source_printing.colorize_source_p = true;
+ test_context dc;
+ dc.colorize_source (true);
diagnostic_color_init (&dc, DIAGNOSTICS_COLOR_YES);
const location_t pi = linemap_position_for_column (line_table, 12);
rich_location richloc (line_table, pi);
@@ -5675,9 +5707,9 @@ static const char * const one_liner_utf8_content
1111222233334444567890122223333456789999000011112222345678999900001
Byte columns. */
-diagnostic_show_locus_fixture_one_liner_utf8::
-diagnostic_show_locus_fixture_one_liner_utf8 (const line_table_case &case_)
-: diagnostic_show_locus_fixture (case_, one_liner_utf8_content)
+source_printing_fixture_one_liner_utf8::
+source_printing_fixture_one_liner_utf8 (const line_table_case &case_)
+: source_printing_fixture (case_, one_liner_utf8_content)
{
}
@@ -5686,7 +5718,7 @@ diagnostic_show_locus_fixture_one_liner_utf8 (const line_table_case &case_)
static void
test_diagnostic_show_locus_one_liner_utf8 (const line_table_case &case_)
{
- diagnostic_show_locus_fixture_one_liner_utf8 f (case_);
+ source_printing_fixture_one_liner_utf8 f (case_);
location_t line_end = linemap_position_for_column (line_table, 31);
@@ -5698,7 +5730,7 @@ test_diagnostic_show_locus_one_liner_utf8 (const line_table_case &case_)
ASSERT_EQ (1, LOCATION_LINE (line_end));
ASSERT_EQ (31, LOCATION_COLUMN (line_end));
- char_span lspan = f.m_fc.get_source_line (f.get_filename (), 1);
+ diagnostics::char_span lspan = f.m_fc.get_source_line (f.get_filename (), 1);
ASSERT_EQ (25, cpp_display_width (lspan.get_buffer (), lspan.length (),
def_policy ()));
ASSERT_EQ (25, location_compute_display_column (f.m_fc,
@@ -5755,7 +5787,7 @@ test_add_location_if_nearby (const line_table_case &case_)
/* Test of add_location_if_nearby on the same line as the
primary location. */
{
- test_diagnostic_context dc;
+ test_context dc;
const location_t missing_close_brace_1_39
= linemap_position_for_line_and_column (line_table, ord_map, 1, 39);
const location_t matching_open_brace_1_18
@@ -5773,7 +5805,7 @@ test_add_location_if_nearby (const line_table_case &case_)
/* Test of add_location_if_nearby on a different line to the
primary location. */
{
- test_diagnostic_context dc;
+ test_context dc;
const location_t missing_close_brace_6_1
= linemap_position_for_line_and_column (line_table, ord_map, 6, 1);
const location_t matching_open_brace_3_1
@@ -5822,7 +5854,7 @@ test_diagnostic_show_locus_fixit_lines (const line_table_case &case_)
/* The one-liner case (line 2). */
{
- test_diagnostic_context dc;
+ test_context dc;
const location_t x
= linemap_position_for_line_and_column (line_table, ord_map, 2, 24);
const location_t colon
@@ -5841,7 +5873,7 @@ test_diagnostic_show_locus_fixit_lines (const line_table_case &case_)
span starts are printed due to the gap between the span at line 3
and that at line 6). */
{
- test_diagnostic_context dc;
+ test_context dc;
const location_t y
= linemap_position_for_line_and_column (line_table, ord_map, 3, 24);
const location_t colon
@@ -5869,8 +5901,8 @@ test_diagnostic_show_locus_fixit_lines (const line_table_case &case_)
rich_location richloc (line_table, colon);
richloc.add_fixit_insert_before (y, ".");
richloc.add_fixit_replace (colon, "=");
- test_diagnostic_context dc;
- dc.m_source_printing.show_line_numbers_p = true;
+ test_context dc;
+ dc.show_line_numbers (true);
ASSERT_STREQ (" 3 | y\n"
" | .\n"
"......\n"
@@ -6043,7 +6075,7 @@ test_overlapped_fixit_printing (const line_table_case &case_)
const char *content
= (" foo *f = (foo *)ptr->field;\n");
temp_source_file tmp (SELFTEST_LOCATION, ".C", content);
- file_cache fc;
+ diagnostics::file_cache fc;
line_table_test ltt (case_);
const line_map_ordinary *ord_map
@@ -6075,7 +6107,7 @@ test_overlapped_fixit_printing (const line_table_case &case_)
/* Example where 3 fix-it hints are printed as one. */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, expr);
richloc.add_fixit_replace (open_paren, "const_cast<");
richloc.add_fixit_replace (close_paren, "> (");
@@ -6144,7 +6176,7 @@ test_overlapped_fixit_printing (const line_table_case &case_)
/* Example where two are consolidated during printing. */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, expr);
richloc.add_fixit_replace (open_paren, "CAST (");
richloc.add_fixit_replace (close_paren, ") (");
@@ -6160,7 +6192,7 @@ test_overlapped_fixit_printing (const line_table_case &case_)
/* Example where none are consolidated during printing. */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, expr);
richloc.add_fixit_replace (open_paren, "CST (");
richloc.add_fixit_replace (close_paren, ") (");
@@ -6176,7 +6208,7 @@ test_overlapped_fixit_printing (const line_table_case &case_)
/* Example of deletion fix-it hints. */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, expr);
richloc.add_fixit_insert_before (open_paren, "(bar *)");
source_range victim = {open_paren, close_paren};
@@ -6195,7 +6227,7 @@ test_overlapped_fixit_printing (const line_table_case &case_)
/* Example of deletion fix-it hints that would overlap. */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, expr);
richloc.add_fixit_insert_before (open_paren, "(longer *)");
source_range victim = {expr_start, expr_finish};
@@ -6214,7 +6246,7 @@ test_overlapped_fixit_printing (const line_table_case &case_)
/* Example of insertion fix-it hints that would overlap. */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, expr);
richloc.add_fixit_insert_before (open_paren, "LONGER THAN THE CAST");
richloc.add_fixit_insert_after (close_paren, "TEST");
@@ -6280,8 +6312,8 @@ test_overlapped_fixit_printing_utf8 (const line_table_case &case_)
/* Example where 3 fix-it hints are printed as one. */
{
- test_diagnostic_context dc;
- file_cache &fc = dc.get_file_cache ();
+ test_context dc;
+ diagnostics::file_cache &fc = dc.get_file_cache ();
rich_location richloc (line_table, expr);
richloc.add_fixit_replace (open_paren, "const_cast<");
richloc.add_fixit_replace (close_paren, "> (");
@@ -6356,7 +6388,7 @@ test_overlapped_fixit_printing_utf8 (const line_table_case &case_)
/* Example where two are consolidated during printing. */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, expr);
richloc.add_fixit_replace (open_paren, "CAST (");
richloc.add_fixit_replace (close_paren, ") (");
@@ -6375,7 +6407,7 @@ test_overlapped_fixit_printing_utf8 (const line_table_case &case_)
/* Example where none are consolidated during printing. */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, expr);
richloc.add_fixit_replace (open_paren, "CST (");
richloc.add_fixit_replace (close_paren, ") (");
@@ -6394,7 +6426,7 @@ test_overlapped_fixit_printing_utf8 (const line_table_case &case_)
/* Example of deletion fix-it hints. */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, expr);
richloc.add_fixit_insert_before (open_paren, "(bar\xf0\x9f\x98\x82 *)");
source_range victim = {open_paren, close_paren};
@@ -6417,7 +6449,7 @@ test_overlapped_fixit_printing_utf8 (const line_table_case &case_)
/* Example of deletion fix-it hints that would overlap. */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, expr);
richloc.add_fixit_insert_before (open_paren, "(long\xf0\x9f\x98\x82 *)");
source_range victim = {expr_start, expr_finish};
@@ -6441,7 +6473,7 @@ test_overlapped_fixit_printing_utf8 (const line_table_case &case_)
/* Example of insertion fix-it hints that would overlap. */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, expr);
richloc.add_fixit_insert_before
(open_paren, "L\xf0\x9f\x98\x82NGER THAN THE CAST");
@@ -6505,8 +6537,8 @@ test_overlapped_fixit_printing_2 (const line_table_case &case_)
/* Two insertions, in the wrong order. */
{
- test_diagnostic_context dc;
- file_cache &fc = dc.get_file_cache ();
+ test_context dc;
+ diagnostics::file_cache &fc = dc.get_file_cache ();
rich_location richloc (line_table, col_20);
richloc.add_fixit_insert_before (col_23, "{");
@@ -6534,7 +6566,7 @@ test_overlapped_fixit_printing_2 (const line_table_case &case_)
/* Various overlapping insertions, some occurring "out of order"
(reproducing the fix-it hints from PR c/81405). */
{
- test_diagnostic_context dc;
+ test_context dc;
rich_location richloc (line_table, col_20);
richloc.add_fixit_insert_before (col_20, "{{");
@@ -6588,7 +6620,7 @@ test_fixit_insert_containing_newline (const line_table_case &case_)
/* Without line numbers. */
{
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" x = a;\n"
"+ break;\n"
" case 'b':\n"
@@ -6598,8 +6630,8 @@ test_fixit_insert_containing_newline (const line_table_case &case_)
/* With line numbers. */
{
- test_diagnostic_context dc;
- dc.m_source_printing.show_line_numbers_p = true;
+ test_context dc;
+ dc.show_line_numbers (true);
ASSERT_STREQ (" 2 | x = a;\n"
" +++ |+ break;\n"
" 3 | case 'b':\n"
@@ -6614,7 +6646,7 @@ test_fixit_insert_containing_newline (const line_table_case &case_)
rich_location richloc (line_table, case_loc);
richloc.add_fixit_insert_before (case_start, "break;\n");
ASSERT_TRUE (richloc.seen_impossible_fixit_p ());
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" case 'b':\n"
" ^~~~~~~~~\n",
dc.test_show_locus (richloc));
@@ -6661,7 +6693,7 @@ test_fixit_insert_containing_newline_2 (const line_table_case &case_)
return;
{
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ ("FILENAME:1:1:\n"
"+#include <stdio.h>\n"
" test (int ch)\n"
@@ -6674,8 +6706,8 @@ test_fixit_insert_containing_newline_2 (const line_table_case &case_)
/* With line-numbering, the line spans are close enough to be
consolidated, since it makes little sense to skip line 2. */
{
- test_diagnostic_context dc;
- dc.m_source_printing.show_line_numbers_p = true;
+ test_context dc;
+ dc.show_line_numbers (true);
ASSERT_STREQ (" +++ |+#include <stdio.h>\n"
" 1 | test (int ch)\n"
" 2 | {\n"
@@ -6717,7 +6749,7 @@ test_fixit_replace_containing_newline (const line_table_case &case_)
if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
return;
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar ();\n"
" ^\n",
dc.test_show_locus (richloc));
@@ -6760,7 +6792,7 @@ test_fixit_deletion_affecting_newline (const line_table_case &case_)
if (finish > LINE_MAP_MAX_LOCATION_WITH_COLS)
return;
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" foo = bar (\n"
" ~^\n"
" );\n"
@@ -6800,7 +6832,7 @@ test_tab_expansion (const line_table_case &case_)
into 11 spaces. Recall that print_line() also puts one space before
everything too. */
{
- test_diagnostic_context dc;
+ test_context dc;
dc.m_tabstop = tabstop;
rich_location richloc (line_table,
linemap_position_for_column (line_table,
@@ -6813,7 +6845,7 @@ test_tab_expansion (const line_table_case &case_)
/* Confirm the display width was tracked correctly across the internal tab
as well. */
{
- test_diagnostic_context dc;
+ test_context dc;
dc.m_tabstop = tabstop;
rich_location richloc (line_table,
linemap_position_for_column (line_table,
@@ -6854,14 +6886,14 @@ test_escaping_bytes_1 (const line_table_case &case_)
richloc.add_range (v_loc);
{
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" before \1\2\3\v\x80\xff""after\n"
" ^ ~\n",
dc.test_show_locus (richloc));
}
richloc.set_escape_on_output (true);
{
- test_diagnostic_context dc;
+ test_context dc;
dc.set_escape_format (DIAGNOSTICS_ESCAPE_FORMAT_UNICODE);
ASSERT_STREQ
(" before<U+0000><U+0001><U+0002><U+0003><U+000B><80><ff>after\n"
@@ -6869,7 +6901,7 @@ test_escaping_bytes_1 (const line_table_case &case_)
dc.test_show_locus (richloc));
}
{
- test_diagnostic_context dc;
+ test_context dc;
dc.set_escape_format (DIAGNOSTICS_ESCAPE_FORMAT_BYTES);
ASSERT_STREQ (" before<00><01><02><03><0b><80><ff>after\n"
" ^~~~ ~~~~\n",
@@ -6904,21 +6936,21 @@ test_escaping_bytes_2 (const line_table_case &case_)
gcc_rich_location richloc (nul_loc);
{
- test_diagnostic_context dc;
+ test_context dc;
ASSERT_STREQ (" after\n"
" ^\n",
dc.test_show_locus (richloc));
}
richloc.set_escape_on_output (true);
{
- test_diagnostic_context dc;
+ test_context dc;
dc.set_escape_format (DIAGNOSTICS_ESCAPE_FORMAT_UNICODE);
ASSERT_STREQ (" <U+0000>after\n"
" ^~~~~~~~\n",
dc.test_show_locus (richloc));
}
{
- test_diagnostic_context dc;
+ test_context dc;
dc.set_escape_format (DIAGNOSTICS_ESCAPE_FORMAT_BYTES);
ASSERT_STREQ (" <00>after\n"
" ^~~~\n",
@@ -6957,9 +6989,10 @@ test_line_numbers_multiline_range ()
= linemap_position_for_line_and_column (line_table, ord_map, 11, 4);
location_t loc = make_location (caret, start, finish);
- test_diagnostic_context dc;
- dc.m_source_printing.show_line_numbers_p = true;
- dc.m_source_printing.min_margin_width = 0;
+ test_context dc;
+ dc.show_line_numbers (true);
+ auto &source_printing_opts = dc.get_source_printing_options ();
+ source_printing_opts.min_margin_width = 0;
gcc_rich_location richloc (loc);
ASSERT_STREQ (" 9 | this is line 9\n"
" | ~~~~~~\n"
@@ -6973,7 +7006,7 @@ test_line_numbers_multiline_range ()
/* Run all of the selftests within this file. */
void
-diagnostic_show_locus_cc_tests ()
+source_printing_cc_tests ()
{
test_line_span ();
@@ -7009,7 +7042,8 @@ diagnostic_show_locus_cc_tests ()
test_line_numbers_multiline_range ();
}
-} // namespace selftest
+} // namespace diagnostics::selftest
+} // namespace diagnostics
#endif /* #if CHECKING_P */
diff --git a/gcc/diagnostic-state-to-dot.cc b/gcc/diagnostics/state-graphs-to-dot.cc
index 90ceaee..2d80e6b 100644
--- a/gcc/diagnostic-state-to-dot.cc
+++ b/gcc/diagnostics/state-graphs-to-dot.cc
@@ -27,16 +27,17 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
-#include "diagnostic-state-graphs.h"
+#include "diagnostics/state-graphs.h"
#include "graphviz.h"
#include "xml.h"
#include "xml-printer.h"
#include "intl.h"
+using namespace diagnostics;
using namespace diagnostics::state_graphs;
static int
-get_depth (const diagnostics::digraphs::node &n)
+get_depth (const digraphs::node &n)
{
int deepest_child = 0;
for (size_t i = 0; i < n.get_num_children (); ++i)
@@ -77,7 +78,7 @@ class state_diagram : public dot::graph
{
public:
state_diagram (const diagnostics::digraphs::digraph &input_state_graph,
- const logical_location_manager &logical_loc_mgr)
+ const logical_locations::manager &logical_loc_mgr)
: m_logical_loc_mgr (logical_loc_mgr)
{
// "node [shape=plaintext]\n"
@@ -268,12 +269,12 @@ private:
default:
gcc_unreachable ();
case style::h1:
- // from diagnostic-format-html.cc: HTML_STYLE .linenum
+ // from diagnostics/html-sink.cc: HTML_STYLE .linenum
bgcolor = "#0088ce";
color = "white";
break;
case style::h2:
- // from diagnostic-format-html.cc: HTML_STYLE .events-hdr
+ // from diagnostics/html-sink.cc: HTML_STYLE .events-hdr
bgcolor = "#393f44"; // pf-black-800
color = "white";
break;
@@ -531,20 +532,20 @@ private:
}
private:
- const logical_location_manager &m_logical_loc_mgr;
+ const logical_locations::manager &m_logical_loc_mgr;
/* All nodes involved in edges (and thus will need a port). */
- std::set<diagnostics::digraphs::node *> m_src_nodes;
- std::set<diagnostics::digraphs::node *> m_dst_nodes;
+ std::set<digraphs::node *> m_src_nodes;
+ std::set<digraphs::node *> m_dst_nodes;
- std::map<diagnostics::digraphs::node *, dot::node_id> m_src_node_to_port_id;
- std::map<diagnostics::digraphs::node *, dot::node_id> m_dst_node_to_port_id;
+ std::map<digraphs::node *, dot::node_id> m_src_node_to_port_id;
+ std::map<digraphs::node *, dot::node_id> m_dst_node_to_port_id;
};
std::unique_ptr<dot::graph>
-diagnostics::state_graphs::
-make_dot_graph (const diagnostics::digraphs::digraph &state_graph,
- const logical_location_manager &logical_loc_mgr)
+state_graphs::
+make_dot_graph (const digraphs::digraph &state_graph,
+ const logical_locations::manager &logical_loc_mgr)
{
return std::make_unique<state_diagram> (state_graph, logical_loc_mgr);
}
diff --git a/gcc/diagnostic-state-graphs.cc b/gcc/diagnostics/state-graphs.cc
index 62eb6f5..5941c41 100644
--- a/gcc/diagnostic-state-graphs.cc
+++ b/gcc/diagnostics/state-graphs.cc
@@ -27,11 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
-#include "diagnostic-state-graphs.h"
-#include "graphviz.h"
-#include "xml.h"
-#include "xml-printer.h"
-#include "intl.h"
+#include "diagnostics/state-graphs.h"
#include "selftest.h"
using namespace diagnostics::state_graphs;
@@ -123,13 +119,14 @@ state_node_ref::set_json_attr (const char *key,
#if CHECKING_P
+namespace diagnostics {
namespace selftest {
static void
test_node_attrs ()
{
- diagnostics::digraphs::digraph g;
- diagnostics::digraphs::node n (g, "a");
+ digraphs::digraph g;
+ digraphs::node n (g, "a");
state_node_ref node_ref (n);
ASSERT_EQ (node_ref.get_node_kind (), node_kind::other);
@@ -148,11 +145,12 @@ test_node_attrs ()
/* Run all of the selftests within this file. */
void
-diagnostic_state_graphs_cc_tests ()
+state_graphs_cc_tests ()
{
test_node_attrs ();
}
-} // namespace selftest
+} // namespace diagnostics::selftest
+} // namespace diagnostics
#endif /* CHECKING_P */
diff --git a/gcc/diagnostic-state-graphs.h b/gcc/diagnostics/state-graphs.h
index def6d05..ad18f82 100644
--- a/gcc/diagnostic-state-graphs.h
+++ b/gcc/diagnostics/state-graphs.h
@@ -18,11 +18,11 @@ 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_DIAGNOSTIC_STATE_GRAPHS_H
-#define GCC_DIAGNOSTIC_STATE_GRAPHS_H
+#ifndef GCC_DIAGNOSTICS_STATE_GRAPHS_H
+#define GCC_DIAGNOSTICS_STATE_GRAPHS_H
-#include "diagnostic-digraphs.h"
-#include "logical-location.h"
+#include "diagnostics/digraphs.h"
+#include "diagnostics/logical-locations.h"
/* diagnostics::digraphs provides support for directed graphs.
@@ -96,7 +96,7 @@ struct state_node_ref
set_node_kind (enum node_kind);
// For node_kind::stack_frame, this will be the function
- logical_location
+ logical_locations::key
get_logical_loc () const
{
return m_node.get_logical_loc ();
@@ -148,9 +148,9 @@ struct state_node_ref
extern std::unique_ptr<dot::graph>
make_dot_graph (const diagnostics::digraphs::digraph &state_graph,
- const logical_location_manager &logical_loc_mgr);
+ const logical_locations::manager &logical_loc_mgr);
} // namespace state_graphs
} // namespace diagnostics
-#endif /* ! GCC_DIAGNOSTIC_STATE_GRAPHS_H */
+#endif /* ! GCC_DIAGNOSTICS_STATE_GRAPHS_H */
diff --git a/gcc/diagnostic-format-text.cc b/gcc/diagnostics/text-sink.cc
index 7ecbe5f..bcf91cf 100644
--- a/gcc/diagnostic-format-text.cc
+++ b/gcc/diagnostics/text-sink.cc
@@ -25,14 +25,14 @@ along with GCC; see the file COPYING3. If not see
#include "version.h"
#include "intl.h"
#include "diagnostic.h"
-#include "diagnostic-color.h"
-#include "diagnostic-url.h"
-#include "diagnostic-metadata.h"
-#include "diagnostic-path.h"
-#include "diagnostic-client-data-hooks.h"
-#include "diagnostic-diagram.h"
-#include "diagnostic-format-text.h"
-#include "diagnostic-buffer.h"
+#include "diagnostics/color.h"
+#include "diagnostics/url.h"
+#include "diagnostics/metadata.h"
+#include "diagnostics/paths.h"
+#include "diagnostics/client-data-hooks.h"
+#include "diagnostics/diagram.h"
+#include "diagnostics/text-sink.h"
+#include "diagnostics/buffering.h"
#include "text-art/theme.h"
/* Disable warnings about quoting issues in the pp_xxx calls below
@@ -42,54 +42,55 @@ along with GCC; see the file COPYING3. If not see
# pragma GCC diagnostic ignored "-Wformat-diag"
#endif
-/* Concrete buffering implementation subclass for JSON output. */
+namespace diagnostics {
-class diagnostic_text_format_buffer : public diagnostic_per_format_buffer
+/* Concrete buffering implementation subclass for text output. */
+
+class text_sink_buffer : public per_sink_buffer
{
public:
- friend class diagnostic_text_output_format;
+ friend class text_sink;
- diagnostic_text_format_buffer (diagnostic_output_format &format);
+ text_sink_buffer (sink &sink_);
void dump (FILE *out, int indent) const final override;
bool empty_p () const final override;
- void move_to (diagnostic_per_format_buffer &dest) final override;
+ void move_to (per_sink_buffer &dest) final override;
void clear () final override;
void flush () final override;
private:
- diagnostic_output_format &m_format;
+ sink &m_sink;
output_buffer m_output_buffer;
};
-/* class diagnostic_text_format_buffer : public diagnostic_per_format_buffer. */
+/* class text_sink_buffer : public per_sink_buffer. */
-diagnostic_text_format_buffer::
-diagnostic_text_format_buffer (diagnostic_output_format &format)
-: m_format (format)
+text_sink_buffer::text_sink_buffer (sink &sink_)
+: m_sink (sink_)
{
m_output_buffer.m_flush_p = false;
}
void
-diagnostic_text_format_buffer::dump (FILE *out, int indent) const
+text_sink_buffer::dump (FILE *out, int indent) const
{
- fprintf (out, "%*sdiagnostic_text_format_buffer:\n", indent, "");
+ fprintf (out, "%*stext_sink_buffer:\n", indent, "");
m_output_buffer.dump (out, indent + 2);
}
bool
-diagnostic_text_format_buffer::empty_p () const
+text_sink_buffer::empty_p () const
{
return output_buffer_last_position_in_text (&m_output_buffer) == nullptr;
}
void
-diagnostic_text_format_buffer::move_to (diagnostic_per_format_buffer &base_dest)
+text_sink_buffer::move_to (per_sink_buffer &base_dest)
{
- diagnostic_text_format_buffer &dest
- = static_cast<diagnostic_text_format_buffer &> (base_dest);
+ text_sink_buffer &dest
+ = static_cast<text_sink_buffer &> (base_dest);
const char *str = output_buffer_formatted_text (&m_output_buffer);
output_buffer_append_r (&dest.m_output_buffer, str, strlen (str));
@@ -99,9 +100,9 @@ diagnostic_text_format_buffer::move_to (diagnostic_per_format_buffer &base_dest)
}
void
-diagnostic_text_format_buffer::clear ()
+text_sink_buffer::clear ()
{
- pretty_printer *const pp = m_format.get_printer ();
+ pretty_printer *const pp = m_sink.get_printer ();
output_buffer *const old_output_buffer = pp_buffer (pp);
pp_buffer (pp) = &m_output_buffer;
@@ -113,9 +114,9 @@ diagnostic_text_format_buffer::clear ()
}
void
-diagnostic_text_format_buffer::flush ()
+text_sink_buffer::flush ()
{
- pretty_printer *const pp = m_format.get_printer ();
+ pretty_printer *const pp = m_sink.get_printer ();
output_buffer *const old_output_buffer = pp_buffer (pp);
pp_buffer (pp) = &m_output_buffer;
@@ -126,12 +127,12 @@ diagnostic_text_format_buffer::flush ()
pp_buffer (pp) = old_output_buffer;
}
-/* class diagnostic_text_output_format : public diagnostic_output_format. */
+/* class diagnostics::text_sink : public diagnostics::sink. */
-diagnostic_text_output_format::~diagnostic_text_output_format ()
+text_sink::~text_sink ()
{
/* Some of the errors may actually have been warnings. */
- if (m_context.diagnostic_count (DK_WERROR))
+ if (m_context.diagnostic_count (kind::werror))
{
pretty_printer *pp = get_printer ();
/* -Werror was given. */
@@ -155,13 +156,13 @@ diagnostic_text_output_format::~diagnostic_text_output_format ()
}
void
-diagnostic_text_output_format::dump (FILE *out, int indent) const
+text_sink::dump (FILE *out, int indent) const
{
- fprintf (out, "%*sdiagnostic_text_output_format\n", indent, "");
+ fprintf (out, "%*stext_sink\n", indent, "");
fprintf (out, "%*sm_follows_reference_printer: %s\n",
indent, "",
m_follows_reference_printer ? "true" : "false");
- diagnostic_output_format::dump (out, indent);
+ sink::dump (out, indent);
fprintf (out, "%*ssaved_output_buffer:\n", indent + 2, "");
if (m_saved_output_buffer)
m_saved_output_buffer->dump (out, indent + 4);
@@ -170,10 +171,10 @@ diagnostic_text_output_format::dump (FILE *out, int indent) const
}
void
-diagnostic_text_output_format::set_buffer (diagnostic_per_format_buffer *base)
+text_sink::set_buffer (per_sink_buffer *base)
{
- diagnostic_text_format_buffer * const buffer
- = static_cast<diagnostic_text_format_buffer *> (base);
+ text_sink_buffer * const buffer
+ = static_cast<text_sink_buffer *> (base);
pretty_printer *const pp = get_printer ();
@@ -189,23 +190,22 @@ diagnostic_text_output_format::set_buffer (diagnostic_per_format_buffer *base)
}
}
-std::unique_ptr<diagnostic_per_format_buffer>
-diagnostic_text_output_format::make_per_format_buffer ()
+std::unique_ptr<per_sink_buffer>
+text_sink::make_per_sink_buffer ()
{
- return std::make_unique<diagnostic_text_format_buffer> (*this);
+ return std::make_unique<text_sink_buffer> (*this);
}
-/* Implementation of diagnostic_output_format::on_report_diagnostic vfunc
+/* Implementation of diagnostics::sink::on_report_diagnostic vfunc
for GCC's standard textual output. */
void
-diagnostic_text_output_format::
-on_report_diagnostic (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind)
+text_sink::on_report_diagnostic (const diagnostic_info &diagnostic,
+ enum kind orig_diag_kind)
{
pretty_printer *pp = get_printer ();
- (*diagnostic_text_starter (&m_context)) (*this, &diagnostic);
+ (*text_starter (&m_context)) (*this, &diagnostic);
pp_output_formatted_text (pp, m_context.get_urlifier ());
@@ -242,23 +242,23 @@ on_report_diagnostic (const diagnostic_info &diagnostic,
}
}
- (*diagnostic_text_finalizer (&m_context)) (*this,
- &diagnostic,
- orig_diag_kind);
+ (*text_finalizer (&m_context)) (*this,
+ &diagnostic,
+ orig_diag_kind);
if (m_show_nesting && m_show_locations_in_nesting)
get_context ().m_last_location = diagnostic_location (&diagnostic);
}
void
-diagnostic_text_output_format::on_report_verbatim (text_info &text)
+text_sink::on_report_verbatim (text_info &text)
{
pp_format_verbatim (get_printer (), &text);
pp_newline_and_flush (get_printer ());
}
void
-diagnostic_text_output_format::on_diagram (const diagnostic_diagram &diagram)
+text_sink::on_diagram (const diagnostics::diagram &d)
{
pretty_printer *const pp = get_printer ();
@@ -267,17 +267,17 @@ diagnostic_text_output_format::on_diagram (const diagnostic_diagram &diagram)
/* Use a newline before and after and a two-space indent
to make the diagram stand out a little from the wall of text. */
pp_newline (pp);
- diagram.get_canvas ().print_to_pp (pp, " ");
+ d.get_canvas ().print_to_pp (pp, " ");
pp_newline (pp);
pp_set_prefix (pp, saved_prefix);
pp_flush (pp);
}
void
-diagnostic_text_output_format::
+text_sink::
after_diagnostic (const diagnostic_info &diagnostic)
{
- if (const diagnostic_path *path = diagnostic.richloc->get_path ())
+ if (const paths::path *path = diagnostic.m_richloc->get_path ())
print_path (*path);
}
@@ -289,16 +289,15 @@ after_diagnostic (const diagnostic_info &diagnostic)
The caller is responsible for freeing the memory. */
char *
-diagnostic_text_output_format::
-build_prefix (const diagnostic_info &diagnostic) const
+text_sink::build_prefix (const diagnostic_info &diagnostic) const
{
- gcc_assert (diagnostic.kind < DK_LAST_DIAGNOSTIC_KIND);
+ gcc_assert (diagnostic.m_kind < kind::last_diagnostic_kind);
- const char *text = _(get_diagnostic_kind_text (diagnostic.kind));
+ const char *text = _(get_text_for_kind (diagnostic.m_kind));
const char *text_cs = "", *text_ce = "";
pretty_printer *pp = get_printer ();
- if (const char *color_name = diagnostic_get_color_for_kind (diagnostic.kind))
+ if (const char *color_name = get_color_for_kind (diagnostic.m_kind))
{
text_cs = colorize_start (pp_show_color (pp), color_name);
text_ce = colorize_stop (pp_show_color (pp));
@@ -311,7 +310,7 @@ build_prefix (const diagnostic_info &diagnostic) const
/* Reduce verbosity of nested diagnostics by not printing "note: "
all the time. */
- if (diagnostic.kind == DK_NOTE)
+ if (diagnostic.m_kind == kind::note)
return indent_prefix;
char *result = build_message_string ("%s%s%s%s", indent_prefix,
@@ -330,7 +329,7 @@ build_prefix (const diagnostic_info &diagnostic) const
/* Same as build_prefix, but only the source FILE is given. */
char *
-diagnostic_text_output_format::file_name_as_prefix (const char *f) const
+text_sink::file_name_as_prefix (const char *f) const
{
pretty_printer *const pp = get_printer ();
const char *locus_cs
@@ -354,7 +353,7 @@ get_bullet_point_unichar (bool unicode)
/* Return true if DC's theme supports unicode characters. */
static bool
-use_unicode_p (const diagnostic_context &dc)
+use_unicode_p (const context &dc)
{
if (text_art::theme *theme = dc.get_diagram_theme ())
return theme->unicode_p ();
@@ -366,7 +365,7 @@ use_unicode_p (const diagnostic_context &dc)
nested diagnostics. */
static unsigned
-get_bullet_point_unichar (diagnostic_context &dc)
+get_bullet_point_unichar (context &dc)
{
return get_bullet_point_unichar (use_unicode_p (dc));
}
@@ -382,7 +381,7 @@ get_bullet_point_unichar (diagnostic_context &dc)
The caller is responsible for freeing the memory. */
char *
-diagnostic_text_output_format::build_indent_prefix (bool with_bullet) const
+text_sink::build_indent_prefix (bool with_bullet) const
{
if (!m_show_nesting)
return xstrdup ("");
@@ -407,18 +406,18 @@ diagnostic_text_output_format::build_indent_prefix (bool with_bullet) const
/* Add a purely textual note with text GMSGID and with LOCATION. */
void
-diagnostic_text_output_format::append_note (location_t location,
- const char * gmsgid, ...)
+text_sink::append_note (location_t location,
+ const char * gmsgid, ...)
{
- diagnostic_context *context = &get_context ();
+ context *dc = &get_context ();
diagnostic_info diagnostic;
va_list ap;
rich_location richloc (line_table, location);
va_start (ap, gmsgid);
- diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE);
- if (context->m_inhibit_notes_p)
+ diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, kind::note);
+ if (dc->m_inhibit_notes_p)
{
va_end (ap);
return;
@@ -426,25 +425,24 @@ diagnostic_text_output_format::append_note (location_t location,
pretty_printer *pp = get_printer ();
char *saved_prefix = pp_take_prefix (pp);
pp_set_prefix (pp, build_prefix (diagnostic));
- pp_format (pp, &diagnostic.message);
+ pp_format (pp, &diagnostic.m_message);
pp_output_formatted_text (pp);
pp_destroy_prefix (pp);
pp_set_prefix (pp, saved_prefix);
pp_newline (pp);
- diagnostic_show_locus (context, get_source_printing_options (),
- &richloc, DK_NOTE, pp);
+ diagnostic_show_locus (dc, get_source_printing_options (),
+ &richloc, kind::note, pp);
va_end (ap);
}
bool
-diagnostic_text_output_format::follows_reference_printer_p () const
+text_sink::follows_reference_printer_p () const
{
return m_follows_reference_printer;
}
void
-diagnostic_text_output_format::
-update_printer ()
+text_sink::update_printer ()
{
pretty_printer *copy_from_pp
= (m_follows_reference_printer
@@ -469,18 +467,18 @@ update_printer ()
description of the security issue. */
void
-diagnostic_text_output_format::print_any_cwe (const diagnostic_info &diagnostic)
+text_sink::print_any_cwe (const diagnostic_info &diagnostic)
{
- if (!diagnostic.metadata)
+ if (!diagnostic.m_metadata)
return;
- int cwe = diagnostic.metadata->get_cwe ();
+ int cwe = diagnostic.m_metadata->get_cwe ();
if (cwe)
{
pretty_printer * const pp = get_printer ();
char *saved_prefix = pp_take_prefix (pp);
pp_string (pp, " [");
- const char *kind_color = diagnostic_get_color_for_kind (diagnostic.kind);
+ const char *kind_color = get_color_for_kind (diagnostic.m_kind);
pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
if (pp->supports_urls_p ())
{
@@ -504,23 +502,21 @@ diagnostic_text_output_format::print_any_cwe (const diagnostic_info &diagnostic)
with any URL provided by the rule. */
void
-diagnostic_text_output_format::
-print_any_rules (const diagnostic_info &diagnostic)
+text_sink::print_any_rules (const diagnostic_info &diagnostic)
{
- if (!diagnostic.metadata)
+ if (!diagnostic.m_metadata)
return;
- for (unsigned idx = 0; idx < diagnostic.metadata->get_num_rules (); idx++)
+ for (unsigned idx = 0; idx < diagnostic.m_metadata->get_num_rules (); idx++)
{
- const diagnostic_metadata::rule &rule
- = diagnostic.metadata->get_rule (idx);
+ const diagnostics::metadata::rule &rule
+ = diagnostic.m_metadata->get_rule (idx);
if (char *desc = rule.make_description ())
{
pretty_printer * const pp = get_printer ();
char *saved_prefix = pp_take_prefix (pp);
pp_string (pp, " [");
- const char *kind_color
- = diagnostic_get_color_for_kind (diagnostic.kind);
+ const char *kind_color = get_color_for_kind (diagnostic.m_kind);
pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
char *url = nullptr;
if (pp->supports_urls_p ())
@@ -542,25 +538,23 @@ print_any_rules (const diagnostic_info &diagnostic)
}
}
-/* Print any metadata about the option used to control DIAGNOSTIC to CONTEXT's
- printer, e.g. " [-Werror=uninitialized]".
- Subroutine of diagnostic_context::report_diagnostic. */
+/* Print any metadata about the option used to control DIAGNOSTIC to
+ the context's printer, e.g. " [-Werror=uninitialized]". */
void
-diagnostic_text_output_format::
-print_option_information (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind)
+text_sink::print_option_information (const diagnostic_info &diagnostic,
+ enum kind orig_diag_kind)
{
if (char *option_text
- = m_context.make_option_name (diagnostic.option_id,
- orig_diag_kind, diagnostic.kind))
+ = m_context.make_option_name (diagnostic.m_option_id,
+ orig_diag_kind, diagnostic.m_kind))
{
char *option_url = nullptr;
pretty_printer * const pp = get_printer ();
if (pp->supports_urls_p ())
- option_url = m_context.make_option_url (diagnostic.option_id);
+ option_url = m_context.make_option_url (diagnostic.m_option_id);
pp_string (pp, " [");
- const char *kind_color = diagnostic_get_color_for_kind (diagnostic.kind);
+ const char *kind_color = get_color_for_kind (diagnostic.m_kind);
pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
if (option_url)
pp_begin_url (pp, option_url);
@@ -579,7 +573,7 @@ print_option_information (const diagnostic_info &diagnostic,
/* Only dump the "In file included from..." stack once for each file. */
bool
-diagnostic_text_output_format::includes_seen_p (const line_map_ordinary *map)
+text_sink::includes_seen_p (const line_map_ordinary *map)
{
/* No include path for main. */
if (MAIN_FILE_P (map))
@@ -602,13 +596,12 @@ diagnostic_text_output_format::includes_seen_p (const line_map_ordinary *map)
}
label_text
-diagnostic_text_output_format::
-get_location_text (const expanded_location &s) const
+text_sink::get_location_text (const expanded_location &s) const
{
- diagnostic_column_policy column_policy (get_context ());
- return column_policy.get_location_text (s,
- show_column_p (),
- pp_show_color (get_printer ()));
+ column_policy column_policy_ (get_context ());
+ return column_policy_.get_location_text (s,
+ show_column_p (),
+ pp_show_color (get_printer ()));
}
/* Helpers for writing lang-specific starters/finalizers for text output. */
@@ -636,7 +629,7 @@ maybe_line_and_column (int line, int col)
}
void
-diagnostic_text_output_format::report_current_module (location_t where)
+text_sink::report_current_module (location_t where)
{
pretty_printer *pp = get_printer ();
const line_map_ordinary *map = nullptr;
@@ -704,8 +697,8 @@ diagnostic_text_output_format::report_current_module (location_t where)
}
void
-default_diagnostic_text_starter (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic)
+default_text_starter (text_sink &text_output,
+ const diagnostic_info *diagnostic)
{
text_output.report_current_module (diagnostic_location (diagnostic));
pretty_printer *const pp = text_output.get_printer ();
@@ -713,9 +706,9 @@ default_diagnostic_text_starter (diagnostic_text_output_format &text_output,
}
void
-default_diagnostic_text_finalizer (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic,
- diagnostic_t)
+default_text_finalizer (text_sink &text_output,
+ const diagnostic_info *diagnostic,
+ enum kind)
{
pretty_printer *const pp = text_output.get_printer ();
char *saved_prefix = pp_take_prefix (pp);
@@ -723,7 +716,7 @@ default_diagnostic_text_finalizer (diagnostic_text_output_format &text_output,
pp_newline (pp);
diagnostic_show_locus (&text_output.get_context (),
text_output.get_source_printing_options (),
- diagnostic->richloc, diagnostic->kind, pp);
+ diagnostic->m_richloc, diagnostic->m_kind, pp);
pp_set_prefix (pp, saved_prefix);
pp_flush (pp);
}
@@ -731,3 +724,5 @@ default_diagnostic_text_finalizer (diagnostic_text_output_format &text_output,
#if __GNUC__ >= 10
# pragma GCC diagnostic pop
#endif
+
+} // namespace diagnostics
diff --git a/gcc/diagnostic-format-text.h b/gcc/diagnostics/text-sink.h
index 64a4452..5c60976 100644
--- a/gcc/diagnostic-format-text.h
+++ b/gcc/diagnostics/text-sink.h
@@ -18,49 +18,51 @@ 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_DIAGNOSTIC_FORMAT_TEXT_H
-#define GCC_DIAGNOSTIC_FORMAT_TEXT_H
+#ifndef GCC_DIAGNOSTICS_TEXT_SINK_H
+#define GCC_DIAGNOSTICS_TEXT_SINK_H
-#include "diagnostic-format.h"
+#include "diagnostics/sink.h"
-/* Subclass of diagnostic_output_format for classic text-based output
+namespace diagnostics {
+
+/* Subclass of diagnostics::sink for classic text-based output
to stderr.
- Uses diagnostic_context.m_text_callbacks to provide client-specific
+ Uses diagnostics::context.m_text_callbacks to provide client-specific
textual output (e.g. include paths, macro expansions, etc). */
-class diagnostic_text_output_format : public diagnostic_output_format
+class text_sink : public sink
{
public:
- diagnostic_text_output_format (diagnostic_context &context,
- diagnostic_source_printing_options *source_printing = nullptr,
- bool follows_reference_printer = false)
- : diagnostic_output_format (context),
+ text_sink (context &dc,
+ source_printing_options *source_printing = nullptr,
+ bool follows_reference_printer = false)
+ : sink (dc),
m_saved_output_buffer (nullptr),
- m_column_policy (context),
+ m_column_policy (dc),
m_last_module (nullptr),
m_includes_seen (nullptr),
m_source_printing (source_printing
? *source_printing
- : context.m_source_printing),
+ : dc.get_source_printing_options ()),
m_follows_reference_printer (follows_reference_printer),
m_show_nesting (false),
m_show_nesting_levels (false)
{}
- ~diagnostic_text_output_format ();
+ ~text_sink ();
void dump (FILE *out, int indent) const override;
- std::unique_ptr<diagnostic_per_format_buffer>
- make_per_format_buffer () final override;
- void set_buffer (diagnostic_per_format_buffer *) final override;
+ std::unique_ptr<per_sink_buffer>
+ make_per_sink_buffer () final override;
+ void set_buffer (per_sink_buffer *) final override;
void on_begin_group () override {}
void on_end_group () override {}
void on_report_diagnostic (const diagnostic_info &,
- diagnostic_t orig_diag_kind) override;
+ enum kind orig_diag_kind) override;
void on_report_verbatim (text_info &) final override;
- void on_diagram (const diagnostic_diagram &diagram) override;
+ void on_diagram (const diagram &d) override;
void after_diagnostic (const diagnostic_info &) override;
bool machine_readable_stderr_p () const final override
{
@@ -71,7 +73,8 @@ public:
void update_printer () override;
void
- report_global_digraph (const diagnostics::digraphs::lazy_digraph &) final override
+ report_global_digraph (const lazily_created<digraphs::digraph> &)
+ final override
{
// no-op for text
}
@@ -87,15 +90,15 @@ public:
char *build_indent_prefix (bool with_bullet) const;
- void print_path (const diagnostic_path &path);
+ void print_path (const paths::path &path);
bool show_column_p () const { return get_context ().m_show_column; }
- const diagnostic_column_policy &get_column_policy () const
+ const column_policy &get_column_policy () const
{
return m_column_policy;
}
- diagnostic_location_print_policy get_location_print_policy () const;
+ location_print_policy get_location_print_policy () const;
bool show_nesting_p () const { return m_show_nesting; }
bool show_locations_in_nesting_p () const
@@ -115,11 +118,11 @@ public:
label_text get_location_text (const expanded_location &s) const;
- diagnostic_source_printing_options &get_source_printing_options ()
+ source_printing_options &get_source_printing_options ()
{
return m_source_printing;
}
- const diagnostic_source_printing_options &get_source_printing_options () const
+ const source_printing_options &get_source_printing_options () const
{
return m_source_printing;
}
@@ -128,14 +131,14 @@ protected:
void print_any_cwe (const diagnostic_info &diagnostic);
void print_any_rules (const diagnostic_info &diagnostic);
void print_option_information (const diagnostic_info &diagnostic,
- diagnostic_t orig_diag_kind);
+ enum kind orig_diag_kind);
bool includes_seen_p (const line_map_ordinary *map);
- /* For handling diagnostic_buffer. */
+ /* For handling diagnostics::buffer. */
output_buffer *m_saved_output_buffer;
- diagnostic_column_policy m_column_policy;
+ column_policy m_column_policy;
/* Used to detect when the input file stack has changed since last
described. */
@@ -145,10 +148,10 @@ protected:
include path for. */
hash_set<location_t, false, location_hash> *m_includes_seen;
- diagnostic_source_printing_options &m_source_printing;
+ source_printing_options &m_source_printing;
/* If true, this is the initial default text output format created
- when the diagnostic_context was created, and, in particular, before
+ when the diagnostics::context was created, and, in particular, before
initializations of color and m_url_format. Hence this should follow
the dc's reference printer for these.
If false, this text output was created after the dc was created, and
@@ -168,4 +171,6 @@ protected:
bool m_show_nesting_levels;
};
-#endif /* ! GCC_DIAGNOSTIC_FORMAT_TEXT_H */
+} // namespace diagnostics
+
+#endif /* ! GCC_DIAGNOSTICS_TEXT_SINK_H */
diff --git a/gcc/diagnostic-url.h b/gcc/diagnostics/url.h
index d54775b..89efa36 100644
--- a/gcc/diagnostic-url.h
+++ b/gcc/diagnostics/url.h
@@ -17,8 +17,8 @@ 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_DIAGNOSTIC_URL_H
-#define GCC_DIAGNOSTIC_URL_H
+#ifndef GCC_DIAGNOSTICS_URL_H
+#define GCC_DIAGNOSTICS_URL_H
/* Whether to add URLs to diagnostics:
- DIAGNOSTICS_URL_NO: never
@@ -49,4 +49,4 @@ const diagnostic_url_format URL_FORMAT_DEFAULT = URL_FORMAT_BEL;
extern diagnostic_url_format determine_url_format (diagnostic_url_rule_t);
-#endif /* ! GCC_DIAGNOSTIC_URL_H */
+#endif /* ! GCC_DIAGNOSTICS_URL_H */
diff --git a/gcc/doc/analyzer.texi b/gcc/doc/analyzer.texi
index 4efba4d..87a2a40 100644
--- a/gcc/doc/analyzer.texi
+++ b/gcc/doc/analyzer.texi
@@ -432,7 +432,7 @@ binop_svalue (mult_expr, initial_svalue(‘size_t’, decl_region(frame_region(â
@subsection Analyzer Paths
We need to explain to the user what the problem is, and to persuade them
-that there really is a problem. Hence having a @code{diagnostic_path}
+that there really is a problem. Hence having a @code{diagnostics::paths::path}
isn't just an incidental detail of the analyzer; it's required.
Paths ought to be:
@@ -491,7 +491,7 @@ and notes if it is infeasible.
The above gives us a shortest feasible @code{exploded_path} through the
@code{exploded_graph} (a list of @code{exploded_edge *}). We use this
-@code{exploded_path} to build a @code{diagnostic_path} (a list of
+@code{exploded_path} to build a @code{diagnostics::paths::path} (a list of
@strong{events} for the diagnostic subsystem) - specifically a
@code{checker_path}.
diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi
index fc60792..cc1656f 100644
--- a/gcc/doc/cpp.texi
+++ b/gcc/doc/cpp.texi
@@ -3252,7 +3252,7 @@ helps people match the @samp{#endif} to the corresponding @samp{#ifdef}.
Older programs sometimes put @var{MACRO} directly after the
@samp{#endif} without enclosing it in a comment. This is invalid code
according to the C standard. CPP accepts it with a warning. It
-never affects which @samp{#ifndef} the @samp{#endif} matches.
+never affects which @samp{#ifdef} the @samp{#endif} matches.
@findex #ifndef
Sometimes you wish to use some code if a macro is @emph{not} defined.
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 8c29e24..224d619 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -5654,12 +5654,12 @@ You can specify the kind of interrupt to be handled by adding an optional
parameter to the interrupt attribute like this:
@smallexample
-void f (void) __attribute__ ((interrupt ("user")));
+void f (void) __attribute__ ((interrupt ("supervisor")));
@end smallexample
-Permissible values for this parameter are @code{user}, @code{supervisor},
-and @code{machine}. If there is no parameter, then it defaults to
-@code{machine}.
+Permissible values for this parameter are @code{supervisor},
+@code{machine}, and @code{rnmi}. If there is no parameter, then it
+defaults to @code{machine}.
@cindex @code{riscv_vector_cc} function attribute, RISC-V
@item riscv_vector_cc
@@ -12775,6 +12775,7 @@ the two, as explained in the sections below.
@menu
* Global Register Variables:: Variables declared at global scope.
* Local Register Variables:: Variables declared within a function.
+* Hard Register Constraints:: Operands forced into specific machine registers.
@end menu
@node Global Register Variables
@@ -12980,6 +12981,167 @@ with slightly different characteristics (@pxref{MIPS Coprocessors,,
Defining coprocessor specifics for MIPS targets, gccint,
GNU Compiler Collection (GCC) Internals}).
+@node Hard Register Constraints
+@subsubsection Hard Register Constraints
+
+Similar to register @code{asm} but still distinct, hard register constraints
+are another way to force operands of inline @code{asm} into specific machine
+registers. In contrast to register @code{asm} where a variable is bound to a
+machine register, a hard register constraint binds an @code{asm} operand to a
+machine register. Assume in the following that @code{r4} is a general-purpose
+register, @code{f5} a floating-point register, and @code{v6} a vector register
+for some target.
+
+@smallexample
+int x;
+int y __attribute__ ((vector_size (16)));
+@dots{}
+asm ("some instructions"
+ : "=@{r4@}" (x)
+ : "@{f5@}" (42.0), "@{v6@}" (y));
+@end smallexample
+
+For the inline @code{asm}, variable @code{x} is bound to register @code{r4},
+and @code{y} is loaded to @code{v6}. Furthermore, constant @code{42.0} is
+loaded into floating-point register @code{f5}.
+
+A key difference between register @code{asm} and hard register constraints is
+that the latter are specified at the point where they are supposed to
+materialize, namely at inline @code{asm}, which may lead to more readable code.
+
+@subsubheading Usage
+
+Each input operand is loaded into the register specified by its corresponding
+hard register constraint. Furthermore, each hard register must be used at most
+once among an alternative for inputs. This renders hard register constraints
+more strict compared to register @code{asm} where multiple inputs may share a
+register as for example in
+
+@smallexample
+int x;
+register int y asm ("0") = @dots{};
+asm ("" : "=r" (x) : "r" (y), "r" (y));
+@end smallexample
+
+or even
+
+@smallexample
+register int x asm ("0") = 42;
+register int y asm ("0") = 24;
+asm ("" : "=r" (x) : "r" (x), "r" (y));
+@end smallexample
+
+The analogue for hard register constraints is invalid in order to prevent
+subtle bugs.
+
+Likewise, two outputs must not share a register among an alternative. That
+means, the following example is invalid
+
+@smallexample
+int x, y;
+asm ("" : "=@{r4@}" (x), "=@{r4@}" (y)); // invalid
+@end smallexample
+
+which also aligns with register @code{asm}. Despite that, each output must
+refer to a distinct object if a hard register constraint is involved. For
+example, in the following, object @code{x} is assigned two registers.
+
+@smallexample
+int x;
+asm ("" : "=r" (x), "=r" (x));
+@end smallexample
+
+This is not allowed for hard register constraints in order to prevent subtle
+bugs. Even if only one output operand has a hard register constraint, the code
+is rejected since the allocation for the object is still ambiguous.
+
+@smallexample
+int x;
+asm ("" : "=r" (x), "=@{1@}" (x)); // invalid
+@end smallexample
+
+The type of an operand must be supported by the corresponding machine register.
+
+A hard register constraint may refer to any general, floating-point, or vector
+register except a fixed register as e.g.@: the stack-pointer register. The set
+of allowed registers is target dependent analogue to register @code{asm}.
+Furthermore, the referenced register must be a valid register name of the
+target. Note, on some targets, a single register may be referred to by
+different names where each name specifies the length of the register. For
+example, on x86_64 the register names @code{rcx}, @code{ecx}, and @code{cx} all
+refer to the same register but in different sizes. If any of those names is
+used for a hard register constraint, the actual size of a register is
+determined by its corresponding operand. For example
+
+@smallexample
+long x;
+asm ("mov\t$42, %0" : "=@{ecx@}" (x));
+@end smallexample
+
+Although the hard register constraint refers to register @code{ecx}, the actual
+register will be @code{rcx} since on x86_64 a @code{long} is 8 byte in total.
+This aligns with register @code{asm} where you could have
+
+@smallexample
+register long x asm ("ecx");
+@end smallexample
+
+@subsubheading Interaction with Register @code{asm}
+
+A mixture of both constructs as for example
+
+@smallexample
+register int x asm ("r4") = 42;
+int y;
+asm ("" : "=@{r5@}" (y) : "r" (x));
+@end smallexample
+
+is valid.
+
+If an operand is a register @code{asm} and the corresponding constraint a hard
+register, then both must refer to the same register. That means
+
+@smallexample
+register int x asm ("r4");
+asm ("" : "=@{r4@}" (x));
+@end smallexample
+
+is valid and
+
+@smallexample
+register int x asm ("r4");
+asm ("" : "=@{r5@}" (x)); // invalid
+@end smallexample
+
+is invalid.
+
+Note, register @code{asm} may not only be clobbered by function calls but also
+by inline @code{asm} in conjunction with hard register constraints. For
+example, in the following
+
+@smallexample
+register int x asm ("r5") = 42;
+int y;
+asm ("" : "=@{r5@}" (y));
+asm ("" : "+r" (x));
+@end smallexample
+
+variable @code{x} materializes before the very first inline @code{asm} which
+writes to register @code{r5} and therefore clobbers @code{x} which in turn is
+read by the subsequent inline @code{asm}.
+
+@subsubheading Limitations
+
+At the moment fixed registers are not supported for hard register constraints.
+Thus, idioms like
+
+@smallexample
+register void *x asm ("rsp");
+asm ("" : "=r" (x));
+@end smallexample
+
+are not supported for hard register constraints. This might be lifted.
+
@node Size of an asm
@subsection Size of an @code{asm}
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 28159b2..aba93f6 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -1366,6 +1366,12 @@ as for @samp{<} apply.
A register operand is allowed provided that it is in a general
register.
+@cindex hard registers in constraint
+@item @samp{@{r@}}
+An operand is bound to hard register @samp{r} which may be any general,
+floating-point, or vector register except a fixed register like a stack pointer
+register. The set of fixed registers is target dependent.
+
@cindex constants in constraints
@cindex @samp{i} in constraint
@item @samp{i}
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 5e30564..928578b 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -6382,12 +6382,14 @@ return type of the vectorized function shall be of vector type
@var{vec_type_out} and the argument types should be @var{vec_type_in}.
@end deftypefn
-@deftypefn {Target Hook} bool TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT (machine_mode @var{mode}, const_tree @var{type}, int @var{misalignment}, bool @var{is_packed})
+@deftypefn {Target Hook} bool TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT (machine_mode @var{mode}, const_tree @var{type}, int @var{misalignment}, bool @var{is_packed}, bool @var{is_gather_scatter})
This hook should return true if the target supports misaligned vector
store/load of a specific factor denoted in the @var{misalignment}
parameter. The vector store/load should be of machine mode @var{mode} and
-the elements in the vectors should be of type @var{type}. @var{is_packed}
-parameter is true if the memory access is defined in a packed struct.
+the elements in the vectors should be of type @var{type}. The
+@var{is_packed} parameter is true if the misalignment is unknown and the
+memory access is defined in a packed struct. @var{is_gather_scatter} is true
+if the load/store is a gather or scatter.
@end deftypefn
@deftypefn {Target Hook} machine_mode TARGET_VECTORIZE_PREFERRED_SIMD_MODE (scalar_mode @var{mode})
diff --git a/gcc/errors.cc b/gcc/errors.cc
index 6d1ecc7..fb6b19d 100644
--- a/gcc/errors.cc
+++ b/gcc/errors.cc
@@ -19,7 +19,8 @@ along with GCC; see the file COPYING3. If not see
/* warning, error, and fatal. These definitions are suitable for use
in the generator programs; the compiler has a more elaborate suite
- of diagnostic printers, found in diagnostic.cc. */
+ of diagnostic printers, found in diagnostic-global-context.cc using
+ the diagnostics/ subdirectory. */
#ifdef HOST_GENERATOR_FILE
#include "config.h"
@@ -126,7 +127,7 @@ trim_filename (const char *name)
/* "Fancy" abort. Reports where in the compiler someone gave up.
This file is used only by build programs, so we're not as polite as
- the version in diagnostic.cc. */
+ the version in diagnostics/context.cc. */
void
fancy_abort (const char *file, int line, const char *func)
{
diff --git a/gcc/expr.cc b/gcc/expr.cc
index ac4fdfa..3f2b121 100644
--- a/gcc/expr.cc
+++ b/gcc/expr.cc
@@ -13206,6 +13206,8 @@ constant_byte_string (tree arg, tree *ptr_offset, tree *mem_size, tree *decl,
of the expected type and size. */
if (!initsize)
initsize = integer_zero_node;
+ else if (!tree_fits_uhwi_p (initsize))
+ return NULL_TREE;
unsigned HOST_WIDE_INT size = tree_to_uhwi (initsize);
if (size > (unsigned HOST_WIDE_INT) INT_MAX)
diff --git a/gcc/final.cc b/gcc/final.cc
index a4dbab7..afcb0bb 100644
--- a/gcc/final.cc
+++ b/gcc/final.cc
@@ -83,6 +83,7 @@ along with GCC; see the file COPYING3. If not see
#include "function-abi.h"
#include "common/common-target.h"
#include "diagnostic.h"
+#include "diagnostics/file-cache.h"
#include "dwarf2out.h"
@@ -2116,7 +2117,7 @@ asm_show_source (const char *filename, int linenum)
if (!filename)
return;
- char_span line
+ diagnostics::char_span line
= global_dc->get_file_cache ().get_source_line (filename, linenum);
if (!line)
return;
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 33e12f1..4c7e8d1 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,81 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * error.cc: Make diagnostics::context::m_source_printing private.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * cpp.cc: Update usage of "diagnostic_info" to explicitly refer to
+ "diagnostics::diagnostic_info".
+ * error.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * cpp.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * error.cc: Likewise.
+ * options.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * cpp.cc: Update for renaming of
+ diagnostic_option_id to diagnostics::option_id.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * error.cc: Update for move of diagnostic-color.h to
+ diagnostics/color.h.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * error.cc: Update for diagnostic_context becoming
+ diagnostics::context.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * error.cc: Update to add "m_" prefix to fields of
+ diagnostic_info throughout.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * error.cc: Update for move of diagnostics output formats into
+ namespace "diagnostics" as "sinks".
+ * gfortran.h: Likewise.
+
+2025-07-23 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/121203
+ * trans-expr.cc (gfc_conv_procedure_call): Obtain the character
+ length of an assumed character length procedure from the typespec
+ of the actual argument even if there is no explicit interface.
+
+2025-07-21 Mikael Morin <mikael@gcc.gnu.org>
+
+ * trans-decl.cc (gfc_trans_deferred_vars): Fix indentation.
+
+2025-07-21 Andre Vehreschild <vehre@gcc.gnu.org>
+
+ PR fortran/119106
+ * expr.cc (simplify_constructor): Do not simplify constants.
+ (gfc_simplify_expr): Continue to simplify expression when an
+ iterator is present.
+
+2025-07-21 Mikael Morin <mikael@gcc.gnu.org>
+
+ * trans-array.cc (gfc_conv_ss_descriptor): Move the descriptor
+ expression initialisation...
+ (set_factored_descriptor_value): ... to this new function.
+ Before initialisation, walk the reference expression passed as
+ argument and save some of its subexpressions to a variable.
+ (substitute_t): New struct.
+ (maybe_substitute_expr): New function.
+ (substitute_subexpr_in_expr): New function.
+
+2025-07-18 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/121145
+ * trans-expr.cc (gfc_conv_procedure_call): Do not create pointer
+ check for proc-pointer actual passed to optional dummy.
+
2025-07-16 Paul Thomas <pault@gcc.gnu.org>
PR fortran/121060
diff --git a/gcc/fortran/cpp.cc b/gcc/fortran/cpp.cc
index 1b70420..15ecc7d 100644
--- a/gcc/fortran/cpp.cc
+++ b/gcc/fortran/cpp.cc
@@ -1063,7 +1063,7 @@ cb_used_define (cpp_reader *pfile, location_t line ATTRIBUTE_UNUSED,
/* Return the gcc option code associated with the reason for a cpp
message, or 0 if none. */
-static diagnostic_option_id
+static diagnostics::option_id
cb_cpp_diagnostic_cpp_option (enum cpp_warning_reason reason)
{
const struct cpp_reason_option_codes_t *entry;
@@ -1088,8 +1088,8 @@ cb_cpp_diagnostic (cpp_reader *pfile ATTRIBUTE_UNUSED,
rich_location *richloc,
const char *msg, va_list *ap)
{
- diagnostic_info diagnostic;
- diagnostic_t dlevel;
+ diagnostics::diagnostic_info diagnostic;
+ enum diagnostics::kind dlevel;
bool save_warn_system_headers = global_dc->m_warn_system_headers;
bool ret;
@@ -1099,22 +1099,22 @@ cb_cpp_diagnostic (cpp_reader *pfile ATTRIBUTE_UNUSED,
global_dc->m_warn_system_headers = 1;
/* Fall through. */
case CPP_DL_WARNING:
- dlevel = DK_WARNING;
+ dlevel = diagnostics::kind::warning;
break;
case CPP_DL_PEDWARN:
- dlevel = DK_PEDWARN;
+ dlevel = diagnostics::kind::pedwarn;
break;
case CPP_DL_ERROR:
- dlevel = DK_ERROR;
+ dlevel = diagnostics::kind::error;
break;
case CPP_DL_ICE:
- dlevel = DK_ICE;
+ dlevel = diagnostics::kind::ice;
break;
case CPP_DL_NOTE:
- dlevel = DK_NOTE;
+ dlevel = diagnostics::kind::note;
break;
case CPP_DL_FATAL:
- dlevel = DK_FATAL;
+ dlevel = diagnostics::kind::fatal;
break;
default:
gcc_unreachable ();
diff --git a/gcc/fortran/error.cc b/gcc/fortran/error.cc
index 004a4b2..ebf9e61 100644
--- a/gcc/fortran/error.cc
+++ b/gcc/fortran/error.cc
@@ -31,9 +31,9 @@ along with GCC; see the file COPYING3. If not see
#include "gfortran.h"
#include "diagnostic.h"
-#include "diagnostic-color.h"
+#include "diagnostics/color.h"
#include "tree-diagnostic.h" /* tree_diagnostics_defaults */
-#include "diagnostic-format-text.h"
+#include "diagnostics/text-sink.h"
static int suppress_errors = 0;
@@ -43,7 +43,7 @@ static bool warnings_not_errors = false;
static bool buffered_p;
static gfc_error_buffer *error_buffer;
-static diagnostic_buffer *pp_error_buffer, *pp_warning_buffer;
+static diagnostics::buffer *pp_error_buffer, *pp_warning_buffer;
gfc_error_buffer::gfc_error_buffer ()
: flag (false), buffer (*global_dc)
@@ -228,7 +228,7 @@ gfc_print_wide_char (gfc_char_t c)
it to global_dc. */
static void
-gfc_clear_diagnostic_buffer (diagnostic_buffer *this_buffer)
+gfc_clear_diagnostic_buffer (diagnostics::buffer *this_buffer)
{
gcc_assert (this_buffer);
global_dc->clear_diagnostic_buffer (*this_buffer);
@@ -237,13 +237,13 @@ gfc_clear_diagnostic_buffer (diagnostic_buffer *this_buffer)
/* The currently-printing diagnostic, for use by gfc_format_decoder,
for colorizing %C and %L. */
-static diagnostic_info *curr_diagnostic;
+static diagnostics::diagnostic_info *curr_diagnostic;
/* A helper function to call diagnostic_report_diagnostic, while setting
curr_diagnostic for the duration of the call. */
static bool
-gfc_report_diagnostic (diagnostic_info *diagnostic)
+gfc_report_diagnostic (diagnostics::diagnostic_info *diagnostic)
{
gcc_assert (diagnostic != NULL);
curr_diagnostic = diagnostic;
@@ -261,9 +261,9 @@ gfc_warning (int opt, const char *gmsgid, va_list ap)
va_list argp;
va_copy (argp, ap);
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
rich_location rich_loc (line_table, UNKNOWN_LOCATION);
- diagnostic_buffer *old_buffer = global_dc->get_diagnostic_buffer ();
+ diagnostics::buffer *old_buffer = global_dc->get_diagnostic_buffer ();
gcc_assert (!old_buffer);
gfc_clear_diagnostic_buffer (pp_warning_buffer);
@@ -272,8 +272,8 @@ gfc_warning (int opt, const char *gmsgid, va_list ap)
global_dc->set_diagnostic_buffer (pp_warning_buffer);
diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
- DK_WARNING);
- diagnostic.option_id = opt;
+ diagnostics::kind::warning);
+ diagnostic.m_option_id = opt;
bool ret = gfc_report_diagnostic (&diagnostic);
if (buffered_p)
@@ -441,7 +441,7 @@ gfc_format_decoder (pretty_printer *pp, text_info *text, const char *spec,
const char *color
= (loc_num
? "range1"
- : diagnostic_get_color_for_kind (curr_diagnostic->kind));
+ : diagnostics::get_color_for_kind (curr_diagnostic->m_kind));
pp_string (pp, colorize_start (pp_show_color (pp), color));
pp_string (pp, result[loc_num]);
pp_string (pp, colorize_stop (pp_show_color (pp)));
@@ -460,8 +460,8 @@ gfc_format_decoder (pretty_printer *pp, text_info *text, const char *spec,
/* Return a malloc'd string describing the kind of diagnostic. The
caller is responsible for freeing the memory. */
static char *
-gfc_diagnostic_build_kind_prefix (diagnostic_context *context,
- const diagnostic_info *diagnostic)
+gfc_diagnostic_build_kind_prefix (diagnostics::context *context,
+ const diagnostics::diagnostic_info *diagnostic)
{
static const char *const diagnostic_kind_text[] = {
#define DEFINE_DIAGNOSTIC_KIND(K, T, C) (T),
@@ -475,15 +475,16 @@ gfc_diagnostic_build_kind_prefix (diagnostic_context *context,
#undef DEFINE_DIAGNOSTIC_KIND
NULL
};
- gcc_assert (diagnostic->kind < DK_LAST_DIAGNOSTIC_KIND);
- const char *text = _(diagnostic_kind_text[diagnostic->kind]);
+ const int diag_kind_idx = static_cast<int> (diagnostic->m_kind);
+ gcc_assert (diagnostic->m_kind < diagnostics::kind::last_diagnostic_kind);
+ const char *text = _(diagnostic_kind_text[diag_kind_idx]);
const char *text_cs = "", *text_ce = "";
pretty_printer *const pp = context->get_reference_printer ();
- if (diagnostic_kind_color[diagnostic->kind])
+if (diagnostic_kind_color[diag_kind_idx])
{
text_cs = colorize_start (pp_show_color (pp),
- diagnostic_kind_color[diagnostic->kind]);
+ diagnostic_kind_color[diag_kind_idx]);
text_ce = colorize_stop (pp_show_color (pp));
}
return build_message_string ("%s%s:%s ", text_cs, text, text_ce);
@@ -492,7 +493,7 @@ gfc_diagnostic_build_kind_prefix (diagnostic_context *context,
/* Return a malloc'd string describing a location. The caller is
responsible for freeing the memory. */
static char *
-gfc_diagnostic_build_locus_prefix (const diagnostic_location_print_policy &loc_policy,
+gfc_diagnostic_build_locus_prefix (const diagnostics::location_print_policy &loc_policy,
expanded_location s,
bool colorize)
{
@@ -511,7 +512,7 @@ gfc_diagnostic_build_locus_prefix (const diagnostic_location_print_policy &loc_p
/* Return a malloc'd string describing two locations. The caller is
responsible for freeing the memory. */
static char *
-gfc_diagnostic_build_locus_prefix (const diagnostic_location_print_policy &loc_policy,
+gfc_diagnostic_build_locus_prefix (const diagnostics::location_print_policy &loc_policy,
expanded_location s, expanded_location s2,
bool colorize)
{
@@ -548,16 +549,16 @@ gfc_diagnostic_build_locus_prefix (const diagnostic_location_print_policy &loc_p
[locus of primary range]: Error: Some error at (1) and (2)
*/
static void
-gfc_diagnostic_text_starter (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic)
+gfc_diagnostic_text_starter (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic)
{
- diagnostic_context *const context = &text_output.get_context ();
+ diagnostics::context *const context = &text_output.get_context ();
pretty_printer *const pp = text_output.get_printer ();
char * kind_prefix = gfc_diagnostic_build_kind_prefix (context, diagnostic);
expanded_location s1 = diagnostic_expand_location (diagnostic);
expanded_location s2;
- bool one_locus = diagnostic->richloc->get_num_locations () < 2;
+ bool one_locus = diagnostic->m_richloc->get_num_locations () < 2;
bool same_locus = false;
if (!one_locus)
@@ -566,13 +567,13 @@ gfc_diagnostic_text_starter (diagnostic_text_output_format &text_output,
same_locus = diagnostic_same_line (context, s1, s2);
}
- diagnostic_location_print_policy loc_policy (text_output);
+ diagnostics::location_print_policy loc_policy (text_output);
const bool colorize = pp_show_color (pp);
char * locus_prefix = (one_locus || !same_locus)
? gfc_diagnostic_build_locus_prefix (loc_policy, s1, colorize)
: gfc_diagnostic_build_locus_prefix (loc_policy, s1, s2, colorize);
- if (!context->m_source_printing.enabled
+ if (!context->get_source_printing_options ().enabled
|| diagnostic_location (diagnostic, 0) <= BUILTINS_LOCATION
|| diagnostic_location (diagnostic, 0) == context->m_last_location)
{
@@ -608,7 +609,7 @@ gfc_diagnostic_text_starter (diagnostic_text_output_format &text_output,
pp_newline (pp);
diagnostic_show_locus (context,
text_output.get_source_printing_options (),
- diagnostic->richloc, diagnostic->kind,
+ diagnostic->m_richloc, diagnostic->m_kind,
pp);
/* If the caret line was shown, the prefix does not contain the
locus. */
@@ -617,11 +618,11 @@ gfc_diagnostic_text_starter (diagnostic_text_output_format &text_output,
}
static void
-gfc_diagnostic_start_span (const diagnostic_location_print_policy &loc_policy,
- to_text &sink,
+gfc_diagnostic_start_span (const diagnostics::location_print_policy &loc_policy,
+ diagnostics::to_text &sink,
expanded_location exploc)
{
- pretty_printer *pp = get_printer (sink);
+ pretty_printer *pp = diagnostics::get_printer (sink);
const bool colorize = pp_show_color (pp);
char *locus_prefix
= gfc_diagnostic_build_locus_prefix (loc_policy, exploc, colorize);
@@ -634,9 +635,9 @@ gfc_diagnostic_start_span (const diagnostic_location_print_policy &loc_policy,
static void
-gfc_diagnostic_text_finalizer (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic ATTRIBUTE_UNUSED,
- diagnostic_t orig_diag_kind ATTRIBUTE_UNUSED)
+gfc_diagnostic_text_finalizer (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *,
+ enum diagnostics::kind orig_diag_kind ATTRIBUTE_UNUSED)
{
pretty_printer *const pp = text_output.get_printer ();
pp_destroy_prefix (pp);
@@ -650,13 +651,14 @@ bool
gfc_warning_now_at (location_t loc, int opt, const char *gmsgid, ...)
{
va_list argp;
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
rich_location rich_loc (line_table, loc);
bool ret;
va_start (argp, gmsgid);
- diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_WARNING);
- diagnostic.option_id = opt;
+ diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
+ diagnostics::kind::warning);
+ diagnostic.m_option_id = opt;
ret = gfc_report_diagnostic (&diagnostic);
va_end (argp);
return ret;
@@ -668,14 +670,14 @@ bool
gfc_warning_now (int opt, const char *gmsgid, ...)
{
va_list argp;
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
rich_location rich_loc (line_table, UNKNOWN_LOCATION);
bool ret;
va_start (argp, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
- DK_WARNING);
- diagnostic.option_id = opt;
+ diagnostics::kind::warning);
+ diagnostic.m_option_id = opt;
ret = gfc_report_diagnostic (&diagnostic);
va_end (argp);
return ret;
@@ -687,14 +689,14 @@ bool
gfc_warning_internal (int opt, const char *gmsgid, ...)
{
va_list argp;
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
rich_location rich_loc (line_table, UNKNOWN_LOCATION);
bool ret;
va_start (argp, gmsgid);
diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
- DK_WARNING);
- diagnostic.option_id = opt;
+ diagnostics::kind::warning);
+ diagnostic.m_option_id = opt;
ret = gfc_report_diagnostic (&diagnostic);
va_end (argp);
return ret;
@@ -706,13 +708,14 @@ void
gfc_error_now (const char *gmsgid, ...)
{
va_list argp;
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
rich_location rich_loc (line_table, UNKNOWN_LOCATION);
error_buffer->flag = true;
va_start (argp, gmsgid);
- diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ERROR);
+ diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
+ diagnostics::kind::error);
gfc_report_diagnostic (&diagnostic);
va_end (argp);
}
@@ -724,11 +727,12 @@ void
gfc_fatal_error (const char *gmsgid, ...)
{
va_list argp;
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
rich_location rich_loc (line_table, UNKNOWN_LOCATION);
va_start (argp, gmsgid);
- diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_FATAL);
+ diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
+ diagnostics::kind::fatal);
gfc_report_diagnostic (&diagnostic);
va_end (argp);
@@ -776,9 +780,9 @@ gfc_error_opt (int opt, const char *gmsgid, va_list ap)
return;
}
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
rich_location richloc (line_table, UNKNOWN_LOCATION);
- diagnostic_buffer *old_buffer = global_dc->get_diagnostic_buffer ();
+ diagnostics::buffer *old_buffer = global_dc->get_diagnostic_buffer ();
gcc_assert (!old_buffer);
gfc_clear_diagnostic_buffer (pp_error_buffer);
@@ -786,7 +790,8 @@ gfc_error_opt (int opt, const char *gmsgid, va_list ap)
if (buffered_p)
global_dc->set_diagnostic_buffer (pp_error_buffer);
- diagnostic_set_info (&diagnostic, gmsgid, &argp, &richloc, DK_ERROR);
+ diagnostic_set_info (&diagnostic, gmsgid, &argp, &richloc,
+ diagnostics::kind::error);
gfc_report_diagnostic (&diagnostic);
if (buffered_p)
@@ -823,7 +828,7 @@ gfc_internal_error (const char *gmsgid, ...)
{
int e, w;
va_list argp;
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
rich_location rich_loc (line_table, UNKNOWN_LOCATION);
gfc_get_errors (&w, &e);
@@ -831,7 +836,8 @@ gfc_internal_error (const char *gmsgid, ...)
exit(EXIT_FAILURE);
va_start (argp, gmsgid);
- diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc, DK_ICE);
+ diagnostic_set_info (&diagnostic, gmsgid, &argp, &rich_loc,
+ diagnostics::kind::ice);
gfc_report_diagnostic (&diagnostic);
va_end (argp);
@@ -885,8 +891,8 @@ static void
gfc_move_error_buffer_from_to (gfc_error_buffer * buffer_from,
gfc_error_buffer * buffer_to)
{
- diagnostic_buffer * from = &(buffer_from->buffer);
- diagnostic_buffer * to = &(buffer_to->buffer);
+ diagnostics::buffer * from = &(buffer_from->buffer);
+ diagnostics::buffer * to = &(buffer_to->buffer);
buffer_to->flag = buffer_from->flag;
buffer_from->flag = false;
@@ -950,13 +956,14 @@ gfc_errors_to_warnings (bool f)
void
gfc_diagnostics_init (void)
{
- diagnostic_text_starter (global_dc) = gfc_diagnostic_text_starter;
- diagnostic_start_span (global_dc) = gfc_diagnostic_start_span;
- diagnostic_text_finalizer (global_dc) = gfc_diagnostic_text_finalizer;
+ diagnostics::text_starter (global_dc) = gfc_diagnostic_text_starter;
+ diagnostics::start_span (global_dc) = gfc_diagnostic_start_span;
+ diagnostics::text_finalizer (global_dc) = gfc_diagnostic_text_finalizer;
global_dc->set_format_decoder (gfc_format_decoder);
- global_dc->m_source_printing.caret_chars[0] = '1';
- global_dc->m_source_printing.caret_chars[1] = '2';
- pp_warning_buffer = new diagnostic_buffer (*global_dc);
+ auto &source_printing_opts = global_dc->get_source_printing_options ();
+ source_printing_opts.caret_chars[0] = '1';
+ source_printing_opts.caret_chars[1] = '2';
+ pp_warning_buffer = new diagnostics::buffer (*global_dc);
error_buffer = new gfc_error_buffer ();
pp_error_buffer = &(error_buffer->buffer);
}
@@ -967,10 +974,11 @@ gfc_diagnostics_finish (void)
tree_diagnostics_defaults (global_dc);
/* We still want to use the gfc starter and finalizer, not the tree
defaults. */
- diagnostic_text_starter (global_dc) = gfc_diagnostic_text_starter;
- diagnostic_text_finalizer (global_dc) = gfc_diagnostic_text_finalizer;
- global_dc->m_source_printing.caret_chars[0] = '^';
- global_dc->m_source_printing.caret_chars[1] = '^';
+ diagnostics::text_starter (global_dc) = gfc_diagnostic_text_starter;
+ diagnostics::text_finalizer (global_dc) = gfc_diagnostic_text_finalizer;
+ auto &source_printing_opts = global_dc->get_source_printing_options ();
+ source_printing_opts.caret_chars[0] = '^';
+ source_printing_opts.caret_chars[1] = '^';
delete error_buffer;
error_buffer = nullptr;
pp_error_buffer = nullptr;
diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index b0495b7..b8d04ff 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -1372,7 +1372,7 @@ simplify_constructor (gfc_constructor_base base, int type)
|| !gfc_simplify_expr (c->iterator->step, type)))
return false;
- if (c->expr)
+ if (c->expr && c->expr->expr_type != EXPR_CONSTANT)
{
/* Try and simplify a copy. Replace the original if successful
but keep going through the constructor at all costs. Not
@@ -2469,7 +2469,8 @@ gfc_simplify_expr (gfc_expr *p, int type)
{
if (!simplify_parameter_variable (p, type))
return false;
- break;
+ if (!iter_stack)
+ break;
}
if (type == 1)
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index d85095c..85feb18 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -3594,11 +3594,11 @@ bool gfc_notify_std (int, const char *, ...) ATTRIBUTE_GCC_GFC(2,3);
#define gfc_syntax_error(ST) \
gfc_error ("Syntax error in %s statement at %C", gfc_ascii_statement (ST));
-#include "diagnostic-buffer.h" /* For diagnostic_buffer. */
+#include "diagnostics/buffering.h" /* For diagnostics::buffer. */
struct gfc_error_buffer
{
bool flag;
- diagnostic_buffer buffer;
+ diagnostics::buffer buffer;
gfc_error_buffer();
};
diff --git a/gcc/fortran/options.cc b/gcc/fortran/options.cc
index d3c9066..821a8c8 100644
--- a/gcc/fortran/options.cc
+++ b/gcc/fortran/options.cc
@@ -406,7 +406,8 @@ gfc_post_options (const char **pfilename)
if (warn_line_truncation && !OPTION_SET_P (warnings_are_errors)
&& option_unspecified_p (OPT_Wline_truncation))
diagnostic_classify_diagnostic (global_dc, OPT_Wline_truncation,
- DK_ERROR, UNKNOWN_LOCATION);
+ diagnostics::kind::error,
+ UNKNOWN_LOCATION);
}
else
{
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 1561936..6b759d1 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -3437,6 +3437,166 @@ save_descriptor_data (tree descr, tree data)
}
+/* Type of the DATA argument passed to walk_tree by substitute_subexpr_in_expr
+ and used by maybe_substitute_expr. */
+
+typedef struct
+{
+ tree target, repl;
+}
+substitute_t;
+
+
+/* Check if the expression in *TP is equal to the substitution target provided
+ in DATA->TARGET and replace it with DATA->REPL in that case. This is a
+ callback function for use with walk_tree. */
+
+static tree
+maybe_substitute_expr (tree *tp, int *walk_subtree, void *data)
+{
+ substitute_t *subst = (substitute_t *) data;
+ if (*tp == subst->target)
+ {
+ *tp = subst->repl;
+ *walk_subtree = 0;
+ }
+
+ return NULL_TREE;
+}
+
+
+/* Substitute in EXPR any occurence of TARGET with REPLACEMENT. */
+
+static void
+substitute_subexpr_in_expr (tree target, tree replacement, tree expr)
+{
+ substitute_t subst;
+ subst.target = target;
+ subst.repl = replacement;
+
+ walk_tree (&expr, maybe_substitute_expr, &subst, nullptr);
+}
+
+
+/* Save REF to a fresh variable in all of REPLACEMENT_ROOTS, appending extra
+ code to CODE. Before returning, add REF to REPLACEMENT_ROOTS and clear
+ REF. */
+
+static void
+save_ref (tree &code, tree &ref, vec<tree> &replacement_roots)
+{
+ stmtblock_t tmp_block;
+ gfc_init_block (&tmp_block);
+ tree var = gfc_evaluate_now (ref, &tmp_block);
+ gfc_add_expr_to_block (&tmp_block, code);
+ code = gfc_finish_block (&tmp_block);
+
+ unsigned i;
+ tree repl_root;
+ FOR_EACH_VEC_ELT (replacement_roots, i, repl_root)
+ substitute_subexpr_in_expr (ref, var, repl_root);
+
+ replacement_roots.safe_push (ref);
+ ref = NULL_TREE;
+}
+
+
+/* Save the descriptor reference VALUE to storage pointed by DESC_PTR. Before
+ that, try to factor subexpressions of VALUE to variables, adding extra code
+ to BLOCK.
+
+ The candidate references to factoring are dereferenced pointers because they
+ are cheap to copy and array descriptors because they are often the base of
+ multiple subreferences. */
+
+static void
+set_factored_descriptor_value (tree *desc_ptr, tree value, stmtblock_t *block)
+{
+ /* As the reference is processed from outer to inner, variable definitions
+ will be generated in reversed order, so can't be put directly in BLOCK.
+ We use TMP_BLOCK instead. */
+ tree accumulated_code = NULL_TREE;
+
+ /* The current candidate to factoring. */
+ tree saveable_ref = NULL_TREE;
+
+ /* The root expressions in which we look for subexpressions to replace with
+ variables. */
+ auto_vec<tree> replacement_roots;
+ replacement_roots.safe_push (value);
+
+ tree data_ref = value;
+ tree next_ref = NULL_TREE;
+
+ /* If the candidate reference is not followed by a subreference, it can't be
+ saved to a variable as it may be reallocatable, and we have to keep the
+ parent reference to be able to store the new pointer value in case of
+ reallocation. */
+ bool maybe_reallocatable = true;
+
+ while (true)
+ {
+ if (!maybe_reallocatable
+ && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (data_ref)))
+ saveable_ref = data_ref;
+
+ if (TREE_CODE (data_ref) == INDIRECT_REF)
+ {
+ next_ref = TREE_OPERAND (data_ref, 0);
+
+ if (!maybe_reallocatable)
+ {
+ if (saveable_ref != NULL_TREE && saveable_ref != data_ref)
+ {
+ /* A reference worth saving has been seen, and now the pointer
+ to the current reference is also worth saving. If the
+ previous reference to save wasn't the current one, do save
+ it now. Otherwise drop it as we prefer saving the
+ pointer. */
+ save_ref (accumulated_code, saveable_ref, replacement_roots);
+ }
+
+ /* Don't evaluate the pointer to a variable yet; do it only if the
+ variable would be significantly more simple than the reference
+ it replaces. That is if the reference contains anything
+ different from NOPs, COMPONENTs and DECLs. */
+ saveable_ref = next_ref;
+ }
+ }
+ else if (TREE_CODE (data_ref) == COMPONENT_REF)
+ {
+ maybe_reallocatable = false;
+ next_ref = TREE_OPERAND (data_ref, 0);
+ }
+ else if (TREE_CODE (data_ref) == NOP_EXPR)
+ next_ref = TREE_OPERAND (data_ref, 0);
+ else
+ {
+ if (DECL_P (data_ref))
+ break;
+
+ if (TREE_CODE (data_ref) == ARRAY_REF)
+ {
+ maybe_reallocatable = false;
+ next_ref = TREE_OPERAND (data_ref, 0);
+ }
+
+ if (saveable_ref != NULL_TREE)
+ /* We have seen a reference worth saving. Do it now. */
+ save_ref (accumulated_code, saveable_ref, replacement_roots);
+
+ if (TREE_CODE (data_ref) != ARRAY_REF)
+ break;
+ }
+
+ data_ref = next_ref;
+ }
+
+ *desc_ptr = value;
+ gfc_add_expr_to_block (block, accumulated_code);
+}
+
+
/* Translate expressions for the descriptor and data pointer of a SS. */
/*GCC ARRAYS*/
@@ -3457,7 +3617,7 @@ gfc_conv_ss_descriptor (stmtblock_t * block, gfc_ss * ss, int base)
se.descriptor_only = 1;
gfc_conv_expr_lhs (&se, ss_info->expr);
gfc_add_block_to_block (block, &se.pre);
- info->descriptor = se.expr;
+ set_factored_descriptor_value (&info->descriptor, se.expr, block);
ss_info->string_length = se.string_length;
ss_info->class_container = se.class_container;
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 43bd7be..d5acdca 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -4773,14 +4773,14 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
/* Nullify explicit return class arrays on entry. */
tree type;
tmp = get_proc_result (proc_sym);
- if (tmp && GFC_CLASS_TYPE_P (TREE_TYPE (tmp)))
- {
- gfc_start_block (&init);
- tmp = gfc_class_data_get (tmp);
- type = TREE_TYPE (gfc_conv_descriptor_data_get (tmp));
- gfc_conv_descriptor_data_set (&init, tmp, build_int_cst (type, 0));
- gfc_add_init_cleanup (block, gfc_finish_block (&init), NULL_TREE);
- }
+ if (tmp && GFC_CLASS_TYPE_P (TREE_TYPE (tmp)))
+ {
+ gfc_start_block (&init);
+ tmp = gfc_class_data_get (tmp);
+ type = TREE_TYPE (gfc_conv_descriptor_data_get (tmp));
+ gfc_conv_descriptor_data_set (&init, tmp, build_int_cst (type, 0));
+ gfc_add_init_cleanup (block, gfc_finish_block (&init), NULL_TREE);
+ }
}
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 082987f..0db7ba3 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -714,6 +714,8 @@ gfc_get_class_from_expr (tree expr)
{
tree tmp;
tree type;
+ bool array_descr_found = false;
+ bool comp_after_descr_found = false;
for (tmp = expr; tmp; tmp = TREE_OPERAND (tmp, 0))
{
@@ -725,6 +727,8 @@ gfc_get_class_from_expr (tree expr)
{
if (GFC_CLASS_TYPE_P (type))
return tmp;
+ if (GFC_DESCRIPTOR_TYPE_P (type))
+ array_descr_found = true;
if (type != TYPE_CANONICAL (type))
type = TYPE_CANONICAL (type);
else
@@ -732,6 +736,23 @@ gfc_get_class_from_expr (tree expr)
}
if (VAR_P (tmp) || TREE_CODE (tmp) == PARM_DECL)
break;
+
+ /* Avoid walking up the reference chain too far. For class arrays, the
+ array descriptor is a direct component (through a pointer) of the class
+ container. So there is exactly one COMPONENT_REF between a class
+ container and its child array descriptor. After seeing an array
+ descriptor, we can give up on the second COMPONENT_REF we see, if no
+ class container was found until that point. */
+ if (array_descr_found)
+ {
+ if (comp_after_descr_found)
+ {
+ if (TREE_CODE (tmp) == COMPONENT_REF)
+ return NULL_TREE;
+ }
+ else if (TREE_CODE (tmp) == COMPONENT_REF)
+ comp_after_descr_found = true;
+ }
}
if (POINTER_TYPE_P (TREE_TYPE (tmp)))
@@ -7909,21 +7930,21 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
se->ss->info->class_container = arg1_cntnr;
}
- if (fsym && e)
+ /* Obtain the character length of an assumed character length procedure
+ from the typespec of the actual argument. */
+ if (e
+ && parmse.string_length == NULL_TREE
+ && e->ts.type == BT_PROCEDURE
+ && e->symtree->n.sym->ts.type == BT_CHARACTER
+ && e->symtree->n.sym->ts.u.cl->length != NULL
+ && e->symtree->n.sym->ts.u.cl->length->expr_type == EXPR_CONSTANT)
{
- /* Obtain the character length of an assumed character length
- length procedure from the typespec. */
- if (fsym->ts.type == BT_CHARACTER
- && parmse.string_length == NULL_TREE
- && e->ts.type == BT_PROCEDURE
- && e->symtree->n.sym->ts.type == BT_CHARACTER
- && e->symtree->n.sym->ts.u.cl->length != NULL
- && e->symtree->n.sym->ts.u.cl->length->expr_type == EXPR_CONSTANT)
- {
- gfc_conv_const_charlen (e->symtree->n.sym->ts.u.cl);
- parmse.string_length = e->symtree->n.sym->ts.u.cl->backend_decl;
- }
+ gfc_conv_const_charlen (e->symtree->n.sym->ts.u.cl);
+ parmse.string_length = e->symtree->n.sym->ts.u.cl->backend_decl;
+ }
+ if (fsym && e)
+ {
/* Obtain the character length for a NULL() actual with a character
MOLD argument. Otherwise substitute a suitable dummy length.
Here we handle non-optional dummies of non-bind(c) procedures. */
@@ -8159,7 +8180,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
msg = xasprintf ("Pointer actual argument '%s' is not "
"associated", e->symtree->n.sym->name);
else if (attr.proc_pointer && !e->value.function.actual
- && (fsym == NULL || !fsym_attr.proc_pointer))
+ && (fsym == NULL
+ || (!fsym_attr.proc_pointer && !fsym_attr.optional)))
msg = xasprintf ("Proc-pointer actual argument '%s' is not "
"associated", e->symtree->n.sym->name);
else
@@ -12870,9 +12892,16 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
gfc_init_se (&lse, NULL);
gfc_init_se (&rse, NULL);
+ gfc_fix_class_refs (expr1);
+
+ realloc_flag = flag_realloc_lhs
+ && gfc_is_reallocatable_lhs (expr1)
+ && expr2->rank
+ && !is_runtime_conformable (expr1, expr2);
+
/* Walk the lhs. */
lss = gfc_walk_expr (expr1);
- if (gfc_is_reallocatable_lhs (expr1))
+ if (realloc_flag)
{
lss->no_bounds_check = 1;
lss->is_alloc_lhs = 1;
@@ -12923,11 +12952,6 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
assoc_assign = is_assoc_assign (expr1, expr2);
- realloc_flag = flag_realloc_lhs
- && gfc_is_reallocatable_lhs (expr1)
- && expr2->rank
- && !is_runtime_conformable (expr1, expr2);
-
/* Only analyze the expressions for coarray properties, when in coarray-lib
mode. Avoid false-positive uninitialized diagnostics with initializing
the codimension flag unconditionally. */
diff --git a/gcc/function.cc b/gcc/function.cc
index 48167b0c..2b77bbd 100644
--- a/gcc/function.cc
+++ b/gcc/function.cc
@@ -7009,6 +7009,115 @@ match_asm_constraints_1 (rtx_insn *insn, rtx *p_sets, int noutputs)
df_insn_rescan (insn);
}
+/* It is expected and desired that optimizations coalesce multiple pseudos into
+ one whenever possible. However, in case of hard register constraints we may
+ have to undo this and introduce copies since otherwise we could constraint a
+ single pseudo to different hard registers. For example, during register
+ allocation the following insn would be unsatisfiable since pseudo 60 is
+ constrained to hard register r5 and r6 at the same time.
+
+ (insn 7 5 0 2 (asm_operands/v ("foo") ("") 0 [
+ (reg:DI 60) repeated x2
+ ]
+ [
+ (asm_input:DI ("{r5}") t.c:4)
+ (asm_input:DI ("{r6}") t.c:4)
+ ]
+ [] t.c:4) "t.c":4:3 -1
+ (expr_list:REG_DEAD (reg:DI 60)
+ (nil)))
+
+ Therefore, introduce a copy of pseudo 60 and transform it into
+
+ (insn 10 5 7 2 (set (reg:DI 62)
+ (reg:DI 60)) "t.c":4:3 1503 {*movdi_64}
+ (nil))
+ (insn 7 10 11 2 (asm_operands/v ("foo") ("") 0 [
+ (reg:DI 60)
+ (reg:DI 62)
+ ]
+ [
+ (asm_input:DI ("{r5}") t.c:4)
+ (asm_input:DI ("{r6}") t.c:4)
+ ]
+ [] t.c:4) "t.c":4:3 -1
+ (expr_list:REG_DEAD (reg:DI 62)
+ (expr_list:REG_DEAD (reg:DI 60)
+ (nil))))
+
+ Now, LRA can assign pseudo 60 to r5, and pseudo 62 to r6.
+
+ TODO: The current implementation is conservative and we could do a bit
+ better in case of alternatives. For example
+
+ (insn 7 5 0 2 (asm_operands/v ("foo") ("") 0 [
+ (reg:DI 60) repeated x2
+ ]
+ [
+ (asm_input:DI ("r,{r5}") t.c:4)
+ (asm_input:DI ("{r6},r") t.c:4)
+ ]
+ [] t.c:4) "t.c":4:3 -1
+ (expr_list:REG_DEAD (reg:DI 60)
+ (nil)))
+
+ For this insn we wouldn't need to come up with a copy of pseudo 60 since in
+ each alternative pseudo 60 is constrained exactly one time. */
+
+static void
+match_asm_constraints_2 (rtx_insn *insn, rtx pat)
+{
+ rtx op;
+ if (GET_CODE (pat) == SET && GET_CODE (SET_SRC (pat)) == ASM_OPERANDS)
+ op = SET_SRC (pat);
+ else if (GET_CODE (pat) == ASM_OPERANDS)
+ op = pat;
+ else
+ return;
+ int ninputs = ASM_OPERANDS_INPUT_LENGTH (op);
+ rtvec inputs = ASM_OPERANDS_INPUT_VEC (op);
+ bool changed = false;
+ auto_bitmap constrained_regs;
+
+ for (int i = 0; i < ninputs; ++i)
+ {
+ rtx input = RTVEC_ELT (inputs, i);
+ const char *constraint = ASM_OPERANDS_INPUT_CONSTRAINT (op, i);
+ if ((!REG_P (input) && !SUBREG_P (input))
+ || (REG_P (input) && HARD_REGISTER_P (input))
+ || strchr (constraint, '{') == nullptr)
+ continue;
+ int regno;
+ if (SUBREG_P (input))
+ {
+ if (REG_P (SUBREG_REG (input)))
+ regno = REGNO (SUBREG_REG (input));
+ else
+ continue;
+ }
+ else
+ regno = REGNO (input);
+ /* Keep the first usage of a constrained pseudo as is and only
+ introduce copies for subsequent usages. */
+ if (! bitmap_bit_p (constrained_regs, regno))
+ {
+ bitmap_set_bit (constrained_regs, regno);
+ continue;
+ }
+ rtx tmp = gen_reg_rtx (GET_MODE (input));
+ start_sequence ();
+ emit_move_insn (tmp, input);
+ rtx_insn *insns = get_insns ();
+ end_sequence ();
+ emit_insn_before (insns, insn);
+ RTVEC_ELT (inputs, i) = tmp;
+ changed = true;
+ }
+
+ if (changed)
+ df_insn_rescan (insn);
+}
+
/* Add the decl D to the local_decls list of FUN. */
void
@@ -7065,6 +7174,13 @@ pass_match_asm_constraints::execute (function *fun)
continue;
pat = PATTERN (insn);
+
+ if (GET_CODE (pat) == PARALLEL)
+ for (int i = XVECLEN (pat, 0) - 1; i >= 0; --i)
+ match_asm_constraints_2 (insn, XVECEXP (pat, 0, i));
+ else
+ match_asm_constraints_2 (insn, pat);
+
if (GET_CODE (pat) == PARALLEL)
p_sets = &XVECEXP (pat, 0, 0), noutputs = XVECLEN (pat, 0);
else if (GET_CODE (pat) == SET)
diff --git a/gcc/diagnostic-spec.cc b/gcc/gcc-diagnostic-spec.cc
index b43ae63..99ca6a0 100644
--- a/gcc/diagnostic-spec.cc
+++ b/gcc/gcc-diagnostic-spec.cc
@@ -27,7 +27,7 @@
#include "tree.h"
#include "cgraph.h"
#include "hash-map.h"
-#include "diagnostic-spec.h"
+#include "gcc-diagnostic-spec.h"
#include "pretty-print.h"
#include "options.h"
diff --git a/gcc/diagnostic-spec.h b/gcc/gcc-diagnostic-spec.h
index 13455ce..2b5e784 100644
--- a/gcc/diagnostic-spec.h
+++ b/gcc/gcc-diagnostic-spec.h
@@ -19,8 +19,8 @@
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
-#ifndef DIAGNOSTIC_SPEC_H_INCLUDED
-#define DIAGNOSTIC_SPEC_H_INCLUDED
+#ifndef GCC_DIAGNOSTIC_SPEC_H_INCLUDED
+#define GCC_DIAGNOSTIC_SPEC_H_INCLUDED
#include "hash-map.h"
@@ -146,4 +146,4 @@ typedef hash_map<location_hash, nowarn_spec_t> nowarn_map_t;
/* A mapping from a 'location_t' to the warning spec set for it. */
extern GTY(()) nowarn_map_t *nowarn_map;
-#endif // DIAGNOSTIC_SPEC_H_INCLUDED
+#endif // GCC_DIAGNOSTIC_SPEC_H_INCLUDED
diff --git a/gcc/gcc-rich-location.cc b/gcc/gcc-rich-location.cc
index 2095987..beb7b6c 100644
--- a/gcc/gcc-rich-location.cc
+++ b/gcc/gcc-rich-location.cc
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "cpplib.h"
#include "diagnostic.h"
+#include "diagnostics/file-cache.h"
/* Add a range to the rich_location, covering expression EXPR,
using LABEL if non-NULL. */
@@ -79,11 +80,11 @@ gcc_rich_location::add_fixit_misspelled_id (location_t misspelled_token_loc,
/* Return true if there is nothing on LOC's line before LOC. */
static bool
-blank_line_before_p (file_cache &fc,
+blank_line_before_p (diagnostics::file_cache &fc,
location_t loc)
{
expanded_location exploc = expand_location (loc);
- char_span line = fc.get_source_line (exploc.file, exploc.line);
+ diagnostics::char_span line = fc.get_source_line (exploc.file, exploc.line);
if (!line)
return false;
if (line.length () < (size_t)exploc.column)
@@ -101,7 +102,7 @@ blank_line_before_p (file_cache &fc,
If true is returned then *OUT_START_OF_LINE is written to. */
static bool
-use_new_line (file_cache &fc,
+use_new_line (diagnostics::file_cache &fc,
location_t insertion_point, location_t indent,
location_t *out_start_of_line)
{
diff --git a/gcc/gcc-rich-location.h b/gcc/gcc-rich-location.h
index cbf59b7..69cf074 100644
--- a/gcc/gcc-rich-location.h
+++ b/gcc/gcc-rich-location.h
@@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "rich-location.h"
-class diagnostic_source_print_policy;
+namespace diagnostics { class source_print_policy; }
/* A gcc_rich_location is libcpp's rich_location with additional
helper methods for working with gcc's types. The class is not
@@ -79,14 +79,14 @@ class gcc_rich_location : public rich_location
if (!added secondary)
inform (secondary_loc, "message for secondary");
- Implemented in diagnostic-show-locus.cc. */
+ Implemented in diagnostics/source-printing.cc. */
- bool add_location_if_nearby (const diagnostic_source_print_policy &policy,
+ bool add_location_if_nearby (const diagnostics::source_print_policy &policy,
location_t loc,
bool restrict_to_current_line_spans = true,
const range_label *label = NULL);
- bool add_location_if_nearby (const diagnostic_context &dc,
+ bool add_location_if_nearby (const diagnostics::context &dc,
location_t loc,
bool restrict_to_current_line_spans = true,
const range_label *label = NULL);
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index 235fe80..bfa588e 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -43,7 +43,7 @@ compilation is specified by a string called a "spec". */
#include "opt-suggestions.h"
#include "gcc.h"
#include "diagnostic.h"
-#include "diagnostic-format.h"
+#include "diagnostics/sink.h"
#include "pretty-print-urlifier.h"
#include "flags.h"
#include "opts.h"
@@ -4195,7 +4195,7 @@ driver_handle_option (struct gcc_options *opts,
unsigned int lang_mask ATTRIBUTE_UNUSED, int kind,
location_t loc,
const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED,
- diagnostic_context *dc,
+ diagnostics::context *dc,
void (*) (void))
{
size_t opt_index = decoded->opt_index;
@@ -4207,7 +4207,8 @@ driver_handle_option (struct gcc_options *opts,
gcc_assert (opts == &global_options);
gcc_assert (opts_set == &global_options_set);
- gcc_assert (kind == DK_UNSPECIFIED);
+ gcc_assert (static_cast<diagnostics::kind> (kind)
+ == diagnostics::kind::unspecified);
gcc_assert (loc == UNKNOWN_LOCATION);
gcc_assert (dc == global_dc);
@@ -4367,10 +4368,10 @@ driver_handle_option (struct gcc_options *opts,
const char *basename = (opts->x_dump_base_name ? opts->x_dump_base_name
: opts->x_main_input_basename);
gcc_assert (dc);
- diagnostic_output_format_init (*dc,
- opts->x_main_input_filename, basename,
- (enum diagnostics_output_format)value,
- opts->x_flag_diagnostics_json_formatting);
+ diagnostics::output_format_init (*dc,
+ opts->x_main_input_filename, basename,
+ (enum diagnostics_output_format)value,
+ opts->x_flag_diagnostics_json_formatting);
break;
}
diff --git a/gcc/gdbinit.in b/gcc/gdbinit.in
index 417571f..1ee3d92 100644
--- a/gcc/gdbinit.in
+++ b/gcc/gdbinit.in
@@ -293,12 +293,12 @@ See also 'help-gcc-hooks'.
end
define break-on-diagnostic
-break diagnostic_context::maybe_show_locus
+break diagnostics::context::maybe_show_locus
end
document break-on-diagnostic
-Put a breakpoint on diagnostic_show_locus, called whenever a diagnostic
-is emitted (as opposed to those warnings that are suppressed by
+Put a breakpoint on diagnostics::context::show_locus, called whenever
+a diagnostic is emitted (as opposed to those warnings that are suppressed by
command-line options).
end
diff --git a/gcc/gengtype.cc b/gcc/gengtype.cc
index 6a3621c..84c7636 100644
--- a/gcc/gengtype.cc
+++ b/gcc/gengtype.cc
@@ -1722,7 +1722,7 @@ open_base_files (void)
"target-globals.h", "ipa-ref.h", "cgraph.h", "symbol-summary.h",
"sreal.h", "ipa-cp.h", "ipa-prop.h", "ipa-fnsummary.h", "dwarf2out.h",
"omp-general.h", "omp-offload.h", "ipa-modref-tree.h", "ipa-modref.h",
- "symtab-thunks.h", "symtab-clones.h", "diagnostic-spec.h", "ctfc.h",
+ "symtab-thunks.h", "symtab-clones.h", "gcc-diagnostic-spec.h", "ctfc.h",
NULL
};
const char *const *ifp;
diff --git a/gcc/genoutput.cc b/gcc/genoutput.cc
index 25d0b8b..183ffc1 100644
--- a/gcc/genoutput.cc
+++ b/gcc/genoutput.cc
@@ -200,6 +200,8 @@ static const char indep_constraints[] = ",=+%*?!^$#&g";
static class constraint_data *
constraints_by_letter_table[1 << CHAR_BIT];
+static hash_set<free_string_hash> used_reg_names;
+
static int mdep_constraint_len (const char *, file_location, int);
static void note_constraint (md_rtx_info *);
@@ -1156,6 +1158,45 @@ main (int argc, const char **argv)
output_insn_data ();
output_get_insn_name ();
+ /* Since genoutput has no information about hard register names we cannot
+ statically verify hard register names in constraints of the machine
+ description. Therefore, we have to do it at runtime. Although
+ verification shouldn't be too expensive, restrict it to checking builds.
+ */
+ printf ("\n\n#if CHECKING_P\n");
+ if (used_reg_names.is_empty ())
+ printf ("void verify_reg_names_in_constraints () { }\n");
+ else
+ {
+ size_t max_len = 0;
+ for (auto it = used_reg_names.begin (); it != used_reg_names.end (); ++it)
+ {
+ size_t len = strlen (*it);
+ if (len > max_len)
+ max_len = len;
+ }
+ printf ("void\nverify_reg_names_in_constraints ()\n{\n");
+ printf (" static const char hregnames[%zu][%zu] = {\n",
+ used_reg_names.elements (), max_len + 1);
+ auto it = used_reg_names.begin ();
+ while (it != used_reg_names.end ())
+ {
+ printf (" \"%s\"", *it);
+ ++it;
+ if (it != used_reg_names.end ())
+ printf (",");
+ printf ("\n");
+ }
+ printf (" };\n");
+ printf (" for (size_t i = 0; i < %zu; ++i)\n",
+ used_reg_names.elements ());
+ printf (" if (decode_reg_name (hregnames[i]) < 0)\n");
+ printf (" internal_error (\"invalid register %%qs used in "
+ "constraint of machine description\", hregnames[i]);\n");
+ printf ("}\n");
+ }
+ printf ("#endif\n");
+
fflush (stdout);
return (ferror (stdout) != 0 || have_error
? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
@@ -1284,6 +1325,25 @@ mdep_constraint_len (const char *s, file_location loc, int opno)
if (!strncmp (s, p->name, p->namelen))
return p->namelen;
+ if (*s == '{')
+ {
+ const char *end = s + 1;
+ while (*end != '}' && *end != '"' && *end != '\0')
+ ++end;
+ /* Similarly as in decode_hreg_constraint(), consider any hard register
+ name longer than a few characters as an error. */
+ ptrdiff_t len = end - s;
+ if (*end == '}' && len > 1 && len < 31)
+ {
+ char *regname = new char[len];
+ memcpy (regname, s + 1, len - 1);
+ regname[len - 1] = '\0';
+ if (used_reg_names.add (regname))
+ delete[] regname;
+ return len + 1;
+ }
+ }
+
error_at (loc, "error: undefined machine-specific constraint "
"at this point: \"%s\"", s);
message_at (loc, "note: in operand %d", opno);
diff --git a/gcc/genpreds.cc b/gcc/genpreds.cc
index d09d769..7ee68c9 100644
--- a/gcc/genpreds.cc
+++ b/gcc/genpreds.cc
@@ -719,7 +719,6 @@ static const char const_dbl_constraints[] = "GH";
/* Summary data used to decide whether to output various functions and
macro definitions. */
-static unsigned int constraint_max_namelen;
static bool have_register_constraints;
static bool have_memory_constraints;
static bool have_special_memory_constraints;
@@ -942,7 +941,6 @@ add_constraint (const char *name, const char *regclass,
*last_constraint_ptr = c;
last_constraint_ptr = &c->next_textual;
- constraint_max_namelen = MAX (constraint_max_namelen, strlen (name));
have_register_constraints |= c->is_register;
have_const_int_constraints |= c->is_const_int;
have_extra_constraints |= c->is_extra;
@@ -1150,7 +1148,7 @@ write_insn_constraint_len (void)
unsigned int i;
puts ("static inline size_t\n"
- "insn_constraint_len (char fc, const char *str ATTRIBUTE_UNUSED)\n"
+ "insn_constraint_len (char fc, const char *str)\n"
"{\n"
" switch (fc)\n"
" {");
@@ -1183,6 +1181,13 @@ write_insn_constraint_len (void)
puts (" default: break;\n"
" }\n"
+ " if (str[0] == '{')\n"
+ " {\n"
+ " size_t len = 1;\n"
+ " while (str[len] != '}' && str[len] != '\\0')\n"
+ " ++len;\n"
+ " return len + 1;\n"
+ " }\n"
" return 1;\n"
"}\n");
}
@@ -1556,133 +1561,124 @@ write_tm_preds_h (void)
"#endif\n"
"\n");
- if (constraint_max_namelen > 0)
- {
- write_enum_constraint_num ();
- puts ("extern enum constraint_num lookup_constraint_1 (const char *);\n"
- "extern const unsigned char lookup_constraint_array[];\n"
+ write_enum_constraint_num ();
+ puts ("extern enum constraint_num lookup_constraint_1 (const char *);\n"
+ "extern const unsigned char lookup_constraint_array[];\n"
+ "\n"
+ "/* Return the constraint at the beginning of P, or"
+ " CONSTRAINT__UNKNOWN if it\n"
+ " isn't recognized. */\n"
+ "\n"
+ "static inline enum constraint_num\n"
+ "lookup_constraint (const char *p)\n"
+ "{\n"
+ " unsigned int index = lookup_constraint_array"
+ "[(unsigned char) *p];\n"
+ " return (index == UCHAR_MAX\n"
+ " ? lookup_constraint_1 (p)\n"
+ " : (enum constraint_num) index);\n"
+ "}\n");
+ if (satisfied_start == num_constraints)
+ puts ("/* Return true if X satisfies constraint C. */\n"
+ "\n"
+ "static inline bool\n"
+ "constraint_satisfied_p (rtx, enum constraint_num)\n"
+ "{\n"
+ " return false;\n"
+ "}\n");
+ else
+ printf ("extern bool (*constraint_satisfied_p_array[]) (rtx);\n"
"\n"
- "/* Return the constraint at the beginning of P, or"
- " CONSTRAINT__UNKNOWN if it\n"
- " isn't recognized. */\n"
+ "/* Return true if X satisfies constraint C. */\n"
"\n"
- "static inline enum constraint_num\n"
- "lookup_constraint (const char *p)\n"
- "{\n"
- " unsigned int index = lookup_constraint_array"
- "[(unsigned char) *p];\n"
- " return (index == UCHAR_MAX\n"
- " ? lookup_constraint_1 (p)\n"
- " : (enum constraint_num) index);\n"
- "}\n");
- if (satisfied_start == num_constraints)
- puts ("/* Return true if X satisfies constraint C. */\n"
- "\n"
- "static inline bool\n"
- "constraint_satisfied_p (rtx, enum constraint_num)\n"
- "{\n"
- " return false;\n"
- "}\n");
- else
- printf ("extern bool (*constraint_satisfied_p_array[]) (rtx);\n"
- "\n"
- "/* Return true if X satisfies constraint C. */\n"
- "\n"
- "static inline bool\n"
- "constraint_satisfied_p (rtx x, enum constraint_num c)\n"
- "{\n"
- " int i = (int) c - (int) CONSTRAINT_%s;\n"
- " return i >= 0 && constraint_satisfied_p_array[i] (x);\n"
- "}\n"
- "\n",
- enum_order[satisfied_start]->name);
-
- write_range_function ("insn_extra_register_constraint",
- register_start, register_end);
- write_range_function ("insn_extra_memory_constraint",
- memory_start, memory_end);
- write_range_function ("insn_extra_special_memory_constraint",
- special_memory_start, special_memory_end);
- write_range_function ("insn_extra_relaxed_memory_constraint",
- relaxed_memory_start, relaxed_memory_end);
- write_range_function ("insn_extra_address_constraint",
- address_start, address_end);
- write_allows_reg_mem_function ();
-
- if (constraint_max_namelen > 1)
- {
- write_insn_constraint_len ();
- puts ("#define CONSTRAINT_LEN(c_,s_) "
- "insn_constraint_len (c_,s_)\n");
- }
- else
- puts ("#define CONSTRAINT_LEN(c_,s_) 1\n");
- if (have_register_constraints)
- puts ("extern enum reg_class reg_class_for_constraint_1 "
- "(enum constraint_num);\n"
- "\n"
- "static inline enum reg_class\n"
- "reg_class_for_constraint (enum constraint_num c)\n"
- "{\n"
- " if (insn_extra_register_constraint (c))\n"
- " return reg_class_for_constraint_1 (c);\n"
- " return NO_REGS;\n"
- "}\n");
- else
- puts ("static inline enum reg_class\n"
- "reg_class_for_constraint (enum constraint_num)\n"
- "{\n"
- " return NO_REGS;\n"
- "}\n");
- if (have_const_int_constraints)
- puts ("extern bool insn_const_int_ok_for_constraint "
- "(HOST_WIDE_INT, enum constraint_num);\n"
- "#define CONST_OK_FOR_CONSTRAINT_P(v_,c_,s_) \\\n"
- " insn_const_int_ok_for_constraint (v_, "
- "lookup_constraint (s_))\n");
- else
- puts ("static inline bool\n"
- "insn_const_int_ok_for_constraint (HOST_WIDE_INT,"
- " enum constraint_num)\n"
- "{\n"
- " return false;\n"
- "}\n");
-
- puts ("enum constraint_type\n"
+ "static inline bool\n"
+ "constraint_satisfied_p (rtx x, enum constraint_num c)\n"
"{\n"
- " CT_REGISTER,\n"
- " CT_CONST_INT,\n"
- " CT_MEMORY,\n"
- " CT_SPECIAL_MEMORY,\n"
- " CT_RELAXED_MEMORY,\n"
- " CT_ADDRESS,\n"
- " CT_FIXED_FORM\n"
- "};\n"
- "\n"
- "static inline enum constraint_type\n"
- "get_constraint_type (enum constraint_num c)\n"
- "{");
- auto_vec <std::pair <unsigned int, const char *>, 4> values;
- if (const_int_start != const_int_end)
- values.safe_push (std::make_pair (const_int_start, "CT_CONST_INT"));
- if (memory_start != memory_end)
- values.safe_push (std::make_pair (memory_start, "CT_MEMORY"));
- if (special_memory_start != special_memory_end)
- values.safe_push (std::make_pair (special_memory_start,
- "CT_SPECIAL_MEMORY"));
- if (relaxed_memory_start != relaxed_memory_end)
- values.safe_push (std::make_pair (relaxed_memory_start,
- "CT_RELAXED_MEMORY"));
- if (address_start != address_end)
- values.safe_push (std::make_pair (address_start, "CT_ADDRESS"));
- if (address_end != num_constraints)
- values.safe_push (std::make_pair (address_end, "CT_FIXED_FORM"));
- print_type_tree (values, 0, values.length (), "CT_REGISTER", 2);
- puts ("}");
-
- write_get_register_filter ();
- write_get_register_filter_id ();
- }
+ " int i = (int) c - (int) CONSTRAINT_%s;\n"
+ " return i >= 0 && constraint_satisfied_p_array[i] (x);\n"
+ "}\n"
+ "\n",
+ enum_order[satisfied_start]->name);
+
+ write_range_function ("insn_extra_register_constraint",
+ register_start, register_end);
+ write_range_function ("insn_extra_memory_constraint",
+ memory_start, memory_end);
+ write_range_function ("insn_extra_special_memory_constraint",
+ special_memory_start, special_memory_end);
+ write_range_function ("insn_extra_relaxed_memory_constraint",
+ relaxed_memory_start, relaxed_memory_end);
+ write_range_function ("insn_extra_address_constraint",
+ address_start, address_end);
+ write_allows_reg_mem_function ();
+
+ write_insn_constraint_len ();
+ puts ("#define CONSTRAINT_LEN(c_,s_) insn_constraint_len (c_,s_)\n");
+ if (have_register_constraints)
+ puts ("extern enum reg_class reg_class_for_constraint_1 "
+ "(enum constraint_num);\n"
+ "\n"
+ "static inline enum reg_class\n"
+ "reg_class_for_constraint (enum constraint_num c)\n"
+ "{\n"
+ " if (insn_extra_register_constraint (c))\n"
+ " return reg_class_for_constraint_1 (c);\n"
+ " return NO_REGS;\n"
+ "}\n");
+ else
+ puts ("static inline enum reg_class\n"
+ "reg_class_for_constraint (enum constraint_num)\n"
+ "{\n"
+ " return NO_REGS;\n"
+ "}\n");
+ if (have_const_int_constraints)
+ puts ("extern bool insn_const_int_ok_for_constraint "
+ "(HOST_WIDE_INT, enum constraint_num);\n"
+ "#define CONST_OK_FOR_CONSTRAINT_P(v_,c_,s_) \\\n"
+ " insn_const_int_ok_for_constraint (v_, "
+ "lookup_constraint (s_))\n");
+ else
+ puts ("static inline bool\n"
+ "insn_const_int_ok_for_constraint (HOST_WIDE_INT,"
+ " enum constraint_num)\n"
+ "{\n"
+ " return false;\n"
+ "}\n");
+
+ puts ("enum constraint_type\n"
+ "{\n"
+ " CT_REGISTER,\n"
+ " CT_CONST_INT,\n"
+ " CT_MEMORY,\n"
+ " CT_SPECIAL_MEMORY,\n"
+ " CT_RELAXED_MEMORY,\n"
+ " CT_ADDRESS,\n"
+ " CT_FIXED_FORM\n"
+ "};\n"
+ "\n"
+ "static inline enum constraint_type\n"
+ "get_constraint_type (enum constraint_num c)\n"
+ "{");
+ auto_vec <std::pair <unsigned int, const char *>, 4> values;
+ if (const_int_start != const_int_end)
+ values.safe_push (std::make_pair (const_int_start, "CT_CONST_INT"));
+ if (memory_start != memory_end)
+ values.safe_push (std::make_pair (memory_start, "CT_MEMORY"));
+ if (special_memory_start != special_memory_end)
+ values.safe_push (std::make_pair (special_memory_start,
+ "CT_SPECIAL_MEMORY"));
+ if (relaxed_memory_start != relaxed_memory_end)
+ values.safe_push (std::make_pair (relaxed_memory_start,
+ "CT_RELAXED_MEMORY"));
+ if (address_start != address_end)
+ values.safe_push (std::make_pair (address_start, "CT_ADDRESS"));
+ if (address_end != num_constraints)
+ values.safe_push (std::make_pair (address_end, "CT_FIXED_FORM"));
+ print_type_tree (values, 0, values.length (), "CT_REGISTER", 2);
+ puts ("}");
+
+ write_get_register_filter ();
+ write_get_register_filter_id ();
puts ("#endif /* tm-preds.h */");
}
@@ -1743,17 +1739,14 @@ write_insn_preds_c (void)
FOR_ALL_PREDICATES (p)
write_one_predicate_function (p);
- if (constraint_max_namelen > 0)
- {
- write_lookup_constraint_1 ();
- write_lookup_constraint_array ();
- if (have_register_constraints)
- write_reg_class_for_constraint_1 ();
- write_constraint_satisfied_p_array ();
-
- if (have_const_int_constraints)
- write_insn_const_int_ok_for_constraint ();
- }
+ write_lookup_constraint_1 ();
+ write_lookup_constraint_array ();
+ if (have_register_constraints)
+ write_reg_class_for_constraint_1 ();
+ write_constraint_satisfied_p_array ();
+
+ if (have_const_int_constraints)
+ write_insn_const_int_ok_for_constraint ();
write_init_reg_class_start_regs ();
}
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index c5c8e22..49e3440 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -9916,10 +9916,17 @@ fold_nonarray_ctor_reference (tree type, tree ctor,
{
if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
return NULL_TREE;
- const unsigned int encoding_size
- = GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (TREE_TYPE (cfield)));
if (BYTES_BIG_ENDIAN)
- inner_offset += encoding_size - wi::to_offset (field_size);
+ {
+ tree ctype = TREE_TYPE (cfield);
+ unsigned int encoding_size;
+ if (TYPE_MODE (ctype) != BLKmode)
+ encoding_size
+ = GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (ctype));
+ else
+ encoding_size = TREE_INT_CST_LOW (TYPE_SIZE (ctype));
+ inner_offset += encoding_size - wi::to_offset (field_size);
+ }
}
return fold_ctor_reference (type, cval,
diff --git a/gcc/gimple-walk.cc b/gcc/gimple-walk.cc
index eceda41..b8b1077 100644
--- a/gcc/gimple-walk.cc
+++ b/gcc/gimple-walk.cc
@@ -118,7 +118,7 @@ walk_gimple_asm (gasm *stmt, walk_tree_fn callback_op,
if (wi)
{
if (parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
- &allows_reg, &is_inout))
+ &allows_reg, &is_inout, nullptr))
wi->val_only = (allows_reg || !allows_mem);
}
if (wi)
@@ -137,7 +137,8 @@ walk_gimple_asm (gasm *stmt, walk_tree_fn callback_op,
if (wi)
{
if (parse_input_constraint (&constraint, 0, 0, noutputs, 0,
- oconstraints, &allows_mem, &allows_reg))
+ oconstraints, &allows_mem, &allows_reg,
+ nullptr))
{
wi->val_only = (allows_reg || !allows_mem);
/* Although input "m" is not really a LHS, we need a lvalue. */
@@ -897,7 +898,7 @@ walk_stmt_load_store_addr_ops (gimple *stmt, void *data,
(TREE_VALUE (TREE_PURPOSE (link)));
oconstraints[i] = constraint;
parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
- &allows_reg, &is_inout);
+ &allows_reg, &is_inout, nullptr);
if (op && !allows_reg && allows_mem)
ret |= visit_addr (stmt, op, TREE_VALUE (link), data);
}
@@ -922,8 +923,8 @@ walk_stmt_load_store_addr_ops (gimple *stmt, void *data,
constraint = TREE_STRING_POINTER
(TREE_VALUE (TREE_PURPOSE (link)));
parse_input_constraint (&constraint, 0, 0, noutputs,
- 0, oconstraints,
- &allows_mem, &allows_reg);
+ 0, oconstraints, &allows_mem,
+ &allows_reg, nullptr);
if (!allows_reg && allows_mem)
ret |= visit_addr (stmt, op, TREE_VALUE (link),
data);
diff --git a/gcc/gimplify-me.cc b/gcc/gimplify-me.cc
index 7407822..5b4b987 100644
--- a/gcc/gimplify-me.cc
+++ b/gcc/gimplify-me.cc
@@ -194,7 +194,7 @@ gimple_regimplify_operands (gimple *stmt, gimple_stmt_iterator *gsi_p)
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
oconstraints[i] = constraint;
parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
- &allows_reg, &is_inout);
+ &allows_reg, &is_inout, nullptr);
gimplify_expr (&TREE_VALUE (op), &pre, NULL,
is_inout ? is_gimple_min_lval : is_gimple_lvalue,
fb_lvalue | fb_mayfail);
@@ -204,7 +204,8 @@ gimple_regimplify_operands (gimple *stmt, gimple_stmt_iterator *gsi_p)
tree op = gimple_asm_input_op (asm_stmt, i);
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
parse_input_constraint (&constraint, 0, 0, noutputs, 0,
- oconstraints, &allows_mem, &allows_reg);
+ oconstraints, &allows_mem, &allows_reg,
+ nullptr);
if (TREE_ADDRESSABLE (TREE_TYPE (TREE_VALUE (op))) && allows_mem)
allows_reg = 0;
if (!allows_reg && allows_mem)
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 910314b..fbf47dd 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -71,6 +71,10 @@ along with GCC; see the file COPYING3. If not see
#include "context.h"
#include "tree-nested.h"
#include "gcc-urlifier.h"
+#include "insn-config.h"
+#include "recog.h"
+#include "output.h"
+#include "gimplify_reg_info.h"
/* Identifier for a basic condition, mapping it to other basic conditions of
its Boolean expression. Basic conditions given the same uid (in the same
@@ -7823,6 +7827,42 @@ gimplify_addr_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
return ret;
}
+/* Return the number of times character C occurs in string S. */
+
+static int
+num_occurrences (int c, const char *s)
+{
+ int n = 0;
+ while (*s)
+ n += (*s++ == c);
+ return n;
+}
+
+/* A subroutine of gimplify_asm_expr. Check that all operands have
+ the same number of alternatives. Return -1 if this is violated. Otherwise
+ return the number of alternatives. */
+
+static int
+num_alternatives (const_tree link)
+{
+ if (link == nullptr)
+ return 0;
+
+ const char *constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+ int num = num_occurrences (',', constraint);
+
+ if (num + 1 > MAX_RECOG_ALTERNATIVES)
+ return -1;
+
+ for (link = TREE_CHAIN (link); link; link = TREE_CHAIN (link))
+ {
+ constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+ if (num_occurrences (',', constraint) != num)
+ return -1;
+ }
+ return num + 1;
+}
+
/* Gimplify the operands of an ASM_EXPR. Input operands should be a gimple
value; output operands should be a gimple lvalue. */
@@ -7853,6 +7893,36 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
clobbers = NULL;
labels = NULL;
+ int num_alternatives_out = num_alternatives (ASM_OUTPUTS (expr));
+ int num_alternatives_in = num_alternatives (ASM_INPUTS (expr));
+ if (num_alternatives_out == -1 || num_alternatives_in == -1
+ || (num_alternatives_out > 0 && num_alternatives_in > 0
+ && num_alternatives_out != num_alternatives_in))
+ {
+ error ("operand constraints for %<asm%> differ "
+ "in number of alternatives");
+ return GS_ERROR;
+ }
+ int num_alternatives = MAX (num_alternatives_out, num_alternatives_in);
+
+ gimplify_reg_info reg_info (num_alternatives, noutputs);
+
+ link_next = NULL_TREE;
+ for (link = ASM_CLOBBERS (expr); link; link = link_next)
+ {
+ /* The clobber entry could also be an error marker. */
+ if (TREE_CODE (TREE_VALUE (link)) == STRING_CST)
+ {
+ const char *regname= TREE_STRING_POINTER (TREE_VALUE (link));
+ int regno = decode_reg_name (regname);
+ if (regno >= 0)
+ reg_info.set_clobbered (regno);
+ }
+ link_next = TREE_CHAIN (link);
+ TREE_CHAIN (link) = NULL_TREE;
+ vec_safe_push (clobbers, link);
+ }
+
ret = GS_ALL_DONE;
link_next = NULL_TREE;
for (i = 0, link = ASM_OUTPUTS (expr); link; ++i, link = link_next)
@@ -7869,8 +7939,9 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
if (constraint_len == 0)
continue;
- ok = parse_output_constraint (&constraint, i, 0, 0,
- &allows_mem, &allows_reg, &is_inout);
+ reg_info.operand = TREE_VALUE (link);
+ ok = parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
+ &allows_reg, &is_inout, &reg_info);
if (!ok)
{
ret = GS_ERROR;
@@ -8001,8 +8072,8 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
*end = '\0';
beg[-1] = '=';
tem = beg - 1;
- parse_output_constraint (&tem, i, 0, 0,
- &mem_p, &reg_p, &inout_p);
+ parse_output_constraint (&tem, i, 0, 0, &mem_p, &reg_p,
+ &inout_p, nullptr);
if (dst != str)
*dst++ = ',';
if (reg_p)
@@ -8041,13 +8112,60 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
}
}
+ /* After all output operands have been gimplified, verify that each output
+ operand is used at most once in case of hard register constraints. Thus,
+ error out in cases like
+ asm ("" : "={0}" (x), "={1}" (x));
+ or even for
+ asm ("" : "=r" (x), "={1}" (x));
+
+ FIXME: Ideally we would also error out for cases like
+ int x;
+ asm ("" : "=r" (x), "=r" (x));
+ However, since code like that was previously accepted, erroring out now might
+ break existing code. On the other hand, we already error out for register
+ asm like
+ register int x asm ("0");
+ asm ("" : "=r" (x), "=r" (x));
+ Thus, maybe it wouldn't be too bad to also error out in the former
+ non-register-asm case.
+ */
+ for (unsigned i = 0; i < vec_safe_length (outputs); ++i)
+ {
+ tree link = (*outputs)[i];
+ tree op1 = TREE_VALUE (link);
+ const char *constraint
+ = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+ if (strchr (constraint, '{') != nullptr)
+ for (unsigned j = 0; j < vec_safe_length (outputs); ++j)
+ {
+ if (i == j)
+ continue;
+ tree link2 = (*outputs)[j];
+ tree op2 = TREE_VALUE (link2);
+ if (op1 == op2)
+ {
+ error ("multiple outputs to lvalue %qE", op2);
+ return GS_ERROR;
+ }
+ }
+ }
+
link_next = NULL_TREE;
- for (link = ASM_INPUTS (expr); link; ++i, link = link_next)
+ int input_num = 0;
+ for (link = ASM_INPUTS (expr); link; ++input_num, ++i, link = link_next)
{
link_next = TREE_CHAIN (link);
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
- parse_input_constraint (&constraint, 0, 0, noutputs, 0,
- oconstraints, &allows_mem, &allows_reg);
+ reg_info.operand = TREE_VALUE (link);
+ bool ok = parse_input_constraint (&constraint, input_num, 0, noutputs, 0,
+ oconstraints, &allows_mem, &allows_reg,
+ &reg_info);
+ if (!ok)
+ {
+ ret = GS_ERROR;
+ is_inout = false;
+ }
/* If we can't make copies, we can only accept memory. */
tree intype = TREE_TYPE (TREE_VALUE (link));
@@ -8129,15 +8247,7 @@ gimplify_asm_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
}
link_next = NULL_TREE;
- for (link = ASM_CLOBBERS (expr); link; ++i, link = link_next)
- {
- link_next = TREE_CHAIN (link);
- TREE_CHAIN (link) = NULL_TREE;
- vec_safe_push (clobbers, link);
- }
-
- link_next = NULL_TREE;
- for (link = ASM_LABELS (expr); link; ++i, link = link_next)
+ for (link = ASM_LABELS (expr); link; link = link_next)
{
link_next = TREE_CHAIN (link);
TREE_CHAIN (link) = NULL_TREE;
diff --git a/gcc/gimplify_reg_info.h b/gcc/gimplify_reg_info.h
new file mode 100644
index 0000000..b56b225
--- /dev/null
+++ b/gcc/gimplify_reg_info.h
@@ -0,0 +1,182 @@
+/* gimplify_reg_info is used during gimplification while walking over
+ operands and their corresponding constraints of asm statements in order to
+ detect errors.
+
+ m_alt_output is a mapping describing which registers are potentially used in
+ which alternative over all outputs. Similarly for m_alt_input but over all
+ inputs.
+
+ m_early_clobbered_alt is a mapping describing which register is early
+ clobbered in which alternative over all outputs.
+
+ m_early_clobbered_output is the counter part to the prior one, i.e., it
+ is a mapping describing which register is early clobbered in which operand
+ over all alternatives.
+
+ m_reg_asm_output is the set of registers (including register pairs) used for
+ register asm output operands.
+
+ m_reg_asm_input similar as m_reg_asm_output but for inputs. */
+
+#include "regs.h"
+
+class gimplify_reg_info
+{
+ HARD_REG_SET *m_buf;
+ HARD_REG_SET *m_alt_output;
+ HARD_REG_SET *m_alt_input;
+ HARD_REG_SET *m_early_clobbered_alt;
+ HARD_REG_SET *m_early_clobbered_output;
+ HARD_REG_SET m_reg_asm_output;
+ HARD_REG_SET m_reg_asm_input;
+ const unsigned m_num_alternatives;
+ const unsigned m_num_outputs;
+ /* Member m_clobbered describes all the registers marked as clobbered in an
+ asm statement, i.e., this is the clobbers list of an extended asm
+
+ asm asm-qualifiers ( AssemblerTemplate
+ : OutputOperands
+ [ : InputOperands
+ [ : Clobbers ] ])
+
+ and is not to be confused with the early clobbers sets. */
+ HARD_REG_SET m_clobbered;
+
+ /* Return the first overlapping register of REGS and REGNO:MODE or -1. */
+ int test (const HARD_REG_SET &regs, int regno) const
+ {
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+
+ if (TEST_HARD_REG_BIT (regs, regno))
+ return regno;
+
+ int end_regno = end_hard_regno (mode, regno);
+ while (++regno < end_regno)
+ if (TEST_HARD_REG_BIT (regs, regno))
+ return regno;
+
+ return -1;
+ }
+
+public:
+ tree operand;
+
+ gimplify_reg_info (unsigned num_alternatives,
+ unsigned num_outputs)
+ : m_num_alternatives{num_alternatives}
+ , m_num_outputs{num_outputs}
+ {
+ CLEAR_HARD_REG_SET (m_reg_asm_output);
+ CLEAR_HARD_REG_SET (m_reg_asm_input);
+ CLEAR_HARD_REG_SET (m_clobbered);
+
+ /* If there are no alternatives, then there are no outputs/inputs and there
+ is nothing to do on our end. Thus, we are dealing most likely with a
+ basic asm. */
+ if (num_alternatives == 0)
+ return;
+
+ unsigned buf_size = num_alternatives * 3 + num_outputs;
+ m_buf = new HARD_REG_SET[buf_size];
+ for (unsigned i = 0; i < buf_size; ++i)
+ CLEAR_HARD_REG_SET (m_buf[i]);
+ m_alt_output = &m_buf[0];
+ m_alt_input = &m_buf[num_alternatives];
+ m_early_clobbered_alt = &m_buf[num_alternatives * 2];
+ if (num_outputs > 0)
+ m_early_clobbered_output = &m_buf[num_alternatives * 3];
+ else
+ m_early_clobbered_output = nullptr;
+ }
+
+ ~gimplify_reg_info ()
+ {
+ if (m_num_alternatives > 0)
+ delete[] m_buf;
+ }
+
+ void set_output (unsigned alt, int regno)
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ add_to_hard_reg_set (&m_alt_output[alt], mode, regno);
+ }
+
+ void set_input (unsigned alt, int regno)
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ add_to_hard_reg_set (&m_alt_input[alt], mode, regno);
+ }
+
+ int test_alt_output (unsigned alt, int regno) const
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ return test (m_alt_output[alt], regno);
+ }
+
+ int test_alt_input (unsigned alt, int regno) const
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ return test (m_alt_input[alt], regno);
+ }
+
+ void set_reg_asm_output (int regno)
+ {
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ add_to_hard_reg_set (&m_reg_asm_output, mode, regno);
+ }
+
+ int test_reg_asm_output (int regno) const
+ {
+ return test (m_reg_asm_output, regno);
+ }
+
+ void set_reg_asm_input (int regno)
+ {
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ add_to_hard_reg_set (&m_reg_asm_input, mode, regno);
+ }
+
+ int test_reg_asm_input (int regno) const
+ {
+ return test (m_reg_asm_input, regno);
+ }
+
+ void set_early_clobbered (unsigned alt, unsigned output, int regno)
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ gcc_checking_assert (output < m_num_outputs);
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ add_to_hard_reg_set (&m_early_clobbered_alt[alt], mode, regno);
+ add_to_hard_reg_set (&m_early_clobbered_output[output], mode, regno);
+ }
+
+ bool test_early_clobbered_alt (unsigned alt, int regno) const
+ {
+ gcc_checking_assert (alt < m_num_alternatives);
+ return TEST_HARD_REG_BIT (m_early_clobbered_alt[alt], regno);
+ }
+
+ bool is_early_clobbered_in_any_output_unequal (unsigned operand,
+ int regno) const
+ {
+ gcc_checking_assert (operand < m_num_outputs);
+ for (unsigned op = 0; op < m_num_outputs; ++op)
+ if (op != operand
+ && TEST_HARD_REG_BIT (m_early_clobbered_output[op], regno))
+ return true;
+ return false;
+ }
+
+ void set_clobbered (int regno)
+ {
+ SET_HARD_REG_BIT (m_clobbered, regno);
+ }
+
+ bool is_clobbered (int regno) const
+ {
+ machine_mode mode = TYPE_MODE (TREE_TYPE (operand));
+ return overlaps_hard_reg_set_p (m_clobbered, mode, regno);
+ }
+};
diff --git a/gcc/input.cc b/gcc/input.cc
index fabfbfb..b9a5539 100644
--- a/gcc/input.cc
+++ b/gcc/input.cc
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "intl.h"
#include "diagnostic.h"
+#include "diagnostics/file-cache.h"
#include "selftest.h"
#include "cpplib.h"
@@ -35,188 +36,6 @@ special_fname_builtin ()
return _("<built-in>");
}
-/* Input charset configuration. */
-static const char *default_charset_callback (const char *)
-{
- return nullptr;
-}
-
-void
-file_cache::initialize_input_context (diagnostic_input_charset_callback ccb,
- bool should_skip_bom)
-{
- m_input_context.ccb = (ccb ? ccb : default_charset_callback);
- m_input_context.should_skip_bom = should_skip_bom;
-}
-
-/* This is a cache used by get_next_line to store the content of a
- file to be searched for file lines. */
-class file_cache_slot
-{
-public:
- file_cache_slot ();
- ~file_cache_slot ();
-
- void dump (FILE *out, int indent) const;
- void DEBUG_FUNCTION dump () const { dump (stderr, 0); }
-
- bool read_line_num (size_t line_num,
- char ** line, ssize_t *line_len);
-
- /* Accessors. */
- const char *get_file_path () const { return m_file_path; }
- unsigned get_use_count () const { return m_use_count; }
- bool missing_trailing_newline_p () const
- {
- return m_missing_trailing_newline;
- }
- char_span get_full_file_content ();
-
- void inc_use_count () { m_use_count++; }
-
- bool create (const file_cache::input_context &in_context,
- const char *file_path, FILE *fp, unsigned highest_use_count);
- void evict ();
- void set_content (const char *buf, size_t sz);
-
- static size_t tune (size_t line_record_size_)
- {
- size_t ret = line_record_size;
- line_record_size = line_record_size_;
- return ret;
- }
-
- private:
- /* These are information used to store a line boundary. */
- class line_info
- {
- public:
- /* The line number. It starts from 1. */
- size_t line_num;
-
- /* The position (byte count) of the beginning of the line,
- relative to the file data pointer. This starts at zero. */
- size_t start_pos;
-
- /* The position (byte count) of the last byte of the line. This
- normally points to the '\n' character, or to one byte after the
- last byte of the file, if the file doesn't contain a '\n'
- character. */
- size_t end_pos;
-
- line_info (size_t l, size_t s, size_t e)
- : line_num (l), start_pos (s), end_pos (e)
- {}
-
- line_info ()
- :line_num (0), start_pos (0), end_pos (0)
- {}
-
- static bool less_than(const line_info &a, const line_info &b)
- {
- return a.line_num < b.line_num;
- }
- };
-
- bool needs_read_p () const;
- bool needs_grow_p () const;
- void maybe_grow ();
- bool read_data ();
- bool maybe_read_data ();
- bool get_next_line (char **line, ssize_t *line_len);
- bool read_next_line (char ** line, ssize_t *line_len);
- bool goto_next_line ();
-
- static const size_t buffer_size = 4 * 1024;
- static size_t line_record_size;
- static size_t recent_cached_lines_shift;
-
- /* The number of time this file has been accessed. This is used
- to designate which file cache to evict from the cache
- array. */
- unsigned m_use_count;
-
- /* The file_path is the key for identifying a particular file in
- the cache. This copy is owned by the slot. */
- char *m_file_path;
-
- FILE *m_fp;
-
- /* True when an read error happened. */
- bool m_error;
-
- /* This points to the content of the file that we've read so
- far. */
- char *m_data;
-
- /* The allocated buffer to be freed may start a little earlier than DATA,
- e.g. if a UTF8 BOM was skipped at the beginning. */
- int m_alloc_offset;
-
- /* The size of the DATA array above.*/
- size_t m_size;
-
- /* The number of bytes read from the underlying file so far. This
- must be less (or equal) than SIZE above. */
- size_t m_nb_read;
-
- /* The index of the beginning of the current line. */
- size_t m_line_start_idx;
-
- /* The number of the previous line read. This starts at 1. Zero
- means we've read no line so far. */
- size_t m_line_num;
-
- /* Could this file be missing a trailing newline on its final line?
- Initially true (to cope with empty files), set to true/false
- as each line is read. */
- bool m_missing_trailing_newline;
-
- /* This is a record of the beginning and end of the lines we've seen
- while reading the file. This is useful to avoid walking the data
- from the beginning when we are asked to read a line that is
- before LINE_START_IDX above. When the lines exceed line_record_size
- this is scaled down dynamically, with the line_info becoming anchors. */
- vec<line_info, va_heap> m_line_record;
-
- /* A cache of the recently seen lines. This is maintained as a ring
- buffer. */
- vec<line_info, va_heap> m_line_recent;
-
- /* First and last valid entry in m_line_recent. */
- size_t m_line_recent_last, m_line_recent_first;
-
- void offset_buffer (int offset)
- {
- gcc_assert (offset < 0 ? m_alloc_offset + offset >= 0
- : (size_t) offset <= m_size);
- gcc_assert (m_data);
- m_alloc_offset += offset;
- m_data += offset;
- m_size -= offset;
- }
-
-};
-
-size_t file_cache_slot::line_record_size = 0;
-size_t file_cache_slot::recent_cached_lines_shift = 8;
-
-/* Tune file_cache. */
-void
-file_cache::tune (size_t num_file_slots, size_t lines)
-{
- if (file_cache_slot::tune (lines) != lines
- || m_num_file_slots != num_file_slots)
- {
- delete[] m_file_slots;
- m_file_slots = new file_cache_slot[num_file_slots];
- }
- m_num_file_slots = num_file_slots;
-}
-
-static const char *
-find_end_of_line (const char *s, size_t len);
-
/* Current position in real source file. */
location_t input_location = UNKNOWN_LOCATION;
@@ -320,738 +139,13 @@ expand_location_1 (const line_maps *set,
return xloc;
}
-/* Lookup the cache used for the content of a given file accessed by
- caret diagnostic. Return the found cached file, or NULL if no
- cached file was found. */
-
-file_cache_slot *
-file_cache::lookup_file (const char *file_path)
-{
- gcc_assert (file_path);
-
- /* This will contain the found cached file. */
- file_cache_slot *r = NULL;
- for (unsigned i = 0; i < m_num_file_slots; ++i)
- {
- file_cache_slot *c = &m_file_slots[i];
- if (c->get_file_path () && !strcmp (c->get_file_path (), file_path))
- {
- c->inc_use_count ();
- r = c;
- }
- }
-
- if (r)
- r->inc_use_count ();
-
- return r;
-}
-
-/* Purge any mention of FILENAME from the cache of files used for
- printing source code. For use in selftests when working
- with tempfiles. */
-
-void
-file_cache::forcibly_evict_file (const char *file_path)
-{
- gcc_assert (file_path);
-
- file_cache_slot *r = lookup_file (file_path);
- if (!r)
- /* Not found. */
- return;
-
- r->evict ();
-}
-
-/* Determine if FILE_PATH missing a trailing newline on its final line.
- Only valid to call once all of the file has been loaded, by
- requesting a line number beyond the end of the file. */
-
-bool
-file_cache::missing_trailing_newline_p (const char *file_path)
-{
- gcc_assert (file_path);
-
- file_cache_slot *r = lookup_or_add_file (file_path);
- return r->missing_trailing_newline_p ();
-}
-
-void
-file_cache::add_buffered_content (const char *file_path,
- const char *buffer,
- size_t sz)
-{
- gcc_assert (file_path);
-
- file_cache_slot *r = lookup_file (file_path);
- if (!r)
- {
- unsigned highest_use_count = 0;
- r = evicted_cache_tab_entry (&highest_use_count);
- if (!r->create (m_input_context, file_path, nullptr, highest_use_count))
- return;
- }
-
- r->set_content (buffer, sz);
-}
-
-void
-file_cache_slot::evict ()
-{
- free (m_file_path);
- m_file_path = NULL;
- if (m_fp)
- fclose (m_fp);
- m_error = false;
- m_fp = NULL;
- m_nb_read = 0;
- m_line_start_idx = 0;
- m_line_num = 0;
- m_line_record.truncate (0);
- m_line_recent_first = 0;
- m_line_recent_last = 0;
- m_use_count = 0;
- m_missing_trailing_newline = true;
-}
-
-/* Return the file cache that has been less used, recently, or the
- first empty one. If HIGHEST_USE_COUNT is non-null,
- *HIGHEST_USE_COUNT is set to the highest use count of the entries
- in the cache table. */
-
-file_cache_slot*
-file_cache::evicted_cache_tab_entry (unsigned *highest_use_count)
-{
- file_cache_slot *to_evict = &m_file_slots[0];
- unsigned huc = to_evict->get_use_count ();
- for (unsigned i = 1; i < m_num_file_slots; ++i)
- {
- file_cache_slot *c = &m_file_slots[i];
- bool c_is_empty = (c->get_file_path () == NULL);
-
- if (c->get_use_count () < to_evict->get_use_count ()
- || (to_evict->get_file_path () && c_is_empty))
- /* We evict C because it's either an entry with a lower use
- count or one that is empty. */
- to_evict = c;
-
- if (huc < c->get_use_count ())
- huc = c->get_use_count ();
-
- if (c_is_empty)
- /* We've reached the end of the cache; subsequent elements are
- all empty. */
- break;
- }
-
- if (highest_use_count)
- *highest_use_count = huc;
-
- return to_evict;
-}
-
-/* Create the cache used for the content of a given file to be
- accessed by caret diagnostic. This cache is added to an array of
- cache and can be retrieved by lookup_file_in_cache_tab. This
- function returns the created cache. Note that only the last
- m_num_file_slots files are cached.
-
- This can return nullptr if the FILE_PATH can't be opened for
- reading, or if the content can't be converted to the input_charset. */
-
-file_cache_slot*
-file_cache::add_file (const char *file_path)
-{
-
- FILE *fp = fopen (file_path, "r");
- if (fp == NULL)
- return NULL;
-
- unsigned highest_use_count = 0;
- file_cache_slot *r = evicted_cache_tab_entry (&highest_use_count);
- if (!r->create (m_input_context, file_path, fp, highest_use_count))
- return NULL;
- return r;
-}
-
-/* Get a borrowed char_span to the full content of this file
- as decoded according to the input charset, encoded as UTF-8. */
-
-char_span
-file_cache_slot::get_full_file_content ()
-{
- char *line;
- ssize_t line_len;
- while (get_next_line (&line, &line_len))
- {
- }
- return char_span (m_data, m_nb_read);
-}
-
-/* Populate this slot for use on FILE_PATH and FP, dropping any
- existing cached content within it. */
-
-bool
-file_cache_slot::create (const file_cache::input_context &in_context,
- const char *file_path, FILE *fp,
- unsigned highest_use_count)
-{
- m_file_path = file_path ? xstrdup (file_path) : nullptr;
- if (m_fp)
- fclose (m_fp);
- m_error = false;
- m_fp = fp;
- if (m_alloc_offset)
- offset_buffer (-m_alloc_offset);
- m_nb_read = 0;
- m_line_start_idx = 0;
- m_line_num = 0;
- m_line_recent_first = 0;
- m_line_recent_last = 0;
- m_line_record.truncate (0);
- /* Ensure that this cache entry doesn't get evicted next time
- add_file_to_cache_tab is called. */
- m_use_count = ++highest_use_count;
- m_missing_trailing_newline = true;
-
-
- /* Check the input configuration to determine if we need to do any
- transformations, such as charset conversion or BOM skipping. */
- if (const char *input_charset = in_context.ccb (file_path))
- {
- /* Need a full-blown conversion of the input charset. */
- fclose (m_fp);
- m_fp = NULL;
- const cpp_converted_source cs
- = cpp_get_converted_source (file_path, input_charset);
- if (!cs.data)
- return false;
- if (m_data)
- XDELETEVEC (m_data);
- m_data = cs.data;
- m_nb_read = m_size = cs.len;
- m_alloc_offset = cs.data - cs.to_free;
- }
- else if (in_context.should_skip_bom)
- {
- if (read_data ())
- {
- const int offset = cpp_check_utf8_bom (m_data, m_nb_read);
- offset_buffer (offset);
- m_nb_read -= offset;
- }
- }
-
- return true;
-}
-
-void
-file_cache_slot::set_content (const char *buf, size_t sz)
-{
- m_data = (char *)xmalloc (sz);
- memcpy (m_data, buf, sz);
- m_nb_read = m_size = sz;
- m_alloc_offset = 0;
-
- if (m_fp)
- {
- fclose (m_fp);
- m_fp = nullptr;
- }
-}
-
-/* file_cache's ctor. */
-
-file_cache::file_cache ()
-: m_num_file_slots (16), m_file_slots (new file_cache_slot[m_num_file_slots])
-{
- initialize_input_context (nullptr, false);
-}
-
-/* file_cache's dtor. */
-
-file_cache::~file_cache ()
-{
- delete[] m_file_slots;
-}
-
-void
-file_cache::dump (FILE *out, int indent) const
-{
- for (size_t i = 0; i < m_num_file_slots; ++i)
- {
- fprintf (out, "%*sslot[%i]:\n", indent, "", (int)i);
- m_file_slots[i].dump (out, indent + 2);
- }
-}
-
-void
-file_cache::dump () const
-{
- dump (stderr, 0);
-}
-
-/* Lookup the cache used for the content of a given file accessed by
- caret diagnostic. If no cached file was found, create a new cache
- for this file, add it to the array of cached file and return
- it.
-
- This can return nullptr on a cache miss if FILE_PATH can't be opened for
- reading, or if the content can't be converted to the input_charset. */
-
-file_cache_slot*
-file_cache::lookup_or_add_file (const char *file_path)
-{
- file_cache_slot *r = lookup_file (file_path);
- if (r == NULL)
- r = add_file (file_path);
- return r;
-}
-
-/* Default constructor for a cache of file used by caret
- diagnostic. */
-
-file_cache_slot::file_cache_slot ()
-: m_use_count (0), m_file_path (NULL), m_fp (NULL), m_error (false), m_data (0),
- m_alloc_offset (0), m_size (0), m_nb_read (0), m_line_start_idx (0),
- m_line_num (0), m_missing_trailing_newline (true),
- m_line_recent_last (0), m_line_recent_first (0)
-{
- m_line_record.create (0);
- m_line_recent.create (1U << recent_cached_lines_shift);
- for (int i = 0; i < 1 << recent_cached_lines_shift; i++)
- m_line_recent.quick_push (file_cache_slot::line_info (0, 0, 0));
-}
-
-/* Destructor for a cache of file used by caret diagnostic. */
-
-file_cache_slot::~file_cache_slot ()
-{
- free (m_file_path);
- if (m_fp)
- {
- fclose (m_fp);
- m_fp = NULL;
- }
- if (m_data)
- {
- offset_buffer (-m_alloc_offset);
- XDELETEVEC (m_data);
- m_data = 0;
- }
- m_line_record.release ();
- m_line_recent.release ();
-}
-
-void
-file_cache_slot::dump (FILE *out, int indent) const
-{
- if (!m_file_path)
- {
- fprintf (out, "%*s(unused)\n", indent, "");
- return;
- }
- fprintf (out, "%*sfile_path: %s\n", indent, "", m_file_path);
- fprintf (out, "%*sfp: %p\n", indent, "", (void *)m_fp);
- fprintf (out, "%*sneeds_read_p: %i\n", indent, "", (int)needs_read_p ());
- fprintf (out, "%*sneeds_grow_p: %i\n", indent, "", (int)needs_grow_p ());
- fprintf (out, "%*suse_count: %i\n", indent, "", m_use_count);
- fprintf (out, "%*ssize: %zi\n", indent, "", m_size);
- fprintf (out, "%*snb_read: %zi\n", indent, "", m_nb_read);
- fprintf (out, "%*sstart_line_idx: %zi\n", indent, "", m_line_start_idx);
- fprintf (out, "%*sline_num: %zi\n", indent, "", m_line_num);
- fprintf (out, "%*smissing_trailing_newline: %i\n",
- indent, "", (int)m_missing_trailing_newline);
- fprintf (out, "%*sline records (%i):\n",
- indent, "", m_line_record.length ());
- int idx = 0;
- for (auto &line : m_line_record)
- fprintf (out, "%*s[%i]: line %zi: byte offsets: %zi-%zi\n",
- indent + 2, "",
- idx++, line.line_num, line.start_pos, line.end_pos);
-}
-
-/* Returns TRUE iff the cache would need to be filled with data coming
- from the file. That is, either the cache is empty or full or the
- current line is empty. Note that if the cache is full, it would
- need to be extended and filled again. */
-
-bool
-file_cache_slot::needs_read_p () const
-{
- return m_fp && (m_nb_read == 0
- || m_nb_read == m_size
- || (m_line_start_idx >= m_nb_read - 1));
-}
-
-/* Return TRUE iff the cache is full and thus needs to be
- extended. */
-
-bool
-file_cache_slot::needs_grow_p () const
-{
- return m_nb_read == m_size;
-}
-
-/* Grow the cache if it needs to be extended. */
-
-void
-file_cache_slot::maybe_grow ()
-{
- if (!needs_grow_p ())
- return;
-
- if (!m_data)
- {
- gcc_assert (m_size == 0 && m_alloc_offset == 0);
- m_size = buffer_size;
- m_data = XNEWVEC (char, m_size);
- }
- else
- {
- const int offset = m_alloc_offset;
- offset_buffer (-offset);
- m_size *= 2;
- m_data = XRESIZEVEC (char, m_data, m_size);
- offset_buffer (offset);
- }
-}
-
-/* Read more data into the cache. Extends the cache if need be.
- Returns TRUE iff new data could be read. */
-
-bool
-file_cache_slot::read_data ()
-{
- if (feof (m_fp) || ferror (m_fp))
- return false;
-
- maybe_grow ();
-
- char * from = m_data + m_nb_read;
- size_t to_read = m_size - m_nb_read;
- size_t nb_read = fread (from, 1, to_read, m_fp);
-
- if (ferror (m_fp))
- {
- m_error = true;
- return false;
- }
-
- m_nb_read += nb_read;
- return !!nb_read;
-}
-
-/* Read new data iff the cache needs to be filled with more data
- coming from the file FP. Return TRUE iff the cache was filled with
- mode data. */
-
-bool
-file_cache_slot::maybe_read_data ()
-{
- if (!needs_read_p ())
- return false;
- return read_data ();
-}
-
-/* Helper function for file_cache_slot::get_next_line (), to find the end of
- the next line. Returns with the memchr convention, i.e. nullptr if a line
- terminator was not found. We need to determine line endings in the same
- manner that libcpp does: any of \n, \r\n, or \r is a line ending. */
-
-static const char *
-find_end_of_line (const char *s, size_t len)
-{
- for (const auto end = s + len; s != end; ++s)
- {
- if (*s == '\n')
- return s;
- if (*s == '\r')
- {
- const auto next = s + 1;
- if (next == end)
- {
- /* Don't find the line ending if \r is the very last character
- in the buffer; we do not know if it's the end of the file or
- just the end of what has been read so far, and we wouldn't
- want to break in the middle of what's actually a \r\n
- sequence. Instead, we will handle the case of a file ending
- in a \r later. */
- break;
- }
- return (*next == '\n' ? next : s);
- }
- }
- return nullptr;
-}
-
-/* Read a new line from file FP, using C as a cache for the data
- coming from the file. Upon successful completion, *LINE is set to
- the beginning of the line found. *LINE points directly in the
- line cache and is only valid until the next call of get_next_line.
- *LINE_LEN is set to the length of the line. Note that the line
- does not contain any terminal delimiter. This function returns
- true if some data was read or process from the cache, false
- otherwise. Note that subsequent calls to get_next_line might
- make the content of *LINE invalid. */
-
-bool
-file_cache_slot::get_next_line (char **line, ssize_t *line_len)
-{
- /* Fill the cache with data to process. */
- maybe_read_data ();
-
- size_t remaining_size = m_nb_read - m_line_start_idx;
- if (remaining_size == 0)
- /* There is no more data to process. */
- return false;
-
- const char *line_start = m_data + m_line_start_idx;
-
- const char *next_line_start = NULL;
- size_t len = 0;
- const char *line_end = find_end_of_line (line_start, remaining_size);
- if (line_end == NULL)
- {
- /* We haven't found an end-of-line delimiter in the cache.
- Fill the cache with more data from the file and look again. */
- while (maybe_read_data ())
- {
- line_start = m_data + m_line_start_idx;
- remaining_size = m_nb_read - m_line_start_idx;
- line_end = find_end_of_line (line_start, remaining_size);
- if (line_end != NULL)
- {
- next_line_start = line_end + 1;
- break;
- }
- }
- if (line_end == NULL)
- {
- /* We've loaded all the file into the cache and still no
- terminator. Let's say the line ends up at one byte past the
- end of the file. This is to stay consistent with the case
- of when the line ends up with a terminator and line_end points to
- that. That consistency is useful below in the len calculation.
-
- If the file ends in a \r, we didn't identify it as a line
- terminator above, so do that now instead. */
- line_end = m_data + m_nb_read;
- if (m_nb_read && line_end[-1] == '\r')
- {
- --line_end;
- m_missing_trailing_newline = false;
- }
- else
- m_missing_trailing_newline = true;
- }
- else
- m_missing_trailing_newline = false;
- }
- else
- {
- next_line_start = line_end + 1;
- m_missing_trailing_newline = false;
- }
-
- if (m_error)
- return false;
-
- /* At this point, we've found the end of the of line. It either points to
- the line terminator or to one byte after the last byte of the file. */
- gcc_assert (line_end != NULL);
-
- len = line_end - line_start;
-
- if (m_line_start_idx < m_nb_read)
- *line = const_cast<char *> (line_start);
-
- ++m_line_num;
-
- /* Now update our line record so that re-reading lines from the
- before m_line_start_idx is faster. */
- size_t rlen = m_line_record.length ();
- /* Only update when beyond the previously cached region. */
- if (rlen == 0 || m_line_record[rlen - 1].line_num < m_line_num)
- {
- size_t spacing
- = (rlen >= 2
- ? (m_line_record[rlen - 1].line_num
- - m_line_record[rlen - 2].line_num) : 1);
- size_t delta
- = rlen >= 1 ? m_line_num - m_line_record[rlen - 1].line_num : 1;
-
- size_t max_size = line_record_size;
- /* One anchor per hundred input lines. */
- if (max_size == 0)
- max_size = m_line_num / 100;
-
- /* If we're too far beyond drop half of the lines to rebalance. */
- if (rlen == max_size && delta >= spacing * 2)
- {
- size_t j = 0;
- for (size_t i = 1; i < rlen; i += 2)
- m_line_record[j++] = m_line_record[i];
- m_line_record.truncate (j);
- rlen = j;
- spacing *= 2;
- }
-
- if (rlen < max_size && delta >= spacing)
- {
- file_cache_slot::line_info li (m_line_num, m_line_start_idx,
- line_end - m_data);
- m_line_record.safe_push (li);
- }
- }
-
- /* Cache recent tail lines separately for fast access. This assumes
- most accesses do not skip backwards. */
- if (m_line_recent_last == m_line_recent_first
- || m_line_recent[m_line_recent_last].line_num == m_line_num - 1)
- {
- size_t mask = ((size_t) 1 << recent_cached_lines_shift) - 1;
- m_line_recent_last = (m_line_recent_last + 1) & mask;
- if (m_line_recent_last == m_line_recent_first)
- m_line_recent_first = (m_line_recent_first + 1) & mask;
- m_line_recent[m_line_recent_last]
- = file_cache_slot::line_info (m_line_num, m_line_start_idx,
- line_end - m_data);
- }
-
- /* Update m_line_start_idx so that it points to the next line to be
- read. */
- if (next_line_start)
- m_line_start_idx = next_line_start - m_data;
- else
- /* We didn't find any terminal '\n'. Let's consider that the end
- of line is the end of the data in the cache. The next
- invocation of get_next_line will either read more data from the
- underlying file or return false early because we've reached the
- end of the file. */
- m_line_start_idx = m_nb_read;
-
- *line_len = len;
-
- return true;
-}
-
-/* Consume the next bytes coming from the cache (or from its
- underlying file if there are remaining unread bytes in the file)
- until we reach the next end-of-line (or end-of-file). There is no
- copying from the cache involved. Return TRUE upon successful
- completion. */
-
-bool
-file_cache_slot::goto_next_line ()
-{
- char *l;
- ssize_t len;
-
- return get_next_line (&l, &len);
-}
-
-/* Read an arbitrary line number LINE_NUM from the file cached in C.
- If the line was read successfully, *LINE points to the beginning
- of the line in the file cache and *LINE_LEN is the length of the
- line. *LINE is not nul-terminated, but may contain zero bytes.
- *LINE is only valid until the next call of read_line_num.
- This function returns bool if a line was read. */
-
-bool
-file_cache_slot::read_line_num (size_t line_num,
- char ** line, ssize_t *line_len)
-{
- gcc_assert (line_num > 0);
-
- /* Is the line in the recent line cache?
- This assumes the main file processing is only using
- a single contiguous cursor with only temporary excursions. */
- if (m_line_recent_first != m_line_recent_last
- && m_line_recent[m_line_recent_first].line_num <= line_num
- && m_line_recent[m_line_recent_last].line_num >= line_num)
- {
- line_info &last = m_line_recent[m_line_recent_last];
- size_t mask = (1U << recent_cached_lines_shift) - 1;
- size_t idx = (m_line_recent_last - (last.line_num - line_num)) & mask;
- line_info &recent = m_line_recent[idx];
- gcc_assert (recent.line_num == line_num);
- *line = m_data + recent.start_pos;
- *line_len = recent.end_pos - recent.start_pos;
- return true;
- }
-
- if (line_num <= m_line_num)
- {
- line_info l (line_num, 0, 0);
- int i = m_line_record.lower_bound (l, line_info::less_than);
- if (i == 0)
- {
- m_line_start_idx = 0;
- m_line_num = 0;
- }
- else if (m_line_record[i - 1].line_num == line_num)
- {
- /* We have the start/end of the line. */
- *line = m_data + m_line_record[i - 1].start_pos;
- *line_len = m_line_record[i - 1].end_pos - m_line_record[i - 1].start_pos;
- return true;
- }
- else
- {
- gcc_assert (m_line_record[i - 1].line_num < m_line_num);
- m_line_start_idx = m_line_record[i - 1].start_pos;
- m_line_num = m_line_record[i - 1].line_num - 1;
- }
- }
-
- /* Let's walk from line m_line_num up to line_num - 1, without
- copying any line. */
- while (m_line_num < line_num - 1)
- if (!goto_next_line ())
- return false;
-
- /* The line we want is the next one. Let's read it. */
- return get_next_line (line, line_len);
-}
-
-/* Return the physical source line that corresponds to FILE_PATH/LINE.
- The line is not nul-terminated. The returned pointer is only
- valid until the next call of location_get_source_line.
- Note that the line can contain several null characters,
- so the returned value's length has the actual length of the line.
- If the function fails, a NULL char_span is returned. */
-
-char_span
-file_cache::get_source_line (const char *file_path, int line)
-{
- char *buffer = NULL;
- ssize_t len;
-
- if (line == 0)
- return char_span (NULL, 0);
-
- if (file_path == NULL)
- return char_span (NULL, 0);
-
- file_cache_slot *c = lookup_or_add_file (file_path);
- if (c == NULL)
- return char_span (NULL, 0);
-
- bool read = c->read_line_num (line, &buffer, &len);
- if (!read)
- return char_span (NULL, 0);
-
- return char_span (buffer, len);
-}
-
/* Return a NUL-terminated copy of the source text between two locations, or
NULL if the arguments are invalid. The caller is responsible for freeing
the return value. */
char *
-get_source_text_between (file_cache &fc, location_t start, location_t end)
+get_source_text_between (diagnostics::file_cache &fc,
+ location_t start, location_t end)
{
expanded_location expstart
= expand_location_to_spelling_point (start, LOCATION_ASPECT_START);
@@ -1076,7 +170,8 @@ get_source_text_between (file_cache &fc, location_t start, location_t end)
/* For a single line we need to trim both edges. */
if (expstart.line == expend.line)
{
- char_span line = fc.get_source_line (expstart.file, expstart.line);
+ diagnostics::char_span line
+ = fc.get_source_line (expstart.file, expstart.line);
if (line.length () < 1)
return NULL;
int s = expstart.column - 1;
@@ -1093,7 +188,7 @@ get_source_text_between (file_cache &fc, location_t start, location_t end)
parts of the start and end lines off depending on column values. */
for (int lnum = expstart.line; lnum <= expend.line; ++lnum)
{
- char_span line = fc.get_source_line (expstart.file, lnum);
+ diagnostics::char_span line = fc.get_source_line (expstart.file, lnum);
if (line.length () < 1 && (lnum != expstart.line && lnum != expend.line))
continue;
@@ -1138,16 +233,6 @@ get_source_text_between (file_cache &fc, location_t start, location_t end)
return xstrdup (buf);
}
-
-char_span
-file_cache::get_source_file_content (const char *file_path)
-{
- file_cache_slot *c = lookup_or_add_file (file_path);
- if (c == nullptr)
- return char_span (nullptr, 0);
- return c->get_full_file_content ();
-}
-
/* Test if the location originates from the spelling location of a
builtin-tokens. That is, return TRUE if LOC is a (possibly
virtual) location of a built-in token that appears in the expansion
@@ -1280,13 +365,13 @@ make_location (location_t caret, source_range src_range)
source line in order to calculate the display width. If that cannot be done
for any reason, then returns the byte column as a fallback. */
int
-location_compute_display_column (file_cache &fc,
+location_compute_display_column (diagnostics::file_cache &fc,
expanded_location exploc,
const cpp_char_column_policy &policy)
{
if (!(exploc.file && *exploc.file && exploc.line && exploc.column))
return exploc.column;
- char_span line = fc.get_source_line (exploc.file, exploc.line);
+ diagnostics::char_span line = fc.get_source_line (exploc.file, exploc.line);
/* If line is NULL, this function returns exploc.column which is the
desired fallback. */
return cpp_byte_column_to_display_column (line.get_buffer (), line.length (),
@@ -1431,7 +516,7 @@ dump_labelled_location_range (FILE *stream,
void
dump_location_info (FILE *stream)
{
- file_cache fc;
+ diagnostics::file_cache fc;
/* Visualize the reserved locations. */
dump_labelled_location_range (stream, "RESERVED LOCATIONS",
@@ -1506,8 +591,8 @@ dump_location_info (FILE *stream)
{
/* Beginning of a new source line: draw the line. */
- char_span line_text = fc.get_source_line (exploc.file,
- exploc.line);
+ diagnostics::char_span line_text
+ = fc.get_source_line (exploc.file, exploc.line);
if (!line_text)
break;
fprintf (stream,
@@ -1524,10 +609,10 @@ dump_location_info (FILE *stream)
if (max_col > line_text.length ())
max_col = line_text.length () + 1;
- int len_lnum = num_digits (exploc.line);
+ int len_lnum = diagnostics::num_digits (exploc.line);
if (len_lnum < 3)
len_lnum = 3;
- int len_loc = num_digits (loc);
+ int len_loc = diagnostics::num_digits (loc);
if (len_loc < 5)
len_loc = 5;
@@ -1757,7 +842,7 @@ class auto_cpp_string_vec : public auto_vec <cpp_string>
static const char *
get_substring_ranges_for_loc (cpp_reader *pfile,
- file_cache &fc,
+ diagnostics::file_cache &fc,
string_concat_db *concats,
location_t strloc,
enum cpp_ttype type,
@@ -1837,7 +922,7 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
if (start.column > finish.column)
return "range endpoints are reversed";
- char_span line = fc.get_source_line (start.file, start.line);
+ diagnostics::char_span line = fc.get_source_line (start.file, start.line);
if (!line)
return "unable to read source line";
@@ -1852,7 +937,8 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
if (line.length () < (start.column - 1 + literal_length))
return "line is not wide enough";
- char_span literal = line.subspan (start.column - 1, literal_length);
+ diagnostics::char_span literal
+ = line.subspan (start.column - 1, literal_length);
cpp_string from;
from.len = literal_length;
@@ -1925,7 +1011,7 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
const char *
get_location_within_string (cpp_reader *pfile,
- file_cache &fc,
+ diagnostics::file_cache &fc,
string_concat_db *concats,
location_t strloc,
enum cpp_ttype type,
@@ -2008,7 +1094,7 @@ namespace selftest {
static const char *
get_source_range_for_char (cpp_reader *pfile,
- file_cache &fc,
+ diagnostics::file_cache &fc,
string_concat_db *concats,
location_t strloc,
enum cpp_ttype type,
@@ -2036,7 +1122,7 @@ get_source_range_for_char (cpp_reader *pfile,
static const char *
get_num_source_ranges_for_substring (cpp_reader *pfile,
- file_cache &fc,
+ diagnostics::file_cache &fc,
string_concat_db *concats,
location_t strloc,
enum cpp_ttype type,
@@ -2359,119 +1445,6 @@ test_make_location_nonpure_range_endpoints (const line_table_case &case_)
ASSERT_FALSE (IS_ADHOC_LOC (get_finish (not_aaa_eq_bbb)));
}
-/* Verify reading of a specific line LINENUM in TMP, FC. */
-
-static void
-check_line (temp_source_file &tmp, file_cache &fc, int linenum)
-{
- char_span line = fc.get_source_line (tmp.get_filename (), linenum);
- int n;
- const char *b = line.get_buffer ();
- size_t l = line.length ();
- char buf[5];
- ASSERT_LT (l, 5);
- memcpy (buf, b, l);
- buf[l] = '\0';
- ASSERT_TRUE (sscanf (buf, "%d", &n) == 1);
- ASSERT_EQ (n, linenum);
-}
-
-/* Test file cache replacement. */
-
-static void
-test_replacement ()
-{
- const int maxline = 1000;
-
- char *vec = XNEWVEC (char, maxline * 5);
- char *p = vec;
- int i;
- for (i = 1; i <= maxline; i++)
- p += sprintf (p, "%d\n", i);
-
- temp_source_file tmp (SELFTEST_LOCATION, ".txt", vec);
- free (vec);
- file_cache fc;
-
- for (i = 2; i <= maxline; i++)
- {
- check_line (tmp, fc, i);
- check_line (tmp, fc, i - 1);
- if (i >= 10)
- check_line (tmp, fc, i - 9);
- if (i >= 350) /* Exceed the look behind cache. */
- check_line (tmp, fc, i - 300);
- }
- for (i = 5; i <= maxline; i += 100)
- check_line (tmp, fc, i);
- for (i = 1; i <= maxline; i++)
- check_line (tmp, fc, i);
-}
-
-/* Verify reading of input files (e.g. for caret-based diagnostics). */
-
-static void
-test_reading_source_line ()
-{
- /* Create a tempfile and write some text to it. */
- temp_source_file tmp (SELFTEST_LOCATION, ".txt",
- "01234567890123456789\n"
- "This is the test text\n"
- "This is the 3rd line");
- file_cache fc;
-
- /* Read back a specific line from the tempfile. */
- char_span source_line = fc.get_source_line (tmp.get_filename (), 3);
- ASSERT_TRUE (source_line);
- ASSERT_TRUE (source_line.get_buffer () != NULL);
- ASSERT_EQ (20, source_line.length ());
- ASSERT_TRUE (!strncmp ("This is the 3rd line",
- source_line.get_buffer (), source_line.length ()));
-
- source_line = fc.get_source_line (tmp.get_filename (), 2);
- ASSERT_TRUE (source_line);
- ASSERT_TRUE (source_line.get_buffer () != NULL);
- ASSERT_EQ (21, source_line.length ());
- ASSERT_TRUE (!strncmp ("This is the test text",
- source_line.get_buffer (), source_line.length ()));
-
- source_line = fc.get_source_line (tmp.get_filename (), 4);
- ASSERT_FALSE (source_line);
- ASSERT_TRUE (source_line.get_buffer () == NULL);
-}
-
-/* Verify reading from buffers (e.g. for sarif-replay). */
-
-static void
-test_reading_source_buffer ()
-{
- const char *text = ("01234567890123456789\n"
- "This is the test text\n"
- "This is the 3rd line");
- const char *filename = "foo.txt";
- file_cache fc;
- fc.add_buffered_content (filename, text, strlen (text));
-
- /* Read back a specific line from the tempfile. */
- char_span source_line = fc.get_source_line (filename, 3);
- ASSERT_TRUE (source_line);
- ASSERT_TRUE (source_line.get_buffer () != NULL);
- ASSERT_EQ (20, source_line.length ());
- ASSERT_TRUE (!strncmp ("This is the 3rd line",
- source_line.get_buffer (), source_line.length ()));
-
- source_line = fc.get_source_line (filename, 2);
- ASSERT_TRUE (source_line);
- ASSERT_TRUE (source_line.get_buffer () != NULL);
- ASSERT_EQ (21, source_line.length ());
- ASSERT_TRUE (!strncmp ("This is the test text",
- source_line.get_buffer (), source_line.length ()));
-
- source_line = fc.get_source_line (filename, 4);
- ASSERT_FALSE (source_line);
- ASSERT_TRUE (source_line.get_buffer () == NULL);
-}
-
/* Tests of lexing. */
/* Verify that token TOK from PARSER has cpp_token_as_text
@@ -2628,7 +1601,7 @@ public:
line_table_test m_ltt;
cpp_reader_ptr m_parser;
temp_source_file m_tempfile;
- file_cache m_file_cache;
+ diagnostics::file_cache m_file_cache;
string_concat_db m_concats;
bool m_implicitly_expect_EOF;
};
@@ -4356,10 +3329,6 @@ input_cc_tests ()
for_each_line_table_case (test_lexer_string_locations_raw_string_unterminated);
for_each_line_table_case (test_lexer_char_constants);
- test_reading_source_line ();
- test_reading_source_buffer ();
- test_replacement ();
-
test_line_offset_overflow ();
test_cpp_utf8 ();
diff --git a/gcc/input.h b/gcc/input.h
index b0a1ca0..eeef290 100644
--- a/gcc/input.h
+++ b/gcc/input.h
@@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "line-map.h"
-class file_cache;
+namespace diagnostics { class file_cache; }
extern GTY(()) class line_maps *line_table;
extern GTY(()) class line_maps *saved_line_table;
@@ -69,110 +69,12 @@ extern expanded_location expand_location (location_t);
class cpp_char_column_policy;
extern int
-location_compute_display_column (file_cache &fc,
+location_compute_display_column (diagnostics::file_cache &fc,
expanded_location exploc,
const cpp_char_column_policy &policy);
-/* A class capturing the bounds of a buffer, to allow for run-time
- bounds-checking in a checked build. */
-
-class char_span
-{
- public:
- char_span (const char *ptr, size_t n_elts) : m_ptr (ptr), m_n_elts (n_elts) {}
-
- /* Test for a non-NULL pointer. */
- operator bool() const { return m_ptr; }
-
- /* Get length, not including any 0-terminator (which may not be,
- in fact, present). */
- size_t length () const { return m_n_elts; }
-
- const char *get_buffer () const { return m_ptr; }
-
- char operator[] (int idx) const
- {
- gcc_assert (idx >= 0);
- gcc_assert ((size_t)idx < m_n_elts);
- return m_ptr[idx];
- }
-
- char_span subspan (int offset, int n_elts) const
- {
- gcc_assert (offset >= 0);
- gcc_assert (offset < (int)m_n_elts);
- gcc_assert (n_elts >= 0);
- gcc_assert (offset + n_elts <= (int)m_n_elts);
- return char_span (m_ptr + offset, n_elts);
- }
-
- char *xstrdup () const
- {
- return ::xstrndup (m_ptr, m_n_elts);
- }
-
- private:
- const char *m_ptr;
- size_t m_n_elts;
-};
-
extern char *
-get_source_text_between (file_cache &, location_t, location_t);
-
-/* Forward decl of slot within file_cache, so that the definition doesn't
- need to be in this header. */
-class file_cache_slot;
-
-/* A cache of source files for use when emitting diagnostics
- (and in a few places in the C/C++ frontends).
-
- Results are only valid until the next call to the cache, as
- slots can be evicted.
-
- Filenames are stored by pointer, and so must outlive the cache
- instance. */
-
-class file_cache
-{
- public:
- file_cache ();
- ~file_cache ();
-
- void dump (FILE *out, int indent) const;
- void DEBUG_FUNCTION dump () const;
-
- file_cache_slot *lookup_or_add_file (const char *file_path);
- void forcibly_evict_file (const char *file_path);
-
- /* See comments in diagnostic.h about the input conversion context. */
- struct input_context
- {
- diagnostic_input_charset_callback ccb;
- bool should_skip_bom;
- };
- void initialize_input_context (diagnostic_input_charset_callback ccb,
- bool should_skip_bom);
-
- char_span get_source_file_content (const char *file_path);
- char_span get_source_line (const char *file_path, int line);
- bool missing_trailing_newline_p (const char *file_path);
-
- void add_buffered_content (const char *file_path,
- const char *buffer,
- size_t sz);
-
- void tune (size_t num_file_slots, size_t lines);
-
- private:
- file_cache_slot *evicted_cache_tab_entry (unsigned *highest_use_count);
- file_cache_slot *add_file (const char *file_path);
- file_cache_slot *lookup_file (const char *file_path);
-
- private:
- size_t m_num_file_slots;
- file_cache_slot *m_file_slots;
- input_context m_input_context;
-};
+get_source_text_between (diagnostics::file_cache &, location_t, location_t);
extern expanded_location
expand_location_to_spelling_point (location_t,
diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
index 114f5a9..bf2fac8 100644
--- a/gcc/internal-fn.cc
+++ b/gcc/internal-fn.cc
@@ -3652,8 +3652,8 @@ expand_scatter_store_optab_fn (internal_fn, gcall *stmt, direct_optab optab)
internal_fn ifn = gimple_call_internal_fn (stmt);
int rhs_index = internal_fn_stored_value_index (ifn);
tree base = gimple_call_arg (stmt, 0);
- tree offset = gimple_call_arg (stmt, 1);
- tree scale = gimple_call_arg (stmt, 2);
+ tree offset = gimple_call_arg (stmt, internal_fn_offset_index (ifn));
+ tree scale = gimple_call_arg (stmt, internal_fn_scale_index (ifn));
tree rhs = gimple_call_arg (stmt, rhs_index);
rtx base_rtx = expand_normal (base);
@@ -3678,12 +3678,12 @@ expand_scatter_store_optab_fn (internal_fn, gcall *stmt, direct_optab optab)
/* Expand {MASK_,}GATHER_LOAD call CALL using optab OPTAB. */
static void
-expand_gather_load_optab_fn (internal_fn, gcall *stmt, direct_optab optab)
+expand_gather_load_optab_fn (internal_fn ifn, gcall *stmt, direct_optab optab)
{
tree lhs = gimple_call_lhs (stmt);
tree base = gimple_call_arg (stmt, 0);
- tree offset = gimple_call_arg (stmt, 1);
- tree scale = gimple_call_arg (stmt, 2);
+ tree offset = gimple_call_arg (stmt, internal_fn_offset_index (ifn));
+ tree scale = gimple_call_arg (stmt, internal_fn_scale_index (ifn));
rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
rtx base_rtx = expand_normal (base);
@@ -4967,11 +4967,13 @@ internal_fn_len_index (internal_fn fn)
return 2;
case IFN_MASK_LEN_SCATTER_STORE:
+ return 6;
+
case IFN_MASK_LEN_STRIDED_LOAD:
return 5;
case IFN_MASK_LEN_GATHER_LOAD:
- return 6;
+ return 7;
case IFN_COND_LEN_FMA:
case IFN_COND_LEN_FMS:
@@ -5075,7 +5077,7 @@ internal_fn_else_index (internal_fn fn)
case IFN_MASK_GATHER_LOAD:
case IFN_MASK_LEN_GATHER_LOAD:
- return 5;
+ return 6;
default:
return -1;
@@ -5110,7 +5112,7 @@ internal_fn_mask_index (internal_fn fn)
case IFN_MASK_SCATTER_STORE:
case IFN_MASK_LEN_GATHER_LOAD:
case IFN_MASK_LEN_SCATTER_STORE:
- return 4;
+ return 5;
case IFN_VCOND_MASK:
case IFN_VCOND_MASK_LEN:
@@ -5135,10 +5137,11 @@ internal_fn_stored_value_index (internal_fn fn)
case IFN_MASK_STORE:
case IFN_MASK_STORE_LANES:
+ return 3;
case IFN_SCATTER_STORE:
case IFN_MASK_SCATTER_STORE:
case IFN_MASK_LEN_SCATTER_STORE:
- return 3;
+ return 4;
case IFN_LEN_STORE:
return 4;
@@ -5152,6 +5155,75 @@ internal_fn_stored_value_index (internal_fn fn)
}
}
+/* If FN has an alias pointer return its index, otherwise return -1. */
+
+int
+internal_fn_alias_ptr_index (internal_fn fn)
+{
+ switch (fn)
+ {
+ case IFN_MASK_LOAD:
+ case IFN_MASK_LEN_LOAD:
+ case IFN_GATHER_LOAD:
+ case IFN_MASK_GATHER_LOAD:
+ case IFN_MASK_LEN_GATHER_LOAD:
+ case IFN_SCATTER_STORE:
+ case IFN_MASK_SCATTER_STORE:
+ case IFN_MASK_LEN_SCATTER_STORE:
+ return 1;
+
+ default:
+ return -1;
+ }
+}
+
+/* If FN is a gather/scatter return the index of its offset argument,
+ otherwise return -1. */
+
+int
+internal_fn_offset_index (internal_fn fn)
+{
+ if (!internal_gather_scatter_fn_p (fn))
+ return -1;
+
+ switch (fn)
+ {
+ case IFN_GATHER_LOAD:
+ case IFN_MASK_GATHER_LOAD:
+ case IFN_MASK_LEN_GATHER_LOAD:
+ case IFN_SCATTER_STORE:
+ case IFN_MASK_SCATTER_STORE:
+ case IFN_MASK_LEN_SCATTER_STORE:
+ return 2;
+
+ default:
+ return -1;
+ }
+}
+
+/* If FN is a gather/scatter return the index of its scale argument,
+ otherwise return -1. */
+
+int
+internal_fn_scale_index (internal_fn fn)
+{
+ if (!internal_gather_scatter_fn_p (fn))
+ return -1;
+
+ switch (fn)
+ {
+ case IFN_GATHER_LOAD:
+ case IFN_MASK_GATHER_LOAD:
+ case IFN_MASK_LEN_GATHER_LOAD:
+ case IFN_SCATTER_STORE:
+ case IFN_MASK_SCATTER_STORE:
+ case IFN_MASK_LEN_SCATTER_STORE:
+ return 3;
+
+ default:
+ return -1;
+ }
+}
/* Store all supported else values for the optab referred to by ICODE
in ELSE_VALS. The index of the else operand must be specified in
@@ -5230,13 +5302,9 @@ internal_gather_scatter_fn_supported_p (internal_fn ifn, tree vector_type,
&& insn_operand_matches (icode, 2 + output_ops, GEN_INT (unsigned_p))
&& insn_operand_matches (icode, 3 + output_ops, GEN_INT (scale));
- /* For gather the optab's operand indices do not match the IFN's because
- the latter does not have the extension operand (operand 3). It is
- implicitly added during expansion so we use the IFN's else index + 1.
- */
if (ok && elsvals)
get_supported_else_vals
- (icode, internal_fn_else_index (IFN_MASK_GATHER_LOAD) + 1, *elsvals);
+ (icode, internal_fn_else_index (IFN_MASK_GATHER_LOAD), *elsvals);
return ok;
}
diff --git a/gcc/internal-fn.h b/gcc/internal-fn.h
index 02731ea..fd21694 100644
--- a/gcc/internal-fn.h
+++ b/gcc/internal-fn.h
@@ -240,6 +240,9 @@ extern int internal_fn_mask_index (internal_fn);
extern int internal_fn_len_index (internal_fn);
extern int internal_fn_else_index (internal_fn);
extern int internal_fn_stored_value_index (internal_fn);
+extern int internal_fn_offset_index (internal_fn fn);
+extern int internal_fn_scale_index (internal_fn fn);
+extern int internal_fn_alias_ptr_index (internal_fn fn);
extern bool internal_gather_scatter_fn_supported_p (internal_fn, tree,
tree, tree, int,
vec<int> * = nullptr);
diff --git a/gcc/ipa-pure-const.cc b/gcc/ipa-pure-const.cc
index 93297ed..2519fb8 100644
--- a/gcc/ipa-pure-const.cc
+++ b/gcc/ipa-pure-const.cc
@@ -200,7 +200,7 @@ function_always_visible_to_compiler_p (tree decl)
by the function. */
static hash_set<tree> *
-suggest_attribute (diagnostic_option_id option, tree decl, bool known_finite,
+suggest_attribute (diagnostics::option_id option, tree decl, bool known_finite,
hash_set<tree> *warned_about,
const char * attrib_name)
{
diff --git a/gcc/ira.cc b/gcc/ira.cc
index 979a034..4eebc9c 100644
--- a/gcc/ira.cc
+++ b/gcc/ira.cc
@@ -2113,6 +2113,87 @@ ira_get_dup_out_num (int op_num, alternative_mask alts,
+/* Return true if a replacement of SRC by DEST does not lead to unsatisfiable
+ asm. A replacement is valid if SRC or DEST are not constrained in asm
+ inputs of a single asm statement. See match_asm_constraints_2() for more
+ details. TODO: As in match_asm_constraints_2() consider alternatives more
+ precisely. */
+
+static bool
+valid_replacement_for_asm_input_p_1 (const_rtx asmops, const_rtx src, const_rtx dest)
+{
+ int ninputs = ASM_OPERANDS_INPUT_LENGTH (asmops);
+ rtvec inputs = ASM_OPERANDS_INPUT_VEC (asmops);
+ for (int i = 0; i < ninputs; ++i)
+ {
+ rtx input_src = RTVEC_ELT (inputs, i);
+ const char *constraint_src
+ = ASM_OPERANDS_INPUT_CONSTRAINT (asmops, i);
+ if (rtx_equal_p (input_src, src)
+ && strchr (constraint_src, '{') != nullptr)
+ for (int j = 0; j < ninputs; ++j)
+ {
+ rtx input_dest = RTVEC_ELT (inputs, j);
+ const char *constraint_dest
+ = ASM_OPERANDS_INPUT_CONSTRAINT (asmops, j);
+ if (rtx_equal_p (input_dest, dest)
+ && strchr (constraint_dest, '{') != nullptr)
+ return false;
+ }
+ }
+ return true;
+}
+
+/* Return true if a replacement of SRC by DEST does not lead to unsatisfiable
+ asm. A replacement is valid if SRC or DEST are not constrained in asm
+ inputs of a single asm statement. The final check is done in function
+ valid_replacement_for_asm_input_p_1. */
+
+static bool
+valid_replacement_for_asm_input_p (const_rtx src, const_rtx dest)
+{
+ /* Bail out early if there is no asm statement. */
+ if (!crtl->has_asm_statement)
+ return true;
+ for (df_ref use = DF_REG_USE_CHAIN (REGNO (src));
+ use;
+ use = DF_REF_NEXT_REG (use))
+ {
+ struct df_insn_info *use_info = DF_REF_INSN_INFO (use);
+ /* Only check real uses, not artificial ones. */
+ if (use_info)
+ {
+ rtx_insn *insn = DF_REF_INSN (use);
+ rtx pat = PATTERN (insn);
+ if (asm_noperands (pat) <= 0)
+ continue;
+ if (GET_CODE (pat) == SET)
+ {
+ if (!valid_replacement_for_asm_input_p_1 (SET_SRC (pat), src, dest))
+ return false;
+ }
+ else if (GET_CODE (pat) == PARALLEL)
+ for (int i = 0, len = XVECLEN (pat, 0); i < len; ++i)
+ {
+ rtx asmops = XVECEXP (pat, 0, i);
+ if (GET_CODE (asmops) == SET)
+ asmops = SET_SRC (asmops);
+ if (GET_CODE (asmops) == ASM_OPERANDS
+ && !valid_replacement_for_asm_input_p_1 (asmops, src, dest))
+ return false;
+ }
+ else if (GET_CODE (pat) == ASM_OPERANDS)
+ {
+ if (!valid_replacement_for_asm_input_p_1 (pat, src, dest))
+ return false;
+ }
+ else
+ gcc_unreachable ();
+ }
+ }
+ return true;
+}
+
/* Search forward to see if the source register of a copy insn dies
before either it or the destination register is modified, but don't
scan past the end of the basic block. If so, we can replace the
@@ -2162,7 +2243,8 @@ decrease_live_ranges_number (void)
auto-inc memory reference, so we must disallow this
optimization on them. */
|| sregno == STACK_POINTER_REGNUM
- || dregno == STACK_POINTER_REGNUM)
+ || dregno == STACK_POINTER_REGNUM
+ || !valid_replacement_for_asm_input_p (src, dest))
continue;
dest_death = NULL_RTX;
diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog
index adee3de..da88cc6 100644
--- a/gcc/jit/ChangeLog
+++ b/gcc/jit/ChangeLog
@@ -1,3 +1,30 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * dummy-frontend.cc: Update usage of "diagnostic_info" to
+ explicitly refer to "diagnostics::diagnostic_info".
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * dummy-frontend.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * dummy-frontend.cc: Update for diagnostic_context becoming
+ diagnostics::context.
+ * jit-playback.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * jit-playback.cc: Update for diagnostic_info moving into
+ namespace diagnostics.
+ * jit-playback.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * dummy-frontend.cc: Update for move of diagnostics output formats
+ into namespace "diagnostics" as "sinks".
+
2025-04-28 David Malcolm <dmalcolm@redhat.com>
* dummy-frontend.cc: Drop include of "make-unique.h".
diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc
index bf31a9d..3ffca92 100644
--- a/gcc/jit/dummy-frontend.cc
+++ b/gcc/jit/dummy-frontend.cc
@@ -32,7 +32,7 @@ along with GCC; see the file COPYING3. If not see
#include "attribs.h"
#include "cgraph.h"
#include "target.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/text-sink.h"
#include "print-tree.h"
#include <mpfr.h>
@@ -993,16 +993,16 @@ struct ggc_root_tab jit_root_tab[] =
LAST_GGC_ROOT_TAB
};
-/* Subclass of diagnostic_output_format for libgccjit: like text
+/* Subclass of diagnostics::text_sink for libgccjit: like text
output, but capture the message and call add_diagnostic with it
on the active playback context. */
-class jit_diagnostic_listener : public diagnostic_text_output_format
+class jit_diagnostic_listener : public diagnostics::text_sink
{
public:
- jit_diagnostic_listener (diagnostic_context &dc,
+ jit_diagnostic_listener (diagnostics::context &dc,
gcc::jit::playback::context &playback_ctxt)
- : diagnostic_text_output_format (dc),
+ : diagnostics::text_sink (dc),
m_playback_ctxt (playback_ctxt)
{
}
@@ -1015,13 +1015,13 @@ public:
(void *)&m_playback_ctxt);
}
- void on_report_diagnostic (const diagnostic_info &info,
- diagnostic_t orig_diag_kind) final override
+ void on_report_diagnostic (const diagnostics::diagnostic_info &info,
+ enum diagnostics::kind orig_diag_kind) final override
{
JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ());
/* Let the text output format do most of the work. */
- diagnostic_text_output_format::on_report_diagnostic (info, orig_diag_kind);
+ diagnostics::text_sink::on_report_diagnostic (info, orig_diag_kind);
const char *text = pp_formatted_text (get_printer ());
@@ -1041,8 +1041,8 @@ private:
/* Implementation of "begin_diagnostic". */
static void
-jit_begin_diagnostic (diagnostic_text_output_format &,
- const diagnostic_info */*diagnostic*/)
+jit_begin_diagnostic (diagnostics::text_sink &,
+ const diagnostics::diagnostic_info */*diagnostic*/)
{
gcc_assert (gcc::jit::active_playback_ctxt);
JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ());
@@ -1054,9 +1054,9 @@ jit_begin_diagnostic (diagnostic_text_output_format &,
/* Implementation of "end_diagnostic". */
static void
-jit_end_diagnostic (diagnostic_text_output_format &,
- const diagnostic_info *,
- diagnostic_t)
+jit_end_diagnostic (diagnostics::text_sink &,
+ const diagnostics::diagnostic_info *,
+ enum diagnostics::kind)
{
gcc_assert (gcc::jit::active_playback_ctxt);
JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ());
@@ -1081,13 +1081,13 @@ jit_langhook_init (void)
}
gcc_assert (global_dc);
- diagnostic_text_starter (global_dc) = jit_begin_diagnostic;
- diagnostic_text_finalizer (global_dc) = jit_end_diagnostic;
+ diagnostics::text_starter (global_dc) = jit_begin_diagnostic;
+ diagnostics::text_finalizer (global_dc) = jit_end_diagnostic;
auto sink
= std::make_unique<jit_diagnostic_listener>
(*global_dc,
*gcc::jit::active_playback_ctxt);
- global_dc->set_output_format (std::move (sink));
+ global_dc->set_sink (std::move (sink));
build_common_tree_nodes (flag_signed_char);
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index 6946f10..4473d8b 100644
--- a/gcc/jit/jit-playback.cc
+++ b/gcc/jit/jit-playback.cc
@@ -3892,7 +3892,7 @@ add_error_va (location *loc, const char *fmt, va_list ap)
void
playback::context::
add_diagnostic (const char *text,
- const diagnostic_info &diagnostic)
+ const diagnostics::diagnostic_info &diagnostic)
{
/* Get location information (if any) from the diagnostic.
The recording::context::add_error[_va] methods require a
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index e9a5c38..b0625dc 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -30,8 +30,11 @@ along with GCC; see the file COPYING3. If not see
#include "jit-recording.h"
-class diagnostic_context;
-struct diagnostic_info;
+namespace diagnostics
+{
+ class context;
+ struct diagnostic_info;
+}
namespace gcc {
@@ -298,7 +301,7 @@ public:
void
add_diagnostic (const char *text,
- const diagnostic_info &diagnostic);
+ const diagnostics::diagnostic_info &diagnostic);
void
set_tree_location (tree t, location *loc);
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 010aaed..518509a 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "hooks.h"
-struct diagnostic_info;
+namespace diagnostics { struct diagnostic_info; }
class substring_loc;
/* Note to creators of new hooks:
@@ -49,9 +49,9 @@ extern void lhd_print_tree_nothing (FILE *, tree, int);
extern const char *lhd_decl_printable_name (tree, int);
extern const char *lhd_dwarf_name (tree, int);
extern int lhd_types_compatible_p (tree, tree);
-extern void lhd_print_error_function (diagnostic_text_output_format &,
+extern void lhd_print_error_function (diagnostics::text_sink &,
const char *,
- const struct diagnostic_info *);
+ const diagnostics::diagnostic_info *);
extern void lhd_set_decl_assembler_name (tree decl);
extern void lhd_overwrite_decl_assembler_name (tree decl, tree name);
extern bool lhd_warn_unused_global_decl (const_tree);
@@ -71,7 +71,7 @@ extern tree lhd_builtin_function (tree);
extern tree lhd_enum_underlying_base_type (const_tree);
/* Declarations of default tree inlining hooks. */
-extern void lhd_initialize_diagnostics (diagnostic_context *);
+extern void lhd_initialize_diagnostics (diagnostics::context *);
extern void lhd_init_options (unsigned int,
struct cl_decoded_option *);
extern bool lhd_complain_wrong_lang_p (const struct cl_option *);
diff --git a/gcc/langhooks.cc b/gcc/langhooks.cc
index 194701f..20d27a6 100644
--- a/gcc/langhooks.cc
+++ b/gcc/langhooks.cc
@@ -38,7 +38,7 @@ along with GCC; see the file COPYING3. If not see
#include "stor-layout.h"
#include "cgraph.h"
#include "debug.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/text-sink.h"
/* Do nothing; in many cases the default hook. */
@@ -330,7 +330,7 @@ global_decl_processing (void)
/* Called to perform language-specific initialization of CTX. */
void
-lhd_initialize_diagnostics (diagnostic_context *ctx ATTRIBUTE_UNUSED)
+lhd_initialize_diagnostics (diagnostics::context *ctx ATTRIBUTE_UNUSED)
{
}
@@ -369,11 +369,11 @@ lhd_handle_option (size_t code ATTRIBUTE_UNUSED,
/* The default function to print out name of current function that caused
an error. */
void
-lhd_print_error_function (diagnostic_text_output_format &text_output,
+lhd_print_error_function (diagnostics::text_sink &text_output,
const char *file,
- const diagnostic_info *diagnostic)
+ const diagnostics::diagnostic_info *diagnostic)
{
- diagnostic_context *const context = &text_output.get_context ();
+ diagnostics::context *const context = &text_output.get_context ();
if (diagnostic_last_function_changed (context, diagnostic))
{
pretty_printer *const pp = text_output.get_printer ();
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index cb03c83..3bf4152 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see
/* FIXME: This file should be #include-d after tree.h (for enum tree_code). */
-struct diagnostic_info;
+namespace diagnostics { struct diagnostic_info; }
struct gimplify_omp_ctx;
@@ -421,7 +421,7 @@ struct lang_hooks
/* Callback used to perform language-specific initialization for the
global diagnostic context structure. */
- void (*initialize_diagnostics) (diagnostic_context *);
+ void (*initialize_diagnostics) (diagnostics::context *);
/* Beginning the main source file. */
void (*preprocess_main_file) (cpp_reader *, line_maps *,
@@ -547,9 +547,9 @@ struct lang_hooks
/* Called by diagnostic_report_current_function to print out function name
for textual diagnostic output. */
- void (*print_error_function) (diagnostic_text_output_format &,
+ void (*print_error_function) (diagnostics::text_sink &,
const char *,
- const struct diagnostic_info *);
+ const diagnostics::diagnostic_info *);
/* Convert a character from the host's to the target's character
set. The character should be in what C calls the "basic source
diff --git a/gcc/lazily-created.h b/gcc/lazily-created.h
new file mode 100644
index 0000000..a6010ca
--- /dev/null
+++ b/gcc/lazily-created.h
@@ -0,0 +1,51 @@
+/* Template for deferring object creation until the object is needed.
+ Copyright (C) 2024-2025 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_LAZILY_CREATED_H
+#define GCC_LAZILY_CREATED_H
+
+/* A template for deferring object creation for a type T until the object
+ is needed, to avoid potentially expensive creation of T unless it's
+ actually needed (e.g. for directed graphs associated with a diagnostic,
+ which are ignored by the default "text" sink). */
+
+template <typename T>
+class lazily_created
+{
+ public:
+ virtual ~lazily_created () {}
+
+ const T &
+ get_or_create () const
+ {
+ if (!m_object)
+ m_object = create_object ();
+ gcc_assert (m_object);
+ return *m_object;
+ }
+
+private:
+ virtual std::unique_ptr<T>
+ create_object () const = 0;
+
+ mutable std::unique_ptr<T> m_object;
+};
+
+#endif /* ! GCC_LAZILY_CREATED_H */
diff --git a/gcc/libgdiagnostics.cc b/gcc/libgdiagnostics.cc
index 172f19c..7351d336 100644
--- a/gcc/libgdiagnostics.cc
+++ b/gcc/libgdiagnostics.cc
@@ -25,18 +25,19 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "intl.h"
#include "diagnostic.h"
-#include "diagnostic-color.h"
-#include "diagnostic-url.h"
-#include "diagnostic-metadata.h"
-#include "diagnostic-path.h"
-#include "diagnostic-client-data-hooks.h"
-#include "diagnostic-format-sarif.h"
-#include "diagnostic-format-text.h"
-#include "diagnostic-output-spec.h"
-#include "diagnostic-digraphs.h"
-#include "diagnostic-state-graphs.h"
-#include "logical-location.h"
-#include "edit-context.h"
+#include "diagnostics/color.h"
+#include "diagnostics/file-cache.h"
+#include "diagnostics/url.h"
+#include "diagnostics/metadata.h"
+#include "diagnostics/paths.h"
+#include "diagnostics/client-data-hooks.h"
+#include "diagnostics/sarif-sink.h"
+#include "diagnostics/text-sink.h"
+#include "diagnostics/output-spec.h"
+#include "diagnostics/digraphs.h"
+#include "diagnostics/state-graphs.h"
+#include "diagnostics/logical-locations.h"
+#include "diagnostics/changes.h"
#include "libgdiagnostics.h"
#include "libgdiagnostics-private.h"
#include "pretty-print-format-impl.h"
@@ -210,7 +211,7 @@ struct diagnostic_logical_location
};
static diagnostic_event_id
-as_diagnostic_event_id (diagnostic_event_id_t id)
+as_diagnostic_event_id (diagnostics::paths::event_id_t id)
{
return id.zero_based ();
}
@@ -232,7 +233,7 @@ public:
FILE *dst_stream,
enum diagnostic_colorize colorize);
- diagnostic_source_printing_options &get_source_printing_options ()
+ diagnostics::source_printing_options &get_source_printing_options ()
{
return m_source_printing;
}
@@ -241,12 +242,12 @@ public:
set_colorize (enum diagnostic_colorize colorize);
static void
- text_starter (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic);
+ text_starter (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic);
private:
- diagnostic_text_output_format *m_inner_sink; // borrowed from dc
- diagnostic_source_printing_options m_source_printing;
+ diagnostics::text_sink *m_inner_sink; // borrowed from dc
+ diagnostics::source_printing_options m_source_printing;
};
/* A token_printer that makes a deep copy of the pp_token_list
@@ -346,7 +347,7 @@ public:
sarif_sink (diagnostic_manager &mgr,
FILE *dst_stream,
const diagnostic_file *main_input_file,
- const sarif_generation_options &sarif_gen_opts);
+ const diagnostics::sarif_generation_options &sarif_gen_opts);
};
struct diagnostic_message_buffer
@@ -458,19 +459,23 @@ round_alloc_size (size_t s)
return s;
}
-class impl_logical_location_manager : public logical_location_manager
+class impl_logical_location_manager
+ : public diagnostics::logical_locations::manager
{
public:
+ using key = diagnostics::logical_locations::key;
+ using kind = diagnostics::logical_locations::kind;
+
static const diagnostic_logical_location *
- ptr_from_key (logical_location k)
+ ptr_from_key (key k)
{
return k.cast_to<const diagnostic_logical_location *> ();
}
- static logical_location
+ static key
key_from_ptr (const diagnostic_logical_location *ptr)
{
- return logical_location::from_ptr (ptr);
+ return key::from_ptr (ptr);
}
const char *get_short_name (key k) const final override
@@ -497,7 +502,7 @@ public:
return nullptr;
}
- enum logical_location_kind get_kind (key k) const final override
+ kind get_kind (key k) const final override
{
auto loc = ptr_from_key (k);
gcc_assert (loc);
@@ -507,45 +512,45 @@ public:
gcc_unreachable ();
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_FUNCTION:
- return logical_location_kind::function;
+ return kind::function;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_MEMBER:
- return logical_location_kind::member;
+ return kind::member;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_MODULE:
- return logical_location_kind::module_;
+ return kind::module_;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_NAMESPACE:
- return logical_location_kind::namespace_;
+ return kind::namespace_;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_TYPE:
- return logical_location_kind::type;
+ return kind::type;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_RETURN_TYPE:
- return logical_location_kind::return_type;
+ return kind::return_type;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_PARAMETER:
- return logical_location_kind::parameter;
+ return kind::parameter;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_VARIABLE:
- return logical_location_kind::variable;
+ return kind::variable;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_ELEMENT:
- return logical_location_kind::element;
+ return kind::element;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_ATTRIBUTE:
- return logical_location_kind::attribute;
+ return kind::attribute;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_TEXT:
- return logical_location_kind::text;
+ return kind::text;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_COMMENT:
- return logical_location_kind::comment;
+ return kind::comment;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROCESSING_INSTRUCTION:
- return logical_location_kind::processing_instruction;
+ return kind::processing_instruction;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_DTD:
- return logical_location_kind::dtd;
+ return kind::dtd;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_DECLARATION:
- return logical_location_kind::declaration;
+ return kind::declaration;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_OBJECT:
- return logical_location_kind::object;
+ return kind::object;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_ARRAY:
- return logical_location_kind::array;
+ return kind::array;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_PROPERTY:
- return logical_location_kind::property;
+ return kind::property;
case DIAGNOSTIC_LOGICAL_LOCATION_KIND_VALUE:
- return logical_location_kind::value;
+ return kind::value;
}
}
@@ -564,25 +569,28 @@ public:
}
};
-class impl_diagnostic_client_data_hooks : public diagnostic_client_data_hooks
+class impl_diagnostic_client_data_hooks : public diagnostics::client_data_hooks
{
public:
impl_diagnostic_client_data_hooks (diagnostic_manager &mgr)
: m_mgr (mgr)
{}
- const client_version_info *get_any_version_info () const final override;
+ const diagnostics::client_version_info *
+ get_any_version_info () const final override;
- const logical_location_manager *
+ const diagnostics::logical_locations::manager *
get_logical_location_manager () const final override
{
return &m_logical_location_manager;
}
- logical_location get_current_logical_location () const final override;
+ diagnostics::logical_locations::key
+ get_current_logical_location () const final override;
const char * maybe_get_sarif_source_language (const char *filename)
const final override;
- void add_sarif_invocation_properties (sarif_object &invocation_obj)
+ void
+ add_sarif_invocation_properties (diagnostics::sarif_object &invocation_obj)
const final override;
private:
@@ -590,7 +598,7 @@ private:
impl_logical_location_manager m_logical_location_manager;
};
-class impl_client_version_info : public client_version_info
+class impl_client_version_info : public diagnostics::client_version_info
{
public:
const char *get_tool_name () const final override
@@ -649,23 +657,26 @@ public:
m_dc.set_show_cwe (true);
m_dc.set_show_rules (true);
m_dc.m_show_column = true;
- m_dc.m_source_printing.enabled = true;
- m_dc.m_source_printing.colorize_source_p = true;
+ auto &source_printing_opts = m_dc.get_source_printing_options ();
+ source_printing_opts.enabled = true;
+ source_printing_opts.colorize_source_p = true;
/* We don't currently expose a way for clients to manipulate the
following. */
- m_dc.m_source_printing.show_labels_p = true;
- m_dc.m_source_printing.show_line_numbers_p = true;
- m_dc.m_source_printing.min_margin_width = 6;
+ source_printing_opts.show_labels_p = true;
+ source_printing_opts.show_line_numbers_p = true;
+ source_printing_opts.min_margin_width = 6;
m_dc.set_path_format (DPF_INLINE_EVENTS);
m_dc.m_client_aux_data = this;
m_dc.set_client_data_hooks
(std::make_unique<impl_diagnostic_client_data_hooks> (*this));
- diagnostic_text_starter (&m_dc) = diagnostic_text_sink::text_starter;
+ diagnostics::text_starter (&m_dc) = diagnostic_text_sink::text_starter;
- m_edit_context = std::make_unique <edit_context> (m_dc.get_file_cache ());
+ m_change_set
+ = std::make_unique <diagnostics::changes::change_set>
+ (m_dc.get_file_cache ());
}
~diagnostic_manager ()
@@ -686,9 +697,9 @@ public:
}
line_maps *get_line_table () { return &m_line_table; }
- diagnostic_context &get_dc () { return m_dc; }
+ diagnostics::context &get_dc () { return m_dc; }
- const logical_location_manager &
+ const diagnostics::logical_locations::manager &
get_logical_location_manager () const
{
auto mgr = m_dc.get_logical_location_manager ();
@@ -818,7 +829,8 @@ public:
const diagnostic *get_current_diag () { return m_current_diag; }
- const client_version_info *get_client_version_info () const
+ const diagnostics::client_version_info *
+ get_client_version_info () const
{
return &m_client_version_info;
}
@@ -884,7 +896,7 @@ private:
return phys_loc;
}
- diagnostic_context m_dc;
+ diagnostics::context m_dc;
line_maps m_line_table;
impl_client_version_info m_client_version_info;
std::vector<std::unique_ptr<sink>> m_sinks;
@@ -896,7 +908,7 @@ private:
logical_locs_map_t m_logical_locs;
const diagnostic *m_current_diag;
const diagnostic_logical_location *m_prev_diag_logical_loc;
- std::unique_ptr<edit_context> m_edit_context;
+ std::unique_ptr<diagnostics::changes::change_set> m_change_set;
};
class impl_rich_location : public rich_location
@@ -925,7 +937,7 @@ private:
char *m_text;
};
-class impl_rule : public diagnostic_metadata::rule
+class impl_rule : public diagnostics::metadata::rule
{
public:
impl_rule (const char *title, const char *url)
@@ -985,7 +997,7 @@ struct diagnostic_edge : public diagnostics::digraphs::edge
}
};
-class libgdiagnostics_path_event : public diagnostic_event
+class libgdiagnostics_path_event : public diagnostics::paths::event
{
public:
libgdiagnostics_path_event (const diagnostic_physical_location *physical_loc,
@@ -1002,7 +1014,7 @@ public:
gcc_assert (m_msg_buf);
}
- /* diagnostic_event vfunc implementations. */
+ /* diagnostics::paths::event vfunc implementations. */
location_t get_location () const final override
{
@@ -1023,7 +1035,8 @@ public:
}
}
- logical_location get_logical_location () const final override
+ diagnostics::logical_locations::key
+ get_logical_location () const final override
{
return impl_logical_location_manager::key_from_ptr (m_logical_loc);
}
@@ -1038,7 +1051,7 @@ public:
return false; // TODO
}
- diagnostic_thread_id_t get_thread_id () const final override
+ diagnostics::paths::thread_id_t get_thread_id () const final override
{
return 0;
}
@@ -1081,7 +1094,7 @@ private:
std::unique_ptr<diagnostic_message_buffer> m_msg_buf;
};
-class libgdiagnostics_path_thread : public diagnostic_thread
+class libgdiagnostics_path_thread : public diagnostics::paths::thread
{
public:
libgdiagnostics_path_thread (const char *name) : m_name (name) {}
@@ -1096,15 +1109,15 @@ private:
/* This has to be a "struct" as it is exposed in the C API. */
-struct diagnostic_execution_path : public diagnostic_path
+struct diagnostic_execution_path : public diagnostics::paths::path
{
- diagnostic_execution_path (const logical_location_manager &logical_loc_mgr)
- : diagnostic_path (logical_loc_mgr),
+ diagnostic_execution_path (const diagnostics::logical_locations::manager &logical_loc_mgr)
+ : diagnostics::paths::path (logical_loc_mgr),
m_thread ("")
{
}
- diagnostic_event_id_t
+ diagnostics::paths::event_id_t
add_event_va (const diagnostic_physical_location *physical_loc,
const diagnostic_logical_location *logical_loc,
unsigned stack_depth,
@@ -1139,19 +1152,19 @@ struct diagnostic_execution_path : public diagnostic_path
return m_events.size () - 1;
}
- /* diagnostic_path vfunc implementations. */
+ /* diagnostics::paths::path vfunc implementations. */
unsigned num_events () const final override
{
return m_events.size ();
}
- const diagnostic_event & get_event (int idx) const final override
+ const diagnostics::paths::event & get_event (int idx) const final override
{
return *m_events[idx];
}
unsigned num_threads () const final override { return 1; }
- const diagnostic_thread &
- get_thread (diagnostic_thread_id_t) const final override
+ const diagnostics::paths::thread &
+ get_thread (diagnostics::paths::thread_id_t) const final override
{
return m_thread;
}
@@ -1160,9 +1173,10 @@ struct diagnostic_execution_path : public diagnostic_path
same_function_p (int event_idx_a,
int event_idx_b) const final override
{
+ using logical_location = diagnostics::logical_locations::key;
logical_location logical_loc_a
= m_events[event_idx_a]->get_logical_location ();
- logical_location logical_loc_b
+ logical_location logical_loc_b
= m_events[event_idx_b]->get_logical_location ();
/* Pointer equality, as we uniqify logical location instances. */
@@ -1174,13 +1188,14 @@ private:
std::vector<std::unique_ptr<libgdiagnostics_path_event>> m_events;
};
-class prebuilt_digraphs : public diagnostics::digraphs::lazy_digraphs
+class prebuilt_digraphs
+ : public lazily_created<std::vector<std::unique_ptr<diagnostics::digraphs::digraph>>>
{
public:
using digraph = diagnostics::digraphs::digraph;
std::unique_ptr<std::vector<std::unique_ptr<digraph>>>
- create_digraphs () const final override
+ create_object () const final override
{
return std::make_unique<std::vector<std::unique_ptr<digraph>>> (std::move (m_digraphs));
}
@@ -1219,7 +1234,7 @@ public:
enum diagnostic_level get_level () const { return m_level; }
rich_location *get_rich_location () { return &m_rich_loc; }
- const diagnostic_metadata *get_metadata () { return &m_metadata; }
+ const diagnostics::metadata *get_metadata () { return &m_metadata; }
void set_cwe (unsigned cwe_id)
{
@@ -1315,28 +1330,28 @@ private:
enum diagnostic_level m_level;
impl_rich_location m_rich_loc;
const diagnostic_logical_location *m_logical_loc;
- diagnostic_metadata m_metadata;
+ diagnostics::metadata m_metadata;
prebuilt_digraphs m_graphs;
std::vector<std::unique_ptr<range_label>> m_labels;
std::vector<std::unique_ptr<impl_rule>> m_rules;
std::unique_ptr<diagnostic_execution_path> m_path;
};
-static diagnostic_t
-diagnostic_t_from_diagnostic_level (enum diagnostic_level level)
+static enum diagnostics::kind
+diagnostics_kind_from_diagnostic_level (enum diagnostic_level level)
{
switch (level)
{
default:
gcc_unreachable ();
case DIAGNOSTIC_LEVEL_ERROR:
- return DK_ERROR;
+ return diagnostics::kind::error;
case DIAGNOSTIC_LEVEL_WARNING:
- return DK_WARNING;
+ return diagnostics::kind::warning;
case DIAGNOSTIC_LEVEL_NOTE:
- return DK_NOTE;
+ return diagnostics::kind::note;
case DIAGNOSTIC_LEVEL_SORRY:
- return DK_SORRY;
+ return diagnostics::kind::sorry;
}
}
@@ -1346,7 +1361,7 @@ diagnostic_file::set_buffered_content (const char *buf, size_t sz)
m_content = std::make_unique<content_buffer> (buf, sz);
// Populate file_cache:
- file_cache &fc = m_mgr.get_dc ().get_file_cache ();
+ diagnostics::file_cache &fc = m_mgr.get_dc ().get_file_cache ();
fc.add_buffered_content (m_name.get_str (), buf, sz);
}
@@ -1364,13 +1379,13 @@ diagnostic_physical_location::get_file () const
/* class impl_diagnostic_client_data_hooks. */
-const client_version_info *
+const diagnostics::client_version_info *
impl_diagnostic_client_data_hooks::get_any_version_info () const
{
return m_mgr.get_client_version_info ();
}
-logical_location
+diagnostics::logical_locations::key
impl_diagnostic_client_data_hooks::get_current_logical_location () const
{
gcc_assert (m_mgr.get_current_diag ());
@@ -1388,7 +1403,7 @@ maybe_get_sarif_source_language (const char *filename) const
void
impl_diagnostic_client_data_hooks::
-add_sarif_invocation_properties (sarif_object &) const
+add_sarif_invocation_properties (diagnostics::sarif_object &) const
{
// No-op.
}
@@ -1399,10 +1414,10 @@ diagnostic_text_sink::diagnostic_text_sink (diagnostic_manager &mgr,
FILE *dst_stream,
enum diagnostic_colorize colorize)
: sink (mgr),
- m_source_printing (mgr.get_dc ().m_source_printing)
+ m_source_printing (mgr.get_dc ().get_source_printing_options ())
{
auto inner_sink
- = std::make_unique<diagnostic_text_output_format> (mgr.get_dc (),
+ = std::make_unique<diagnostics::text_sink> (mgr.get_dc (),
&m_source_printing);
inner_sink->get_printer ()->set_output_stream (dst_stream);
m_inner_sink = inner_sink.get ();
@@ -1432,11 +1447,11 @@ diagnostic_text_sink::set_colorize (enum diagnostic_colorize colorize)
}
void
-diagnostic_text_sink::text_starter (diagnostic_text_output_format &text_output,
- const diagnostic_info *info)
+diagnostic_text_sink::text_starter (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *info)
{
- gcc_assert (info->x_data);
- const diagnostic &diag = *static_cast<const diagnostic *> (info->x_data);
+ gcc_assert (info->m_x_data);
+ const diagnostic &diag = *static_cast<const diagnostic *> (info->m_x_data);
pretty_printer *pp = text_output.get_printer ();
const diagnostic_logical_location *diag_logical_loc
= diag.get_logical_location ();
@@ -1502,15 +1517,17 @@ diagnostic_text_sink::text_starter (diagnostic_text_output_format &text_output,
/* class sarif_sink : public sink. */
-sarif_sink::sarif_sink (diagnostic_manager &mgr,
- FILE *dst_stream,
- const diagnostic_file *main_input_file,
- const sarif_generation_options &sarif_gen_opts)
+sarif_sink::
+sarif_sink (diagnostic_manager &mgr,
+ FILE *dst_stream,
+ const diagnostic_file *main_input_file,
+ const diagnostics::sarif_generation_options &sarif_gen_opts)
: sink (mgr)
{
- diagnostic_output_file output_file (dst_stream, false,
- label_text::borrow ("sarif_sink"));
- auto serialization = std::make_unique<sarif_serialization_format_json> (true);
+ diagnostics::output_file output_file (dst_stream, false,
+ label_text::borrow ("sarif_sink"));
+ auto serialization
+ = std::make_unique<diagnostics::sarif_serialization_format_json> (true);
auto inner_sink = make_sarif_sink (mgr.get_dc (),
*mgr.get_line_table (),
std::move (serialization),
@@ -1585,7 +1602,7 @@ diagnostic_manager::write_patch (FILE *dst_stream)
{
pretty_printer pp;
pp.set_output_stream (dst_stream);
- m_edit_context->print_diff (&pp, true);
+ m_change_set->print_diff (&pp, true);
pp_flush (&pp);
}
@@ -1599,13 +1616,14 @@ diagnostic_manager::emit_va (diagnostic &diag, const char *msgid, va_list *args)
{
m_dc.begin_group ();
- diagnostic_info info;
+ diagnostics::diagnostic_info info;
GCC_DIAGNOSTIC_PUSH_IGNORED(-Wsuggest-attribute=format)
diagnostic_set_info (&info, msgid, args, diag.get_rich_location (),
- diagnostic_t_from_diagnostic_level (diag.get_level ()));
+ diagnostics_kind_from_diagnostic_level
+ (diag.get_level ()));
GCC_DIAGNOSTIC_POP
- info.metadata = diag.get_metadata ();
- info.x_data = &diag;
+ info.m_metadata = diag.get_metadata ();
+ info.m_x_data = &diag;
diagnostic_report_diagnostic (&m_dc, &info);
m_dc.end_group ();
@@ -1613,7 +1631,7 @@ GCC_DIAGNOSTIC_POP
rich_location *rich_loc = diag.get_rich_location ();
if (rich_loc->fixits_can_be_auto_applied_p ())
- m_edit_context->add_fixits (rich_loc);
+ m_change_set->add_fixits (rich_loc);
m_prev_diag_logical_loc = diag.get_logical_location ();
m_current_diag = nullptr;
@@ -1648,7 +1666,7 @@ diagnostic_manager::new_execution_path ()
void
diagnostic_manager::take_global_graph (std::unique_ptr<diagnostic_graph> graph)
{
- class prebuilt_lazy_digraph : public diagnostics::digraphs::lazy_digraph
+ class prebuilt_lazy_digraph : public lazily_created<diagnostics::digraphs::digraph>
{
public:
prebuilt_lazy_digraph (std::unique_ptr<diagnostic_graph> graph)
@@ -1657,7 +1675,7 @@ diagnostic_manager::take_global_graph (std::unique_ptr<diagnostic_graph> graph)
}
std::unique_ptr<diagnostics::digraphs::digraph>
- create_digraph () const final override
+ create_object () const final override
{
return std::move (m_graph);
}
@@ -1808,7 +1826,7 @@ diagnostic_manager_add_sarif_sink (diagnostic_manager *diag_mgr,
FAIL_IF_NULL (dst_stream);
FAIL_IF_NULL (main_input_file);
- sarif_generation_options sarif_gen_opts;
+ diagnostics::sarif_generation_options sarif_gen_opts;
switch (version)
{
default:
@@ -1816,10 +1834,11 @@ diagnostic_manager_add_sarif_sink (diagnostic_manager *diag_mgr,
__func__, (int)version);
abort ();
case DIAGNOSTIC_SARIF_VERSION_2_1_0:
- sarif_gen_opts.m_version = sarif_version::v2_1_0;
+ sarif_gen_opts.m_version = diagnostics::sarif_version::v2_1_0;
break;
case DIAGNOSTIC_SARIF_VERSION_2_2_PRERELEASE:
- sarif_gen_opts.m_version = sarif_version::v2_2_prerelease_2024_08_08;
+ sarif_gen_opts.m_version
+ = diagnostics::sarif_version::v2_2_prerelease_2024_08_08;
break;
}
@@ -1949,12 +1968,12 @@ diagnostic_manager_debug_dump_location (const diagnostic_manager *diag_mgr,
diag_mgr->set_line_table_global ();
const expanded_location exp_loc (expand_location (cpplib_loc));
- diagnostic_context dc;
+ diagnostics::context dc;
diagnostic_initialize (&dc, 0);
dc.m_show_column = true;
- diagnostic_text_output_format text_format (dc);
- label_text loc_text = text_format.get_location_text (exp_loc);
+ diagnostics::text_sink text_output (dc);
+ label_text loc_text = text_output.get_location_text (exp_loc);
fprintf (out, "%s", loc_text.get ());
diagnostic_finish (&dc);
@@ -2293,11 +2312,12 @@ diagnostic_execution_path_add_event (diagnostic_execution_path *path,
va_list args;
va_start (args, gmsgid);
- diagnostic_event_id_t result = path->add_event_va (physical_loc,
- logical_loc,
- stack_depth,
- nullptr,
- gmsgid, &args);
+ diagnostics::paths::event_id_t result
+ = path->add_event_va (physical_loc,
+ logical_loc,
+ stack_depth,
+ nullptr,
+ gmsgid, &args);
va_end (args);
return as_diagnostic_event_id (result);
@@ -2316,11 +2336,12 @@ diagnostic_execution_path_add_event_va (diagnostic_execution_path *path,
FAIL_IF_NULL (path);
FAIL_IF_NULL (gmsgid);
- diagnostic_event_id_t result = path->add_event_va (physical_loc,
- logical_loc,
- stack_depth,
- nullptr,
- gmsgid, args);
+ diagnostics::paths::event_id_t result
+ = path->add_event_va (physical_loc,
+ logical_loc,
+ stack_depth,
+ nullptr,
+ gmsgid, args);
return as_diagnostic_event_id (result);
}
@@ -2409,7 +2430,7 @@ diagnostic_logical_location_get_decorated_name (const diagnostic_logical_locatio
namespace {
-struct spec_context : public diagnostics_output_spec::context
+struct spec_context : public diagnostics::output_spec::context
{
public:
spec_context (const char *option_name,
diff --git a/gcc/libsarifreplay.cc b/gcc/libsarifreplay.cc
index 8158698..1e4a74f 100644
--- a/gcc/libsarifreplay.cc
+++ b/gcc/libsarifreplay.cc
@@ -1865,7 +1865,7 @@ handle_thread_flow_location_object (const json::object &tflow_loc_obj,
libgdiagnostics::graph state_graph;
if (auto sarif_state_graph
= maybe_get_property_bag_value<json::object> (tflow_loc_obj,
- "gcc/diagnostic_event/state_graph"))
+ "gcc/diagnostics/paths/event/state_graph"))
{
enum status s
= handle_graph_object (*sarif_state_graph, run_obj, state_graph);
diff --git a/gcc/lra-constraints.cc b/gcc/lra-constraints.cc
index c941d2f..83f8fda 100644
--- a/gcc/lra-constraints.cc
+++ b/gcc/lra-constraints.cc
@@ -114,6 +114,7 @@
#include "target.h"
#include "rtl.h"
#include "tree.h"
+#include "stmt.h"
#include "predict.h"
#include "df.h"
#include "memmodel.h"
@@ -2168,6 +2169,7 @@ process_alt_operands (int only_alternative)
bool costly_p;
enum reg_class cl;
const HARD_REG_SET *cl_filter;
+ HARD_REG_SET hard_reg_constraint;
/* Calculate some data common for all alternatives to speed up the
function. */
@@ -2545,6 +2547,17 @@ process_alt_operands (int only_alternative)
cl_filter = nullptr;
goto reg;
+ case '{':
+ {
+ int regno = decode_hard_reg_constraint (p);
+ gcc_assert (regno >= 0);
+ cl = REGNO_REG_CLASS (regno);
+ CLEAR_HARD_REG_SET (hard_reg_constraint);
+ SET_HARD_REG_BIT (hard_reg_constraint, regno);
+ cl_filter = &hard_reg_constraint;
+ goto reg;
+ }
+
default:
cn = lookup_constraint (p);
switch (get_constraint_type (cn))
diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc
index 27405e8..cb293f2 100644
--- a/gcc/lto-wrapper.cc
+++ b/gcc/lto-wrapper.cc
@@ -2274,13 +2274,13 @@ public:
: gcc_diagnostic_option_manager (0 /* lang_mask */)
{
}
- int option_enabled_p (diagnostic_option_id) const final override
+ int option_enabled_p (diagnostics::option_id) const final override
{
return true;
}
- char *make_option_name (diagnostic_option_id,
- diagnostic_t,
- diagnostic_t) const final override
+ char *make_option_name (diagnostics::option_id,
+ enum diagnostics::kind,
+ enum diagnostics::kind) const final override
{
return nullptr;
}
diff --git a/gcc/m2/ChangeLog b/gcc/m2/ChangeLog
index f7254f9..6babeb9 100644
--- a/gcc/m2/ChangeLog
+++ b/gcc/m2/ChangeLog
@@ -1,3 +1,81 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gm2-gcc/m2linemap.cc: Update usage of "diagnostic_info" to
+ explicitly refer to "diagnostics::diagnostic_info".
+ * gm2-gcc/rtegraph.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gm2-gcc/m2linemap.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * gm2-gcc/rtegraph.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gm2-gcc/m2color.cc: Update for move of diagnostic-color.h to
+ diagnostics/color.h.
+
+2025-07-23 Gaius Mulley <gaiusmod2@gmail.com>
+
+ * gm2-libs/M2EXCEPTION.mod (M2Exception): Add return
+ exException in case Raise completes.
+
+2025-07-23 Gaius Mulley <gaiusmod2@gmail.com>
+
+ PR modula2/121164
+ * gm2-compiler/P1SymBuild.mod: Remove PutProcTypeParam.
+ Remove PutProcTypeParam.
+ (CheckFileName): Remove.
+ (P1EndBuildDefinitionModule): Correct spelling.
+ (P1EndBuildImplementationModule): Ditto.
+ (P1EndBuildProgramModule): Ditto.
+ (EndBuildInnerModule): Ditto.
+ * gm2-compiler/P2SymBuild.mod (P2EndBuildDefModule): Correct
+ spelling.
+ (P2EndBuildImplementationModule): Ditto.
+ (P2EndBuildProgramModule): Ditto.
+ (EndBuildInnerModule): Ditto.
+ (CheckFormalParameterSection): Ditto.
+ * gm2-compiler/P3SymBuild.mod (P3EndBuildDefModule): Ditto.
+ * gm2-compiler/PCSymBuild.mod (PCEndBuildDefModule): Ditto.
+ (fixupProcedureType): Pass tok to PutProcTypeVarParam.
+ Pass tok to PutProcTypeParam.
+ * gm2-compiler/SymbolTable.def (PutProcTypeParam): Add tok
+ parameter.
+ (PutProcTypeVarParam): Ditto.
+ * gm2-compiler/SymbolTable.mod (SymParam): At change type to
+ CARDINAL.
+ New field FullTok.
+ New field Scope.
+ (SymVarParam): At change type to CARDINAL.
+ New field FullTok.
+ New field Scope.
+ (GetVarDeclTok): Check ShadowVar for NulSym and return At.
+ (PutParam): Initialize FullTok.
+ Initialize At.
+ Initialize Scope.
+ (PutVarParam): Initialize FullTok.
+ Assign At.
+ Initialize Scope.
+ (AddProcedureProcTypeParam): Add tok parameter.
+ (GetScope): Add ParamSym and VarParamSym clause.
+ (PutProcTypeVarParam): Add tok parameter.
+ Initialize At.
+ Initialize FullTok.
+ (GetDeclaredDefinition): Clause ParamSym return At.
+ Clause VarParamSym return At.
+ (GetDeclaredModule): Ditto.
+ (PutDeclaredDefinition): Remove clause ParamSym.
+ Remove clause VarParamSym.
+ (PutDeclaredModule): Remove clause ParamSym.
+ Remove clause VarParamSym.
+
+2025-07-18 Gaius Mulley <gaiusmod2@gmail.com>
+
+ PR modula2/121164
+ * gm2-libs/ARRAYOFCHAR.mod (Write): Rename 2nd parameter
+ name a to str.
+
2025-07-01 Gaius Mulley <gaiusmod2@gmail.com>
PR modula2/120912
diff --git a/gcc/m2/gm2-compiler/P1SymBuild.mod b/gcc/m2/gm2-compiler/P1SymBuild.mod
index 02d4ac7..08a0fc3 100644
--- a/gcc/m2/gm2-compiler/P1SymBuild.mod
+++ b/gcc/m2/gm2-compiler/P1SymBuild.mod
@@ -79,7 +79,6 @@ FROM SymbolTable IMPORT NulSym,
MakeSubscript, PutSubscript,
PutArray, GetType, IsArray,
IsProcType, MakeProcType,
- PutProcTypeVarParam, PutProcTypeParam,
PutProcedureBuiltin, PutProcedureInline,
GetSymName,
ResolveImports, PutDeclared,
@@ -109,42 +108,6 @@ VAR
(*
- CheckFileName - checks to see that the module name matches the file name.
-*)
-
-(*
-PROCEDURE CheckFileName (tok: CARDINAL; name: Name; ModuleType: ARRAY OF CHAR) ;
-VAR
- ext,
- basename: INTEGER ;
- s,
- FileName: String ;
-BEGIN
- FileName := GetFileName() ;
- basename := RIndex(FileName, '/', 0) ;
- IF basename=-1
- THEN
- basename := 0
- END ;
- ext := RIndex(FileName, '.', 0) ;
- IF ext=-1
- THEN
- ext := 0
- END ;
- FileName := Slice(FileName, basename, ext) ;
- IF EqualCharStar(FileName, KeyToCharStar(name))
- THEN
- FileName := KillString(FileName)
- ELSE
- s := ConCat (InitString (ModuleType),
- Mark (InitString (" module name {%1Ea} is inconsistant with the filename {%F{%2a}}"))) ;
- MetaErrorString2 (s, MakeError (tok, name), MakeErrorS (tok, FileName))
- END
-END CheckFileName ;
-*)
-
-
-(*
StartBuildDefinitionModule - Creates a definition module and starts
a new scope.
@@ -227,7 +190,7 @@ BEGIN
END ;
IF NameStart#NameEnd
THEN
- MetaError1 ('inconsistant definition module name {%1Wa}', MakeError (start, NameStart))
+ MetaError1 ('inconsistent definition module name {%1Wa}', MakeError (start, NameStart))
END ;
LeaveBlock
END P1EndBuildDefinitionModule ;
@@ -301,7 +264,7 @@ BEGIN
IF NameStart#NameEnd
THEN
MetaErrorT1 (end,
- 'inconsistant implementation module name {%1Wa}', MakeError (start, NameStart))
+ 'inconsistent implementation module name {%1Wa}', MakeError (start, NameStart))
END ;
LeaveBlock
END P1EndBuildImplementationModule ;
@@ -381,7 +344,7 @@ BEGIN
IF NameStart#NameEnd
THEN
MetaErrorT1 (end,
- 'inconsistant program module name {%1Wa}', MakeError (start, NameStart))
+ 'inconsistent program module name {%1Wa}', MakeError (start, NameStart))
END ;
LeaveBlock
END P1EndBuildProgramModule ;
@@ -446,7 +409,7 @@ BEGIN
IF NameStart#NameEnd
THEN
MetaErrorT1 (end,
- 'inconsistant inner module name {%1Wa}', MakeError (start, NameStart))
+ 'inconsistent inner module name {%1Wa}', MakeError (start, NameStart))
END ;
LeaveBlock
END EndBuildInnerModule ;
diff --git a/gcc/m2/gm2-compiler/P2SymBuild.mod b/gcc/m2/gm2-compiler/P2SymBuild.mod
index 5c82ec8..3bb3e47 100644
--- a/gcc/m2/gm2-compiler/P2SymBuild.mod
+++ b/gcc/m2/gm2-compiler/P2SymBuild.mod
@@ -356,7 +356,7 @@ BEGIN
END ;
IF NameStart#NameEnd
THEN
- WriteFormat2('inconsistant definition module name, module began as (%a) and ended with (%a)', NameStart, NameEnd)
+ WriteFormat2('inconsistent definition module name, module began as (%a) and ended with (%a)', NameStart, NameEnd)
END ;
M2Error.LeaveErrorScope
END P2EndBuildDefModule ;
@@ -425,7 +425,7 @@ BEGIN
PopT (NameEnd) ;
IF NameStart#NameEnd
THEN
- WriteFormat1('inconsistant implementation module name %a', NameStart)
+ WriteFormat1('inconsistent implementation module name %a', NameStart)
END ;
M2Error.LeaveErrorScope
END P2EndBuildImplementationModule ;
@@ -499,7 +499,7 @@ BEGIN
END ;
IF NameStart#NameEnd
THEN
- WriteFormat2('inconsistant program module name %a does not match %a', NameStart, NameEnd)
+ WriteFormat2('inconsistent program module name %a does not match %a', NameStart, NameEnd)
END ;
M2Error.LeaveErrorScope
END P2EndBuildProgramModule ;
@@ -564,7 +564,7 @@ BEGIN
PopT(NameEnd) ;
IF NameStart#NameEnd
THEN
- WriteFormat2('inconsistant inner module name %a does not match %a',
+ WriteFormat2('inconsistent inner module name %a does not match %a',
NameStart, NameEnd)
END ;
M2Error.LeaveErrorScope
@@ -1835,13 +1835,13 @@ BEGIN
(* WarnStringAt (InitString ('parampos?'), OperandTok (pi)) ; *)
IF Unbounded AND (NOT IsUnboundedParam (ProcSym, prevkind, ParamTotal+i))
THEN
- ParameterError ('declaration of procedure {%%1a} in the %s differs from the %s, {%%2N} parameter is inconsistant, %s',
+ ParameterError ('declaration of procedure {%%1a} in the %s differs from the %s, {%%2N} parameter is inconsistent, %s',
'the parameter {%3EHa} was not declared as an ARRAY OF type',
'the parameter {%3EVa} was declared as an ARRAY OF type',
ParamTotal+i, ProcSym, curkind, prevkind)
ELSIF (NOT Unbounded) AND IsUnboundedParam (ProcSym, prevkind, ParamTotal+i)
THEN
- ParameterError ('declaration of procedure {%%1a} in the %s differs from the %s, {%%2N} parameter is inconsistant, %s',
+ ParameterError ('declaration of procedure {%%1a} in the %s differs from the %s, {%%2N} parameter is inconsistent, %s',
'the parameter {%3EHa} was declared as an ARRAY OF type',
'the parameter {%3EVa} was not declared as an ARRAY OF type',
ParamTotal+i, ProcSym, curkind, prevkind)
@@ -1850,7 +1850,7 @@ BEGIN
THEN
IF GetDimension (GetNthParam (ProcSym, prevkind, ParamTotal+1)) # ndim
THEN
- ParameterError ('declaration of procedure {%%1a} in the %s differs from the %s, {%%2N} parameter is inconsistant, %s',
+ ParameterError ('declaration of procedure {%%1a} in the %s differs from the %s, {%%2N} parameter is inconsistent, %s',
'the dynamic array parameter {%3EHa} was declared with a different of dimensions',
'the dynamic array parameter {%3EVa} was declared with a different of dimensions',
ParamTotal+i, ProcSym, curkind, prevkind)
@@ -1859,14 +1859,14 @@ BEGIN
IF isVarParam AND (NOT IsVarParam (ProcSym, prevkind, ParamTotal+i))
THEN
(* Expecting non VAR parameter. *)
- ParameterError ('declaration of procedure {%%1a} in the %s differs from the %s, {%%2N} parameter is inconsistant, %s',
+ ParameterError ('declaration of procedure {%%1a} in the %s differs from the %s, {%%2N} parameter is inconsistent, %s',
'{%3EHa} was not declared as a {%kVAR} parameter',
'{%3EVa} was declared as a {%kVAR} parameter',
ParamTotal+i, ProcSym, curkind, prevkind)
ELSIF (NOT isVarParam) AND IsVarParam (ProcSym, prevkind, ParamTotal+i)
THEN
(* Expecting VAR pamarater. *)
- ParameterError ('declaration of procedure {%%1a} in the %s differs from the %s, {%%2N} parameter is inconsistant, %s',
+ ParameterError ('declaration of procedure {%%1a} in the %s differs from the %s, {%%2N} parameter is inconsistent, %s',
'{%3EHa} was declared as a {%kVAR} parameter',
'{%3EVa} was not declared as a {%kVAR} parameter',
ParamTotal+i, ProcSym, curkind, prevkind)
@@ -1877,7 +1877,7 @@ BEGIN
IF GetSymName (ParamI) # OperandT (pi)
THEN
(* Different parameter names. *)
- ParameterError ('procedure {%%1a} in the %s differs from the %s, {%%2N} parameter name is inconsistant, %s',
+ ParameterError ('procedure {%%1a} in the %s differs from the %s, {%%2N} parameter name is inconsistent, %s',
'named as {%3EVa}',
'named as {%3EVa}',
ParamTotal+i, ProcSym, curkind, prevkind)
@@ -1897,7 +1897,7 @@ BEGIN
(NOT IsUnknown(SkipType(ParamIType)))
THEN
(* Different parameter types. *)
- ParameterError ('declaration in the %s differs from the %s, {%%2N} parameter is inconsistant, %s',
+ ParameterError ('declaration in the %s differs from the %s, {%%2N} parameter is inconsistent, %s',
'the parameter {%3EHa} was declared with a different type',
'the parameter {%3EVa} was declared with a different type',
ParamTotal+i, ProcSym, curkind, prevkind)
@@ -3072,10 +3072,10 @@ BEGIN
IF Var=VarTok
THEN
(* VAR parameter *)
- PutProcTypeVarParam(ProcTypeSym, TypeSym, IsUnbounded(TypeSym))
+ PutProcTypeVarParam (tok, ProcTypeSym, TypeSym, IsUnbounded (TypeSym))
ELSE
(* Non VAR parameter *)
- PutProcTypeParam(ProcTypeSym, TypeSym, IsUnbounded(TypeSym))
+ PutProcTypeParam (tok, ProcTypeSym, TypeSym, IsUnbounded (TypeSym))
END ;
PushT(ProcTypeSym) ;
Annotate("%1s(%1d)||proc type")
diff --git a/gcc/m2/gm2-compiler/P3SymBuild.mod b/gcc/m2/gm2-compiler/P3SymBuild.mod
index c4877f7..096057e 100644
--- a/gcc/m2/gm2-compiler/P3SymBuild.mod
+++ b/gcc/m2/gm2-compiler/P3SymBuild.mod
@@ -126,7 +126,7 @@ BEGIN
PopT(NameStart) ;
IF NameStart#NameEnd
THEN
- WriteFormat2('inconsistant definition module was named (%a) and concluded as (%a)',
+ WriteFormat2('inconsistent definition module was named (%a) and concluded as (%a)',
NameStart, NameEnd)
END ;
M2Error.LeaveErrorScope
diff --git a/gcc/m2/gm2-compiler/PCSymBuild.mod b/gcc/m2/gm2-compiler/PCSymBuild.mod
index 3bffe86..4db2730 100644
--- a/gcc/m2/gm2-compiler/PCSymBuild.mod
+++ b/gcc/m2/gm2-compiler/PCSymBuild.mod
@@ -269,7 +269,7 @@ BEGIN
PopT(NameStart) ;
IF NameStart#NameEnd
THEN
- WriteFormat2('inconsistant definition module was named (%a) and concluded as (%a)',
+ WriteFormat2('inconsistent definition module was named (%a) and concluded as (%a)',
NameStart, NameEnd)
END ;
M2Error.LeaveErrorScope
@@ -1168,9 +1168,9 @@ BEGIN
par := GetParam (p, i) ;
IF IsParameterVar (par)
THEN
- PutProcTypeVarParam (t, GetType (par), IsParameterUnbounded (par))
+ PutProcTypeVarParam (tok, t, GetType (par), IsParameterUnbounded (par))
ELSE
- PutProcTypeParam (t, GetType (par), IsParameterUnbounded (par))
+ PutProcTypeParam (tok, t, GetType (par), IsParameterUnbounded (par))
END ;
INC(i)
END ;
diff --git a/gcc/m2/gm2-compiler/SymbolTable.def b/gcc/m2/gm2-compiler/SymbolTable.def
index 2a9865a..5b93f29 100644
--- a/gcc/m2/gm2-compiler/SymbolTable.def
+++ b/gcc/m2/gm2-compiler/SymbolTable.def
@@ -2650,7 +2650,8 @@ PROCEDURE MakeProcType (tok: CARDINAL; ProcTypeName: Name) : CARDINAL ;
ParamType into ProcType Sym.
*)
-PROCEDURE PutProcTypeParam (Sym: CARDINAL;
+PROCEDURE PutProcTypeParam (tok: CARDINAL;
+ Sym: CARDINAL;
ParamType: CARDINAL; isUnbounded: BOOLEAN) ;
@@ -2659,7 +2660,8 @@ PROCEDURE PutProcTypeParam (Sym: CARDINAL;
ParamType into ProcType Sym.
*)
-PROCEDURE PutProcTypeVarParam (Sym: CARDINAL;
+PROCEDURE PutProcTypeVarParam (tok: CARDINAL;
+ Sym: CARDINAL;
ParamType: CARDINAL; isUnbounded: BOOLEAN) ;
diff --git a/gcc/m2/gm2-compiler/SymbolTable.mod b/gcc/m2/gm2-compiler/SymbolTable.mod
index ff661dc..00946e5 100644
--- a/gcc/m2/gm2-compiler/SymbolTable.mod
+++ b/gcc/m2/gm2-compiler/SymbolTable.mod
@@ -463,9 +463,11 @@ TYPE
(* of param. *)
Type : CARDINAL ; (* Index to the type of param. *)
IsUnbounded : BOOLEAN ; (* Is it an ARRAY OF Type? *)
+ Scope : CARDINAL ; (* Procedure declaration. *)
ShadowVar : CARDINAL ; (* The local variable used to *)
(* shadow this parameter. *)
- At : Where ; (* Where was sym declared/used *)
+ FullTok, (* name: type virtual token. *)
+ At : CARDINAL ; (* Where was sym declared. *)
END ;
SymVarParam = RECORD
@@ -476,9 +478,11 @@ TYPE
HeapVar : CARDINAL ;(* The pointer value on heap. *)
(* Only used by static *)
(* analysis. *)
+ Scope : CARDINAL ;(* Procedure declaration. *)
ShadowVar : CARDINAL ;(* The local variable used to *)
(* shadow this parameter. *)
- At : Where ; (* Where was sym declared/used *)
+ FullTok, (* name: type virtual token. *)
+ At : CARDINAL ;(* Where was sym declared. *)
END ;
ConstStringVariant = (m2str, cstr, m2nulstr, cnulstr) ;
@@ -4456,9 +4460,19 @@ BEGIN
pSym := GetPsym (sym) ;
IF IsParameterVar (sym)
THEN
- RETURN GetVarDeclTok (pSym^.VarParam.ShadowVar)
+ IF pSym^.VarParam.ShadowVar = NulSym
+ THEN
+ RETURN pSym^.VarParam.At
+ ELSE
+ RETURN GetVarDeclTok (pSym^.VarParam.ShadowVar)
+ END
ELSE
- RETURN GetVarDeclTok (pSym^.Param.ShadowVar)
+ IF pSym^.Param.ShadowVar = NulSym
+ THEN
+ RETURN pSym^.Param.At
+ ELSE
+ RETURN GetVarDeclTok (pSym^.Param.ShadowVar)
+ END
END
ELSIF IsVar (sym)
THEN
@@ -4549,9 +4563,9 @@ BEGIN
THEN
IF IsParameterVar (sym)
THEN
- RETURN GetVarDeclFullTok (pSym^.VarParam.ShadowVar)
+ RETURN pSym^.VarParam.FullTok
ELSE
- RETURN GetVarDeclFullTok (pSym^.Param.ShadowVar)
+ RETURN pSym^.Param.FullTok
END
ELSIF IsVar (sym)
THEN
@@ -10651,8 +10665,10 @@ BEGIN
name := ParamName ;
Type := ParamType ;
IsUnbounded := isUnbounded ;
+ Scope := Sym ;
ShadowVar := NulSym ;
- InitWhereDeclaredTok(tok, At)
+ FullTok := MakeVirtual2Tok (tok, typetok) ;
+ At := tok
END
END ;
AddParameter (Sym, kind, ParSym) ;
@@ -10671,7 +10687,7 @@ BEGIN
pSym^.Param.ShadowVar := VariableSym
END
END ;
- AddProcedureProcTypeParam (Sym, ParamType, isUnbounded, FALSE)
+ AddProcedureProcTypeParam (tok, Sym, ParamType, isUnbounded, FALSE)
END ;
RETURN( TRUE )
END PutParam ;
@@ -10708,9 +10724,11 @@ BEGIN
name := ParamName ;
Type := ParamType ;
IsUnbounded := isUnbounded ;
+ Scope := Sym ;
ShadowVar := NulSym ;
HeapVar := NulSym ; (* Will contain a pointer value. *)
- InitWhereDeclaredTok(tok, At)
+ FullTok := MakeVirtual2Tok (tok, typetok) ;
+ At := tok
END
END ;
AddParameter (Sym, kind, ParSym) ;
@@ -10729,7 +10747,7 @@ BEGIN
pSym^.VarParam.ShadowVar := VariableSym
END
END ;
- AddProcedureProcTypeParam (Sym, ParamType, isUnbounded, TRUE)
+ AddProcedureProcTypeParam (tok, Sym, ParamType, isUnbounded, TRUE)
END ;
RETURN( TRUE )
END PutVarParam ;
@@ -10816,7 +10834,8 @@ END AddParameter ;
associated with procedure Sym.
*)
-PROCEDURE AddProcedureProcTypeParam (Sym, ParamType: CARDINAL;
+PROCEDURE AddProcedureProcTypeParam (tok: CARDINAL;
+ Sym, ParamType: CARDINAL;
isUnbounded, isVarParam: BOOLEAN) ;
VAR
pSym: PtrToSymbol ;
@@ -10829,10 +10848,12 @@ BEGIN
THEN
IF isVarParam
THEN
- PutProcTypeVarParam (Procedure.ProcedureType,
+ PutProcTypeVarParam (tok,
+ Procedure.ProcedureType,
ParamType, isUnbounded)
ELSE
- PutProcTypeParam (Procedure.ProcedureType,
+ PutProcTypeParam (tok,
+ Procedure.ProcedureType,
ParamType, isUnbounded)
END
END
@@ -13027,18 +13048,8 @@ BEGIN
ConstLitSym : RETURN( ConstLit.Scope ) |
ConstStringSym : RETURN( ConstString.Scope ) |
ConstVarSym : RETURN( ConstVar.Scope ) |
- ParamSym : IF Param.ShadowVar = NulSym
- THEN
- RETURN NulSym
- ELSE
- RETURN( GetScope (Param.ShadowVar) )
- END |
- VarParamSym : IF VarParam.ShadowVar = NulSym
- THEN
- RETURN NulSym
- ELSE
- RETURN( GetScope (VarParam.ShadowVar) )
- END |
+ ParamSym : RETURN( Param.Scope ) |
+ VarParamSym : RETURN( VarParam.Scope ) |
UndefinedSym : RETURN( NulSym ) |
PartialUnboundedSym: InternalError ('should not be requesting the scope of a PartialUnbounded symbol')
@@ -13186,7 +13197,8 @@ END MakeProcType ;
ParamType into ProcType Sym.
*)
-PROCEDURE PutProcTypeParam (Sym: CARDINAL;
+PROCEDURE PutProcTypeParam (tok: CARDINAL;
+ Sym: CARDINAL;
ParamType: CARDINAL; isUnbounded: BOOLEAN) ;
VAR
pSym : PtrToSymbol ;
@@ -13201,7 +13213,8 @@ BEGIN
Type := ParamType ;
IsUnbounded := isUnbounded ;
ShadowVar := NulSym ;
- InitWhereDeclared(At)
+ FullTok := tok ;
+ At := tok
END
END ;
AddParameter (Sym, ProperProcedure, ParSym)
@@ -13213,7 +13226,8 @@ END PutProcTypeParam ;
ParamType into ProcType Sym.
*)
-PROCEDURE PutProcTypeVarParam (Sym: CARDINAL;
+PROCEDURE PutProcTypeVarParam (tok: CARDINAL;
+ Sym: CARDINAL;
ParamType: CARDINAL; isUnbounded: BOOLEAN) ;
VAR
pSym : PtrToSymbol ;
@@ -13228,7 +13242,8 @@ BEGIN
Type := ParamType ;
IsUnbounded := isUnbounded ;
ShadowVar := NulSym ;
- InitWhereDeclared(At)
+ FullTok := tok ;
+ At := tok
END
END ;
AddParameter (Sym, ProperProcedure, ParSym)
@@ -13918,8 +13933,8 @@ BEGIN
UnboundedSym : RETURN( Unbounded.At.DefDeclared ) |
ProcedureSym : RETURN( Procedure.At.DefDeclared ) |
ProcTypeSym : RETURN( ProcType.At.DefDeclared ) |
- ParamSym : RETURN( Param.At.DefDeclared ) |
- VarParamSym : RETURN( VarParam.At.DefDeclared ) |
+ ParamSym : RETURN( Param.At ) |
+ VarParamSym : RETURN( VarParam.At ) |
ConstStringSym : RETURN( ConstString.At.DefDeclared ) |
ConstLitSym : RETURN( ConstLit.At.DefDeclared ) |
ConstVarSym : RETURN( ConstVar.At.DefDeclared ) |
@@ -13968,8 +13983,8 @@ BEGIN
UnboundedSym : RETURN( Unbounded.At.ModDeclared ) |
ProcedureSym : RETURN( Procedure.At.ModDeclared ) |
ProcTypeSym : RETURN( ProcType.At.ModDeclared ) |
- ParamSym : RETURN( Param.At.ModDeclared ) |
- VarParamSym : RETURN( VarParam.At.ModDeclared ) |
+ ParamSym : RETURN( Param.At ) |
+ VarParamSym : RETURN( VarParam.At ) |
ConstStringSym : RETURN( ConstString.At.ModDeclared ) |
ConstLitSym : RETURN( ConstLit.At.ModDeclared ) |
ConstVarSym : RETURN( ConstVar.At.ModDeclared ) |
@@ -14019,8 +14034,6 @@ BEGIN
UnboundedSym : Unbounded.At.DefDeclared := tok |
ProcedureSym : Procedure.At.DefDeclared := tok |
ProcTypeSym : ProcType.At.DefDeclared := tok |
- ParamSym : Param.At.DefDeclared := tok |
- VarParamSym : VarParam.At.DefDeclared := tok |
ConstStringSym : ConstString.At.DefDeclared := tok |
ConstLitSym : ConstLit.At.DefDeclared := tok |
ConstVarSym : ConstVar.At.DefDeclared := tok |
@@ -14067,8 +14080,6 @@ BEGIN
UnboundedSym : Unbounded.At.ModDeclared := tok |
ProcedureSym : Procedure.At.ModDeclared := tok |
ProcTypeSym : ProcType.At.ModDeclared := tok |
- ParamSym : Param.At.ModDeclared := tok |
- VarParamSym : VarParam.At.ModDeclared := tok |
ConstStringSym : ConstString.At.ModDeclared := tok |
ConstLitSym : ConstLit.At.ModDeclared := tok |
ConstVarSym : ConstVar.At.ModDeclared := tok |
@@ -14323,8 +14334,10 @@ BEGIN
UnboundedSym : RETURN( Unbounded.At.FirstUsed ) |
ProcedureSym : RETURN( Procedure.At.FirstUsed ) |
ProcTypeSym : RETURN( ProcType.At.FirstUsed ) |
+ (*
ParamSym : RETURN( Param.At.FirstUsed ) |
VarParamSym : RETURN( VarParam.At.FirstUsed ) |
+ *)
ConstStringSym : RETURN( ConstString.At.FirstUsed ) |
ConstLitSym : RETURN( ConstLit.At.FirstUsed ) |
ConstVarSym : RETURN( ConstVar.At.FirstUsed ) |
diff --git a/gcc/m2/gm2-gcc/m2color.cc b/gcc/m2/gm2-gcc/m2color.cc
index fd30f46..a638d7c 100644
--- a/gcc/m2/gm2-gcc/m2color.cc
+++ b/gcc/m2/gm2-gcc/m2color.cc
@@ -23,7 +23,7 @@ along with GNU Modula-2; see the file COPYING3. If not see
#include "m2color.h"
#include "gcc-consolidation.h"
-#include "diagnostic-color.h"
+#include "diagnostics/color.h"
char *
diff --git a/gcc/m2/gm2-gcc/m2linemap.cc b/gcc/m2/gm2-gcc/m2linemap.cc
index feb62b3..89a1080 100644
--- a/gcc/m2/gm2-gcc/m2linemap.cc
+++ b/gcc/m2/gm2-gcc/m2linemap.cc
@@ -188,12 +188,13 @@ m2linemap_ErrorAt (location_t location, char *message)
static void
m2linemap_ErrorAtf_1 (location_t location, const char *message, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
rich_location richloc (line_table, location);
va_start (ap, message);
- diagnostic_set_info (&diagnostic, message, &ap, &richloc, DK_ERROR);
+ diagnostic_set_info (&diagnostic, message, &ap, &richloc,
+ diagnostics::kind::error);
diagnostic_report_diagnostic (global_dc, &diagnostic);
va_end (ap);
}
@@ -209,12 +210,13 @@ m2linemap_ErrorAtf (location_t location, const char *message)
static void
m2linemap_WarningAtf_1 (location_t location, const char *message, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
rich_location richloc (line_table, location);
va_start (ap, message);
- diagnostic_set_info (&diagnostic, message, &ap, &richloc, DK_WARNING);
+ diagnostic_set_info (&diagnostic, message, &ap, &richloc,
+ diagnostics::kind::warning);
diagnostic_report_diagnostic (global_dc, &diagnostic);
va_end (ap);
}
@@ -230,12 +232,13 @@ m2linemap_WarningAtf (location_t location, const char *message)
static void
m2linemap_NoteAtf_1 (location_t location, const char *message, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
rich_location richloc (line_table, location);
va_start (ap, message);
- diagnostic_set_info (&diagnostic, message, &ap, &richloc, DK_NOTE);
+ diagnostic_set_info (&diagnostic, message, &ap, &richloc,
+ diagnostics::kind::note);
diagnostic_report_diagnostic (global_dc, &diagnostic);
va_end (ap);
}
diff --git a/gcc/m2/gm2-gcc/rtegraph.cc b/gcc/m2/gm2-gcc/rtegraph.cc
index cd12582..f7b3065 100644
--- a/gcc/m2/gm2-gcc/rtegraph.cc
+++ b/gcc/m2/gm2-gcc/rtegraph.cc
@@ -283,9 +283,10 @@ rtegraph_lookup (gimple *g, tree fndecl, bool is_call)
/* rte_error_at - wraps up an error message. */
static void
-rte_error_at (location_t location, diagnostic_t kind, const char *message, ...)
+rte_error_at (location_t location, diagnostics::kind kind,
+ const char *message, ...)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
va_list ap;
rich_location richloc (line_table, location);
@@ -338,7 +339,7 @@ access_string (tree t, const char **value)
give the function context which might be misleading if this is inlined. */
static void
-generate_report (gimple *stmt, const char *report, diagnostic_t kind)
+generate_report (gimple *stmt, const char *report, diagnostics::kind kind)
{
if (gimple_call_num_args (stmt) == 5)
{
@@ -393,15 +394,16 @@ const char *rtenode::create_message (const char *with_name, const char *without_
return message;
}
-/* error_message issue an DK_ERROR from grtenode. */
+/* error_message issue an diagnostics::kind::error from grtenode. */
void rtenode::error_message (void)
{
if (grtenode != NULL)
- generate_report (grtenode, "runtime error will occur", DK_ERROR);
+ generate_report (grtenode, "runtime error will occur",
+ diagnostics::kind::error);
}
-/* warning_message issue an DK_WARNING from grtenode. */
+/* warning_message issue an diagnostics::kind::warning from grtenode. */
void rtenode::warning_message (void)
{
@@ -409,15 +411,16 @@ void rtenode::warning_message (void)
("runtime error will occur if an exported procedure is called from %s",
"runtime error will occur if an exported procedure is called");
if (grtenode != NULL)
- generate_report (grtenode, message, DK_WARNING);
+ generate_report (grtenode, message, diagnostics::kind::warning);
}
-/* note_message issue an DK_NOTE from grtenode. */
+/* note_message issue an diagnostics::kind::note from grtenode. */
void rtenode::note_message (void)
{
if (grtenode != NULL)
- generate_report (grtenode, "runtime will occur if this procedure is called", DK_NOTE);
+ generate_report (grtenode, "runtime will occur if this procedure is called",
+ diagnostics::kind::note);
}
/* dump_vec display contents of vector array list. */
diff --git a/gcc/m2/gm2-libs/ARRAYOFCHAR.mod b/gcc/m2/gm2-libs/ARRAYOFCHAR.mod
index f27378a..41aaf68 100644
--- a/gcc/m2/gm2-libs/ARRAYOFCHAR.mod
+++ b/gcc/m2/gm2-libs/ARRAYOFCHAR.mod
@@ -34,14 +34,14 @@ IMPORT StrLib ;
Write - writes a string to file f.
*)
-PROCEDURE Write (f: File; a: ARRAY OF CHAR) ;
+PROCEDURE Write (f: File; str: ARRAY OF CHAR) ;
VAR
len, i: CARDINAL ;
BEGIN
- len := StrLib.StrLen (a) ;
+ len := StrLib.StrLen (str) ;
i := 0 ;
WHILE i < len DO
- WriteChar (f, a[i]) ;
+ WriteChar (f, str[i]) ;
INC (i)
END
END Write ;
diff --git a/gcc/m2/gm2-libs/M2EXCEPTION.mod b/gcc/m2/gm2-libs/M2EXCEPTION.mod
index a17310f..e92b16d 100644
--- a/gcc/m2/gm2-libs/M2EXCEPTION.mod
+++ b/gcc/m2/gm2-libs/M2EXCEPTION.mod
@@ -33,7 +33,7 @@ FROM RTExceptions IMPORT EHBlock, GetExceptionBlock, GetNumber, Raise,
(* If the program or coroutine is in the exception state then return the enumeration
value representing the exception cause. If it is not in the exception state then
- raises and exception (exException). *)
+ raises an exException exception. *)
PROCEDURE M2Exception () : M2Exceptions;
VAR
@@ -45,7 +45,8 @@ BEGIN
IF n = MAX (CARDINAL)
THEN
Raise (ORD (exException), ADR (__FILE__), __LINE__, __COLUMN__, ADR (__FUNCTION__),
- ADR ('current coroutine is not in the exceptional execution state'))
+ ADR ('current coroutine is not in the exceptional execution state')) ;
+ RETURN exException
ELSE
RETURN VAL (M2Exceptions, n)
END
diff --git a/gcc/match.pd b/gcc/match.pd
index 7f84d51..4903552 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -7035,6 +7035,22 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(icmp @0 @1)
(if (ic == ncmp)
(ncmp @0 @1)))))
+ /* ((cast)cmp) - 1 -> -(cast)icmp . */
+ (simplify
+ (plus (convert? (cmp@2 @0 @1)) integer_minus_onep)
+ (if (TYPE_PRECISION (type) > 1
+ && INTEGRAL_TYPE_P (TREE_TYPE (@2)) && TYPE_PRECISION (TREE_TYPE (@2)) == 1)
+ /* Comparison inversion may be impossible for trapping math,
+ invert_tree_comparison will tell us. But we can't use
+ a computed operator in the replacement tree thus we have
+ to play the trick below. */
+ (with { enum tree_code ic = invert_tree_comparison
+ (cmp, HONOR_NANS (@0));
+ tree cmptype = TREE_TYPE (@2); }
+ (if (ic == icmp)
+ (negate (convert (icmp:cmptype @0 @1)))
+ (if (ic == ncmp)
+ (negate (convert (ncmp:cmptype @0 @1))))))))
/* The following bits are handled by fold_binary_op_with_conditional_arg. */
(simplify
(ne (cmp@2 @0 @1) integer_zerop)
@@ -11678,4 +11694,4 @@ and,
&& VECTOR_TYPE_P (type)
&& direct_internal_fn_supported_p (IFN_AVG_CEIL, type, OPTIMIZE_FOR_BOTH))
(IFN_AVG_CEIL @0 @2)))
-#endif \ No newline at end of file
+#endif
diff --git a/gcc/optabs-query.cc b/gcc/optabs-query.cc
index f5ca98d..5335d0d 100644
--- a/gcc/optabs-query.cc
+++ b/gcc/optabs-query.cc
@@ -719,13 +719,9 @@ supports_vec_gather_load_p (machine_mode mode, vec<int> *elsvals)
= (icode != CODE_FOR_nothing) ? 1 : -1;
}
- /* For gather the optab's operand indices do not match the IFN's because
- the latter does not have the extension operand (operand 3). It is
- implicitly added during expansion so we use the IFN's else index + 1.
- */
if (elsvals && icode != CODE_FOR_nothing)
get_supported_else_vals
- (icode, internal_fn_else_index (IFN_MASK_GATHER_LOAD) + 1, *elsvals);
+ (icode, internal_fn_else_index (IFN_MASK_GATHER_LOAD), *elsvals);
return this_fn_optabs->supports_vec_gather_load[mode] > 0;
}
diff --git a/gcc/optc-gen.awk b/gcc/optc-gen.awk
index 3d074e4..4e9b538 100644
--- a/gcc/optc-gen.awk
+++ b/gcc/optc-gen.awk
@@ -497,7 +497,7 @@ print " const struct cl_decoded_option *decoded, "
print " unsigned int lang_mask, int kind, "
print " location_t loc, "
print " const struct cl_option_handlers *handlers, "
-print " diagnostic_context *dc) "
+print " diagnostics::context *dc) "
print "{ "
print " size_t scode = decoded->opt_index; "
print " HOST_WIDE_INT value = decoded->value; "
@@ -554,7 +554,7 @@ for (i = 0; i < n_langs; i++) {
print " unsigned int lang_mask" mark_unused ", int kind" mark_unused ", "
print " location_t loc" mark_unused ", "
print " const struct cl_option_handlers *handlers" mark_unused ", "
- print " diagnostic_context *dc" mark_unused ") "
+ print " diagnostics::context *dc" mark_unused ") "
print "{ "
print " enum opt_code code = (enum opt_code) scode; "
print " "
diff --git a/gcc/opth-gen.awk b/gcc/opth-gen.awk
index b6613d3..91fcf56 100644
--- a/gcc/opth-gen.awk
+++ b/gcc/opth-gen.awk
@@ -357,7 +357,7 @@ print " const struct cl_decoded_option *decoded, "
print " unsigned int lang_mask, int kind, "
print " location_t loc, "
print " const struct cl_option_handlers *handlers, "
-print " diagnostic_context *dc); "
+print " diagnostics::context *dc); "
for (i = 0; i < n_langs; i++) {
lang_name = lang_sanitized_name(langs[i]);
print "bool"
@@ -368,7 +368,7 @@ for (i = 0; i < n_langs; i++) {
print " unsigned int lang_mask, int kind,"
print " location_t loc,"
print " const struct cl_option_handlers *handlers,"
- print " diagnostic_context *dc);"
+ print " diagnostics::context *dc);"
}
print "void cpp_handle_option_auto (const struct gcc_options * opts, size_t scode,"
print " struct cpp_options * cpp_opts);"
diff --git a/gcc/opts-common.cc b/gcc/opts-common.cc
index 03b1a79..91cad49 100644
--- a/gcc/opts-common.cc
+++ b/gcc/opts-common.cc
@@ -1282,9 +1282,9 @@ keep:
/* Handle option DECODED for the language indicated by LANG_MASK,
using the handlers in HANDLERS and setting fields in OPTS and
- OPTS_SET. KIND is the diagnostic_t if this is a diagnostics
- option, DK_UNSPECIFIED otherwise, and LOC is the location of the
- option for options from the source file, UNKNOWN_LOCATION
+ OPTS_SET. KIND is the enum diagnostics::kind if this is a diagnostics
+ option, diagnostics::kind::unspecified otherwise, and LOC is the location
+ of the option for options from the source file, UNKNOWN_LOCATION
otherwise. GENERATED_P is true for an option generated as part of
processing another option or otherwise generated internally, false
for one explicitly passed by the user. control_warning_option
@@ -1298,7 +1298,7 @@ handle_option (struct gcc_options *opts,
const struct cl_decoded_option *decoded,
unsigned int lang_mask, int kind, location_t loc,
const struct cl_option_handlers *handlers,
- bool generated_p, diagnostic_context *dc)
+ bool generated_p, diagnostics::context *dc)
{
size_t opt_index = decoded->opt_index;
const char *arg = decoded->arg;
@@ -1336,7 +1336,7 @@ handle_generated_option (struct gcc_options *opts,
size_t opt_index, const char *arg, HOST_WIDE_INT value,
unsigned int lang_mask, int kind, location_t loc,
const struct cl_option_handlers *handlers,
- bool generated_p, diagnostic_context *dc)
+ bool generated_p, diagnostics::context *dc)
{
struct cl_decoded_option decoded;
@@ -1604,7 +1604,7 @@ read_cmdline_option (struct gcc_options *opts,
location_t loc,
unsigned int lang_mask,
const struct cl_option_handlers *handlers,
- diagnostic_context *dc)
+ diagnostics::context *dc)
{
const struct cl_option *option;
const char *opt = decoded->orig_option_with_args_text;
@@ -1645,7 +1645,8 @@ read_cmdline_option (struct gcc_options *opts,
gcc_assert (!decoded->errors);
- if (!handle_option (opts, opts_set, decoded, lang_mask, DK_UNSPECIFIED,
+ if (!handle_option (opts, opts_set, decoded, lang_mask,
+ static_cast<int> (diagnostics::kind::unspecified),
loc, handlers, false, dc))
error_at (loc, "unrecognized command-line option %qs", opt);
}
@@ -1658,7 +1659,7 @@ read_cmdline_option (struct gcc_options *opts,
void
set_option (struct gcc_options *opts, struct gcc_options *opts_set,
size_t opt_index, HOST_WIDE_INT value, const char *arg,
- int kind, location_t loc, diagnostic_context *dc,
+ int kind, location_t loc, diagnostics::context *dc,
HOST_WIDE_INT mask /* = 0 */)
{
const struct cl_option *option = &cl_options[opt_index];
@@ -1668,8 +1669,10 @@ set_option (struct gcc_options *opts, struct gcc_options *opts_set,
if (!flag_var)
return;
- if ((diagnostic_t) kind != DK_UNSPECIFIED && dc != NULL)
- diagnostic_classify_diagnostic (dc, opt_index, (diagnostic_t) kind, loc);
+ if ((enum diagnostics::kind) kind != diagnostics::kind::unspecified
+ && dc != nullptr)
+ diagnostic_classify_diagnostic (dc, opt_index,
+ (enum diagnostics::kind) kind, loc);
if (opts_set != NULL)
set_flag_var = option_flag_var (opt_index, opts_set);
@@ -1874,7 +1877,7 @@ option_enabled (int opt_idx, unsigned lang_mask, void *opts)
int
compiler_diagnostic_option_manager::
-option_enabled_p (diagnostic_option_id opt_id) const
+option_enabled_p (diagnostics::option_id opt_id) const
{
return option_enabled (opt_id.m_idx, m_lang_mask, m_opts);
}
@@ -1941,7 +1944,7 @@ control_warning_option (unsigned int opt_index, int kind, const char *arg,
const struct cl_option_handlers *handlers,
struct gcc_options *opts,
struct gcc_options *opts_set,
- diagnostic_context *dc)
+ diagnostics::context *dc)
{
if (cl_options[opt_index].alias_target != N_OPTS)
{
@@ -1954,7 +1957,9 @@ control_warning_option (unsigned int opt_index, int kind, const char *arg,
if (opt_index == OPT_SPECIAL_ignore || opt_index == OPT_SPECIAL_warn_removed)
return;
if (dc)
- diagnostic_classify_diagnostic (dc, opt_index, (diagnostic_t) kind, loc);
+ diagnostic_classify_diagnostic (dc, opt_index,
+ static_cast<enum diagnostics::kind> (kind),
+ loc);
if (imply)
{
/* -Werror=foo implies -Wfoo. */
diff --git a/gcc/opts-diagnostic.cc b/gcc/opts-diagnostic.cc
index d2c3a93..70d7d74 100644
--- a/gcc/opts-diagnostic.cc
+++ b/gcc/opts-diagnostic.cc
@@ -20,7 +20,7 @@ along with GCC; see the file COPYING3. If not see
/* This file implements the options -fdiagnostics-add-output=,
-fdiagnostics-set-output=. Most of the work is done
- by diagnostic-output-spec.cc so it can be shared by libgdiagnostics. */
+ by diagnostics/output-spec.cc so it can be shared by libgdiagnostics. */
#include "config.h"
#define INCLUDE_ARRAY
@@ -31,7 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "version.h"
#include "intl.h"
#include "diagnostic.h"
-#include "diagnostic-output-spec.h"
+#include "diagnostics/output-spec.h"
#include "opts.h"
#include "options.h"
@@ -39,19 +39,19 @@ along with GCC; see the file COPYING3. If not see
namespace {
-struct opt_spec_context : public diagnostics_output_spec::gcc_spec_context
+struct opt_spec_context : public diagnostics::output_spec::dc_spec_context
{
public:
opt_spec_context (const gcc_options &opts,
- diagnostic_context &dc,
+ diagnostics::context &dc,
line_maps *location_mgr,
location_t loc,
const char *option_name)
- : gcc_spec_context (dc,
- location_mgr,
- location_mgr,
- loc,
- option_name),
+ : dc_spec_context (dc,
+ location_mgr,
+ location_mgr,
+ loc,
+ option_name),
m_opts (opts)
{}
@@ -70,7 +70,7 @@ public:
void
handle_OPT_fdiagnostics_add_output_ (const gcc_options &opts,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *arg,
location_t loc)
{
@@ -89,7 +89,7 @@ handle_OPT_fdiagnostics_add_output_ (const gcc_options &opts,
void
handle_OPT_fdiagnostics_set_output_ (const gcc_options &opts,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *arg,
location_t loc)
{
@@ -103,5 +103,5 @@ handle_OPT_fdiagnostics_set_output_ (const gcc_options &opts,
return;
sink->set_main_input_filename (opts.x_main_input_filename);
- dc.set_output_format (std::move (sink));
+ dc.set_sink (std::move (sink));
}
diff --git a/gcc/opts-diagnostic.h b/gcc/opts-diagnostic.h
index 384fbb3..4fa4ea8 100644
--- a/gcc/opts-diagnostic.h
+++ b/gcc/opts-diagnostic.h
@@ -20,12 +20,12 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_OPTS_DIAGNOSTIC_H
#define GCC_OPTS_DIAGNOSTIC_H
-/* Abstract subclass of diagnostic_option_manager for gcc options. */
+/* Abstract subclass of diagnostics::option_manager for gcc options. */
-class gcc_diagnostic_option_manager : public diagnostic_option_manager
+class gcc_diagnostic_option_manager : public diagnostics::option_manager
{
public:
- char *make_option_url (diagnostic_option_id option_id) const final override;
+ char *make_option_url (diagnostics::option_id option_id) const final override;
protected:
gcc_diagnostic_option_manager (unsigned lang_mask)
@@ -40,7 +40,7 @@ protected:
class compiler_diagnostic_option_manager : public gcc_diagnostic_option_manager
{
public:
- compiler_diagnostic_option_manager (const diagnostic_context &context,
+ compiler_diagnostic_option_manager (const diagnostics::context &context,
unsigned lang_mask,
void *opts)
: gcc_diagnostic_option_manager (lang_mask),
@@ -49,25 +49,26 @@ public:
{
}
- int option_enabled_p (diagnostic_option_id option_id) const final override;
- char *make_option_name (diagnostic_option_id option_id,
- diagnostic_t orig_diag_kind,
- diagnostic_t diag_kind) const final override;
+ int option_enabled_p (diagnostics::option_id option_id) const final override;
+ char *
+ make_option_name (diagnostics::option_id option_id,
+ enum diagnostics::kind orig_diag_kind,
+ enum diagnostics::kind diag_kind) const final override;
private:
- const diagnostic_context &m_context;
+ const diagnostics::context &m_context;
void *m_opts;
};
extern void
handle_OPT_fdiagnostics_add_output_ (const gcc_options &opts,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *arg,
location_t loc);
extern void
handle_OPT_fdiagnostics_set_output_ (const gcc_options &opts,
- diagnostic_context &dc,
+ diagnostics::context &dc,
const char *arg,
location_t loc);
#endif
diff --git a/gcc/opts-global.cc b/gcc/opts-global.cc
index b9b42d3..701a6bb 100644
--- a/gcc/opts-global.cc
+++ b/gcc/opts-global.cc
@@ -181,7 +181,7 @@ lang_handle_option (struct gcc_options *opts,
unsigned int lang_mask ATTRIBUTE_UNUSED, int kind,
location_t loc,
const struct cl_option_handlers *handlers,
- diagnostic_context *dc,
+ diagnostics::context *dc,
void (*) (void))
{
gcc_assert (opts == &global_options);
@@ -215,7 +215,7 @@ read_cmdline_options (struct gcc_options *opts, struct gcc_options *opts_set,
location_t loc,
unsigned int lang_mask,
const struct cl_option_handlers *handlers,
- diagnostic_context *dc)
+ diagnostics::context *dc)
{
unsigned int i;
@@ -312,7 +312,7 @@ void
decode_options (struct gcc_options *opts, struct gcc_options *opts_set,
struct cl_decoded_option *decoded_options,
unsigned int decoded_options_count,
- location_t loc, diagnostic_context *dc,
+ location_t loc, diagnostics::context *dc,
void (*target_option_override_hook) (void))
{
struct cl_option_handlers handlers;
diff --git a/gcc/opts.cc b/gcc/opts.cc
index 063fbd0..c21e66b 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -31,8 +31,8 @@ along with GCC; see the file COPYING3. If not see
#include "common/common-target.h"
#include "spellcheck.h"
#include "opt-suggestions.h"
-#include "diagnostic-color.h"
-#include "diagnostic-format.h"
+#include "diagnostics/color.h"
+#include "diagnostics/sink.h"
#include "version.h"
#include "selftest.h"
#include "file-prefix-map.h"
@@ -347,7 +347,7 @@ static void set_debug_level (uint32_t dinfo, int extended,
location_t loc);
static void set_fast_math_flags (struct gcc_options *opts, int set);
static void decode_d_option (const char *arg, struct gcc_options *opts,
- location_t loc, diagnostic_context *dc);
+ location_t loc, diagnostics::context *dc);
static void set_unsafe_math_optimizations_flags (struct gcc_options *opts,
int set);
static void enable_warning_as_error (const char *arg, int value,
@@ -356,7 +356,7 @@ static void enable_warning_as_error (const char *arg, int value,
struct gcc_options *opts,
struct gcc_options *opts_set,
location_t loc,
- diagnostic_context *dc);
+ diagnostics::context *dc);
/* Handle a back-end option; arguments and return value as for
handle_option. */
@@ -368,10 +368,11 @@ target_handle_option (struct gcc_options *opts,
unsigned int lang_mask ATTRIBUTE_UNUSED, int kind,
location_t loc,
const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED,
- diagnostic_context *dc, void (*) (void))
+ diagnostics::context *dc, void (*) (void))
{
gcc_assert (dc == global_dc);
- gcc_assert (kind == DK_UNSPECIFIED);
+ gcc_assert (static_cast<diagnostics::kind> (kind)
+ == diagnostics::kind::unspecified);
return targetm_common.handle_option (opts, opts_set, decoded, loc);
}
@@ -469,7 +470,7 @@ maybe_default_option (struct gcc_options *opts,
unsigned int lang_mask,
const struct cl_option_handlers *handlers,
location_t loc,
- diagnostic_context *dc)
+ diagnostics::context *dc)
{
const struct cl_option *option = &cl_options[default_opt->opt_index];
bool enabled;
@@ -535,14 +536,18 @@ maybe_default_option (struct gcc_options *opts,
if (enabled)
handle_generated_option (opts, opts_set, default_opt->opt_index,
default_opt->arg, default_opt->value,
- lang_mask, DK_UNSPECIFIED, loc,
+ lang_mask,
+ static_cast<int> (diagnostics::kind::unspecified),
+ loc,
handlers, true, dc);
else if (default_opt->arg == NULL
&& !option->cl_reject_negative
&& !(option->flags & CL_PARAMS))
handle_generated_option (opts, opts_set, default_opt->opt_index,
default_opt->arg, !default_opt->value,
- lang_mask, DK_UNSPECIFIED, loc,
+ lang_mask,
+ static_cast<int> (diagnostics::kind::unspecified),
+ loc,
handlers, true, dc);
}
@@ -559,7 +564,7 @@ maybe_default_options (struct gcc_options *opts,
unsigned int lang_mask,
const struct cl_option_handlers *handlers,
location_t loc,
- diagnostic_context *dc)
+ diagnostics::context *dc)
{
size_t i;
@@ -727,7 +732,7 @@ default_options_optimization (struct gcc_options *opts,
location_t loc,
unsigned int lang_mask,
const struct cl_option_handlers *handlers,
- diagnostic_context *dc)
+ diagnostics::context *dc)
{
unsigned int i;
int opt2;
@@ -2703,7 +2708,7 @@ common_handle_option (struct gcc_options *opts,
unsigned int lang_mask, int kind ATTRIBUTE_UNUSED,
location_t loc,
const struct cl_option_handlers *handlers,
- diagnostic_context *dc,
+ diagnostics::context *dc,
void (*target_option_override_hook) (void))
{
size_t scode = decoded->opt_index;
@@ -2957,19 +2962,19 @@ common_handle_option (struct gcc_options *opts,
break;
case OPT_fdiagnostics_show_caret:
- dc->m_source_printing.enabled = value;
+ dc->get_source_printing_options ().enabled = value;
break;
case OPT_fdiagnostics_show_event_links:
- dc->m_source_printing.show_event_links_p = value;
+ dc->get_source_printing_options ().show_event_links_p = value;
break;
case OPT_fdiagnostics_show_labels:
- dc->m_source_printing.show_labels_p = value;
+ dc->get_source_printing_options ().show_labels_p = value;
break;
case OPT_fdiagnostics_show_line_numbers:
- dc->m_source_printing.show_line_numbers_p = value;
+ dc->get_source_printing_options ().show_line_numbers_p = value;
break;
case OPT_fdiagnostics_color_:
@@ -2985,10 +2990,10 @@ common_handle_option (struct gcc_options *opts,
const char *basename = (opts->x_dump_base_name ? opts->x_dump_base_name
: opts->x_main_input_basename);
gcc_assert (dc);
- diagnostic_output_format_init (*dc,
- opts->x_main_input_filename, basename,
- (enum diagnostics_output_format)value,
- opts->x_flag_diagnostics_json_formatting);
+ diagnostics::output_format_init (*dc,
+ opts->x_main_input_filename, basename,
+ (enum diagnostics_output_format)value,
+ opts->x_flag_diagnostics_json_formatting);
break;
}
@@ -3047,7 +3052,7 @@ common_handle_option (struct gcc_options *opts,
break;
case OPT_fdiagnostics_minimum_margin_width_:
- dc->m_source_printing.min_margin_width = value;
+ dc->get_source_printing_options ().min_margin_width = value;
break;
case OPT_fdump_:
@@ -3085,7 +3090,7 @@ common_handle_option (struct gcc_options *opts,
case OPT_fmessage_length_:
pp_set_line_maximum_length (dc->get_reference_printer (), value);
- diagnostic_set_caret_max_width (dc, value);
+ dc->set_caret_max_width (value);
break;
case OPT_fopt_info:
@@ -3317,7 +3322,9 @@ common_handle_option (struct gcc_options *opts,
case OPT_pedantic_errors:
dc->m_pedantic_errors = 1;
- control_warning_option (OPT_Wpedantic, DK_ERROR, NULL, value,
+ control_warning_option (OPT_Wpedantic,
+ static_cast<int> (diagnostics::kind::error),
+ NULL, value,
loc, lang_mask,
handlers, opts, opts_set,
dc);
@@ -3618,7 +3625,7 @@ set_debug_level (uint32_t dinfo, int extended, const char *arg,
abort ().) */
static void
-setup_core_dumping (diagnostic_context *dc)
+setup_core_dumping (diagnostics::context *dc)
{
#ifdef SIGABRT
signal (SIGABRT, SIG_DFL);
@@ -3642,7 +3649,7 @@ setup_core_dumping (diagnostic_context *dc)
static void
decode_d_option (const char *arg, struct gcc_options *opts,
- location_t loc, diagnostic_context *dc)
+ location_t loc, diagnostics::context *dc)
{
int c;
@@ -3691,7 +3698,7 @@ enable_warning_as_error (const char *arg, int value, unsigned int lang_mask,
const struct cl_option_handlers *handlers,
struct gcc_options *opts,
struct gcc_options *opts_set,
- location_t loc, diagnostic_context *dc)
+ location_t loc, diagnostics::context *dc)
{
char *new_option;
int option_index;
@@ -3717,7 +3724,9 @@ enable_warning_as_error (const char *arg, int value, unsigned int lang_mask,
"controls warnings", arg, new_option);
else
{
- const diagnostic_t kind = value ? DK_ERROR : DK_WARNING;
+ const enum diagnostics::kind kind = (value
+ ? diagnostics::kind::error
+ : diagnostics::kind::warning);
const char *arg = NULL;
if (cl_options[option_index].flags & CL_JOINED)
@@ -3736,15 +3745,16 @@ enable_warning_as_error (const char *arg, int value, unsigned int lang_mask,
char *
compiler_diagnostic_option_manager::
-make_option_name (diagnostic_option_id option_id,
- diagnostic_t orig_diag_kind,
- diagnostic_t diag_kind) const
+make_option_name (diagnostics::option_id option_id,
+ enum diagnostics::kind orig_diag_kind,
+ enum diagnostics::kind diag_kind) const
{
if (option_id.m_idx)
{
/* A warning classified as an error. */
- if ((orig_diag_kind == DK_WARNING || orig_diag_kind == DK_PEDWARN)
- && diag_kind == DK_ERROR)
+ if ((orig_diag_kind == diagnostics::kind::warning
+ || orig_diag_kind == diagnostics::kind::pedwarn)
+ && diag_kind == diagnostics::kind::error)
return concat (cl_options[OPT_Werror_].opt_text,
/* Skip over "-W". */
cl_options[option_id.m_idx].opt_text + 2,
@@ -3754,8 +3764,9 @@ make_option_name (diagnostic_option_id option_id,
return xstrdup (cl_options[option_id.m_idx].opt_text);
}
/* A warning without option classified as an error. */
- else if ((orig_diag_kind == DK_WARNING || orig_diag_kind == DK_PEDWARN
- || diag_kind == DK_WARNING)
+ else if ((orig_diag_kind == diagnostics::kind::warning
+ || orig_diag_kind == diagnostics::kind::pedwarn
+ || diag_kind == diagnostics::kind::warning)
&& m_context.warning_as_error_requested_p ())
return xstrdup (cl_options[OPT_Werror].opt_text);
else
@@ -3813,7 +3824,7 @@ get_option_url_suffix (int option_index, unsigned lang_mask)
char *
gcc_diagnostic_option_manager::
-make_option_url (diagnostic_option_id option_id) const
+make_option_url (diagnostics::option_id option_id) const
{
if (option_id.m_idx)
{
diff --git a/gcc/opts.h b/gcc/opts.h
index 382faab..ea92c49 100644
--- a/gcc/opts.h
+++ b/gcc/opts.h
@@ -313,7 +313,7 @@ struct cl_option_handler_func
const struct cl_decoded_option *decoded,
unsigned int lang_mask, int kind, location_t loc,
const struct cl_option_handlers *handlers,
- diagnostic_context *dc,
+ diagnostics::context *dc,
void (*target_option_override_hook) (void));
/* The mask that must have some bit in common with the flags for the
@@ -390,7 +390,7 @@ extern void decode_options (struct gcc_options *opts,
struct cl_decoded_option *decoded_options,
unsigned int decoded_options_count,
location_t loc,
- diagnostic_context *dc,
+ diagnostics::context *dc,
void (*target_option_override_hook) (void));
extern int option_enabled (int opt_idx, unsigned lang_mask, void *opts);
@@ -399,7 +399,7 @@ extern bool get_option_state (struct gcc_options *, int,
extern void set_option (struct gcc_options *opts,
struct gcc_options *opts_set,
size_t opt_index, HOST_WIDE_INT value, const char *arg,
- int kind, location_t loc, diagnostic_context *dc,
+ int kind, location_t loc, diagnostics::context *dc,
HOST_WIDE_INT = 0);
extern void *option_flag_var (int opt_index, struct gcc_options *opts);
bool handle_generated_option (struct gcc_options *opts,
@@ -408,7 +408,7 @@ bool handle_generated_option (struct gcc_options *opts,
HOST_WIDE_INT value,
unsigned int lang_mask, int kind, location_t loc,
const struct cl_option_handlers *handlers,
- bool generated_p, diagnostic_context *dc);
+ bool generated_p, diagnostics::context *dc);
void generate_option (size_t opt_index, const char *arg, HOST_WIDE_INT value,
unsigned int lang_mask,
struct cl_decoded_option *decoded);
@@ -420,14 +420,14 @@ extern void read_cmdline_option (struct gcc_options *opts,
location_t loc,
unsigned int lang_mask,
const struct cl_option_handlers *handlers,
- diagnostic_context *dc);
+ diagnostics::context *dc);
extern void control_warning_option (unsigned int opt_index, int kind,
const char *arg, bool imply, location_t loc,
unsigned int lang_mask,
const struct cl_option_handlers *handlers,
struct gcc_options *opts,
struct gcc_options *opts_set,
- diagnostic_context *dc);
+ diagnostics::context *dc);
extern char *write_langs (unsigned int mask);
extern void print_ignored_options (void);
extern void handle_common_deferred_options (void);
@@ -442,7 +442,7 @@ extern bool common_handle_option (struct gcc_options *opts,
unsigned int lang_mask, int kind,
location_t loc,
const struct cl_option_handlers *handlers,
- diagnostic_context *dc,
+ diagnostics::context *dc,
void (*target_option_override_hook) (void));
extern bool target_handle_option (struct gcc_options *opts,
struct gcc_options *opts_set,
@@ -450,7 +450,7 @@ extern bool target_handle_option (struct gcc_options *opts,
unsigned int lang_mask, int kind,
location_t loc,
const struct cl_option_handlers *handlers,
- diagnostic_context *dc,
+ diagnostics::context *dc,
void (*target_option_override_hook) (void));
extern void finish_options (struct gcc_options *opts,
struct gcc_options *opts_set,
@@ -466,7 +466,7 @@ extern void default_options_optimization (struct gcc_options *opts,
location_t loc,
unsigned int lang_mask,
const struct cl_option_handlers *handlers,
- diagnostic_context *dc);
+ diagnostics::context *dc);
extern void set_struct_debug_option (struct gcc_options *opts,
location_t loc,
const char *value);
diff --git a/gcc/output.h b/gcc/output.h
index 372d63c..0c329ff 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -639,4 +639,6 @@ extern int default_address_cost (rtx, machine_mode, addr_space_t, bool);
/* Stack usage. */
extern void output_stack_usage (void);
+extern void verify_reg_names_in_constraints ();
+
#endif /* ! GCC_OUTPUT_H */
diff --git a/gcc/params.opt b/gcc/params.opt
index 31aa0bd..c7d5fd4 100644
--- a/gcc/params.opt
+++ b/gcc/params.opt
@@ -1177,7 +1177,7 @@ Common Joined UInteger Var(param_uninit_control_dep_attempts) Init(1000) Integer
Maximum number of nested calls to search for control dependencies during uninitialized variable analysis.
-param=uninit-max-chain-len=
-Common Joined UInteger Var(param_uninit_max_chain_len) Init(8) IntegerRange(1, 128) Param Optimization
+Common Joined UInteger Var(param_uninit_max_chain_len) Init(12) IntegerRange(1, 128) Param Optimization
Maximum number of predicates anded for each predicate ored in the normalized
predicate chain.
diff --git a/gcc/pretty-print-format-impl.h b/gcc/pretty-print-format-impl.h
index 90692c8..2aded64 100644
--- a/gcc/pretty-print-format-impl.h
+++ b/gcc/pretty-print-format-impl.h
@@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see
#define GCC_PRETTY_PRINT_FORMAT_IMPL_H
#include "pretty-print.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
/* A struct representing a pending item to be printed within
pp_format.
@@ -224,14 +224,14 @@ struct pp_token_end_url : public pp_token
struct pp_token_event_id : public pp_token
{
- pp_token_event_id (diagnostic_event_id_t event_id)
+ pp_token_event_id (diagnostics::paths::event_id_t event_id)
: pp_token (kind::event_id),
m_event_id (event_id)
{
gcc_assert (event_id.known_p ());
}
- diagnostic_event_id_t m_event_id;
+ diagnostics::paths::event_id_t m_event_id;
};
template <>
diff --git a/gcc/pretty-print-markup.h b/gcc/pretty-print-markup.h
index 6c0719d..e4346f1 100644
--- a/gcc/pretty-print-markup.h
+++ b/gcc/pretty-print-markup.h
@@ -20,7 +20,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_PRETTY_PRINT_MARKUP_H
#define GCC_PRETTY_PRINT_MARKUP_H
-#include "diagnostic-color.h"
+#include "diagnostics/color.h"
class pp_token_list;
diff --git a/gcc/pretty-print.cc b/gcc/pretty-print.cc
index 7e1b52a..77d40ec 100644
--- a/gcc/pretty-print.cc
+++ b/gcc/pretty-print.cc
@@ -27,8 +27,8 @@ along with GCC; see the file COPYING3. If not see
#include "pretty-print-format-impl.h"
#include "pretty-print-markup.h"
#include "pretty-print-urlifier.h"
-#include "diagnostic-color.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/color.h"
+#include "diagnostics/event-id.h"
#include "diagnostic-highlight-colors.h"
#include "auto-obstack.h"
#include "selftest.h"
@@ -3413,8 +3413,8 @@ test_pp_format ()
"foo", 0x12345678);
/* Verify "%@". */
{
- diagnostic_event_id_t first (2);
- diagnostic_event_id_t second (7);
+ diagnostics::paths::event_id_t first (2);
+ diagnostics::paths::event_id_t second (7);
ASSERT_PP_FORMAT_2 ("first `free' at (3); second `free' at (8)",
"first %<free%> at %@; second %<free%> at %@",
diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h
index 6cd9150..ced2e3c 100644
--- a/gcc/pretty-print.h
+++ b/gcc/pretty-print.h
@@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "obstack.h"
#include "rich-location.h"
-#include "diagnostic-url.h"
+#include "diagnostics/url.h"
/* Maximum number of format string arguments. */
#define PP_NL_ARGMAX 30
diff --git a/gcc/recog.cc b/gcc/recog.cc
index edf22cb..67d7fa6 100644
--- a/gcc/recog.cc
+++ b/gcc/recog.cc
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "rtl.h"
#include "tree.h"
+#include "stmt.h"
#include "cfghooks.h"
#include "df.h"
#include "memmodel.h"
@@ -2363,7 +2364,8 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints)
{
case CT_REGISTER:
if (!result
- && reg_class_for_constraint (cn) != NO_REGS
+ && (reg_class_for_constraint (cn) != NO_REGS
+ || constraint[0] == '{')
&& GET_MODE (op) != BLKmode
&& register_operand (op, VOIDmode))
result = 1;
@@ -3304,6 +3306,13 @@ constrain_operands (int strict, alternative_mask alternatives)
win = true;
break;
+ case '{':
+ if ((REG_P (op) && HARD_REGISTER_P (op)
+ && (int) REGNO (op) == decode_hard_reg_constraint (p))
+ || !reload_completed)
+ win = true;
+ break;
+
default:
{
enum constraint_num cn = lookup_constraint (p);
diff --git a/gcc/rtl-error.cc b/gcc/rtl-error.cc
index 06d060c..7391a2f 100644
--- a/gcc/rtl-error.cc
+++ b/gcc/rtl-error.cc
@@ -28,7 +28,7 @@ along with GCC; see the file COPYING3. If not see
static location_t location_for_asm (const rtx_insn *);
static void diagnostic_for_asm (const rtx_insn *, const char *, va_list *,
- diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0);
+ enum diagnostics::kind) ATTRIBUTE_GCC_DIAG(2,0);
/* Figure the location of the given INSN. */
static location_t
@@ -64,9 +64,9 @@ location_for_asm (const rtx_insn *insn)
and each ASM_OPERANDS records its own source file and line. */
static void
diagnostic_for_asm (const rtx_insn *insn, const char *msg, va_list *args_ptr,
- diagnostic_t kind)
+ enum diagnostics::kind kind)
{
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
rich_location richloc (line_table, location_for_asm (insn));
diagnostic_set_info (&diagnostic, msg, args_ptr,
@@ -80,7 +80,7 @@ error_for_asm (const rtx_insn *insn, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
- diagnostic_for_asm (insn, gmsgid, &ap, DK_ERROR);
+ diagnostic_for_asm (insn, gmsgid, &ap, diagnostics::kind::error);
va_end (ap);
}
@@ -90,7 +90,7 @@ warning_for_asm (const rtx_insn *insn, const char *gmsgid, ...)
va_list ap;
va_start (ap, gmsgid);
- diagnostic_for_asm (insn, gmsgid, &ap, DK_WARNING);
+ diagnostic_for_asm (insn, gmsgid, &ap, diagnostics::kind::warning);
va_end (ap);
}
diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog
index 2a5219d..f103c7e 100644
--- a/gcc/rust/ChangeLog
+++ b/gcc/rust/ChangeLog
@@ -1,3 +1,37 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * resolve/rust-ice-finalizer.cc: Update usage of "diagnostic_info"
+ to explicitly refer to "diagnostics::diagnostic_info".
+ * resolve/rust-ice-finalizer.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * backend/rust-tree.cc: Update for diagnostic_t becoming
+ enum class diagnostics::kind.
+ * backend/rust-tree.h: Likewise.
+ * resolve/rust-ast-resolve-expr.cc: Likewise.
+ * resolve/rust-ice-finalizer.cc: Likewise.
+ * resolve/rust-ice-finalizer.h: Likewise.
+ * resolve/rust-late-name-resolver-2.0.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * resolve/rust-ast-resolve-expr.cc: Update for diagnostic_text_finalizer
+ becoming diagnostics::text_finalizer.
+ * resolve/rust-late-name-resolver-2.0.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * resolve/rust-ice-finalizer.cc: Update for move of diagnostics
+ output formats into namespace "diagnostics" as "sinks".
+ * resolve/rust-ice-finalizer.h: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * rust-diagnostics.cc: Update #include for move of
+ "diagnostic-metadata.h" to "diagnostics/metadata.h", and update
+ for move of diagnostic_metadata to diagnostics::metadata.
+
2025-06-26 Martin Jambor <mjambor@suse.cz>
* checks/errors/borrowck/rust-borrow-checker-diagnostics.cc
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 6cba04b..2302ffb 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -3848,16 +3848,18 @@ strip_top_quals (tree t)
/* Print an error message for invalid use of an incomplete type.
VALUE is the expression that was used (or 0 if that isn't known)
and TYPE is the type that was invalid. DIAG_KIND indicates the
- type of diagnostic (see diagnostic.def). */
+ type of diagnostic (see diagnostics/kinds.def). */
void
cxx_incomplete_type_diagnostic (location_t loc, const_tree value,
- const_tree type, diagnostic_t diag_kind)
+ const_tree type,
+ enum diagnostics::kind diag_kind)
{
// bool is_decl = false, complained = false;
- gcc_assert (diag_kind == DK_WARNING || diag_kind == DK_PEDWARN
- || diag_kind == DK_ERROR);
+ gcc_assert (diag_kind == diagnostics::kind::warning
+ || diag_kind == diagnostics::kind::pedwarn
+ || diag_kind == diagnostics::kind::error);
/* Avoid duplicate error message. */
if (TREE_CODE (type) == ERROR_MARK)
@@ -5131,7 +5133,7 @@ complete_type_or_maybe_complain (tree type, tree value, tsubst_flags_t complain)
else if (!COMPLETE_TYPE_P (type))
{
if (complain & tf_error)
- cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+ cxx_incomplete_type_diagnostic (value, type, diagnostics::kind::error);
note_failed_type_completion_for_satisfaction (type);
return NULL_TREE;
}
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index bb99684..3630b0e 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -3137,7 +3137,7 @@ extern bool reject_gcc_builtin (const_tree, location_t = UNKNOWN_LOCATION);
extern tree resolve_nondeduced_context (tree, tsubst_flags_t);
extern void cxx_incomplete_type_diagnostic (location_t, const_tree, const_tree,
- diagnostic_t);
+ enum diagnostics::kind);
extern void cxx_incomplete_type_error (location_t, const_tree, const_tree);
@@ -3430,7 +3430,7 @@ null_node_p (const_tree expr)
inline void
cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
- diagnostic_t diag_kind)
+ enum diagnostics::kind diag_kind)
{
cxx_incomplete_type_diagnostic (rs_expr_loc_or_input_loc (value), value, type,
diag_kind);
@@ -3439,7 +3439,7 @@ cxx_incomplete_type_diagnostic (const_tree value, const_tree type,
inline void
cxx_incomplete_type_error (const_tree value, const_tree type)
{
- cxx_incomplete_type_diagnostic (value, type, DK_ERROR);
+ cxx_incomplete_type_diagnostic (value, type, diagnostics::kind::error);
}
extern location_t
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc
index 6242235..5524e18 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc
@@ -129,8 +129,8 @@ ResolveExpr::visit (AST::IdentifierExpr &expr)
resolve. Emit a funny ICE. We set the finalizer to our custom one,
and use the lower-level emit_diagnostic () instead of the more common
internal_error_no_backtrace () in order to pass our locus. */
- diagnostic_text_finalizer (global_dc) = funny_ice_text_finalizer;
- emit_diagnostic (DK_ICE_NOBT, expr.get_locus (), -1,
+ diagnostics::text_finalizer (global_dc) = funny_ice_text_finalizer;
+ emit_diagnostic (diagnostics::kind::ice_nobt, expr.get_locus (), -1,
"are you trying to break %s? how dare you?",
expr.as_string ().c_str ());
}
diff --git a/gcc/rust/resolve/rust-ice-finalizer.cc b/gcc/rust/resolve/rust-ice-finalizer.cc
index bd4763f..79a06c3 100644
--- a/gcc/rust/resolve/rust-ice-finalizer.cc
+++ b/gcc/rust/resolve/rust-ice-finalizer.cc
@@ -22,12 +22,12 @@ namespace Rust {
namespace Resolver {
void ATTRIBUTE_NORETURN
-funny_ice_text_finalizer (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic,
- diagnostic_t diag_kind)
+funny_ice_text_finalizer (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic,
+ enum diagnostics::kind diag_kind)
{
- gcc_assert (diag_kind == DK_ICE_NOBT);
- default_diagnostic_text_finalizer (text_output, diagnostic, diag_kind);
+ gcc_assert (diag_kind == diagnostics::kind::ice_nobt);
+ diagnostics::default_text_finalizer (text_output, diagnostic, diag_kind);
fnotice (stderr, "You have broken GCC Rust. This is a feature.\n");
exit (ICE_EXIT_CODE);
}
diff --git a/gcc/rust/resolve/rust-ice-finalizer.h b/gcc/rust/resolve/rust-ice-finalizer.h
index 85ab88f..5120176 100644
--- a/gcc/rust/resolve/rust-ice-finalizer.h
+++ b/gcc/rust/resolve/rust-ice-finalizer.h
@@ -55,9 +55,9 @@ namespace Resolver {
the default bug reporting instructions, as there is no bug to report. */
void ATTRIBUTE_NORETURN
-funny_ice_text_finalizer (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic,
- diagnostic_t diag_kind);
+funny_ice_text_finalizer (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic,
+ enum diagnostics::kind diag_kind);
} // namespace Resolver
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
index 6ec0422..a15e17f 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
@@ -375,8 +375,8 @@ Late::visit (AST::IdentifierExpr &expr)
}
else if (funny_error)
{
- diagnostic_text_finalizer (global_dc) = Resolver::funny_ice_text_finalizer;
- emit_diagnostic (DK_ICE_NOBT, expr.get_locus (), -1,
+ diagnostics::text_finalizer (global_dc) = Resolver::funny_ice_text_finalizer;
+ emit_diagnostic (diagnostics::kind::ice_nobt, expr.get_locus (), -1,
"are you trying to break %s? how dare you?",
expr.as_string ().c_str ());
}
diff --git a/gcc/rust/rust-diagnostics.cc b/gcc/rust/rust-diagnostics.cc
index 0c0ef6e..702da71 100644
--- a/gcc/rust/rust-diagnostics.cc
+++ b/gcc/rust/rust-diagnostics.cc
@@ -22,7 +22,7 @@
#include "rust-diagnostics.h"
#include "options.h"
-#include "diagnostic-metadata.h"
+#include "diagnostics/metadata.h"
static std::string
mformat_value ()
@@ -192,7 +192,7 @@ rust_error_at (const location_t location, const char *fmt, ...)
va_end (ap);
}
-class rust_error_code_rule : public diagnostic_metadata::rule
+class rust_error_code_rule : public diagnostics::metadata::rule
{
public:
rust_error_code_rule (const ErrorCode code) : m_code (code) {}
@@ -237,7 +237,7 @@ rust_be_error_at (const location_t location, const ErrorCode code,
const std::string &errmsg)
{
rich_location gcc_loc (line_table, location);
- diagnostic_metadata m;
+ diagnostics::metadata m;
rust_error_code_rule rule (code);
m.add_rule (rule);
error_meta (&gcc_loc, m, "%s", errmsg.c_str ());
@@ -260,7 +260,7 @@ rust_be_error_at (const rich_location &location, const ErrorCode code,
{
/* TODO: 'error_at' would like a non-'const' 'rich_location *'. */
rich_location &gcc_loc = const_cast<rich_location &> (location);
- diagnostic_metadata m;
+ diagnostics::metadata m;
rust_error_code_rule rule (code);
m.add_rule (rule);
error_meta (&gcc_loc, m, "%s", errmsg.c_str ());
@@ -281,7 +281,7 @@ void
rust_be_error_at (rich_location *richloc, const ErrorCode code,
const std::string &errmsg)
{
- diagnostic_metadata m;
+ diagnostics::metadata m;
rust_error_code_rule rule (code);
m.add_rule (rule);
error_meta (richloc, m, "%s", errmsg.c_str ());
diff --git a/gcc/selftest-run-tests.cc b/gcc/selftest-run-tests.cc
index d43d9dd..c68d3e7 100644
--- a/gcc/selftest-run-tests.cc
+++ b/gcc/selftest-run-tests.cc
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "analyzer/analyzer-selftests.h"
+#include "diagnostics/diagnostics-selftests.h"
#include "text-art/selftests.h"
/* This function needed to be split out from selftest.cc as it references
@@ -94,25 +95,17 @@ selftest::run_tests ()
digraph_cc_tests ();
tristate_cc_tests ();
ipa_modref_tree_cc_tests ();
- selftest_logical_location_cc_tests ();
+
+ /* Run the diagnostics selftests. */
+ diagnostics::selftest::run_diagnostics_selftests ();
/* Higher-level tests, or for components that other selftests don't
rely on. */
- diagnostic_color_cc_tests ();
- diagnostic_show_locus_cc_tests ();
- diagnostic_format_html_cc_tests ();
- diagnostic_format_sarif_cc_tests ();
- diagnostic_digraphs_cc_tests ();
- diagnostic_output_spec_cc_tests ();
- diagnostic_state_graphs_cc_tests ();
- edit_context_cc_tests ();
fold_const_cc_tests ();
spellcheck_cc_tests ();
spellcheck_tree_cc_tests ();
tree_cfg_cc_tests ();
- diagnostic_path_output_cc_tests ();
simple_diagnostic_path_cc_tests ();
- lazy_diagnostic_path_cc_tests ();
attribs_cc_tests ();
path_coverage_cc_tests ();
diff --git a/gcc/selftest.cc b/gcc/selftest.cc
index 4fdce07..dc90340 100644
--- a/gcc/selftest.cc
+++ b/gcc/selftest.cc
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "selftest.h"
+#include "diagnostics/file-cache.h"
#include "intl.h"
#if CHECKING_P
@@ -186,7 +187,7 @@ assert_str_startswith (const location &loc,
/* Constructor. Generate a name for the file. */
named_temp_file::named_temp_file (const char *suffix,
- file_cache *fc)
+ diagnostics::file_cache *fc)
{
m_filename = make_temp_file (suffix);
ASSERT_NE (m_filename, NULL);
@@ -210,7 +211,7 @@ named_temp_file::~named_temp_file ()
temp_source_file::temp_source_file (const location &loc,
const char *suffix,
const char *content,
- file_cache *fc)
+ diagnostics::file_cache *fc)
: named_temp_file (suffix, fc)
{
FILE *out = fopen (get_filename (), "w");
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 06485e1..4501d34 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -25,7 +25,7 @@ along with GCC; see the file COPYING3. If not see
#if CHECKING_P
-class file_cache;
+namespace diagnostics { class file_cache; }
namespace selftest {
@@ -100,13 +100,13 @@ extern void assert_str_startswith (const location &loc,
class named_temp_file
{
public:
- named_temp_file (const char *suffix, file_cache *fc = nullptr);
+ named_temp_file (const char *suffix, diagnostics::file_cache *fc = nullptr);
~named_temp_file ();
const char *get_filename () const { return m_filename; }
private:
char *m_filename;
- file_cache *m_file_cache;
+ diagnostics::file_cache *m_file_cache;
};
/* A class for writing out a temporary sourcefile for use in selftests
@@ -116,7 +116,7 @@ class temp_source_file : public named_temp_file
{
public:
temp_source_file (const location &loc, const char *suffix,
- const char *content, file_cache *fc = nullptr);
+ const char *content, diagnostics::file_cache *fc = nullptr);
temp_source_file (const location &loc, const char *suffix,
const char *content, size_t sz);
};
@@ -221,17 +221,8 @@ extern void bitmap_cc_tests ();
extern void cgraph_cc_tests ();
extern void convert_cc_tests ();
extern void dbgcnt_cc_tests ();
-extern void diagnostic_color_cc_tests ();
-extern void diagnostic_digraphs_cc_tests ();
-extern void diagnostic_format_html_cc_tests ();
-extern void diagnostic_format_sarif_cc_tests ();
-extern void diagnostic_output_spec_cc_tests ();
-extern void diagnostic_path_output_cc_tests ();
-extern void diagnostic_show_locus_cc_tests ();
-extern void diagnostic_state_graphs_cc_tests ();
extern void digraph_cc_tests ();
extern void dumpfile_cc_tests ();
-extern void edit_context_cc_tests ();
extern void et_forest_cc_tests ();
extern void fibonacci_heap_cc_tests ();
extern void fold_const_cc_tests ();
@@ -248,7 +239,6 @@ extern void input_cc_tests ();
extern void ipa_modref_tree_cc_tests ();
extern void json_cc_tests ();
extern void json_parser_cc_tests ();
-extern void lazy_diagnostic_path_cc_tests ();
extern void opt_suggestions_cc_tests ();
extern void optinfo_emit_json_cc_tests ();
extern void opts_cc_tests ();
@@ -263,7 +253,6 @@ extern void relation_tests ();
extern void rtl_tests_cc_tests ();
extern void sbitmap_cc_tests ();
extern void selftest_cc_tests ();
-extern void selftest_logical_location_cc_tests ();
extern void simple_diagnostic_path_cc_tests ();
extern void simplify_rtx_cc_tests ();
extern void spellcheck_cc_tests ();
diff --git a/gcc/simple-diagnostic-path.cc b/gcc/simple-diagnostic-path.cc
index d64f7b6..2e112b5 100644
--- a/gcc/simple-diagnostic-path.cc
+++ b/gcc/simple-diagnostic-path.cc
@@ -1,4 +1,4 @@
-/* Concrete classes for implementing diagnostic paths.
+/* Concrete classes for implementing diagnostic paths, using tree.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>
@@ -32,29 +32,31 @@ along with GCC; see the file COPYING3. If not see
#include "simple-diagnostic-path.h"
#include "selftest.h"
-/* class simple_diagnostic_path : public diagnostic_path. */
+using namespace diagnostics::paths;
+
+/* class simple_diagnostic_path : public diagnostics::paths::path. */
simple_diagnostic_path::
simple_diagnostic_path (const tree_logical_location_manager &logical_loc_mgr,
pretty_printer *event_pp)
-: diagnostic_path (logical_loc_mgr),
+: path (logical_loc_mgr),
m_event_pp (event_pp),
m_localize_events (true)
{
add_thread ("main");
}
-/* Implementation of diagnostic_path::get_event vfunc for
+/* Implementation of path::get_event vfunc for
simple_diagnostic_path: simply return the event in the vec. */
-const diagnostic_event &
+const event &
simple_diagnostic_path::get_event (int idx) const
{
return *m_events[idx];
}
-const diagnostic_thread &
-simple_diagnostic_path::get_thread (diagnostic_thread_id_t idx) const
+const thread &
+simple_diagnostic_path::get_thread (thread_id_t idx) const
{
return *m_threads[idx];
}
@@ -67,7 +69,7 @@ simple_diagnostic_path::same_function_p (int event_idx_a,
== m_events[event_idx_b]->get_fndecl ());
}
-diagnostic_thread_id_t
+thread_id_t
simple_diagnostic_path::add_thread (const char *name)
{
m_threads.safe_push (new simple_diagnostic_thread (name));
@@ -82,7 +84,7 @@ simple_diagnostic_path::add_thread (const char *name)
Return the id of the new event. */
-diagnostic_event_id_t
+event_id_t
simple_diagnostic_path::add_event (location_t loc, tree fndecl, int depth,
const char *fmt, ...)
{
@@ -108,11 +110,11 @@ simple_diagnostic_path::add_event (location_t loc, tree fndecl, int depth,
pp_clear_output_area (pp);
- return diagnostic_event_id_t (m_events.length () - 1);
+ return event_id_t (m_events.length () - 1);
}
-diagnostic_event_id_t
-simple_diagnostic_path::add_thread_event (diagnostic_thread_id_t thread_id,
+event_id_t
+simple_diagnostic_path::add_thread_event (thread_id_t thread_id,
location_t loc,
tree fndecl,
int depth,
@@ -141,7 +143,7 @@ simple_diagnostic_path::add_thread_event (diagnostic_thread_id_t thread_id,
pp_clear_output_area (pp);
- return diagnostic_event_id_t (m_events.length () - 1);
+ return event_id_t (m_events.length () - 1);
}
/* Mark the most recent event on this path (which must exist) as being
@@ -163,7 +165,7 @@ simple_diagnostic_event (location_t loc,
tree fndecl,
int depth,
const char *desc,
- diagnostic_thread_id_t thread_id)
+ thread_id_t thread_id)
: m_loc (loc), m_fndecl (fndecl),
m_logical_loc (tree_logical_location_manager::key_from_tree (fndecl)),
m_depth (depth), m_desc (xstrdup (desc)),
diff --git a/gcc/simple-diagnostic-path.h b/gcc/simple-diagnostic-path.h
index d2b366e..d549c24 100644
--- a/gcc/simple-diagnostic-path.h
+++ b/gcc/simple-diagnostic-path.h
@@ -1,4 +1,4 @@
-/* Concrete classes for implementing diagnostic paths.
+/* Concrete classes for implementing diagnostic paths, using tree.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>
@@ -21,26 +21,30 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_SIMPLE_DIAGNOSTIC_PATH_H
#define GCC_SIMPLE_DIAGNOSTIC_PATH_H
-#include "diagnostic-path.h"
+#include "diagnostics/paths.h"
#include "tree-logical-location.h"
/* Concrete subclasses of the abstract base classes
declared in diagnostic-path.h. */
-/* A simple implementation of diagnostic_event. */
+/* A simple implementation of diagnostic event.
+ This uses "tree" and so is not in "namespace diagnostics". */
-class simple_diagnostic_event : public diagnostic_event
+class simple_diagnostic_event : public diagnostics::paths::event
{
public:
+ using thread_id_t = diagnostics::paths::thread_id_t;
+
simple_diagnostic_event (location_t loc, tree fndecl, int depth,
const char *desc,
- diagnostic_thread_id_t thread_id = 0);
+ thread_id_t thread_id = 0);
~simple_diagnostic_event ();
location_t get_location () const final override { return m_loc; }
int get_stack_depth () const final override { return m_depth; }
void print_desc (pretty_printer &pp) const final override;
- logical_location get_logical_location () const final override
+ diagnostics::logical_locations::key
+ get_logical_location () const final override
{
return tree_logical_location_manager::key_from_tree (m_fndecl);
}
@@ -52,7 +56,7 @@ class simple_diagnostic_event : public diagnostic_event
{
return m_connected_to_next_event;
}
- diagnostic_thread_id_t get_thread_id () const final override
+ thread_id_t get_thread_id () const final override
{
return m_thread_id;
}
@@ -67,16 +71,16 @@ class simple_diagnostic_event : public diagnostic_event
private:
location_t m_loc;
tree m_fndecl;
- logical_location m_logical_loc;
+ diagnostics::logical_locations::key m_logical_loc;
int m_depth;
char *m_desc; // has been i18n-ed and formatted
bool m_connected_to_next_event;
- diagnostic_thread_id_t m_thread_id;
+ thread_id_t m_thread_id;
};
-/* A simple implementation of diagnostic_thread. */
+/* A simple implementation of diagnostics::paths::thread. */
-class simple_diagnostic_thread : public diagnostic_thread
+class simple_diagnostic_thread : public diagnostics::paths::thread
{
public:
simple_diagnostic_thread (const char *name) : m_name (name) {}
@@ -92,28 +96,33 @@ private:
/* A simple implementation of diagnostic_path, as a vector of
simple_diagnostic_event instances. */
-class simple_diagnostic_path : public diagnostic_path
+class simple_diagnostic_path : public diagnostics::paths::path
{
public:
+ using thread = diagnostics::paths::thread;
+ using thread_id_t = diagnostics::paths::thread_id_t;
+ using event = diagnostics::paths::event;
+ using event_id_t = diagnostics::paths::event_id_t;
+
simple_diagnostic_path (const tree_logical_location_manager &logical_loc_mgr,
pretty_printer *event_pp);
unsigned num_events () const final override { return m_events.length (); }
- const diagnostic_event & get_event (int idx) const final override;
+ const event & get_event (int idx) const final override;
unsigned num_threads () const final override { return m_threads.length (); }
- const diagnostic_thread &
- get_thread (diagnostic_thread_id_t) const final override;
+ const thread &
+ get_thread (thread_id_t) const final override;
bool
same_function_p (int event_idx_a,
int event_idx_b) const final override;
- diagnostic_thread_id_t add_thread (const char *name);
+ thread_id_t add_thread (const char *name);
- diagnostic_event_id_t add_event (location_t loc, tree fndecl, int depth,
- const char *fmt, ...)
+ event_id_t add_event (location_t loc, tree fndecl, int depth,
+ const char *fmt, ...)
ATTRIBUTE_GCC_DIAG(5,6);
- diagnostic_event_id_t
- add_thread_event (diagnostic_thread_id_t thread_id,
+ event_id_t
+ add_thread_event (thread_id_t thread_id,
location_t loc, tree fndecl, int depth,
const char *fmt, ...)
ATTRIBUTE_GCC_DIAG(6,7);
diff --git a/gcc/stmt.cc b/gcc/stmt.cc
index a510f8f..7942aa3 100644
--- a/gcc/stmt.cc
+++ b/gcc/stmt.cc
@@ -39,6 +39,8 @@ along with GCC; see the file COPYING3. If not see
#include "emit-rtl.h"
#include "pretty-print.h"
#include "diagnostic-core.h"
+#include "output.h"
+#include "gimplify_reg_info.h"
#include "fold-const.h"
#include "varasm.h"
@@ -53,6 +55,7 @@ along with GCC; see the file COPYING3. If not see
#include "dumpfile.h"
#include "builtins.h"
#include "cfgexpand.h"
+#include "output.h"
/* Functions and data structures for expanding case statements. */
@@ -175,6 +178,77 @@ expand_label (tree label)
maybe_set_first_label_num (label_r);
}
+/* Parse a hard register constraint and return its number or -1 in case of an
+ error. BEGIN should point to a string of the form `{regname}`. For the
+ sake of simplicity assume that a register name is not longer than 31
+ characters, if not error out. */
+
+int
+decode_hard_reg_constraint (const char *begin)
+{
+ if (*begin != '{')
+ return -1;
+ ++begin;
+ const char *end = begin;
+ while (*end != '}' && *end != '\0')
+ ++end;
+ if (*end != '}' || end == begin)
+ return -1;
+ ptrdiff_t len = end - begin;
+ if (len >= 31)
+ return -1;
+ char regname[32];
+ memcpy (regname, begin, len);
+ regname[len] = '\0';
+ int regno = decode_reg_name (regname);
+ return regno;
+}
+
+static bool
+eliminable_regno_p (int regnum)
+{
+ static const struct
+ {
+ const int from;
+ const int to;
+ } eliminables[] = ELIMINABLE_REGS;
+ for (size_t i = 0; i < ARRAY_SIZE (eliminables); i++)
+ if (regnum == eliminables[i].from)
+ return true;
+ return false;
+}
+
+/* Perform a similar check as done in make_decl_rtl(). */
+
+static bool
+hardreg_ok_p (int reg_number, machine_mode mode, int operand_num)
+{
+ if (mode == BLKmode)
+ error ("data type isn%'t suitable for register %s of operand %i",
+ reg_names[reg_number], operand_num);
+ else if (!in_hard_reg_set_p (accessible_reg_set, mode, reg_number))
+ error ("register %s for operand %i cannot be accessed"
+ " by the current target", reg_names[reg_number], operand_num);
+ else if (!in_hard_reg_set_p (operand_reg_set, mode, reg_number))
+ error ("register %s for operand %i is not general enough"
+ " to be used as a register variable", reg_names[reg_number], operand_num);
+ else if (!targetm.hard_regno_mode_ok (reg_number, mode))
+ error ("register %s for operand %i isn%'t suitable for data type",
+ reg_names[reg_number], operand_num);
+ else if (reg_number != HARD_FRAME_POINTER_REGNUM
+ && (reg_number == FRAME_POINTER_REGNUM
+#ifdef RETURN_ADDRESS_POINTER_REGNUM
+ || reg_number == RETURN_ADDRESS_POINTER_REGNUM
+#endif
+ || reg_number == ARG_POINTER_REGNUM)
+ && eliminable_regno_p (reg_number))
+ error ("register for operand %i is an internal GCC "
+ "implementation detail", operand_num);
+ else
+ return true;
+ return false;
+}
+
/* Parse the output constraint pointed to by *CONSTRAINT_P. It is the
OPERAND_NUMth output operand, indexed from zero. There are NINPUTS
inputs and NOUTPUTS outputs to this extended-asm. Upon return,
@@ -191,7 +265,8 @@ expand_label (tree label)
bool
parse_output_constraint (const char **constraint_p, int operand_num,
int ninputs, int noutputs, bool *allows_mem,
- bool *allows_reg, bool *is_inout)
+ bool *allows_reg, bool *is_inout,
+ gimplify_reg_info *reg_info)
{
const char *constraint = *constraint_p;
const char *p;
@@ -245,6 +320,9 @@ parse_output_constraint (const char **constraint_p, int operand_num,
constraint = *constraint_p;
}
+ unsigned int alt = 0;
+ bool early_clobbered = false;
+
/* Loop through the constraint string. */
for (p = constraint + 1; *p; )
{
@@ -264,12 +342,21 @@ parse_output_constraint (const char **constraint_p, int operand_num,
}
break;
- case '?': case '!': case '*': case '&': case '#':
+ case '&':
+ early_clobbered = true;
+ break;
+
+ case '?': case '!': case '*': case '#':
case '$': case '^':
case 'E': case 'F': case 'G': case 'H':
case 's': case 'i': case 'n':
case 'I': case 'J': case 'K': case 'L': case 'M':
- case 'N': case 'O': case 'P': case ',': case '-':
+ case 'N': case 'O': case 'P': case '-':
+ break;
+
+ case ',':
+ ++alt;
+ early_clobbered = false;
break;
case '0': case '1': case '2': case '3': case '4':
@@ -294,6 +381,60 @@ parse_output_constraint (const char **constraint_p, int operand_num,
*allows_mem = true;
break;
+ case '{':
+ {
+ if (!targetm.lra_p ())
+ {
+ error ("hard register constraints are only supported while using LRA");
+ return false;
+ }
+ if (reg_info)
+ {
+ int regno = decode_hard_reg_constraint (p);
+ if (regno < 0)
+ {
+ error ("invalid output constraint: %s", p);
+ return false;
+ }
+ int overlap_regno = reg_info->test_alt_output (alt, regno);
+ if (overlap_regno < 0)
+ overlap_regno = reg_info->test_reg_asm_output (regno);
+ if (overlap_regno >= 0)
+ {
+ error ("multiple outputs to hard register: %s",
+ reg_names[overlap_regno]);
+ return false;
+ }
+ reg_info->set_output (alt, regno);
+ if (early_clobbered)
+ reg_info->set_early_clobbered (alt, operand_num, regno);
+ if (reg_info->is_clobbered (regno))
+ {
+ error ("hard register constraint for output %i conflicts "
+ "with %<asm%> clobber list", operand_num);
+ return false;
+ }
+ if (VAR_P (reg_info->operand)
+ && DECL_HARD_REGISTER (reg_info->operand))
+ {
+ tree id = DECL_ASSEMBLER_NAME (reg_info->operand);
+ const char *asmspec = IDENTIFIER_POINTER (id) + 1;
+ int regno_op = decode_reg_name (asmspec);
+ if (regno != regno_op)
+ {
+ error ("constraint and register %<asm%> for output "
+ "operand %i are unsatisfiable", operand_num);
+ return false;
+ }
+ }
+ machine_mode mode = TYPE_MODE (TREE_TYPE (reg_info->operand));
+ if (!hardreg_ok_p (regno, mode, operand_num))
+ return false;
+ }
+ *allows_reg = true;
+ break;
+ }
+
default:
if (!ISALPHA (*p))
break;
@@ -305,6 +446,31 @@ parse_output_constraint (const char **constraint_p, int operand_num,
*allows_mem = true;
else
insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
+ if (reg_info && *allows_reg
+ && VAR_P (reg_info->operand)
+ && DECL_HARD_REGISTER (reg_info->operand))
+ {
+ tree id = DECL_ASSEMBLER_NAME (reg_info->operand);
+ const char *asmspec = IDENTIFIER_POINTER (id) + 1;
+ int regno = decode_reg_name (asmspec);
+ if (regno < 0)
+ {
+ location_t loc = DECL_SOURCE_LOCATION (reg_info->operand);
+ error_at (loc, "invalid register name for %q+D",
+ reg_info->operand);
+ return false;
+ }
+ int overlap_regno = reg_info->test_alt_output (alt, regno);
+ if (overlap_regno >= 0)
+ {
+ error ("multiple outputs to hard register: %s",
+ reg_names[overlap_regno]);
+ return false;
+ }
+ reg_info->set_reg_asm_output (regno);
+ if (early_clobbered)
+ reg_info->set_early_clobbered (alt, operand_num, regno);
+ }
break;
}
@@ -322,7 +488,8 @@ bool
parse_input_constraint (const char **constraint_p, int input_num,
int ninputs, int noutputs, int ninout,
const char * const * constraints,
- bool *allows_mem, bool *allows_reg)
+ bool *allows_mem, bool *allows_reg,
+ gimplify_reg_info *reg_info)
{
const char *constraint = *constraint_p;
const char *orig_constraint = constraint;
@@ -338,6 +505,9 @@ parse_input_constraint (const char **constraint_p, int input_num,
/* Make sure constraint has neither `=', `+', nor '&'. */
+ unsigned int alt = 0;
+ unsigned long match = 0;
+
for (j = 0; j < c_len; j += CONSTRAINT_LEN (constraint[j], constraint+j))
switch (constraint[j])
{
@@ -364,7 +534,7 @@ parse_input_constraint (const char **constraint_p, int input_num,
case 'E': case 'F': case 'G': case 'H':
case 's': case 'i': case 'n':
case 'I': case 'J': case 'K': case 'L': case 'M':
- case 'N': case 'O': case 'P': case ',': case '-':
+ case 'N': case 'O': case 'P': case '-':
break;
case ':':
@@ -382,6 +552,10 @@ parse_input_constraint (const char **constraint_p, int input_num,
}
break;
+ case ',':
+ ++alt;
+ break;
+
/* Whether or not a numeric constraint allows a register is
decided by the matching constraint, and so there is no need
to do anything special with them. We must handle them in
@@ -391,7 +565,6 @@ parse_input_constraint (const char **constraint_p, int input_num,
case '5': case '6': case '7': case '8': case '9':
{
char *end;
- unsigned long match;
saw_match = true;
@@ -429,6 +602,65 @@ parse_input_constraint (const char **constraint_p, int input_num,
*allows_mem = true;
break;
+ case '{':
+ {
+ if (!targetm.lra_p ())
+ {
+ error ("hard register constraints are only supported while using LRA");
+ return false;
+ }
+ if (reg_info)
+ {
+ int regno = decode_hard_reg_constraint (constraint + j);
+ if (regno < 0)
+ {
+ error ("invalid input constraint: %s", constraint + j);
+ return false;
+ }
+ int overlap_regno = reg_info->test_alt_input (alt, regno);
+ if (overlap_regno < 0)
+ overlap_regno = reg_info->test_reg_asm_input (regno);
+ if (overlap_regno >= 0)
+ {
+ error ("multiple inputs to hard register: %s",
+ reg_names[overlap_regno]);
+ return false;
+ }
+ reg_info->set_input (alt, regno);
+ if (reg_info->is_clobbered (regno))
+ {
+ error ("hard register constraint for input %i conflicts "
+ "with %<asm%> clobber list", input_num);
+ return false;
+ }
+ if (constraint == orig_constraint
+ && reg_info->test_early_clobbered_alt (alt, regno))
+ {
+ error ("invalid hard register usage between earlyclobber "
+ "operand and input operand");
+ return false;
+ }
+ if (VAR_P (reg_info->operand)
+ && DECL_HARD_REGISTER (reg_info->operand))
+ {
+ tree id = DECL_ASSEMBLER_NAME (reg_info->operand);
+ const char *asmspec = IDENTIFIER_POINTER (id) + 1;
+ int regno_op = decode_reg_name (asmspec);
+ if (regno != regno_op)
+ {
+ error ("constraint and register %<asm%> for input "
+ "operand %i are unsatisfiable", input_num);
+ return false;
+ }
+ }
+ machine_mode mode = TYPE_MODE (TREE_TYPE (reg_info->operand));
+ if (!hardreg_ok_p (regno, mode, input_num))
+ return false;
+ }
+ *allows_reg = true;
+ break;
+ }
+
default:
if (! ISALPHA (constraint[j]))
{
@@ -445,6 +677,39 @@ parse_input_constraint (const char **constraint_p, int input_num,
*allows_mem = true;
else
insn_extra_constraint_allows_reg_mem (cn, allows_reg, allows_mem);
+ if (reg_info && *allows_reg
+ && VAR_P (reg_info->operand)
+ && DECL_HARD_REGISTER (reg_info->operand))
+ {
+ tree id = DECL_ASSEMBLER_NAME (reg_info->operand);
+ const char *asmspec = IDENTIFIER_POINTER (id) + 1;
+ int regno = decode_reg_name (asmspec);
+ if (regno < 0)
+ {
+ location_t loc = DECL_SOURCE_LOCATION (reg_info->operand);
+ error_at (loc, "invalid register name for %q+D",
+ reg_info->operand);
+ return false;
+ }
+ int overlap_regno = reg_info->test_alt_input (alt, regno);
+ if (overlap_regno >= 0)
+ {
+ error ("multiple inputs to hard register: %s",
+ reg_names[overlap_regno]);
+ return false;
+ }
+ reg_info->set_reg_asm_input (regno);
+ if ((constraint == orig_constraint
+ && reg_info->test_early_clobbered_alt (alt, regno))
+ || (constraint != orig_constraint
+ && reg_info->is_early_clobbered_in_any_output_unequal
+ (match, regno)))
+ {
+ error ("invalid hard register usage between earlyclobber "
+ "operand and input operand");
+ return false;
+ }
+ }
break;
}
diff --git a/gcc/stmt.h b/gcc/stmt.h
index 2beb4d5..c178036 100644
--- a/gcc/stmt.h
+++ b/gcc/stmt.h
@@ -20,11 +20,16 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_STMT_H
#define GCC_STMT_H
+class gimplify_reg_info;
+
extern void expand_label (tree);
extern bool parse_output_constraint (const char **, int, int, int,
- bool *, bool *, bool *);
+ bool *, bool *, bool *,
+ gimplify_reg_info *);
extern bool parse_input_constraint (const char **, int, int, int, int,
- const char * const *, bool *, bool *);
+ const char * const *, bool *, bool *,
+ gimplify_reg_info *);
+extern int decode_hard_reg_constraint (const char *);
extern tree resolve_asm_operand_names (tree, tree, tree, tree);
#ifdef HARD_CONST
/* Silly ifdef to avoid having all includers depend on hard-reg-set.h. */
diff --git a/gcc/substring-locations.cc b/gcc/substring-locations.cc
index 78ce722..2f920ca 100644
--- a/gcc/substring-locations.cc
+++ b/gcc/substring-locations.cc
@@ -151,7 +151,7 @@ format_string_diagnostic_t (const substring_loc &fmt_loc,
Return true if a warning was emitted, false otherwise. */
bool
-format_string_diagnostic_t::emit_warning_n_va (diagnostic_option_id option_id,
+format_string_diagnostic_t::emit_warning_n_va (diagnostics::option_id option_id,
unsigned HOST_WIDE_INT n,
const char *singular_gmsgid,
const char *plural_gmsgid,
@@ -203,7 +203,7 @@ format_string_diagnostic_t::emit_warning_n_va (diagnostic_option_id option_id,
if (!err && m_corrected_substring && substring_within_range)
richloc.add_fixit_replace (fmt_substring_range, m_corrected_substring);
- diagnostic_info diagnostic;
+ diagnostics::diagnostic_info diagnostic;
if (singular_gmsgid != plural_gmsgid)
{
unsigned long gtn;
@@ -218,12 +218,12 @@ format_string_diagnostic_t::emit_warning_n_va (diagnostic_option_id option_id,
const char *text = ngettext (singular_gmsgid, plural_gmsgid, gtn);
diagnostic_set_info_translated (&diagnostic, text, ap, &richloc,
- DK_WARNING);
+ diagnostics::kind::warning);
}
else
diagnostic_set_info (&diagnostic, singular_gmsgid, ap, &richloc,
- DK_WARNING);
- diagnostic.option_id = option_id;
+ diagnostics::kind::warning);
+ diagnostic.m_option_id = option_id;
bool warned = diagnostic_report_diagnostic (global_dc, &diagnostic);
if (!err && fmt_substring_loc && !substring_within_range)
@@ -248,7 +248,7 @@ format_string_diagnostic_t::emit_warning_n_va (diagnostic_option_id option_id,
/* Singular-only version of the above. */
bool
-format_string_diagnostic_t::emit_warning_va (diagnostic_option_id option_id,
+format_string_diagnostic_t::emit_warning_va (diagnostics::option_id option_id,
const char *gmsgid,
va_list *ap) const
{
@@ -258,7 +258,7 @@ format_string_diagnostic_t::emit_warning_va (diagnostic_option_id option_id,
/* Variadic version of the above (singular only). */
bool
-format_string_diagnostic_t::emit_warning (diagnostic_option_id option_id,
+format_string_diagnostic_t::emit_warning (diagnostics::option_id option_id,
const char *gmsgid,
...) const
{
@@ -273,7 +273,7 @@ format_string_diagnostic_t::emit_warning (diagnostic_option_id option_id,
/* Variadic version of the above (singular vs plural). */
bool
-format_string_diagnostic_t::emit_warning_n (diagnostic_option_id option_id,
+format_string_diagnostic_t::emit_warning_n (diagnostics::option_id option_id,
unsigned HOST_WIDE_INT n,
const char *singular_gmsgid,
const char *plural_gmsgid,
diff --git a/gcc/substring-locations.h b/gcc/substring-locations.h
index fee7a89..94139e2 100644
--- a/gcc/substring-locations.h
+++ b/gcc/substring-locations.h
@@ -90,23 +90,23 @@ class format_string_diagnostic_t
/* Functions for emitting a warning about a format string. */
- bool emit_warning_va (diagnostic_option_id option_id,
+ bool emit_warning_va (diagnostics::option_id option_id,
const char *gmsgid,
va_list *ap) const
ATTRIBUTE_GCC_DIAG (3, 0);
- bool emit_warning_n_va (diagnostic_option_id option_id,
+ bool emit_warning_n_va (diagnostics::option_id option_id,
unsigned HOST_WIDE_INT n,
const char *singular_gmsgid,
const char *plural_gmsgid,
va_list *ap) const
ATTRIBUTE_GCC_DIAG (4, 0) ATTRIBUTE_GCC_DIAG (5, 0);
- bool emit_warning (diagnostic_option_id option_id,
+ bool emit_warning (diagnostics::option_id option_id,
const char *gmsgid, ...) const
ATTRIBUTE_GCC_DIAG (3, 4);
- bool emit_warning_n (diagnostic_option_id option_id,
+ bool emit_warning_n (diagnostics::option_id option_id,
unsigned HOST_WIDE_INT n,
const char *singular_gmsgid,
const char *plural_gmsgid, ...) const
@@ -125,7 +125,7 @@ class format_string_diagnostic_t
LANG_HOOKS_GET_SUBSTRING_LOCATION. */
extern const char *get_location_within_string (cpp_reader *pfile,
- file_cache &fc,
+ diagnostics::file_cache &fc,
string_concat_db *concats,
location_t strloc,
enum cpp_ttype type,
diff --git a/gcc/symtab.cc b/gcc/symtab.cc
index fc1155f..652f66a 100644
--- a/gcc/symtab.cc
+++ b/gcc/symtab.cc
@@ -305,6 +305,7 @@ symbol_table::change_decl_assembler_name (tree decl, tree name)
SET_DECL_ASSEMBLER_NAME (decl, name);
if (alias)
{
+ gcc_assert (!IDENTIFIER_INTERNAL_P (name));
IDENTIFIER_TRANSPARENT_ALIAS (name) = 1;
TREE_CHAIN (name) = alias;
}
diff --git a/gcc/target.def b/gcc/target.def
index 38903eb..427dc40 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -1918,17 +1918,21 @@ implementation approaches itself.",
NULL)
/* Return true if the target supports misaligned store/load of a
- specific factor denoted in the third parameter. The last parameter
- is true if the access is defined in a packed struct. */
+ specific factor denoted in the third parameter. The second to the last
+ parameter is true if the access is defined in a packed struct and
+ the last parameter is true if the access is a gather/scatter. */
DEFHOOK
(support_vector_misalignment,
"This hook should return true if the target supports misaligned vector\n\
store/load of a specific factor denoted in the @var{misalignment}\n\
parameter. The vector store/load should be of machine mode @var{mode} and\n\
-the elements in the vectors should be of type @var{type}. @var{is_packed}\n\
-parameter is true if the memory access is defined in a packed struct.",
+the elements in the vectors should be of type @var{type}. The\n\
+@var{is_packed} parameter is true if the misalignment is unknown and the\n\
+memory access is defined in a packed struct. @var{is_gather_scatter} is true\n\
+if the load/store is a gather or scatter.",
bool,
- (machine_mode mode, const_tree type, int misalignment, bool is_packed),
+ (machine_mode mode, const_tree type, int misalignment, bool is_packed,
+ bool is_gather_scatter),
default_builtin_support_vector_misalignment)
/* Returns the preferred mode for SIMD operations for the specified
diff --git a/gcc/target.h b/gcc/target.h
index c9c7b52..47f1846 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -169,7 +169,6 @@ class predefined_function_abi;
struct store_fwd_info;
/* These are defined in tree-vect-stmts.cc. */
-extern tree stmt_vectype (class _stmt_vec_info *);
extern bool stmt_in_inner_loop_p (class vec_info *, class _stmt_vec_info *);
/* Assembler instructions for creating various kinds of integer object. */
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index c79458e..e723bbb 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -1556,6 +1556,8 @@ default_builtin_support_vector_misalignment (machine_mode mode,
int misalignment
ATTRIBUTE_UNUSED,
bool is_packed
+ ATTRIBUTE_UNUSED,
+ bool is_gather_scatter
ATTRIBUTE_UNUSED)
{
if (optab_handler (movmisalign_optab, mode) != CODE_FOR_nothing)
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index f16b587..3fa20af 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -114,7 +114,7 @@ extern bool default_builtin_vector_alignment_reachable (const_tree, bool);
extern bool
default_builtin_support_vector_misalignment (machine_mode mode,
const_tree,
- int, bool);
+ int, bool, bool);
extern machine_mode default_preferred_simd_mode (scalar_mode mode);
extern machine_mode default_split_reduction (machine_mode);
extern unsigned int default_autovectorize_vector_modes (vector_modes *, bool);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 0818631..3b5f40c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,627 @@
+2025-07-27 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ * g++.dg/modules/class-11_a.H: New test.
+ * g++.dg/modules/class-11_b.C: New test.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/diagnostic_plugin_test_graphs.cc: Eliminate
+ digraphs::lazy_digraph and digraphs::lazy_digraphs in favor of
+ lazily_created template.
+ * gcc.dg/plugin/diagnostic_plugin_test_metadata.cc: Define
+ INCLUDE_VECTOR since diagnostics/metadata.h now requires it.
+ * gcc.dg/plugin/diagnostic_plugin_test_paths.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/diagnostic_plugin_show_trees.cc: Make
+ diagnostics::context::m_source_printing private.
+ * gcc.dg/plugin/diagnostic_plugin_test_inlining.cc: Likewise.
+ * gcc.dg/plugin/diagnostic_plugin_test_string_literals.cc:
+ Likewise.
+ * gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.cc:
+ Likewise.
+ * gcc.dg/plugin/diagnostic_plugin_test_paths.cc: Likewise.
+ * gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc: Likewise.
+ * gcc.dg/plugin/expensive_selftests_plugin.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * g++.dg/plugin/show_template_tree_color_plugin.cc: Update usage
+ of "diagnostic_info" to explicitly refer to
+ "diagnostics::diagnostic_info".
+ * gcc.dg/plugin/diagnostic_group_plugin.cc: Likewise.
+ * gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc: Likewise.
+ * gcc.dg/plugin/location_overflow_plugin.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc: Update for
+ file_cache and char_span moving from input.h to
+ diagnostics/file-cache.h and into the "diagnostics::" namespace.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc: Update for
+ diagnostic_t becoming enum class diagnostics::kind.
+ * gcc.dg/plugin/expensive_selftests_plugin.cc: Likewise.
+ * gcc.dg/plugin/location_overflow_plugin.cc: Likewise.
+ * lib/gcc-dg.exp: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/expensive_selftests_plugin.cc: Update for change
+ from edit-context.h to changes.h.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/expensive_selftests_plugin.cc: Update for move of
+ selftest::test_diagnostic_context to
+ diagnostics::selftest::test_context.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/analyzer_cpython_plugin.cc: Update for move of
+ diagnostic-color.h to diagnostics/color.h.
+ * gcc.dg/plugin/analyzer_kernel_plugin.cc: Likewise.
+ * gcc.dg/plugin/analyzer_known_fns_plugin.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/expensive_selftests_plugin.cc: Update for move of
+ selftest-diagnostic.h to diagnostics/selftest-context.h.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * g++.dg/plugin/show_template_tree_color_plugin.cc: Update for
+ moves to namespace diagnostics.
+ * gcc.dg/plugin/diagnostic_group_plugin.cc: Likewise.
+ * gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc: Likewise.
+ * gcc.dg/plugin/location_overflow_plugin.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc: Update to
+ add "m_" prefix to fields of diagnostic_info throughout.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * g++.dg/plugin/show-template-tree-color-labels.C: Update for
+ moves to "source-printing".
+ * gcc.dg/plugin/diagnostic-test-show-locus.py: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/diagnostic_group_plugin.cc: Update for move of
+ diagnostics output formats into namespace "diagnostics" as
+ "sinks".
+ * gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc: Likewise.
+ * gcc.dg/plugin/location_overflow_plugin.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/analyzer_gil_plugin.cc: Update #include for
+ "diagnostic-path.h" moving to "diagnostics/paths.h",
+ diagnostic_thread_id_t to diagnostics::paths::thread_id_t,
+ diagnostic_event_id_t to diagnostics::paths::event_id_t,
+ diagnostic_path to diagnostics::paths::path, and
+ diagnostic_thread to diagnostics::paths::thread, and
+ diagnostic_event to diagnostics::paths::event.
+ * gcc.dg/plugin/diagnostic_plugin_test_paths.cc: Likewise.
+ * lib/sarif.py (get_state_graph): Update property prefix for
+ threadFlowLocations from "gcc/diagnostic_event/" to
+ "gcc/diagnostics/paths/event/".
+ * gcc.dg/sarif-output/include-chain-2.h: Update comment.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/expensive_selftests_plugin.cc: Update #include for
+ move of edit-context.h to diagnostics subdir. Update
+ for move of edit_context to diagnostics::edit_context.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/diagnostic_plugin_test_text_art.cc: Update
+ #include for move of "diagnostic-diagram.h" to
+ "diagnostics/diagram.h". Update for move of diagnostic_diagram to
+ diagnostics::diagram.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/analyzer_cpython_plugin.cc: : Update #include for
+ move of "diagnostic-metadata.h" to "diagnostics/metadata.h"
+ * gcc.dg/plugin/analyzer_kernel_plugin.cc: Likewise.
+ * gcc.dg/plugin/analyzer_known_fns_plugin.cc: Likewise.
+ * gcc.dg/plugin/diagnostic_plugin_test_graphs.cc: Likewise. Also
+ update for move of diagnostic_metadata to diagnostics::metadata.
+ * gcc.dg/plugin/diagnostic_plugin_test_metadata.cc: Likewise.
+ * gcc.dg/plugin/diagnostic_plugin_test_paths.cc: Likewise.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/diagnostic_plugin_test_graphs.cc: Update #include
+ for move of "diagnostic-digraphs.h" to "diagnostics/digraphs.h".
+
+2025-07-25 Patrick Palka <ppalka@redhat.com>
+
+ * g++.dg/lookup/operator-8.C: Remove XFAILs and properly
+ suppress all -Wunused-result warnings.
+
+2025-07-25 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/121219
+ * g++.dg/coroutines/torture/pr121219.C: New test.
+
+2025-07-25 Christoph Müllner <christoph.muellner@vrull.eu>
+
+ * gcc.target/riscv/interrupt-conflict-mode.c: Remove "user"
+ interrupts.
+ * gcc.target/riscv/xtheadint-push-pop.c: Likewise.
+ * gcc.target/riscv/interrupt-umode.c: Removed.
+
+2025-07-25 Christoph Müllner <christoph.muellner@vrull.eu>
+
+ * gcc.target/riscv/interrupt-rnmi.c: New test.
+
+2025-07-24 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/117294
+ PR c++/113854
+ * g++.dg/cpp2a/concepts-traits3.C: Adjust diagnostics.
+ * g++.dg/cpp2a/concepts-traits4.C: New test.
+ * g++.dg/diagnostic/static_assert5.C: New test.
+ * g++.dg/ext/has_virtual_destructor2.C: New test.
+ * g++.dg/ext/is_assignable2.C: New test.
+ * g++.dg/ext/is_constructible9.C: New test.
+ * g++.dg/ext/is_convertible7.C: New test.
+ * g++.dg/ext/is_destructible3.C: New test.
+ * g++.dg/ext/is_invocable6.C: New test.
+ * g++.dg/ext/is_virtual_base_of_diagnostic2.C: New test.
+
+2025-07-24 Jason Merrill <jason@redhat.com>
+
+ PR c++/114632
+ PR c++/101233
+ * g++.dg/cpp23/explicit-obj-lambda18.C: New test.
+ * g++.dg/cpp23/static-operator-call7.C: New test.
+
+2025-07-24 Robert Dubner <rdubner@symas.com>
+
+ * cobol.dg/group2/_-static__compilation.cob: Modify for -static warning.
+ * cobol.dg/group2/_-static__compilation.out: Removed.
+
+2025-07-24 Robin Dapp <rdapp@ventanamicro.com>
+
+ * lib/target-supports.exp: Fix misalignment check.
+
+2025-07-24 Spencer Abson <spencer.abson@arm.com>
+
+ * g++.target/aarch64/sve/unpacked_cond_binary_bf16_1.C: New test.
+ * gcc.target/aarch64/sve/unpacked_cond_builtin_fmax_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_builtin_fmin_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_fadd_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_fdiv_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_fmaxnm_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_fminnm_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_fmul_1.c: Likewise..
+ * gcc.target/aarch64/sve/unpacked_cond_fsubr_1.c: Likewise.
+
+2025-07-24 Spencer Abson <spencer.abson@arm.com>
+
+ * gcc.target/aarch64/sve/unpacked_fdiv_1.c: New test.
+ * gcc.target/aarch64/sve/unpacked_fdiv_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_fdiv_3.c: Likewise.
+
+2025-07-24 Spencer Abson <spencer.abson@arm.com>
+
+ * g++.target/aarch64/sve/unpacked_binary_bf16_1.C: New test.
+ * g++.target/aarch64/sve/unpacked_binary_bf16_2.C: Likewise.
+ * gcc.target/aarch64/sve/unpacked_builtin_fmax_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_builtin_fmax_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_builtin_fmin_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_builtin_fmin_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_fadd_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_fadd_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_fmaxnm_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_fmaxnm_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_fminnm_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_fminnm_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_fmul_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_fmul_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_fsubr_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_fsubr_2.c: Likewise.
+
+2025-07-24 Jeevitha Palanisamy <jeevitha@linux.ibm.com>
+
+ PR testsuite/119382
+ * gcc.target/powerpc/vsx-builtin-7.c: Add '-fno-ipa-icf' to dg-options.
+
+2025-07-24 Pan Li <pan2.li@intel.com>
+
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u16.c: New test.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u32.c: New test.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u64.c: New test.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u8.c: New test.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm.h: New test.
+
+2025-07-24 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/120412
+ * g++.dg/modules/internal-14_a.C: New test.
+ * g++.dg/modules/internal-14_b.C: New test.
+ * g++.dg/modules/internal-14_c.C: New test.
+
+2025-07-23 Spencer Abson <spencer.abson@arm.com>
+
+ * gcc.target/aarch64/sve/unpacked_cond_fabs_1.c: New test.
+ * gcc.target/aarch64/sve/unpacked_cond_fneg_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_frinta_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_frinta_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_frinti_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_frintm_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_frintp_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_frintx_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_frintz_1.c: Likewise.
+
+2025-07-23 Spencer Abson <spencer.abson@arm.com>
+
+ * gcc.target/aarch64/sve/unpacked_fabs_1.c: New test.
+ * gcc.target/aarch64/sve/unpacked_fneg_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frinta_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frinta_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frinti_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frinti_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frintm_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frintm_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frintp_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frintp_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frintx_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frintx_2.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frintz_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_frintz_2.c: Likewise.
+
+2025-07-23 Spencer Abson <spencer.abson@arm.com>
+
+ * gcc.target/aarch64/sve/unpacked_cond_cvtf_1.c: New test.
+ * gcc.target/aarch64/sve/unpacked_cond_fcvt_1.c: Likewise.
+ * gcc.target/aarch64/sve/unpacked_cond_fcvtz_1.c: Likewise.
+
+2025-07-23 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/121203
+ * gfortran.dg/function_charlen_4.f90: New test.
+
+2025-07-23 Robin Dapp <rdapp@ventanamicro.com>
+
+ PR target/121073
+ * gcc.target/riscv/rvv/autovec/vls-vlmax/repeat-6.c: Adjust test
+ expectation.
+ * gcc.target/riscv/rvv/base/scalar_move-5.c: Ditto.
+ * gcc.target/riscv/rvv/base/scalar_move-6.c: Ditto.
+ * gcc.target/riscv/rvv/base/scalar_move-7.c: Ditto.
+ * gcc.target/riscv/rvv/base/scalar_move-8.c: Ditto.
+ * gcc.target/riscv/rvv/base/scalar_move-9.c: Ditto.
+ * gcc.target/riscv/rvv/pr121073.c: New test.
+
+2025-07-23 Robin Dapp <rdapp@ventanamicro.com>
+
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmacc-run-1-f16.c:
+ Add zvfh requirements and options.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c:
+ Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsac-run-1-f16.c:
+ Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c:
+ Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmacc-run-1-f16.c:
+ Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmadd-run-1-f16.c:
+ Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsac-run-1-f16.c:
+ Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsub-run-1-f16.c:
+ Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmacc-run-1-f16.c:
+ Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmsac-run-1-f16.c:
+ Ditto.
+ * lib/target-supports.exp: Add zvfh options.
+
+2025-07-23 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR target/120119
+ * g++.dg/torture/pr120119-1.C: New test.
+
+2025-07-23 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/121179
+ * g++.dg/lookup/operator-8.C: Strengthen test and remove one
+ XFAIL.
+
+2025-07-23 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/121055
+ * g++.dg/ext/is_invocable5.C: New test.
+
+2025-07-23 Spencer Abson <spencer.abson@arm.com>
+
+ * lib/gcc-defs.exp (aarch64-arg-dg-options): Split add_tune into
+ add_tune and add_override, so that specifying -moverride does not
+ change the baseline tuning from the testuite's default (generic).
+
+2025-07-23 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/121220
+ * gcc.dg/tree-ssa/ssa-sink-23.c: New testcase.
+
+2025-07-23 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/119085
+ * gcc.dg/tree-ssa/pr119085.c: New test.
+
+2025-07-23 Gaius Mulley <gaiusmod2@gmail.com>
+
+ PR modula2/121164
+ * gm2/switches/pedantic-params/fail/arrayofchar.def: New test.
+ * gm2/switches/pedantic-params/fail/arrayofchar.mod: New test.
+
+2025-07-23 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/121216
+ * gcc.dg/pr121216.c: New testcase.
+
+2025-07-23 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR testsuite/120101
+ * gcc.dg/tree-ssa/pr81627.c (fn1): Mark as noinline.
+
+2025-07-23 Siddhesh Poyarekar <siddhesh@gotplt.org>
+
+ * gcc.dg/vect/pr116125.c (mem_overlap): Expand A to 10 members.
+
+2025-07-22 Jason Merrill <jason@redhat.com>
+
+ PR c++/121068
+ * g++.dg/cpp2a/constexpr-union6.C: Expect x5 to work.
+ * g++.dg/cpp26/constexpr-new4.C: New test.
+
+2025-07-22 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/warn/Wmismatched-new-delete-5.C: Fix allocation.
+
+2025-07-22 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR middle-end/109267
+ * lib/target-supports.exp (check_effective_target_trap): New proc.
+ * g++.dg/missing-return.C: Update testcase for the !trap case.
+ * gcc.dg/pr109267-1.c: New test.
+ * gcc.dg/pr109267-2.c: New test.
+
+2025-07-22 Karl Meakin <karl.meakin@arm.com>
+
+ * gcc.target/aarch64/sve/mask_load_2.c: Update tests.
+
+2025-07-22 Karl Meakin <karl.meakin@arm.com>
+
+ * gcc.target/aarch64/sve/mask_load_2.c: New test.
+
+2025-07-22 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/121202
+ * gcc.dg/pr121202.c: New testcase.
+
+2025-07-22 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/vect/slp-28.c: Adjust.
+
+2025-07-21 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR tree-optimization/110949
+ PR tree-optimization/95906
+ * gcc.dg/tree-ssa/cmp-2.c: New test.
+ * gcc.dg/tree-ssa/max-bitcmp-1.c: New test.
+
+2025-07-21 Pan Li <pan2.li@intel.com>
+
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u64.c: Add asm check.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u64.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u64.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u64.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u64.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u64.c: New test.
+
+2025-07-21 Pan Li <pan2.li@intel.com>
+
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c: Add asm check.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u8.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u16.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u32.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u8.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u16.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u32.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u8.c: Ditto.
+
+2025-07-21 Pan Li <pan2.li@intel.com>
+
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c: Add asm check.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u8.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u16.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u32.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u8.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u16.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u32.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u8.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h: Add test
+ helper macros.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h: Add test
+ data for run test.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u16.c: New test.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u32.c: New test.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u8.c: New test.
+
+2025-07-21 Kyrylo Tkachov <ktkachov@nvidia.com>
+
+ * gcc.target/aarch64/simd/mf8_data_1.c (test_set_lane4,
+ test_setq_lane4): Relax allowed assembly.
+ * gcc.target/aarch64/vec-set-zero.c: Use -Os in flags.
+ * gcc.target/aarch64/inszero_split_1.c: New test.
+
+2025-07-21 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/121194
+ * gcc.dg/torture/pr121194.c: New testcase.
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * gcc.dg/pr87600-2.c: Split test into two files since errors for
+ functions test{0,1} are thrown during expand, and for
+ test{2,3} during gimplification.
+ * lib/scanasm.exp: On s390, skip lines beginning with #.
+ * gcc.dg/asm-hard-reg-error-1.c: New test.
+ * gcc.dg/asm-hard-reg-error-2.c: New test.
+ * gcc.dg/asm-hard-reg-error-3.c: New test.
+ * gcc.dg/asm-hard-reg-error-4.c: New test.
+ * gcc.dg/asm-hard-reg-error-5.c: New test.
+ * gcc.dg/pr87600-3.c: New test.
+ * gcc.target/aarch64/asm-hard-reg-2.c: New test.
+ * gcc.target/s390/asm-hard-reg-7.c: New test.
+
+2025-07-21 Stefan Schulze Frielinghaus <stefansf@gcc.gnu.org>
+
+ * gcc.dg/asm-hard-reg-1.c: New test.
+ * gcc.dg/asm-hard-reg-2.c: New test.
+ * gcc.dg/asm-hard-reg-3.c: New test.
+ * gcc.dg/asm-hard-reg-4.c: New test.
+ * gcc.dg/asm-hard-reg-5.c: New test.
+ * gcc.dg/asm-hard-reg-6.c: New test.
+ * gcc.dg/asm-hard-reg-7.c: New test.
+ * gcc.dg/asm-hard-reg-8.c: New test.
+ * gcc.target/aarch64/asm-hard-reg-1.c: New test.
+ * gcc.target/i386/asm-hard-reg-1.c: New test.
+ * gcc.target/i386/asm-hard-reg-2.c: New test.
+ * gcc.target/s390/asm-hard-reg-1.c: New test.
+ * gcc.target/s390/asm-hard-reg-2.c: New test.
+ * gcc.target/s390/asm-hard-reg-3.c: New test.
+ * gcc.target/s390/asm-hard-reg-4.c: New test.
+ * gcc.target/s390/asm-hard-reg-5.c: New test.
+ * gcc.target/s390/asm-hard-reg-6.c: New test.
+ * gcc.target/s390/asm-hard-reg-longdouble.h: New test.
+
+2025-07-21 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/vect/vect-127.c: New testcase.
+
+2025-07-21 Andre Vehreschild <vehre@gcc.gnu.org>
+
+ PR fortran/119106
+ * gfortran.dg/array_constructor_58.f90: New test.
+
+2025-07-21 panciyan <panciyan@eswincomputing.com>
+
+ * gcc.target/riscv/sat/sat_arith.h: Unsigned testcase form8 form9.
+ * gcc.target/riscv/sat/sat_u_add-8-u16.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-8-u32.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-8-u64.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-8-u8.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-9-u16.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-9-u32.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-9-u64.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-9-u8.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-run-8-u16.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-run-8-u32.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-run-8-u64.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-run-8-u8.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-run-9-u16.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-run-9-u32.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-run-9-u64.c: New test.
+ * gcc.target/riscv/sat/sat_u_add-run-9-u8.c: New test.
+
+2025-07-20 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR testsuite/120859
+ * gcc.dg/tree-prof/afdo-crossmodule-1b.c: Add some dg-*
+ commands like what is in afdo-crossmodule-1.c
+
+2025-07-20 Pan Li <pan2.li@intel.com>
+
+ * gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i32.c:
+ Leverage DEF_AVG_0_WRAP to generate the correct func name.
+ * gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i64.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_floor-1-i32-from-i64.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_floor-1-i64-from-i128.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i16.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i32.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i64.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i32.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i64.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_ceil-1-i32-from-i64.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i16.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i32.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i64.c: Ditto.
+ * gcc.target/riscv/rvv/autovec/avg_ceil-1-i64-from-i128.c: Ditto.
+
+2025-07-19 Dimitar Dimitrov <dimitar@dinux.eu>
+
+ PR target/121124
+ * gcc.target/pru/pragma-ctable_entry-2.c: New test.
+
+2025-07-19 Paul-Antoine Arras <parras@baylibre.com>
+
+ PR target/119100
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c: Add vfwnmacc and
+ vfwnmsac.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c: Likewise.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c: Likewise.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c: Likewise.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c: Likewise.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c: Likewise.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c: Likewise.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c: Likewise.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmacc-run-1-f16.c: New test.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmacc-run-1-f32.c: New test.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmsac-run-1-f16.c: New test.
+ * gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmsac-run-1-f32.c: New test.
+
+2025-07-18 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/121145
+ * gfortran.dg/pointer_check_15.f90: New test.
+
+2025-07-18 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR testsuite/121153
+ * gcc.dg/vect/vect-reduc-cond-1.c: Require vect_condition.
+ * gcc.dg/vect/vect-reduc-cond-2.c: Likewise.
+
+2025-07-18 Pan Li <pan2.li@intel.com>
+
+ * gcc.target/riscv/rvv/autovec/avg_data.h: Adjust the test data.
+ * gcc.target/riscv/rvv/autovec/avg_ceil-1-i64-from-i128.c: New test.
+ * gcc.target/riscv/rvv/autovec/avg_ceil-run-1-i64-from-i128.c: New test.
+
+2025-07-18 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/117423
+ * gcc.dg/tree-ssa/pr117423.c: New test.
+
+2025-07-18 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/121126
+ * gcc.dg/vect/pr121126.c: New testcase.
+
+2025-07-18 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/120924
+ * gcc.dg/uninit-pr120924.c: New testcase.
+
+2025-07-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/121131
+ * gcc.dg/bitint-124.c: New test.
+
2025-07-17 Jason Merrill <jason@redhat.com>
PR c++/87097
diff --git a/gcc/testsuite/cobol.dg/group2/_-static__compilation.cob b/gcc/testsuite/cobol.dg/group2/_-static__compilation.cob
index 7843d3d..f344a84 100644
--- a/gcc/testsuite/cobol.dg/group2/_-static__compilation.cob
+++ b/gcc/testsuite/cobol.dg/group2/_-static__compilation.cob
@@ -1,7 +1,7 @@
*> { dg-do run }
*> { dg-options "-static" }
- *> { dg-output-file "group2/_-static__compilation.out" }
-
+ *> { dg-prune-output {warning} }
+ *> { dg-output {hello, world} }
IDENTIFICATION DIVISION.
PROGRAM-ID. prog.
PROCEDURE DIVISION.
diff --git a/gcc/testsuite/cobol.dg/group2/_-static__compilation.out b/gcc/testsuite/cobol.dg/group2/_-static__compilation.out
deleted file mode 100644
index ae0e511..0000000
--- a/gcc/testsuite/cobol.dg/group2/_-static__compilation.out
+++ /dev/null
@@ -1,2 +0,0 @@
-hello, world
-
diff --git a/gcc/testsuite/g++.dg/coroutines/torture/pr121219.C b/gcc/testsuite/g++.dg/coroutines/torture/pr121219.C
new file mode 100644
index 0000000..d1e7cb1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/torture/pr121219.C
@@ -0,0 +1,149 @@
+// PR c++/121219
+// { dg-do run }
+
+#include <coroutine>
+#ifdef OUTPUT
+#include <iostream>
+#endif
+#include <stdexcept>
+
+struct Task {
+ struct promise_type;
+ using handle_type = std::coroutine_handle<promise_type>;
+
+ struct promise_type {
+ Task* task_;
+ int result_;
+
+ static void* operator new(std::size_t size) noexcept {
+ void* p = ::operator new(size, std::nothrow);
+#ifdef OUTPUT
+ std::cerr << "operator new (no arg) " << size << " -> " << p << std::endl;
+#endif
+ return p;
+ }
+ static void operator delete(void* ptr) noexcept {
+ return ::operator delete(ptr, std::nothrow);
+ }
+#if 1 // change to 0 to fix crash
+ static Task get_return_object_on_allocation_failure() noexcept {
+#ifdef OUTPUT
+ std::cerr << "get_return_object_on_allocation_failure" << std::endl;
+#endif
+ return Task(nullptr);
+ }
+#endif
+
+ auto get_return_object() {
+#ifdef OUTPUT
+ std::cerr << "get_return_object" << std::endl;
+#endif
+ return Task{handle_type::from_promise(*this)};
+ }
+
+ auto initial_suspend() {
+#ifdef OUTPUT
+ std::cerr << "initial_suspend" << std::endl;
+#endif
+ return std::suspend_always{};
+ }
+
+ auto final_suspend() noexcept {
+#ifdef OUTPUT
+ std::cerr << "final_suspend" << std::endl;
+#endif
+ return std::suspend_never{}; // Coroutine auto-destructs
+ }
+
+ ~promise_type() {
+ if (task_) {
+#ifdef OUTPUT
+ std::cerr << "promise_type destructor: Clearing Task handle" << std::endl;
+#endif
+ task_->h_ = nullptr;
+ }
+ }
+
+ void unhandled_exception() {
+#ifdef OUTPUT
+ std::cerr << "unhandled_exception" << std::endl;
+#endif
+ std::terminate();
+ }
+
+ void return_value(int value) {
+#ifdef OUTPUT
+ std::cerr << "return_value: " << value << std::endl;
+#endif
+ result_ = value;
+ if (task_) {
+ task_->result_ = value;
+ task_->completed_ = true;
+ }
+ }
+ };
+
+ handle_type h_;
+ int result_;
+ bool completed_ = false;
+
+ Task(handle_type h) : h_(h) {
+#ifdef OUTPUT
+ std::cerr << "Task constructor" << std::endl;
+#endif
+ if (h_) {
+ h_.promise().task_ = this; // Link promise to Task
+ }
+ }
+
+ ~Task() {
+#ifdef OUTPUT
+ std::cerr << "~Task destructor" << std::endl;
+#endif
+ // Only destroy handle if still valid (coroutine not completed)
+ if (h_) {
+#ifdef OUTPUT
+ std::cerr << "Destroying coroutine handle" << std::endl;
+#endif
+ h_.destroy();
+ }
+ }
+
+ bool done() const {
+ return completed_ || !h_ || h_.done();
+ }
+
+ void resume() {
+#ifdef OUTPUT
+ std::cerr << "Resuming task" << std::endl;
+#endif
+ if (h_) h_.resume();
+ }
+
+ int result() const {
+ if (!done()) throw std::runtime_error("Result not available");
+ return result_;
+ }
+};
+
+Task my_coroutine() {
+#ifdef OUTPUT
+ std::cerr << "Inside my_coroutine" << std::endl;
+#endif
+ co_return 42;
+}
+
+int main() {
+ auto task = my_coroutine();
+ while (!task.done()) {
+#ifdef OUTPUT
+ std::cerr << "Resuming task in main" << std::endl;
+#endif
+ task.resume();
+ }
+#ifdef OUTPUT
+ std::cerr << "Task completed in main, printing result" << std::endl;
+#endif
+ if (task.result() != 42)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda18.C b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda18.C
new file mode 100644
index 0000000..d54a93d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda18.C
@@ -0,0 +1,12 @@
+// PR c++/114632
+// { dg-do compile { target c++23 } }
+
+struct S {};
+
+auto lambda = [](this auto& self, const int x) /* -> void */ {};
+
+int main()
+{
+ void (*func)(S&, int) = lambda; // { dg-error "" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp23/static-operator-call7.C b/gcc/testsuite/g++.dg/cpp23/static-operator-call7.C
new file mode 100644
index 0000000..7c381e6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/static-operator-call7.C
@@ -0,0 +1,12 @@
+// PR c++/114632
+// { dg-do compile { target c++23 } }
+
+struct S {};
+
+auto lambda = [](auto, const int x) static /* -> void */ {};
+
+int main()
+{
+ void (*func)(int, int) = lambda;
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-new4.C b/gcc/testsuite/g++.dg/cpp26/constexpr-new4.C
new file mode 100644
index 0000000..12d8a46
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new4.C
@@ -0,0 +1,21 @@
+// PR c++/121068
+// { dg-do compile { target c++26 } }
+
+constexpr void *operator new (__SIZE_TYPE__, void *p) { return p; }
+constexpr void *operator new[] (__SIZE_TYPE__, void *p) { return p; }
+
+consteval int
+foo()
+{
+ using T = int;
+ union { T arr[3]; };
+ new(arr) T[3]; // makes arr active
+ for (int i = 0; i < 3; ++i)
+ arr[i].~T();
+
+ new (arr + 2) T{10}; // A
+
+ return 1;
+};
+
+constexpr int g = foo();
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C
index 3e87da4..90d859a 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-traits3.C
@@ -1,49 +1,58 @@
// PR c++/100474
// { dg-do compile { target c++20 } }
-struct S { S() = delete; S(const S&); };
+struct S { S() = delete; S(const S&); }; // { dg-line S }
template<class T>
concept Aggregate = __is_aggregate(T);
-// { dg-message "'S' is not an aggregate" "" { target *-*-* } .-1 }
+// { dg-message "'S' is not an aggregate" "" { target *-*-* } S }
template<class T>
concept TriviallyCopyable = __is_trivially_copyable(T);
-// { dg-message "'S' is not trivially copyable" "" { target *-*-* } .-1 }
+// { dg-message "'S' is not trivially copyable" "" { target *-*-* } S }
template<class T, class U>
concept Assignable = __is_assignable(T, U);
-// { dg-message "'S' is not assignable from 'int'" "" { target *-*-* } .-1 }
+// { dg-message "'S' is not assignable from 'int', because" "" { target *-*-* } .-1 }
+// { dg-error "no match for 'operator='" "" { target *-*-* } .-2 }
template<class T, class U>
concept TriviallyAssignable = __is_trivially_assignable(T, U);
// { dg-message "'S' is not trivially assignable from 'int'" "" { target *-*-* } .-1 }
+// { dg-error "no match for 'operator='" "" { target *-*-* } .-2 }
template<class T, class U>
concept NothrowAssignable = __is_nothrow_assignable(T, U);
// { dg-message "'S' is not nothrow assignable from 'int'" "" { target *-*-* } .-1 }
+// { dg-error "no match for 'operator='" "" { target *-*-* } .-2 }
template<class T, class... Args>
concept Constructible = __is_constructible(T, Args...);
// { dg-message "'S' is not default constructible" "" { target *-*-* } .-1 }
-// { dg-message "'S' is not constructible from 'int'" "" { target *-*-* } .-2 }
-// { dg-message "'S' is not constructible from 'int, char'" "" { target *-*-* } .-3 }
+// { dg-error "use of deleted function 'S::S\\(\\)'" "" { target *-*-* } .-2 }
+// { dg-message "'S' is not constructible from 'int'" "" { target *-*-* } .-3 }
+// { dg-message "'S' is not constructible from 'int, char'" "" { target *-*-* } .-4 }
+// { dg-error "no matching function for call to 'S::S" "" { target *-*-* } .-5 }
template<class T, class... Args>
concept TriviallyConstructible = __is_trivially_constructible(T, Args...);
// { dg-message "'S' is not trivially default constructible" "" { target *-*-* } .-1 }
-// { dg-message "'S' is not trivially constructible from 'int'" "" { target *-*-* } .-2 }
-// { dg-message "'S' is not trivially constructible from 'int, char'" "" { target *-*-* } .-3 }
+// { dg-error "use of deleted function 'S::S\\(\\)'" "" { target *-*-* } .-2 }
+// { dg-message "'S' is not trivially constructible from 'int'" "" { target *-*-* } .-3 }
+// { dg-message "'S' is not trivially constructible from 'int, char'" "" { target *-*-* } .-4 }
+// { dg-error "no matching function for call to 'S::S" "" { target *-*-* } .-5 }
template<class T, class... Args>
concept NothrowConstructible = __is_nothrow_constructible(T, Args...);
// { dg-message "'S' is not nothrow default constructible" "" { target *-*-* } .-1 }
-// { dg-message "'S' is not nothrow constructible from 'int'" "" { target *-*-* } .-2 }
-// { dg-message "'S' is not nothrow constructible from 'int, char'" "" { target *-*-* } .-3 }
+// { dg-error "use of deleted function 'S::S\\(\\)'" "" { target *-*-* } .-2 }
+// { dg-message "'S' is not nothrow constructible from 'int'" "" { target *-*-* } .-3 }
+// { dg-message "'S' is not nothrow constructible from 'int, char'" "" { target *-*-* } .-4 }
+// { dg-error "no matching function for call to 'S::S" "" { target *-*-* } .-5 }
template<class T>
concept UniqueObjReps = __has_unique_object_representations(T);
-// { dg-message "'S' does not have unique object representations" "" { target *-*-* } .-1 }
+// { dg-message "'S' does not have unique object representations" "" { target *-*-* } S }
static_assert(Aggregate<S>); // { dg-error "assert" }
static_assert(TriviallyCopyable<S>); // { dg-error "assert" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-traits4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-traits4.C
new file mode 100644
index 0000000..caad816
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-traits4.C
@@ -0,0 +1,77 @@
+// PR c++/117294
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-fconcepts-diagnostics-depth=2" }
+
+template <typename T> struct norm
+ { static constexpr bool value = __is_constructible(T); };
+template <typename T> constexpr bool norm_v = __is_constructible(T);
+
+template <typename T> struct part
+ { static constexpr bool value = __is_constructible(T); };
+template <typename T> struct part<T*>
+ { static constexpr bool value = false; };
+template <typename T> struct part<const T>
+ { static constexpr bool value = __is_same(T, void); };
+template <typename T> constexpr bool part_v = __is_constructible(T);
+template <typename T> constexpr bool part_v<T*> = false;
+template <typename T> constexpr bool part_v<const T> = __is_same(T, void);
+
+template <typename T> struct expl
+ { static constexpr bool value = __is_constructible(T); };
+template <> struct expl<int*>
+ { static constexpr bool value = false; };
+template <> struct expl<const int>
+ { static constexpr bool value = __is_same(int, void); };
+template <typename T> constexpr bool expl_v = __is_constructible(T);
+template <> constexpr bool expl_v<int*> = false;
+template <> constexpr bool expl_v<const int> = __is_same(int, void);
+
+template <typename T> concept test_norm = norm<T>::value; // { dg-line norm }
+template <typename T> concept test_part = part<T>::value; // { dg-line part }
+template <typename T> concept test_expl = expl<T>::value; // { dg-line expl }
+template <typename T> concept test_norm_v = norm_v<T>; // { dg-line norm_v }
+template <typename T> concept test_part_v = part_v<T>; // { dg-line part_v }
+template <typename T> concept test_expl_v = expl_v<T>; // { dg-line expl_v }
+
+static_assert(test_norm<void>); // { dg-error "assert" }
+static_assert(test_part<void>); // { dg-error "assert" }
+static_assert(test_expl<void>); // { dg-error "assert" }
+static_assert(test_norm_v<void>); // { dg-error "assert" }
+static_assert(test_part_v<void>); // { dg-error "assert" }
+static_assert(test_expl_v<void>); // { dg-error "assert" }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } norm }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } part }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } expl }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } norm_v }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } part_v }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } expl_v }
+// { dg-prune-output "'void' is incomplete" }
+
+static_assert(test_part<int*>); // { dg-error "assert" }
+static_assert(test_expl<int*>); // { dg-error "assert" }
+static_assert(test_part_v<int*>); // { dg-error "assert" }
+static_assert(test_expl_v<int*>); // { dg-error "assert" }
+// { dg-message ".with T = int\\*.. evaluated to .false." "" { target *-*-* } part }
+// { dg-message ".with T = int\\*.. evaluated to .false." "" { target *-*-* } expl }
+// { dg-message ".with T = int\\*.. evaluated to .false." "" { target *-*-* } part_v }
+// { dg-message ".with T = int\\*.. evaluated to .false." "" { target *-*-* } expl_v }
+
+static_assert(test_part<const int>); // { dg-error "assert" }
+static_assert(test_part_v<const int>); // { dg-error "assert" }
+// { dg-message "'int' is not the same as 'void'" "" { target *-*-* } part }
+// { dg-message "'int' is not the same as 'void'" "" { target *-*-* } part_v }
+
+struct S { S(int); };
+static_assert(requires { requires test_norm<S>; }); // { dg-error "assert" }
+static_assert(requires { requires test_part<S>; }); // { dg-error "assert" }
+static_assert(requires { requires test_expl<S>; }); // { dg-error "assert" }
+static_assert(requires { requires test_norm_v<S>; }); // { dg-error "assert" }
+static_assert(requires { requires test_part_v<S>; }); // { dg-error "assert" }
+static_assert(requires { requires test_expl_v<S>; }); // { dg-error "assert" }
+// { dg-message "'S' is not default constructible" "" { target *-*-* } norm }
+// { dg-message "'S' is not default constructible" "" { target *-*-* } part }
+// { dg-message "'S' is not default constructible" "" { target *-*-* } expl }
+// { dg-message "'S' is not default constructible" "" { target *-*-* } norm_v }
+// { dg-message "'S' is not default constructible" "" { target *-*-* } part_v }
+// { dg-message "'S' is not default constructible" "" { target *-*-* } expl_v }
+// { dg-prune-output "no matching function for call" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-union6.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-union6.C
index 00bda53..ab8c979 100644
--- a/gcc/testsuite/g++.dg/cpp2a/constexpr-union6.C
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-union6.C
@@ -45,9 +45,9 @@ constexpr int test5() {
union {
int data[1];
} u;
- std::construct_at(u.data, 0); // { dg-message "in .constexpr. expansion" }
+ std::construct_at(u.data, 0); // { dg-bogus "in .constexpr. expansion" }
return 0;
}
-constexpr int x5 = test5(); // { dg-message "in .constexpr. expansion" }
+constexpr int x5 = test5(); // { dg-bogus "in .constexpr. expansion" }
// { dg-error "accessing (uninitialized member|.* member instead of)" "" { target *-*-* } 0 }
diff --git a/gcc/testsuite/g++.dg/diagnostic/static_assert5.C b/gcc/testsuite/g++.dg/diagnostic/static_assert5.C
new file mode 100644
index 0000000..16681b2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/static_assert5.C
@@ -0,0 +1,70 @@
+// PR c++/117294
+// { dg-do compile { target c++14 } }
+
+template <typename T> struct norm
+ { static constexpr bool value = __is_constructible(T); };
+template <typename T> constexpr bool norm_v = __is_constructible(T);
+
+template <typename T> struct part
+ { static constexpr bool value = __is_constructible(T); };
+template <typename T> struct part<T*>
+ { static constexpr bool value = false; };
+template <typename T> struct part<const T>
+ { static constexpr bool value = __is_same(T, void); };
+template <typename T> constexpr bool part_v = __is_constructible(T);
+template <typename T> constexpr bool part_v<T*> = false;
+template <typename T> constexpr bool part_v<const T> = __is_same(T, void);
+
+template <typename T> struct expl
+ { static constexpr bool value = __is_constructible(T); };
+template <> struct expl<int*>
+ { static constexpr bool value = false; };
+template <> struct expl<const int>
+ { static constexpr bool value = __is_same(int, void); };
+template <typename T> constexpr bool expl_v = __is_constructible(T);
+template <> constexpr bool expl_v<int*> = false;
+template <> constexpr bool expl_v<const int> = __is_same(int, void);
+
+// === Primary template can give customised diagnostics when using traits
+static_assert(norm<void>::value); // { dg-error "assert" }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } .-1 }
+static_assert(part<void>::value); // { dg-error "assert" }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } .-1 }
+static_assert(expl<void>::value); // { dg-error "assert" }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } .-1 }
+static_assert(norm_v<void>); // { dg-error "assert" }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } .-1 }
+static_assert(part_v<void>); // { dg-error "assert" }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } .-1 }
+static_assert(expl_v<void>); // { dg-error "assert" }
+// { dg-message "'void' is not default constructible" "" { target *-*-* } .-1 }
+
+// { dg-prune-output "'void' is incomplete" }
+
+
+// === Specialisations don't customise just because primary template had trait
+static_assert(part<int*>::value); // { dg-error "assert" }
+// { dg-bogus "default constructible" "" { target *-*-* } .-1 }
+static_assert(expl<int*>::value); // { dg-error "assert" }
+// { dg-bogus "default constructible" "" { target *-*-* } .-1 }
+static_assert(part_v<int*>); // { dg-error "assert" }
+// { dg-bogus "default constructible" "" { target *-*-* } .-1 }
+static_assert(expl_v<int*>); // { dg-error "assert" }
+// { dg-bogus "default constructible" "" { target *-*-* } .-1 }
+
+
+// === But partial specialisations actually using a trait can customise
+static_assert(part<const int>::value); // { dg-error "assert" }
+// { dg-message "'int' is not the same as 'void'" "" { target *-*-* } .-1 }
+static_assert(part_v<const int>); // { dg-error "assert" }
+// { dg-message "'int' is not the same as 'void'" "" { target *-*-* } .-1 }
+
+
+// === For these cases, we no longer know that the error was caused by the trait
+// === because it's been folded away before we process the failure.
+static_assert(expl<const int>::value); // { dg-error "assert" }
+// { dg-bogus "because" "" { target *-*-* } .-1 }
+static_assert(expl_v<const int>); // { dg-error "assert" }
+// { dg-bogus "because" "" { target *-*-* } .-1 }
+static_assert(__is_constructible(void)); // { dg-error "assert" }
+// { dg-bogus "because" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/ext/has_virtual_destructor2.C b/gcc/testsuite/g++.dg/ext/has_virtual_destructor2.C
new file mode 100644
index 0000000..14eea80
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/has_virtual_destructor2.C
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++11 } }
+
+template <typename T> struct has_virtual_destructor {
+ static constexpr bool value = __has_virtual_destructor(T);
+};
+
+static_assert(has_virtual_destructor<int>::value, ""); // { dg-error "assert" }
+// { dg-message "'int' does not have a virtual destructor" "" { target *-*-* } .-1 }
+
+struct A {}; // { dg-message "'A' does not have a virtual destructor" }
+static_assert(has_virtual_destructor<A>::value, ""); // { dg-error "assert" }
+
+struct B {
+ ~B(); // { dg-message "'B' does not have a virtual destructor" }
+};
+static_assert(has_virtual_destructor<B>::value, ""); // { dg-error "assert" }
+
+struct C { // { dg-bogus "" }
+ virtual ~C(); // { dg-bogus "" }
+};
+static_assert(has_virtual_destructor<C[5]>::value, ""); // { dg-error "assert" }
+// { dg-message "'C \\\[5\\\]' does not have a virtual destructor" "" { target *-*-* } .-1 }
+
+union U { // { dg-message "'U' does not have a virtual destructor" }
+ ~U();
+};
+static_assert(has_virtual_destructor<U>::value, ""); // { dg-error "assert" }
diff --git a/gcc/testsuite/g++.dg/ext/is_assignable2.C b/gcc/testsuite/g++.dg/ext/is_assignable2.C
new file mode 100644
index 0000000..b346d7b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_assignable2.C
@@ -0,0 +1,36 @@
+// { dg-do compile { target c++11 } }
+
+template <typename T>
+struct is_copy_assignable {
+ static constexpr bool value = __is_assignable(T&, const T&);
+};
+
+static_assert(is_copy_assignable<const int>::value, ""); // { dg-error "assert" }
+// { dg-error "assignment to read-only type 'const int'" "" { target *-*-* } .-1 }
+
+struct A {
+ void operator=(A) = delete; // { dg-message "declared here" }
+};
+static_assert(is_copy_assignable<A>::value, ""); // { dg-error "assert" }
+// { dg-message "is not assignable" "" { target *-*-* } .-1 }
+// { dg-error "use of deleted function" "" { target *-*-* } .-2 }
+
+template <typename T>
+struct is_nothrow_copy_assignable {
+ static constexpr bool value = __is_nothrow_assignable(T&, const T&);
+};
+struct B {
+ void operator=(const B&); // { dg-message "noexcept" }
+};
+static_assert(is_nothrow_copy_assignable<B>::value, ""); // { dg-error "assert" }
+// { dg-message "is not nothrow assignable" "" { target *-*-* } .-1 }
+
+template <typename T>
+struct is_trivially_copy_assignable {
+ static constexpr bool value = __is_trivially_assignable(T&, const T&);
+};
+struct C {
+ void operator=(const C&); // { dg-message "non-trivial" }
+};
+static_assert(is_trivially_copy_assignable<C>::value, ""); // { dg-error "assert" }
+// { dg-message "is not trivially assignable" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/ext/is_constructible9.C b/gcc/testsuite/g++.dg/ext/is_constructible9.C
new file mode 100644
index 0000000..5448878
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_constructible9.C
@@ -0,0 +1,60 @@
+// { dg-do compile { target c++11 } }
+
+template <typename T, typename... Args>
+struct is_constructible {
+ static constexpr bool value = __is_constructible(T, Args...);
+};
+
+static_assert(is_constructible<void>::value, ""); // { dg-error "assert" }
+// { dg-message "'void' is not default constructible, because" "" { target *-*-* } .-1 }
+// { dg-error "'void' is incomplete" "" { target *-*-* } .-2 }
+
+static_assert(is_constructible<int&, const int&>::value, ""); // { dg-error "assert" }
+// { dg-message "'int&' is not constructible from 'const int&', because" "" { target *-*-* } .-1 }
+// { dg-error "discards qualifiers" "" { target *-*-* } .-2 }
+
+static_assert(is_constructible<int, int, int>::value, ""); // { dg-error "assert" }
+// { dg-message "'int' is not constructible from 'int, int', because" "" { target *-*-* } .-1 }
+// { dg-error "too many initializers for non-class type 'int'" "" { target *-*-* } .-2 }
+
+struct A {
+ A(int); // { dg-message "candidate" }
+};
+static_assert(is_constructible<A, int, int>::value, ""); // { dg-error "assert" }
+// { dg-message "'A' is not constructible from 'int, int', because" "" { target *-*-* } .-1 }
+// { dg-error "no matching function for call to" "" { target *-*-* } .-2 }
+
+template <typename T, typename... Args>
+struct is_nothrow_constructible {
+ static constexpr bool value = __is_nothrow_constructible(T, Args...);
+};
+
+struct B {
+ B(int); // { dg-message "candidate" }
+};
+static_assert(is_nothrow_constructible<B>::value, ""); // { dg-error "assert" }
+// { dg-message "'B' is not nothrow default constructible, because" "" { target *-*-* } .-1 }
+// { dg-error "no matching function for call to" "" { target *-*-* } .-2 }
+
+struct C {
+ C(int); // { dg-message "noexcept" }
+};
+static_assert(is_nothrow_constructible<C, int>::value, ""); // { dg-error "assert" }
+// { dg-message "'C' is not nothrow constructible from 'int', because" "" { target *-*-* } .-1 }
+
+template <typename T, typename... Args>
+struct is_trivially_constructible {
+ static constexpr bool value = __is_trivially_constructible(T, Args...);
+};
+
+struct D {
+ D(); // { dg-message "non-trivial" }
+};
+static_assert(is_trivially_constructible<D>::value, ""); // { dg-error "assert" }
+// { dg-message "'D' is not trivially default constructible, because" "" { target *-*-* } .-1 }
+
+struct E {
+ operator int(); // { dg-message "non-trivial" }
+};
+static_assert(is_trivially_constructible<int, E>::value, ""); // { dg-error "assert" }
+// { dg-message "'int' is not trivially constructible from 'E', because" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/ext/is_convertible7.C b/gcc/testsuite/g++.dg/ext/is_convertible7.C
new file mode 100644
index 0000000..b38fc04
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_convertible7.C
@@ -0,0 +1,29 @@
+// { dg-do compile { target c++11 } }
+
+template <typename T, typename U>
+struct is_convertible {
+ static constexpr bool value = __is_convertible(T, U);
+};
+
+static_assert(is_convertible<int*, int>::value, ""); // { dg-error "assert" }
+// { dg-error "invalid conversion" "" { target *-*-* } .-1 }
+
+static_assert(is_convertible<int(), double (*)()>::value, ""); // { dg-error "assert" }
+// { dg-error "invalid conversion" "" { target *-*-* } .-1 }
+
+struct A {
+ explicit A(int);
+};
+static_assert(is_convertible<int, A>::value, ""); // { dg-error "assert" }
+// { dg-error "could not convert 'int' to 'A'" "" { target *-*-* } .-1 }
+
+template <typename T, typename U>
+struct is_nothrow_convertible {
+ static constexpr bool value = __is_nothrow_convertible(T, U);
+};
+
+struct B {
+ B(int); // { dg-message "noexcept" }
+};
+static_assert(is_nothrow_convertible<int, B>::value, ""); // { dg-error "assert" }
+// { dg-message "'int' is not nothrow convertible from 'B', because" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/ext/is_destructible3.C b/gcc/testsuite/g++.dg/ext/is_destructible3.C
new file mode 100644
index 0000000..a8501d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_destructible3.C
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++11 } }
+
+template <typename T>
+struct is_destructible {
+ static constexpr bool value = __is_destructible(T);
+};
+
+static_assert(is_destructible<void>::value, ""); // { dg-error "assert" }
+// { dg-message "'void' is not destructible, because" "" { target *-*-* } .-1 }
+// { dg-error "'void' is incomplete" "" { target *-*-* } .-2 }
+
+struct A {
+ ~A() = delete; // { dg-message "declared here" }
+};
+static_assert(is_destructible<A>::value, ""); // { dg-error "assert" }
+// { dg-message "'A' is not destructible, because" "" { target *-*-* } .-1 }
+// { dg-error "use of deleted function" "" { target *-*-* } .-2 }
+
+struct B {
+private:
+ ~B(); // { dg-message "declared private here" }
+};
+static_assert(is_destructible<B>::value, ""); // { dg-error "assert" }
+// { dg-message "'B' is not destructible, because" "" { target *-*-* } .-1 }
+// { dg-error "private within this context" "" { target *-*-* } .-2 }
+
+template <typename T>
+struct is_nothrow_destructible {
+ static constexpr bool value = __is_nothrow_destructible(T);
+};
+
+struct C {
+ ~C() noexcept(false); // { dg-message "noexcept" }
+};
+static_assert(is_nothrow_destructible<C>::value, ""); // { dg-error "assert" }
+// { dg-message "'C' is not nothrow destructible, because" "" { target *-*-* } .-1 }
+
+struct D {
+private:
+ ~D() {} // { dg-message "declared private here" }
+};
+static_assert(is_nothrow_destructible<D>::value, ""); // { dg-error "assert" }
+// { dg-message "'D' is not nothrow destructible, because" "" { target *-*-* } .-1 }
+// { dg-error "private within this context" "" { target *-*-* } .-2 }
+
+template <typename T>
+struct is_trivially_destructible {
+ static constexpr bool value = __is_trivially_destructible(T);
+};
+
+struct E {
+ ~E();
+};
+struct F { E d; }; // { dg-message "non-trivial" }
+static_assert(is_trivially_destructible<F>::value, ""); // { dg-error "assert" }
+// { dg-message "'F' is not trivially destructible, because" "" { target *-*-* } .-1 }
+
+struct G {
+private:
+ ~G(); // { dg-message "declared private here" }
+};
+struct H { G g; }; // { dg-error "private within this context" }
+static_assert(is_trivially_destructible<H>::value, ""); // { dg-error "assert" }
+// { dg-message "'H' is not trivially destructible, because" "" { target *-*-* } .-1 }
+// { dg-error "use of deleted function" "" { target *-*-* } .-2 }
diff --git a/gcc/testsuite/g++.dg/ext/is_invocable5.C b/gcc/testsuite/g++.dg/ext/is_invocable5.C
new file mode 100644
index 0000000..460eed5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_invocable5.C
@@ -0,0 +1,15 @@
+// PR c++/121055
+// { dg-do compile { target c++11 } }
+// { dg-skip-if "requires hosted libstdc++ for functional function" { ! hostedlib } }
+
+#include <functional>
+
+#define SA(X) static_assert((X),#X)
+
+struct F;
+
+SA( __is_invocable(void (F::*)() &, std::reference_wrapper<F>) );
+SA( ! __is_invocable(void (F::*)() &&, std::reference_wrapper<F>) );
+
+SA( __is_invocable(void (F::*)(int) &, std::reference_wrapper<F>, int) );
+SA( ! __is_invocable(void (F::*)(int) &&, std::reference_wrapper<F>, int) );
diff --git a/gcc/testsuite/g++.dg/ext/is_invocable6.C b/gcc/testsuite/g++.dg/ext/is_invocable6.C
new file mode 100644
index 0000000..64c5c76
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_invocable6.C
@@ -0,0 +1,45 @@
+// { dg-do compile { target c++11 } }
+
+template <typename F, typename... Args>
+struct is_invocable {
+ static constexpr bool value = __is_invocable(F, Args...);
+};
+
+static_assert(is_invocable<int>::value, ""); // { dg-error "assert" }
+// { dg-message "'int' is not invocable, because" "" { target *-*-* } .-1 }
+// { dg-error "'int' cannot be used as a function" "" { target *-*-* } .-2 }
+
+static_assert(is_invocable<void(*)(), int>::value, ""); // { dg-error "assert" }
+// { dg-message "'void \[^'\]*' is not invocable by 'int', because" "" { target *-*-* } .-1 }
+// { dg-error "too many arguments" "" { target *-*-* } .-2 }
+
+static_assert(is_invocable<void(void*), void() const>::value, ""); // { dg-error "assert" }
+// { dg-message "'void.void..' is not invocable by 'void.. const', because" "" { target *-*-* } .-1 }
+// { dg-error "qualified function type" "" { target *-*-* } .-2 }
+
+struct A {};
+static_assert(is_invocable<const A&&, int, double>::value, ""); // { dg-error "assert" }
+// { dg-message "'const A&&' is not invocable by 'int, double', because" "" { target *-*-* } .-1 }
+// { dg-error "no match for call to " "" { target *-*-* } .-2 }
+
+struct B {
+ void operator()() = delete; // { dg-message "declared here" }
+};
+static_assert(is_invocable<B>::value, ""); // { dg-error "assert" }
+// { dg-message "'B' is not invocable, because" "" { target *-*-* } .-1 }
+// { dg-error "use of deleted function" "" { target *-*-* } .-2 }
+
+template <typename F, typename... Args>
+struct is_nothrow_invocable {
+ static constexpr bool value = __is_nothrow_invocable(F, Args...);
+};
+
+static_assert(is_nothrow_invocable<void(*)()>::value, ""); // { dg-error "assert" }
+// { dg-message "'void \[^'\]*' is not nothrow invocable, because" "" { target *-*-* } .-1 }
+// { dg-message "'void \[^'\]*' is not 'noexcept'" "" { target *-*-* } .-2 }
+
+struct C {
+ int operator()(int, double) const; // { dg-message "noexcept" }
+};
+static_assert(is_nothrow_invocable<const C&, int, int>::value, ""); // { dg-error "assert" }
+// { dg-message "'const C&' is not nothrow invocable by 'int, int', because" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/ext/is_virtual_base_of_diagnostic2.C b/gcc/testsuite/g++.dg/ext/is_virtual_base_of_diagnostic2.C
new file mode 100644
index 0000000..ac28121
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_virtual_base_of_diagnostic2.C
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++11 } }
+
+template <typename T, typename U>
+struct is_virtual_base_of {
+ static constexpr bool value = __builtin_is_virtual_base_of(T, U);
+};
+
+static_assert(is_virtual_base_of<int, int>::value, ""); // { dg-error "assert" }
+// { dg-message "'int' is not a virtual base of 'int'" "" { target *-*-* } .-1 }
+
+struct A {}; // { dg-message "'A' is not a virtual base of 'B'" }
+struct B : A {}; // { dg-message "declared here" }
+static_assert(is_virtual_base_of<A, B>::value, ""); // { dg-error "assert" }
diff --git a/gcc/testsuite/g++.dg/lookup/operator-8.C b/gcc/testsuite/g++.dg/lookup/operator-8.C
index 64d8a97..32d432d 100644
--- a/gcc/testsuite/g++.dg/lookup/operator-8.C
+++ b/gcc/testsuite/g++.dg/lookup/operator-8.C
@@ -16,11 +16,16 @@ struct A {
template<class T>
void f() {
A a;
- (void)(a != 0, 0 != a); // { dg-bogus "deleted" "" { xfail *-*-* } }
- (void)(a < 0, 0 < a); // { dg-bogus "deleted" "" { xfail *-*-* } }
- (void)(a <= 0, 0 <= a); // { dg-bogus "deleted" "" { xfail *-*-* } }
- (void)(a > 0, 0 > a); // { dg-bogus "deleted" "" { xfail *-*-* } }
- (void)(a >= 0, 0 >= a); // { dg-bogus "deleted" "" { xfail *-*-* } }
+ (void)(a != 0);
+ (void)(0 != a);
+ (void)(a < 0);
+ (void)(0 < a);
+ (void)(a <= 0);
+ (void)(0 <= a);
+ (void)(a > 0);
+ (void)(0 > a);
+ (void)(a >= 0);
+ (void)(0 >= a);
}
// These later-declared namespace-scope overloads shouldn't be considered
@@ -31,4 +36,10 @@ bool operator<=(A, int) = delete;
bool operator>(A, int) = delete;
bool operator>=(A, int) = delete;
+bool operator!=(int, A) = delete;
+bool operator<(int, A) = delete;
+bool operator<=(int, A) = delete;
+bool operator>(int, A) = delete;
+bool operator>=(int, A) = delete;
+
template void f<int>();
diff --git a/gcc/testsuite/g++.dg/missing-return.C b/gcc/testsuite/g++.dg/missing-return.C
index 5f8e2cc..f6934b0 100644
--- a/gcc/testsuite/g++.dg/missing-return.C
+++ b/gcc/testsuite/g++.dg/missing-return.C
@@ -5,4 +5,6 @@ int foo(int a)
{
} /* { dg-warning "no return statement" } */
-/* { dg-final { scan-tree-dump "__builtin_unreachable" "optimized" } } */
+/* For targets without traps, it will be an infinite loop */
+/* { dg-final { scan-tree-dump "__builtin_unreachable" "optimized" { target trap } } } */
+/* { dg-final { scan-tree-dump "goto <" "optimized" { target { ! trap } } } } */
diff --git a/gcc/testsuite/g++.dg/modules/class-11_a.H b/gcc/testsuite/g++.dg/modules/class-11_a.H
new file mode 100644
index 0000000..f7bbf9d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-11_a.H
@@ -0,0 +1,36 @@
+// Check for some additional lang_type flags that we'd missed.
+// { dg-additional-options "-fmodule-header -fabi-version=21 -Wabi=15" }
+// { dg-module-cmi {} }
+
+#if __cpp_trivial_relocatability < 202502L
+#define trivially_relocatable_if_eligible __trivially_relocatable_if_eligible
+#define replaceable_if_eligible __replaceable_if_eligible
+#endif
+
+struct A trivially_relocatable_if_eligible { A(A&&); };
+struct B replaceable_if_eligible { B(B&&); B& operator=(B&&); };
+struct C {};
+static_assert(__builtin_is_trivially_relocatable(C) && __builtin_is_replaceable(C), "");
+
+
+struct pr106381 {
+ long l;
+ char c = -1;
+};
+struct L1 : pr106381 {
+ char x; // { dg-warning "offset" "" { target c++14 } }
+};
+static_assert(sizeof(L1) == sizeof(pr106381));
+
+
+struct pr120012 {
+ pr120012(const pr120012&) = default;
+ pr120012(pr120012&&) = default;
+ pr120012& operator=(pr120012&&) = default;
+ unsigned int a;
+ unsigned char b;
+};
+struct L2 : pr120012 {
+ unsigned char y; // { dg-warning "offset" "" { target c++20 } }
+};
+static_assert(sizeof(L2) > sizeof(pr120012));
diff --git a/gcc/testsuite/g++.dg/modules/class-11_b.C b/gcc/testsuite/g++.dg/modules/class-11_b.C
new file mode 100644
index 0000000..2450a45
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/class-11_b.C
@@ -0,0 +1,15 @@
+// { dg-additional-options "-fmodules -fabi-version=21 -Wabi=15" }
+
+import "class-11_a.H";
+
+static_assert(__builtin_is_trivially_relocatable(A), "");
+static_assert(__builtin_is_replaceable(B), "");
+static_assert(__builtin_is_trivially_relocatable(C) && __builtin_is_replaceable(C), "");
+
+struct M1 : pr106381 {
+ char x; // { dg-warning "offset" "" { target c++14 } }
+};
+
+struct M2 : pr120012 {
+ unsigned char y; // { dg-warning "offset" "" { target c++20 } }
+};
diff --git a/gcc/testsuite/g++.dg/modules/internal-14_a.C b/gcc/testsuite/g++.dg/modules/internal-14_a.C
new file mode 100644
index 0000000..07eb965
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-14_a.C
@@ -0,0 +1,17 @@
+// PR c++/120412
+// { dg-additional-options "-fmodules -std=c++20 -Wtemplate-names-tu-local" }
+// { dg-module-cmi m:part }
+
+export module m:part;
+
+export template <typename F>
+auto fun1(F) {
+ return true;
+}
+
+using Dodgy = decltype([]{});
+
+export template <typename T>
+auto fun2(T&&) { // { dg-warning "TU-local" }
+ return fun1(Dodgy{});
+}
diff --git a/gcc/testsuite/g++.dg/modules/internal-14_b.C b/gcc/testsuite/g++.dg/modules/internal-14_b.C
new file mode 100644
index 0000000..ad3b09d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-14_b.C
@@ -0,0 +1,6 @@
+// PR c++/120412
+// { dg-additional-options "-fmodules -std=c++20 -Wtemplate-names-tu-local" }
+// { dg-module-cmi m }
+
+export module m;
+export import :part;
diff --git a/gcc/testsuite/g++.dg/modules/internal-14_c.C b/gcc/testsuite/g++.dg/modules/internal-14_c.C
new file mode 100644
index 0000000..4f8e785c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/internal-14_c.C
@@ -0,0 +1,9 @@
+// PR c++/120412
+// { dg-additional-options "-fmodules -std=c++20" }
+
+import m;
+
+int main() {
+ // { dg-error "instantiation exposes TU-local entity '(fun1|Dodgy)'" "" { target *-*-* } 0 }
+ fun2(123); // { dg-message "required from here" }
+}
diff --git a/gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C
index 3e93126..71ae8f2 100644
--- a/gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C
+++ b/gcc/testsuite/g++.dg/plugin/show-template-tree-color-labels.C
@@ -1,4 +1,4 @@
-/* Verify colorization of the labels in diagnostic-show-locus.c
+/* Verify colorization of the labels in diagnostics/source-printing.cc
for template comparisons.
Doing so requires a plugin; see the comments in the plugin for the
rationale. */
diff --git a/gcc/testsuite/g++.dg/plugin/show_template_tree_color_plugin.cc b/gcc/testsuite/g++.dg/plugin/show_template_tree_color_plugin.cc
index 6151b6e..5d185ff 100644
--- a/gcc/testsuite/g++.dg/plugin/show_template_tree_color_plugin.cc
+++ b/gcc/testsuite/g++.dg/plugin/show_template_tree_color_plugin.cc
@@ -21,7 +21,8 @@
int plugin_is_GPL_compatible;
void
-noop_text_starter_fn (diagnostic_text_output_format &, const diagnostic_info *)
+noop_text_starter_fn (diagnostics::text_sink &,
+ const diagnostics::diagnostic_info *)
{
}
@@ -32,7 +33,7 @@ plugin_init (struct plugin_name_args *plugin_info,
if (!plugin_default_version_check (version, &gcc_version))
return 1;
- diagnostic_text_starter (global_dc) = noop_text_starter_fn;
+ diagnostics::text_starter (global_dc) = noop_text_starter_fn;
return 0;
}
diff --git a/gcc/testsuite/g++.dg/torture/pr120119-1.C b/gcc/testsuite/g++.dg/torture/pr120119-1.C
new file mode 100644
index 0000000..1206feb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr120119-1.C
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-additional-options "-mcpu=cortex-a57" { target aarch64*-*-* } }
+
+// PR target/120119
+
+struct a {
+ float operator()(int b, int c) { return d[c * 4 + b]; }
+ float *d;
+};
+float e(float *);
+auto f(a b) {
+ float g[]{b(1, 1), b(2, 1), b(3, 1), b(1, 2), b(2, 2), b(3, 2), b(1, 3),
+ b(2, 3), b(3, 3), b(3, 2), b(1, 3), b(2, 3), b(3, 3)};
+ return b.d[0] * e(g);
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-5.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-5.C
index bac2b68..a21e864 100644
--- a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-5.C
+++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-5.C
@@ -31,7 +31,7 @@ void warn_placement_new ()
void warn_placement_array_new ()
{
- void *p = malloc (sizeof (int));
+ void *p = malloc (sizeof (int) * 2);
int *q = new (p) int[2];
delete q; // { dg-warning "-Wmismatched-new-delete" }
}
diff --git a/gcc/testsuite/g++.target/aarch64/sve/unpacked_binary_bf16_1.C b/gcc/testsuite/g++.target/aarch64/sve/unpacked_binary_bf16_1.C
new file mode 100644
index 0000000..9d6342b
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve/unpacked_binary_bf16_1.C
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-signed-zeros -ffinite-math-only -msve-vector-bits=2048" } */
+
+#pragma GCC target "arch=armv9-a+sve-b16b16"
+
+#define ADD(a, b) a + b
+#define SUB(a, b) a - b
+#define MUL(a, b) a * b
+#define MAX(a, b) (a > b) ? a : b
+#define MIN(a, b) (a > b) ? b : a
+
+#define TEST_OP(TYPE, OP) \
+ TYPE test_##TYPE##_##OP (TYPE a, TYPE b) { return OP (a, b); } \
+
+#define TEST_ALL(TYPE, SIZE) \
+ typedef TYPE TYPE##SIZE __attribute__((vector_size(SIZE))); \
+ TEST_OP (TYPE##SIZE, ADD) \
+ TEST_OP (TYPE##SIZE, SUB) \
+ TEST_OP (TYPE##SIZE, MUL) \
+ TEST_OP (TYPE##SIZE, MIN) \
+ TEST_OP (TYPE##SIZE, MAX)
+
+TEST_ALL (__bf16, 64)
+
+TEST_ALL (__bf16, 128)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 5 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 5 } } */
+
+/* { dg-final { scan-assembler-times {\tbfadd\tz[0-9]+\.h, p[0-7]/m. z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tbfsub\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tbfmul\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tbfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tbfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/sve/unpacked_binary_bf16_2.C b/gcc/testsuite/g++.target/aarch64/sve/unpacked_binary_bf16_2.C
new file mode 100644
index 0000000..63de293
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve/unpacked_binary_bf16_2.C
@@ -0,0 +1,15 @@
+/* { dg-do compile }*/
+/* { dg-options "-O2 -ffinite-math-only -fno-signed-zeros -fno-trapping-math -msve-vector-bits=2048 " } */
+
+#include "unpacked_binary_bf16_1.C"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 10 } } */
+
+/* { dg-final { scan-assembler-times {\tbfadd\tz[0-9]+\.h, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tbfsub\tz[0-9]+\.h, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tbfmul\tz[0-9]+\.h, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tbfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tbfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/sve/unpacked_cond_binary_bf16_1.C b/gcc/testsuite/g++.target/aarch64/sve/unpacked_cond_binary_bf16_1.C
new file mode 100644
index 0000000..560d874
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve/unpacked_cond_binary_bf16_1.C
@@ -0,0 +1,46 @@
+/* { dg-do compile }*/
+/* { dg-options "-O -ffinite-math-only -fno-signed-zeros -fno-trapping-math -msve-vector-bits=2048 " } */
+
+#include <stdint.h>
+#pragma GCC target "arch=armv9-a+sve-b16b16"
+
+#define ADD(a, b) a + b
+#define SUB(a, b) a - b
+#define MUL(a, b) a * b
+#define MAX(a, b) (a > b) ? a : b
+#define MIN(a, b) (a > b) ? b : a
+
+#define COND_OP(OP, TYPE, PRED_TYPE, ARG2, MERGE) \
+ TYPE test_##OP##_##TYPE##_##ARG2##_##MERGE (TYPE a, TYPE b, TYPE c, PRED_TYPE p) \
+ {return p ? OP (a, ARG2) : MERGE; }
+
+#define TEST_OP(OP, TYPE, PRED_TYPE, T) \
+ T (OP, TYPE, PRED_TYPE, b, a) \
+ T (OP, TYPE, PRED_TYPE, b, b) \
+ T (OP, TYPE, PRED_TYPE, b, c)
+
+#define TEST_ALL(TYPE, PRED_TYPE, T) \
+ TEST_OP (ADD, TYPE, PRED_TYPE, T) \
+ TEST_OP (SUB, TYPE, PRED_TYPE, T) \
+ TEST_OP (MUL, TYPE, PRED_TYPE, T) \
+ TEST_OP (MAX, TYPE, PRED_TYPE, T) \
+ TEST_OP (MIN, TYPE, PRED_TYPE, T)
+
+#define TEST(TYPE, PTYPE, SIZE) \
+ typedef TYPE TYPE##SIZE __attribute__ ((vector_size (SIZE))); \
+ typedef PTYPE PTYPE##SIZE __attribute__ ((vector_size (SIZE))); \
+ TEST_ALL (TYPE##SIZE, PTYPE##SIZE, COND_OP)
+
+TEST (__bf16, uint16_t, 128)
+
+TEST (__bf16, uint16_t, 64)
+
+/* { dg-final { scan-assembler-times {\tbfadd\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tbfsub\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tbfmul\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 6 } } */
+
+/* { dg-final { scan-assembler-times {\tbfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tbfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 6 } } */
+
+// There's no BFSUBR.
+/* { dg-final { scan-assembler-times {\tsel\t} 2 } } */
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-1.c b/gcc/testsuite/gcc.dg/asm-hard-reg-1.c
new file mode 100644
index 0000000..6a5a9ad
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-1.c
@@ -0,0 +1,85 @@
+/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* powerpc*-*-* riscv*-*-* s390*-*-* x86_64-*-* } } */
+
+#if defined (__aarch64__)
+# define GPR "{x4}"
+/* { dg-final { scan-assembler-times "foo\tx4" 8 { target { aarch64*-*-* } } } } */
+#elif defined (__arm__)
+# define GPR "{r4}"
+/* { dg-final { scan-assembler-times "foo\tr4" 8 { target { arm*-*-* } } } } */
+#elif defined (__i386__)
+# define GPR "{ecx}"
+/* { dg-final { scan-assembler-times "foo\t%cl" 2 { target { i?86-*-* } } } } */
+/* { dg-final { scan-assembler-times "foo\t%cx" 2 { target { i?86-*-* } } } } */
+/* { dg-final { scan-assembler-times "foo\t%ecx" 4 { target { i?86-*-* } } } } */
+#elif defined (__powerpc__) || defined (__POWERPC__)
+# define GPR "{r5}"
+/* { dg-final { scan-assembler-times "foo\t5" 8 { target { powerpc*-*-* } } } } */
+#elif defined (__riscv)
+# define GPR "{t5}"
+/* { dg-final { scan-assembler-times "foo\tt5" 8 { target { riscv*-*-* } } } } */
+#elif defined (__s390__)
+# define GPR "{r4}"
+/* { dg-final { scan-assembler-times "foo\t%r4" 8 { target { s390*-*-* } } } } */
+#elif defined (__x86_64__)
+# define GPR "{rcx}"
+/* { dg-final { scan-assembler-times "foo\t%cl" 2 { target { x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "foo\t%cx" 2 { target { x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "foo\t%ecx" 2 { target { x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "foo\t%rcx" 2 { target { x86_64-*-* } } } } */
+#endif
+
+char
+test_char (char x)
+{
+ __asm__ ("foo\t%0" : "+"GPR (x));
+ return x;
+}
+
+char
+test_char_from_mem (char *x)
+{
+ __asm__ ("foo\t%0" : "+"GPR (*x));
+ return *x;
+}
+
+short
+test_short (short x)
+{
+ __asm__ ("foo\t%0" : "+"GPR (x));
+ return x;
+}
+
+short
+test_short_from_mem (short *x)
+{
+ __asm__ ("foo\t%0" : "+"GPR (*x));
+ return *x;
+}
+
+int
+test_int (int x)
+{
+ __asm__ ("foo\t%0" : "+"GPR (x));
+ return x;
+}
+
+int
+test_int_from_mem (int *x)
+{
+ __asm__ ("foo\t%0" : "+"GPR (*x));
+ return *x;
+}
+
+long
+test_long (long x)
+{
+ __asm__ ("foo\t%0" : "+"GPR (x));
+ return x;
+}
+
+long
+test_long_from_mem (long *x)
+{
+ __asm__ ("foo\t%0" : "+"GPR (*x));
+ return *x;
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-2.c b/gcc/testsuite/gcc.dg/asm-hard-reg-2.c
new file mode 100644
index 0000000..7dabf96
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-2.c
@@ -0,0 +1,33 @@
+/* { dg-do compile { target aarch64*-*-* powerpc64*-*-* riscv64-*-* s390*-*-* x86_64-*-* } } */
+/* { dg-options "-std=c99" } we need long long */
+
+#if defined (__aarch64__)
+# define GPR "{x4}"
+/* { dg-final { scan-assembler-times "foo\tx4" 2 { target { aarch64*-*-* } } } } */
+#elif defined (__powerpc__) || defined (__POWERPC__)
+# define GPR "{r5}"
+/* { dg-final { scan-assembler-times "foo\t5" 2 { target { powerpc64*-*-* } } } } */
+#elif defined (__riscv)
+# define GPR "{t5}"
+/* { dg-final { scan-assembler-times "foo\tt5" 2 { target { riscv64-*-* } } } } */
+#elif defined (__s390__)
+# define GPR "{r4}"
+/* { dg-final { scan-assembler-times "foo\t%r4" 2 { target { s390*-*-* } } } } */
+#elif defined (__x86_64__)
+# define GPR "{rcx}"
+/* { dg-final { scan-assembler-times "foo\t%rcx" 2 { target { x86_64-*-* } } } } */
+#endif
+
+long long
+test_longlong (long long x)
+{
+ __asm__ ("foo\t%0" : "+"GPR (x));
+ return x;
+}
+
+long long
+test_longlong_from_mem (long long *x)
+{
+ __asm__ ("foo\t%0" : "+"GPR (*x));
+ return *x;
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-3.c b/gcc/testsuite/gcc.dg/asm-hard-reg-3.c
new file mode 100644
index 0000000..fa4472a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-3.c
@@ -0,0 +1,25 @@
+/* { dg-do compile { target { { aarch64*-*-* powerpc64*-*-* riscv64-*-* s390*-*-* x86_64-*-* } && int128 } } } */
+/* { dg-options "-O2" } get rid of -ansi since we use __int128 */
+
+#if defined (__aarch64__)
+# define REG "{x4}"
+/* { dg-final { scan-assembler-times "foo\tx4" 1 { target { aarch64*-*-* } } } } */
+#elif defined (__powerpc__) || defined (__POWERPC__)
+# define REG "{r5}"
+/* { dg-final { scan-assembler-times "foo\t5" 1 { target { powerpc*-*-* } } } } */
+#elif defined (__riscv)
+# define REG "{t5}"
+/* { dg-final { scan-assembler-times "foo\tt5" 1 { target { riscv*-*-* } } } } */
+#elif defined (__s390__)
+# define REG "{r4}"
+/* { dg-final { scan-assembler-times "foo\t%r4" 1 { target { s390*-*-* } } } } */
+#elif defined (__x86_64__)
+# define REG "{xmm0}"
+/* { dg-final { scan-assembler-times "foo\t%xmm0" 1 { target { x86_64-*-* } } } } */
+#endif
+
+void
+test (void)
+{
+ __asm__ ("foo\t%0" :: REG ((__int128) 42));
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-4.c b/gcc/testsuite/gcc.dg/asm-hard-reg-4.c
new file mode 100644
index 0000000..0134bf0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-4.c
@@ -0,0 +1,50 @@
+/* { dg-do compile { target aarch64*-*-* arm*-*-* powerpc*-*-* riscv*-*-* s390*-*-* x86_64-*-* } } */
+
+#if defined (__aarch64__)
+# define FPR "{d5}"
+/* { dg-final { scan-assembler-times "foo\tv5" 4 { target { aarch64*-*-* } } } } */
+#elif defined (__arm__)
+# define FPR "{d5}"
+/* { dg-additional-options "-march=armv7-a+fp -mfloat-abi=hard" { target arm*-*-* } } */
+/* { dg-final { scan-assembler-times "foo\ts10" 4 { target { arm*-*-* } } } } */
+#elif defined (__powerpc__) || defined (__POWERPC__)
+# define FPR "{5}"
+/* { dg-final { scan-assembler-times "foo\t5" 4 { target { powerpc*-*-* } } } } */
+#elif defined (__riscv)
+# define FPR "{fa5}"
+/* { dg-final { scan-assembler-times "foo\tfa5" 4 { target { rsicv*-*-* } } } } */
+#elif defined (__s390__)
+# define FPR "{f5}"
+/* { dg-final { scan-assembler-times "foo\t%f5" 4 { target { s390*-*-* } } } } */
+#elif defined (__x86_64__)
+# define FPR "{xmm5}"
+/* { dg-final { scan-assembler-times "foo\t%xmm5" 4 { target { x86_64-*-* } } } } */
+#endif
+
+float
+test_float (float x)
+{
+ __asm__ ("foo\t%0" : "+"FPR (x));
+ return x;
+}
+
+float
+test_float_from_mem (float *x)
+{
+ __asm__ ("foo\t%0" : "+"FPR (*x));
+ return *x;
+}
+
+double
+test_double (double x)
+{
+ __asm__ ("foo\t%0" : "+"FPR (x));
+ return x;
+}
+
+double
+test_double_from_mem (double *x)
+{
+ __asm__ ("foo\t%0" : "+"FPR (*x));
+ return *x;
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-5.c b/gcc/testsuite/gcc.dg/asm-hard-reg-5.c
new file mode 100644
index 0000000..a9e25ce
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-5.c
@@ -0,0 +1,36 @@
+/* { dg-do compile { target aarch64*-*-* powerpc64*-*-* riscv64-*-* s390*-*-* x86_64-*-* } } */
+
+typedef int V __attribute__ ((vector_size (4 * sizeof (int))));
+
+#if defined (__aarch64__)
+# define VR "{v20}"
+/* { dg-final { scan-assembler-times "foo\tv20" 2 { target { aarch64*-*-* } } } } */
+#elif defined (__powerpc__) || defined (__POWERPC__)
+# define VR "{v5}"
+/* { dg-final { scan-assembler-times "foo\t5" 2 { target { powerpc64*-*-* } } } } */
+#elif defined (__riscv)
+# define VR "{v5}"
+/* { dg-additional-options "-march=rv64imv" { target riscv64-*-* } } */
+/* { dg-final { scan-assembler-times "foo\tv5" 2 { target { riscv*-*-* } } } } */
+#elif defined (__s390__)
+# define VR "{v5}"
+/* { dg-require-effective-target s390_mvx { target s390*-*-* } } */
+/* { dg-final { scan-assembler-times "foo\t%v5" 2 { target s390*-*-* } } } */
+#elif defined (__x86_64__)
+# define VR "{xmm9}"
+/* { dg-final { scan-assembler-times "foo\t%xmm9" 2 { target { x86_64-*-* } } } } */
+#endif
+
+V
+test (V x)
+{
+ __asm__ ("foo\t%0" : "+"VR (x));
+ return x;
+}
+
+V
+test_from_mem (V *x)
+{
+ __asm__ ("foo\t%0" : "+"VR (*x));
+ return *x;
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-6.c b/gcc/testsuite/gcc.dg/asm-hard-reg-6.c
new file mode 100644
index 0000000..d9b7fae
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-6.c
@@ -0,0 +1,60 @@
+/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* powerpc*-*-* riscv*-*-* s390*-*-* x86_64-*-* } } */
+/* { dg-options "-O2" } */
+
+/* Test multiple alternatives. */
+
+#if defined (__aarch64__)
+# define GPR1 "{x1}"
+# define GPR2 "{x2}"
+# define GPR3 "{x3}"
+/* { dg-final { scan-assembler-times "foo\tx1,x3" 1 { target { aarch64*-*-* } } } } */
+/* { dg-final { scan-assembler-times "bar\tx2,\\\[x1\\\]" 1 { target { aarch64*-*-* } } } } */
+#elif defined (__arm__)
+# define GPR1 "{r1}"
+# define GPR2 "{r2}"
+# define GPR3 "{r3}"
+/* { dg-final { scan-assembler-times "foo\tr1,r3" 1 { target { arm*-*-* } } } } */
+/* { dg-final { scan-assembler-times "bar\tr2,\\\[r1\\\]" 1 { target { arm*-*-* } } } } */
+#elif defined (__i386__)
+# define GPR1 "{eax}"
+# define GPR2 "{ebx}"
+# define GPR3 "{ecx}"
+/* { dg-final { scan-assembler-times "foo\t4\\(%esp\\),%ecx" 1 { target { i?86-*-* } } } } */
+/* { dg-final { scan-assembler-times "bar\t%ebx,\\(%eax\\)" 1 { target { i?86-*-* } } } } */
+#elif defined (__powerpc__) || defined (__POWERPC__)
+# define GPR1 "{r4}"
+# define GPR2 "{r5}"
+# define GPR3 "{r6}"
+/* { dg-final { scan-assembler-times "foo\t4,6" 1 { target { powerpc*-*-* } } } } */
+/* { dg-final { scan-assembler-times "bar\t5,0\\(4\\)" 1 { target { powerpc*-*-* } } } } */
+#elif defined (__riscv)
+# define GPR1 "{t1}"
+# define GPR2 "{t2}"
+# define GPR3 "{t3}"
+/* { dg-final { scan-assembler-times "foo\tt1,t3" 1 { target { riscv*-*-* } } } } */
+/* { dg-final { scan-assembler-times "bar\tt2,0\\(a1\\)" 1 { target { riscv*-*-* } } } } */
+#elif defined (__s390__)
+# define GPR1 "{r0}"
+# define GPR2 "{r1}"
+# define GPR3 "{r2}"
+/* { dg-final { scan-assembler-times "foo\t%r0,%r2" 1 { target { s390*-*-* } } } } */
+/* { dg-final { scan-assembler-times "bar\t%r1,0\\(%r3\\)" 1 { target { s390*-*-* } } } } */
+#elif defined (__x86_64__)
+# define GPR1 "{eax}"
+# define GPR2 "{ebx}"
+# define GPR3 "{rcx}"
+/* { dg-final { scan-assembler-times "foo\t%eax,%rcx" 1 { target { x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "bar\t%ebx,\\(%rsi\\)" 1 { target { x86_64-*-* } } } } */
+#endif
+
+void
+test_reg_reg (int x, long long *y)
+{
+ __asm__ ("foo\t%0,%1" :: GPR1"m,"GPR2 (x), GPR3",m" (y));
+}
+
+void
+test_reg_mem (int x, long long *y)
+{
+ __asm__ ("bar\t%0,%1" :: GPR1"m,"GPR2 (x), GPR3",m" (*y));
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-7.c b/gcc/testsuite/gcc.dg/asm-hard-reg-7.c
new file mode 100644
index 0000000..761a6b7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-7.c
@@ -0,0 +1,41 @@
+/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* powerpc*-*-* riscv*-*-* s390*-*-* x86_64-*-* } } */
+/* { dg-options "-O2" } */
+
+/* Test multiple alternatives. */
+
+#if defined (__aarch64__)
+# define GPR "{x1}"
+/* { dg-final { scan-assembler-times "foo\tx1,x1" 2 { target { aarch64*-*-* } } } } */
+#elif defined (__arm__)
+# define GPR "{r1}"
+/* { dg-final { scan-assembler-times "foo\tr1,r1" 2 { target { arm*-*-* } } } } */
+#elif defined (__i386__)
+# define GPR "{eax}"
+/* { dg-final { scan-assembler-times "foo\t%eax,%eax" 2 { target { i?86-*-* } } } } */
+#elif defined (__powerpc__) || defined (__POWERPC__)
+# define GPR "{r4}"
+/* { dg-final { scan-assembler-times "foo\t4,4" 2 { target { powerpc*-*-* } } } } */
+#elif defined (__riscv)
+# define GPR "{t1}"
+/* { dg-final { scan-assembler-times "foo\tt1,t1" 2 { target { riscv*-*-* } } } } */
+#elif defined (__s390__)
+# define GPR "{r0}"
+/* { dg-final { scan-assembler-times "foo\t%r0,%r0" 2 { target { s390*-*-* } } } } */
+#elif defined (__x86_64__)
+# define GPR "{eax}"
+/* { dg-final { scan-assembler-times "foo\t%eax,%eax" 2 { target { x86_64-*-* } } } } */
+#endif
+
+int
+test_1 (int x)
+{
+ __asm__ ("foo\t%0,%0" : "+"GPR (x));
+ return x;
+}
+
+int
+test_2 (int x, int y)
+{
+ __asm__ ("foo\t%0,%1" : "="GPR (x) : GPR (y));
+ return x;
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-8.c b/gcc/testsuite/gcc.dg/asm-hard-reg-8.c
new file mode 100644
index 0000000..cda5e3e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-8.c
@@ -0,0 +1,49 @@
+/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* powerpc*-*-* riscv*-*-* s390*-*-* x86_64-*-* } } */
+
+/* Due to hard register constraints, X must be copied. */
+
+#if defined (__aarch64__)
+# define GPR1 "{x1}"
+# define GPR2 "{x2}"
+#elif defined (__arm__)
+# define GPR1 "{r1}"
+# define GPR2 "{r2}"
+#elif defined (__i386__)
+# define GPR1 "{eax}"
+# define GPR2 "{ebx}"
+#elif defined (__powerpc__) || defined (__POWERPC__)
+# define GPR1 "{r4}"
+# define GPR2 "{r5}"
+#elif defined (__riscv)
+# define GPR1 "{t1}"
+# define GPR2 "{t2}"
+#elif defined (__s390__)
+# define GPR1 "{r0}"
+# define GPR2 "{r1}"
+#elif defined (__x86_64__)
+# define GPR1 "{eax}"
+# define GPR2 "{ebx}"
+#endif
+
+#define TEST(T) \
+int \
+test_##T (T x) \
+{ \
+ int out; \
+ __asm__ ("foo" : "=r" (out) : GPR1 (x), GPR2 (x)); \
+ return out; \
+}
+
+TEST(char)
+TEST(short)
+TEST(int)
+TEST(long)
+
+int
+test_subreg (long x)
+{
+ int out;
+ short subreg_x = x;
+ __asm__ ("foo" : "=r" (out) : GPR1 (x), GPR2 (subreg_x));
+ return out;
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-error-1.c b/gcc/testsuite/gcc.dg/asm-hard-reg-error-1.c
new file mode 100644
index 0000000..0d7c2f2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-error-1.c
@@ -0,0 +1,83 @@
+/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* powerpc*-*-* riscv*-*-* s390*-*-* x86_64-*-* } } */
+
+#if defined (__aarch64__)
+# define GPR1_RAW "x0"
+# define GPR2 "{x1}"
+# define GPR3 "{x2}"
+# define INVALID_GPR_A "{x31}"
+#elif defined (__arm__)
+# define GPR1_RAW "r0"
+# define GPR2 "{r1}"
+# define GPR3 "{r2}"
+# define INVALID_GPR_A "{r16}"
+#elif defined (__i386__)
+# define GPR1_RAW "%eax"
+# define GPR2 "{%ebx}"
+# define GPR3 "{%edx}"
+# define INVALID_GPR_A "{%eex}"
+#elif defined (__powerpc__) || defined (__POWERPC__)
+# define GPR1_RAW "r4"
+# define GPR2 "{r5}"
+# define GPR3 "{r6}"
+# define INVALID_GPR_A "{r33}"
+#elif defined (__riscv)
+# define GPR1_RAW "t4"
+# define GPR2 "{t5}"
+# define GPR3 "{t6}"
+# define INVALID_GPR_A "{t7}"
+#elif defined (__s390__)
+# define GPR1_RAW "r4"
+# define GPR2 "{r5}"
+# define GPR3 "{r6}"
+# define INVALID_GPR_A "{r17}"
+#elif defined (__x86_64__)
+# define GPR1_RAW "rax"
+# define GPR2 "{rbx}"
+# define GPR3 "{rcx}"
+# define INVALID_GPR_A "{rex}"
+#endif
+
+#define GPR1 "{"GPR1_RAW"}"
+#define INVALID_GPR_B "{"GPR1_RAW
+
+struct { int a[128]; } s = {0};
+
+void
+test (void)
+{
+ int x, y;
+ register int gpr1 __asm__ (GPR1_RAW) = 0;
+
+ __asm__ ("" :: "{}" (42)); /* { dg-error "invalid input constraint: \{\}" } */
+ __asm__ ("" :: INVALID_GPR_A (42)); /* { dg-error "invalid input constraint" } */
+ __asm__ ("" :: INVALID_GPR_B (42)); /* { dg-error "invalid input constraint" } */
+
+ __asm__ ("" :: GPR1 (s)); /* { dg-error "data type isn't suitable for register .* of operand 0" } */
+
+ __asm__ ("" :: "r" (gpr1), GPR1 (42)); /* { dg-error "multiple inputs to hard register" } */
+ __asm__ ("" :: GPR1 (42), "r" (gpr1)); /* { dg-error "multiple inputs to hard register" } */
+ __asm__ ("" :: GPR1 (42), GPR1 (42)); /* { dg-error "multiple inputs to hard register" } */
+ __asm__ ("" :: GPR1","GPR2 (42), GPR2","GPR3 (42));
+ __asm__ ("" :: GPR1","GPR2 (42), GPR3","GPR2 (42)); /* { dg-error "multiple inputs to hard register" } */
+ __asm__ ("" :: GPR1","GPR2 (42), GPR1","GPR3 (42)); /* { dg-error "multiple inputs to hard register" } */
+ __asm__ ("" :: GPR1 GPR2 (42), GPR2 (42)); /* { dg-error "multiple inputs to hard register" } */
+ __asm__ ("" : "+"GPR1 (x), "="GPR1 (y)); /* { dg-error "multiple outputs to hard register" } */
+ __asm__ ("" : "="GPR1 (y) : GPR1 (42), "0" (42)); /* { dg-error "multiple inputs to hard register" } */
+ __asm__ ("" : "+"GPR1 (x) : GPR1 (42)); /* { dg-error "multiple inputs to hard register" } */
+
+ __asm__ ("" : "="GPR1 (gpr1));
+ __asm__ ("" : "="GPR2 (gpr1)); /* { dg-error "constraint and register 'asm' for output operand 0 are unsatisfiable" } */
+ __asm__ ("" :: GPR2 (gpr1)); /* { dg-error "constraint and register 'asm' for input operand 0 are unsatisfiable" } */
+ __asm__ ("" : "="GPR1 (x) : "0" (gpr1));
+ __asm__ ("" : "="GPR1 GPR2 (x) : "0" (gpr1)); /* { dg-error "constraint and register 'asm' for input operand 0 are unsatisfiable" } */
+
+ __asm__ ("" : "=&"GPR1 (x) : "0" (gpr1));
+ __asm__ ("" : "=&"GPR1 (x) : "0" (42));
+ __asm__ ("" : "=&"GPR2","GPR1 (x) : "r,"GPR1 (42));
+ __asm__ ("" : "="GPR2",&"GPR1 (x) : "r,"GPR1 (42)); /* { dg-error "invalid hard register usage between earlyclobber operand and input operand" } */
+ __asm__ ("" : "=&"GPR1 (x) : GPR1 (42)); /* { dg-error "invalid hard register usage between earlyclobber operand and input operand" } */
+ __asm__ ("" : "=&"GPR2","GPR1 (x) : "r,r" (gpr1));
+ __asm__ ("" : "="GPR2",&"GPR1 (x) : "r,r" (gpr1)); /* { dg-error "invalid hard register usage between earlyclobber operand and input operand" } */
+ __asm__ ("" : "=&r" (gpr1) : GPR1 (42)); /* { dg-error "invalid hard register usage between earlyclobber operand and input operand" } */
+ __asm__ ("" : "=&"GPR1 (x), "=r" (y) : "1" (gpr1)); /* { dg-error "invalid hard register usage between earlyclobber operand and input operand" } */
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-error-2.c b/gcc/testsuite/gcc.dg/asm-hard-reg-error-2.c
new file mode 100644
index 0000000..d0d5cfe
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-error-2.c
@@ -0,0 +1,26 @@
+/* { dg-do compile { target { { aarch64*-*-* s390x-*-* } && int128 } } } */
+/* { dg-options "-O2" } get rid of -ansi since we use __int128 */
+
+/* Test register pairs. */
+
+#if defined (__aarch64__)
+# define GPR1 "{x4}"
+# define GPR2_RAW "x5"
+#elif defined (__s390__)
+# define GPR1 "{r4}"
+# define GPR2_RAW "r5"
+#endif
+
+#define GPR2 "{"GPR2_RAW"}"
+
+void
+test (void)
+{
+ __asm__ ("" :: GPR1 ((__int128) 42));
+ __asm__ ("" :: GPR2 ((__int128) 42)); /* { dg-error "register .* for operand 0 isn't suitable for data type" } */
+ __asm__ ("" :: GPR1 ((__int128) 42), GPR2 (42)); /* { dg-error "multiple inputs to hard register" } */
+
+ __int128 x;
+ __asm__ ("" : "="GPR1 (x) :: GPR2_RAW); /* { dg-error "hard register constraint for output 0 conflicts with 'asm' clobber list" } */
+ __asm__ ("" : "=r" (x) : GPR1 (x) : GPR2_RAW); /* { dg-error "hard register constraint for input 0 conflicts with 'asm' clobber list" } */
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-error-3.c b/gcc/testsuite/gcc.dg/asm-hard-reg-error-3.c
new file mode 100644
index 0000000..17b2317
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-error-3.c
@@ -0,0 +1,27 @@
+/* { dg-do compile { target arm-*-* s390-*-* } } */
+/* { dg-options "-std=c99" } we need long long */
+/* { dg-additional-options "-march=armv7-a" { target arm-*-* } } */
+
+/* Test register pairs. */
+
+#if defined (__arm__)
+# define GPR1 "{r4}"
+# define GPR2_RAW "r5"
+#elif defined (__s390__)
+# define GPR1 "{r4}"
+# define GPR2_RAW "r5"
+#endif
+
+#define GPR2 "{"GPR2_RAW"}"
+
+void
+test (void)
+{
+ __asm__ ("" :: GPR1 (42ll));
+ __asm__ ("" :: GPR2 (42ll)); /* { dg-error "register .* for operand 0 isn't suitable for data type" } */
+ __asm__ ("" :: GPR1 (42ll), GPR2 (42)); /* { dg-error "multiple inputs to hard register" } */
+
+ long long x;
+ __asm__ ("" : "="GPR1 (x) :: GPR2_RAW); /* { dg-error "hard register constraint for output 0 conflicts with 'asm' clobber list" } */
+ __asm__ ("" : "=r" (x) : GPR1 (x) : GPR2_RAW); /* { dg-error "hard register constraint for input 0 conflicts with 'asm' clobber list" } */
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-error-4.c b/gcc/testsuite/gcc.dg/asm-hard-reg-error-4.c
new file mode 100644
index 0000000..465f24b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-error-4.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+/* Verify output operands. */
+
+int
+test (void)
+{
+ int x;
+ register int y __asm__ ("0");
+
+ /* Preserve status quo and don't error out. */
+ __asm__ ("" : "=r" (x), "=r" (x));
+
+ /* Be more strict for hard register constraints and error out. */
+ __asm__ ("" : "={0}" (x), "={1}" (x)); /* { dg-error "multiple outputs to lvalue 'x'" } */
+
+ /* Still error out in case of a mixture. */
+ __asm__ ("" : "=r" (x), "={1}" (x)); /* { dg-error "multiple outputs to lvalue 'x'" } */
+
+ return x + y;
+}
diff --git a/gcc/testsuite/gcc.dg/asm-hard-reg-error-5.c b/gcc/testsuite/gcc.dg/asm-hard-reg-error-5.c
new file mode 100644
index 0000000..85398f0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asm-hard-reg-error-5.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+
+/* Test clobbers.
+ See asm-hard-reg-error-{2,3}.c for tests involving register pairs. */
+
+int
+test (void)
+{
+ int x, y;
+ __asm__ ("" : "={0}" (x), "={1}" (y) : : "1"); /* { dg-error "hard register constraint for output 1 conflicts with 'asm' clobber list" } */
+ __asm__ ("" : "={0}" (x) : "{0}" (y), "{1}" (y) : "1"); /* { dg-error "hard register constraint for input 1 conflicts with 'asm' clobber list" } */
+ return x + y;
+}
diff --git a/gcc/testsuite/gcc.dg/bitint-124.c b/gcc/testsuite/gcc.dg/bitint-124.c
new file mode 100644
index 0000000..160a1e3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/bitint-124.c
@@ -0,0 +1,30 @@
+/* PR tree-optimization/121131 */
+/* { dg-do run { target bitint } } */
+/* { dg-options "-O2" } */
+
+#if __BITINT_MAXWIDTH__ >= 156
+struct A { _BitInt(156) b : 135; };
+
+static inline _BitInt(156)
+foo (struct A *x)
+{
+ return x[1].b;
+}
+
+__attribute__((noipa)) _BitInt(156)
+bar (void)
+{
+ struct A a[] = { 1, 1, -13055525270329736316393717310914023773847wb,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+ return foo (&a[1]);
+}
+#endif
+
+int
+main ()
+{
+#if __BITINT_MAXWIDTH__ >= 156
+ if (bar () != -13055525270329736316393717310914023773847wb)
+ __builtin_abort ();
+#endif
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc
index 1fe5b5c..01ab766 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc
@@ -23,8 +23,8 @@
#include "target.h"
#include "fold-const.h"
#include "tree-pretty-print.h"
-#include "diagnostic-color.h"
-#include "diagnostic-metadata.h"
+#include "diagnostics/color.h"
+#include "diagnostics/metadata.h"
#include "tristate.h"
#include "bitmap.h"
#include "selftest.h"
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc
index fa2f2fa..c101c45 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc
@@ -16,7 +16,7 @@
#include "gimple.h"
#include "gimple-iterator.h"
#include "gimple-walk.h"
-#include "diagnostic-event-id.h"
+#include "diagnostics/event-id.h"
#include "analyzer/common.h"
#include "analyzer/analyzer-logging.h"
#include "json.h"
@@ -120,20 +120,22 @@ public:
return false;
}
- diagnostic_event::meaning
+ diagnostics::paths::event::meaning
get_meaning_for_state_change (const evdesc::state_change &change)
const final override
{
+ using event = diagnostics::paths::event;
+
if (change.is_global_p ())
{
if (change.m_new_state == m_sm.m_released_gil)
- return diagnostic_event::meaning (diagnostic_event::verb::release,
- diagnostic_event::noun::lock);
+ return event::meaning (event::verb::release,
+ event::noun::lock);
else if (change.m_new_state == m_sm.get_start_state ())
- return diagnostic_event::meaning (diagnostic_event::verb::acquire,
- diagnostic_event::noun::lock);
+ return event::meaning (event::verb::acquire,
+ event::noun::lock);
}
- return diagnostic_event::meaning ();
+ return event::meaning ();
}
protected:
gil_diagnostic (const gil_state_machine &sm) : m_sm (sm)
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc
index 18e054b..fc282a7 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc
@@ -23,8 +23,8 @@
#include "target.h"
#include "fold-const.h"
#include "tree-pretty-print.h"
-#include "diagnostic-color.h"
-#include "diagnostic-metadata.h"
+#include "diagnostics/color.h"
+#include "diagnostics/metadata.h"
#include "tristate.h"
#include "bitmap.h"
#include "selftest.h"
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc
index 5a6e075..44fcf37 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc
@@ -23,8 +23,8 @@
#include "target.h"
#include "fold-const.h"
#include "tree-pretty-print.h"
-#include "diagnostic-color.h"
-#include "diagnostic-metadata.h"
+#include "diagnostics/color.h"
+#include "diagnostics/metadata.h"
#include "tristate.h"
#include "bitmap.h"
#include "selftest.h"
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py
index aca1b6c..eaca35a 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-show-locus.py
@@ -1,4 +1,4 @@
-# Verify that diagnostic-show-locus.cc works with HTML output.
+# Verify that diagnostics/source-printing.cc works with HTML output.
from htmltest import *
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc
index 4ade232..48f8325 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc
@@ -27,7 +27,7 @@
#include "plugin-version.h"
#include "c-family/c-common.h"
#include "diagnostic.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/text-sink.h"
#include "context.h"
int plugin_is_GPL_compatible;
@@ -165,8 +165,8 @@ pass_test_groups::execute (function *fun)
expected output. */
void
-test_diagnostic_text_starter (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic)
+test_diagnostic_text_starter (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic)
{
pp_set_prefix (text_output.get_printer (), xstrdup ("PREFIX: "));
}
@@ -175,22 +175,22 @@ test_diagnostic_text_starter (diagnostic_text_output_format &text_output,
expected output. */
void
-test_diagnostic_start_span_fn (const diagnostic_location_print_policy &,
- to_text &sink,
+test_diagnostic_start_span_fn (const diagnostics::location_print_policy &,
+ diagnostics::to_text &sink,
expanded_location)
{
- pretty_printer *pp = get_printer (sink);
+ pretty_printer *pp = diagnostics::get_printer (sink);
pp_string (pp, "START_SPAN_FN: ");
pp_newline (pp);
}
-/* Custom output format subclass. */
+/* Custom text_sink subclass. */
-class test_output_format : public diagnostic_text_output_format
+class custom_test_sink : public diagnostics::text_sink
{
public:
- test_output_format (diagnostic_context &context)
- : diagnostic_text_output_format (context)
+ custom_test_sink (diagnostics::context &context)
+ : diagnostics::text_sink (context)
{}
void on_begin_group () final override
@@ -228,10 +228,9 @@ plugin_init (struct plugin_name_args *plugin_info,
if (!plugin_default_version_check (version, &gcc_version))
return 1;
- diagnostic_text_starter (global_dc) = test_diagnostic_text_starter;
- diagnostic_start_span (global_dc) = test_diagnostic_start_span_fn;
- global_dc->set_output_format
- (::std::make_unique<test_output_format> (*global_dc));
+ diagnostics::text_starter (global_dc) = test_diagnostic_text_starter;
+ diagnostics::start_span (global_dc) = test_diagnostic_start_span_fn;
+ global_dc->set_sink (::std::make_unique<custom_test_sink> (*global_dc));
pass_info.pass = new pass_test_groups (g);
pass_info.reference_pass_name = "*warn_function_noreturn";
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.cc
index 44b94da..7e34a42 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_show_trees.cc
@@ -115,7 +115,7 @@ plugin_init (struct plugin_name_args *plugin_info,
if (!plugin_default_version_check (version, &gcc_version))
return 1;
- global_dc->m_source_printing.max_width = 80;
+ global_dc->get_source_printing_options ().max_width = 80;
register_callback (plugin_name,
PLUGIN_PRE_GENERICIZE,
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc
index d432161..7398a29 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_graphs.cc
@@ -33,8 +33,8 @@
#include "diagnostic.h"
#include "context.h"
#include "gcc-rich-location.h"
-#include "diagnostic-metadata.h"
-#include "diagnostic-digraphs.h"
+#include "diagnostics/metadata.h"
+#include "diagnostics/digraphs.h"
#include "pass_manager.h"
@@ -97,7 +97,7 @@ check_for_named_call (gimple *stmt,
return call;
}
-class lazy_passes_graph : public diagnostics::digraphs::lazy_digraph
+class lazy_passes_graph : public lazily_created<diagnostics::digraphs::digraph>
{
public:
lazy_passes_graph (const ::gcc::pass_manager &pass_manager_)
@@ -105,8 +105,9 @@ public:
{
}
+private:
std::unique_ptr<diagnostics::digraphs::digraph>
- create_digraph () const final override
+ create_object () const final override
{
auto g = std::make_unique<diagnostics::digraphs::digraph> ();
g->set_description ("Optimization Passes");
@@ -176,14 +177,13 @@ public:
return result;
}
-private:
const ::gcc::pass_manager &m_pass_manager;
};
static void
report_diag_with_graphs (location_t loc)
{
- class my_lazy_digraphs : public diagnostics::digraphs::lazy_digraphs
+ class my_lazy_digraphs : public diagnostics::metadata::lazy_digraphs
{
public:
using diagnostic_graph = diagnostics::digraphs::digraph;
@@ -191,7 +191,7 @@ report_diag_with_graphs (location_t loc)
using diagnostic_edge = diagnostics::digraphs::edge;
std::unique_ptr<std::vector<std::unique_ptr<diagnostic_graph>>>
- create_digraphs () const final override
+ create_object () const final override
{
auto graphs
= std::make_unique<std::vector<std::unique_ptr<diagnostic_graph>>> ();
@@ -230,7 +230,7 @@ report_diag_with_graphs (location_t loc)
};
gcc_rich_location rich_loc (loc);
- diagnostic_metadata meta;
+ diagnostics::metadata meta;
my_lazy_digraphs ldg;
meta.set_lazy_digraphs (&ldg);
error_meta (&rich_loc, meta,
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.cc
index 7edce1f..d38538d 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_inlining.cc
@@ -169,7 +169,7 @@ plugin_init (struct plugin_name_args *plugin_info,
if (!plugin_default_version_check (version, &gcc_version))
return 1;
- global_dc->m_source_printing.max_width = 80;
+ global_dc->get_source_printing_options ().max_width = 80;
pass_info.pass = new pass_test_inlining (g);
pass_info.reference_pass_name = "*warn_function_noreturn";
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.cc
index b86a8b3..f172258 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_metadata.cc
@@ -1,5 +1,6 @@
-/* This plugin exercises diagnostic_metadata. */
+/* This plugin exercises diagnostics::metadata. */
+#define INCLUDE_VECTOR
#include "gcc-plugin.h"
#include "config.h"
#include "system.h"
@@ -28,7 +29,7 @@
#include "diagnostic.h"
#include "context.h"
#include "gcc-rich-location.h"
-#include "diagnostic-metadata.h"
+#include "diagnostics/metadata.h"
int plugin_is_GPL_compatible;
@@ -89,7 +90,7 @@ check_for_named_call (gimple *stmt,
return call;
}
-/* Exercise diagnostic_metadata. */
+/* Exercise diagnostics::metadata. */
unsigned int
pass_test_metadata::execute (function *fun)
@@ -106,13 +107,13 @@ pass_test_metadata::execute (function *fun)
if (gcall *call = check_for_named_call (stmt, "gets", 1))
{
gcc_rich_location richloc (gimple_location (call));
- diagnostic_metadata m;
+ diagnostics::metadata m;
/* CWE-242: Use of Inherently Dangerous Function. */
m.add_cwe (242);
- /* Example of a diagnostic_metadata::rule. */
- diagnostic_metadata::precanned_rule
+ /* Example of a diagnostics::metadata::rule. */
+ diagnostics::metadata::precanned_rule
test_rule ("STR34-C", "https://example.com/");
m.add_rule (test_rule);
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc
index a7963fa..875f4a8 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_paths.cc
@@ -6,6 +6,7 @@
specific tests within the compiler's IR. We can't use any real
diagnostics for this, so we have to fake it, hence this plugin. */
+#define INCLUDE_VECTOR
#include "gcc-plugin.h"
#include "config.h"
#include "system.h"
@@ -32,8 +33,7 @@
#include "intl.h"
#include "plugin-version.h"
#include "diagnostic.h"
-#include "diagnostic-path.h"
-#include "diagnostic-metadata.h"
+#include "diagnostics/metadata.h"
#include "context.h"
#include "print-tree.h"
#include "gcc-rich-location.h"
@@ -223,7 +223,7 @@ class test_diagnostic_path : public simple_diagnostic_path
diagnostic_event_id_t
add_event_2 (event_location_t evloc, int stack_depth,
const char *desc,
- diagnostic_thread_id_t thread_id = 0)
+ diagnostics::paths::thread_id_t thread_id = 0)
{
gcc_assert (evloc.m_fun);
return add_thread_event (thread_id, evloc.m_loc, evloc.m_fun->decl,
@@ -232,7 +232,7 @@ class test_diagnostic_path : public simple_diagnostic_path
diagnostic_event_id_t
add_event_2_with_event_id (event_location_t evloc, int stack_depth,
const char *fmt,
- diagnostic_thread_id_t thread_id,
+ diagnostics::paths::thread_id_t thread_id,
diagnostic_event_id_t event_id)
{
gcc_assert (evloc.m_fun);
@@ -242,7 +242,7 @@ class test_diagnostic_path : public simple_diagnostic_path
}
void add_entry (event_location_t evloc, int stack_depth,
const char *funcname,
- diagnostic_thread_id_t thread_id = 0)
+ diagnostics::paths::thread_id_t thread_id = 0)
{
gcc_assert (evloc.m_fun);
add_thread_event (thread_id, evloc.m_loc, evloc.m_fun->decl, stack_depth,
@@ -363,7 +363,7 @@ example_2 ()
richloc.set_path (&path);
- diagnostic_metadata m;
+ diagnostics::metadata m;
m.add_cwe (415); /* CWE-415: Double Free. */
warning_meta (&richloc, m, 0,
@@ -441,7 +441,7 @@ example_3 ()
richloc.set_path (&path);
- diagnostic_metadata m;
+ diagnostics::metadata m;
/* CWE-479: Signal Handler Use of a Non-reentrant Function. */
m.add_cwe (479);
@@ -502,8 +502,8 @@ example_4 ()
gcc_rich_location richloc (call_to_acquire_lock_a_in_bar.m_loc);
test_diagnostic_path path (global_dc->get_reference_printer ());
- diagnostic_thread_id_t thread_1 = path.add_thread ("Thread 1");
- diagnostic_thread_id_t thread_2 = path.add_thread ("Thread 2");
+ diagnostics::paths::thread_id_t thread_1 = path.add_thread ("Thread 1");
+ diagnostics::paths::thread_id_t thread_2 = path.add_thread ("Thread 2");
path.add_entry (entry_to_foo, 0, "foo", thread_1);
diagnostic_event_id_t event_a_acquired
= path.add_event_2 (call_to_acquire_lock_a_in_foo, 1,
@@ -524,7 +524,7 @@ example_4 ()
thread_2, event_a_acquired);
richloc.set_path (&path);
- diagnostic_metadata m;
+ diagnostics::metadata m;
warning_meta (&richloc, m, 0,
"deadlock due to inconsistent lock acquisition order");
}
@@ -559,7 +559,7 @@ plugin_init (struct plugin_name_args *plugin_info,
if (!plugin_default_version_check (version, &gcc_version))
return 1;
- global_dc->m_source_printing.max_width = 80;
+ global_dc->get_source_printing_options ().max_width = 80;
pass_info.pass = make_pass_test_show_path (g);
pass_info.reference_pass_name = "whole-program";
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc
index cd3834b..92839cd 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_show_locus.cc
@@ -62,7 +62,8 @@
#include "print-tree.h"
#include "gcc-rich-location.h"
#include "text-range-label.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/text-sink.h"
+#include "diagnostics/file-cache.h"
int plugin_is_GPL_compatible;
@@ -125,14 +126,14 @@ static bool force_show_locus_color = false;
/* We want to verify the colorized output of diagnostic_show_locus,
but turning on colorization for everything confuses "dg-warning" etc.
Hence we special-case it within this plugin by using this modified
- version of default_diagnostic_text_finalizer, which, if "color" is
+ version of diagnostics::default_text_finalizer, which, if "color" is
passed in as a plugin argument turns on colorization, but just
for diagnostic_show_locus. */
static void
-custom_diagnostic_text_finalizer (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic,
- diagnostic_t)
+custom_diagnostic_text_finalizer (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diag,
+ enum diagnostics::kind)
{
pretty_printer *const pp = text_output.get_printer ();
bool old_show_color = pp_show_color (pp);
@@ -143,7 +144,7 @@ custom_diagnostic_text_finalizer (diagnostic_text_output_format &text_output,
pp_newline (pp);
diagnostic_show_locus (&text_output.get_context (),
text_output.get_source_printing_options (),
- diagnostic->richloc, diagnostic->kind, pp);
+ diag->m_richloc, diag->m_kind, pp);
pp_show_color (pp) = old_show_color;
pp_set_prefix (pp, saved_prefix);
pp_flush (pp);
@@ -176,11 +177,11 @@ test_show_locus (function *fun)
location_t fnstart = fun->function_start_locus;
int fnstart_line = LOCATION_LINE (fnstart);
- diagnostic_text_finalizer (global_dc) = custom_diagnostic_text_finalizer;
+ diagnostics::text_finalizer (global_dc) = custom_diagnostic_text_finalizer;
/* Hardcode the "terminal width", to verify the behavior of
very wide lines. */
- global_dc->m_source_printing.max_width = 71;
+ global_dc->get_source_printing_options ().max_width = 71;
if (0 == strcmp (fnname, "test_simple"))
{
@@ -251,7 +252,7 @@ test_show_locus (function *fun)
if (0 == strcmp (fnname, "test_very_wide_line"))
{
const int line = fnstart_line + 2;
- global_dc->m_source_printing.show_ruler_p = true;
+ global_dc->get_source_printing_options ().show_ruler_p = true;
text_range_label label0 ("label 0");
text_range_label label1 ("label 1");
rich_location richloc (line_table,
@@ -263,7 +264,7 @@ test_show_locus (function *fun)
&label1);
richloc.add_fixit_replace ("bar * foo");
warning_at (&richloc, 0, "test");
- global_dc->m_source_printing.show_ruler_p = false;
+ global_dc->get_source_printing_options ().show_ruler_p = false;
}
/* Likewise, but with a secondary location that's immediately before
@@ -271,7 +272,7 @@ test_show_locus (function *fun)
if (0 == strcmp (fnname, "test_very_wide_line_2"))
{
const int line = fnstart_line + 2;
- global_dc->m_source_printing.show_ruler_p = true;
+ global_dc->get_source_printing_options ().show_ruler_p = true;
text_range_label label0 ("label 0");
text_range_label label1 ("label 1");
rich_location richloc (line_table,
@@ -283,7 +284,7 @@ test_show_locus (function *fun)
richloc.add_range (get_loc (line, 34), SHOW_RANGE_WITHOUT_CARET,
&label1);
warning_at (&richloc, 0, "test");
- global_dc->m_source_printing.show_ruler_p = false;
+ global_dc->get_source_printing_options ().show_ruler_p = false;
}
/* Example of multiple carets. */
@@ -294,11 +295,11 @@ test_show_locus (function *fun)
location_t caret_b = get_loc (line, 11);
rich_location richloc (line_table, caret_a);
add_range (&richloc, caret_b, caret_b, SHOW_RANGE_WITH_CARET);
- global_dc->m_source_printing.caret_chars[0] = 'A';
- global_dc->m_source_printing.caret_chars[1] = 'B';
+ global_dc->get_source_printing_options ().caret_chars[0] = 'A';
+ global_dc->get_source_printing_options ().caret_chars[1] = 'B';
warning_at (&richloc, 0, "test");
- global_dc->m_source_printing.caret_chars[0] = '^';
- global_dc->m_source_printing.caret_chars[1] = '^';
+ global_dc->get_source_printing_options ().caret_chars[0] = '^';
+ global_dc->get_source_printing_options ().caret_chars[1] = '^';
}
/* Tests of rendering fixit hints. */
@@ -412,11 +413,11 @@ test_show_locus (function *fun)
location_t caret_b = get_loc (line - 1, 19);
rich_location richloc (line_table, caret_a);
richloc.add_range (caret_b, SHOW_RANGE_WITH_CARET);
- global_dc->m_source_printing.caret_chars[0] = '1';
- global_dc->m_source_printing.caret_chars[1] = '2';
+ global_dc->get_source_printing_options ().caret_chars[0] = '1';
+ global_dc->get_source_printing_options ().caret_chars[1] = '2';
warning_at (&richloc, 0, "test");
- global_dc->m_source_printing.caret_chars[0] = '^';
- global_dc->m_source_printing.caret_chars[1] = '^';
+ global_dc->get_source_printing_options ().caret_chars[0] = '^';
+ global_dc->get_source_printing_options ().caret_chars[1] = '^';
}
/* Example of using the "%q+D" format code, which as well as printing
@@ -443,8 +444,8 @@ test_show_locus (function *fun)
rich_location richloc (line_table, loc);
for (int line = start_line; line <= finish_line; line++)
{
- file_cache &fc = global_dc->get_file_cache ();
- char_span content = fc.get_source_line (file, line);
+ diagnostics::file_cache &fc = global_dc->get_file_cache ();
+ diagnostics::char_span content = fc.get_source_line (file, line);
gcc_assert (content);
/* Split line up into words. */
for (int idx = 0; idx < content.length (); idx++)
@@ -464,7 +465,8 @@ test_show_locus (function *fun)
richloc.add_range (word, SHOW_RANGE_WITH_CARET, &label);
/* Add a fixit, converting to upper case. */
- char_span word_span = content.subspan (start_idx, idx - start_idx);
+ diagnostics::char_span word_span
+ = content.subspan (start_idx, idx - start_idx);
char *copy = word_span.xstrdup ();
for (char *ch = copy; *ch; ch++)
*ch = TOUPPER (*ch);
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.cc
index 1b5fad2..b64d60f 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_string_literals.cc
@@ -208,7 +208,7 @@ plugin_init (struct plugin_name_args *plugin_info,
if (!plugin_default_version_check (version, &gcc_version))
return 1;
- global_dc->m_source_printing.max_width = 80;
+ global_dc->get_source_printing_options ().max_width = 80;
pass_info.pass = new pass_test_string_literals (g);
pass_info.reference_pass_name = "ssa";
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_text_art.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_text_art.cc
index e28d697..ce2f1d3 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_text_art.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_text_art.cc
@@ -9,7 +9,7 @@
#include "coretypes.h"
#include "plugin-version.h"
#include "diagnostic.h"
-#include "diagnostic-diagram.h"
+#include "diagnostics/diagram.h"
#include "text-art/canvas.h"
#include "text-art/table.h"
@@ -22,7 +22,7 @@ using namespace text_art;
static void
emit_canvas (const canvas &c, const char *alt_text)
{
- diagnostic_diagram diagram (c, alt_text);
+ diagnostics::diagram diagram (c, alt_text);
global_dc->emit_diagram (diagram);
}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.cc
index fbdb2f8..bbd0faa 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_test_tree_expression_range.cc
@@ -89,7 +89,7 @@ plugin_init (struct plugin_name_args *plugin_info,
if (!plugin_default_version_check (version, &gcc_version))
return 1;
- global_dc->m_source_printing.max_width = 130;
+ global_dc->get_source_printing_options ().max_width = 130;
register_callback (plugin_name,
PLUGIN_PRE_GENERICIZE,
diff --git a/gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.cc b/gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.cc
index 7b9b8d4..67722d4 100644
--- a/gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/expensive_selftests_plugin.cc
@@ -6,9 +6,9 @@
#include "system.h"
#include "coretypes.h"
#include "diagnostic.h"
-#include "edit-context.h"
+#include "diagnostics/changes.h"
#include "selftest.h"
-#include "selftest-diagnostic.h"
+#include "diagnostics/selftest-context.h"
int plugin_is_GPL_compatible;
@@ -47,14 +47,15 @@ static void
test_richloc (rich_location *richloc)
{
/* Run the diagnostic and fix-it printing code. */
- test_diagnostic_context dc;
- diagnostic_show_locus (&dc, dc.m_source_printing,
- richloc, DK_ERROR, dc.get_reference_printer ());
+ diagnostics::selftest::test_context dc;
+ diagnostic_show_locus (&dc, dc.get_source_printing_options (),
+ richloc, diagnostics::kind::error,
+ dc.get_reference_printer ());
/* Generate a diff. */
- edit_context ec (global_dc->get_file_cache ());
- ec.add_fixits (richloc);
- char *diff = ec.generate_diff (true);
+ diagnostics::changes::change_set edit (global_dc->get_file_cache ());
+ edit.add_fixits (richloc);
+ char *diff = edit.generate_diff (true);
free (diff);
}
diff --git a/gcc/testsuite/gcc.dg/plugin/location_overflow_plugin.cc b/gcc/testsuite/gcc.dg/plugin/location_overflow_plugin.cc
index f770d35..00ad870 100644
--- a/gcc/testsuite/gcc.dg/plugin/location_overflow_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/location_overflow_plugin.cc
@@ -7,7 +7,7 @@
#include "coretypes.h"
#include "spellcheck.h"
#include "diagnostic.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/text-sink.h"
int plugin_is_GPL_compatible;
@@ -39,12 +39,12 @@ on_pragma_registration (void */*gcc_data*/, void */*user_data*/)
/* We add some extra testing during diagnostics by chaining up
to the text finalizer. */
-static diagnostic_text_finalizer_fn original_text_finalizer = NULL;
+static diagnostics::text_finalizer_fn original_text_finalizer = NULL;
static void
-verify_unpacked_ranges (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic,
- diagnostic_t orig_diag_kind)
+verify_unpacked_ranges (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic,
+ enum diagnostics::kind orig_diag_kind)
{
/* Verify that the locations are ad-hoc, not packed. */
location_t loc = diagnostic_location (diagnostic);
@@ -56,9 +56,9 @@ verify_unpacked_ranges (diagnostic_text_output_format &text_output,
}
static void
-verify_no_columns (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic,
- diagnostic_t orig_diag_kind)
+verify_no_columns (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diagnostic,
+ enum diagnostics::kind orig_diag_kind)
{
/* Verify that the locations have no columns. */
location_t loc = diagnostic_location (diagnostic);
@@ -104,15 +104,15 @@ plugin_init (struct plugin_name_args *plugin_info,
NULL); /* void *user_data */
/* Hack in additional testing, based on the exact value supplied. */
- original_text_finalizer = diagnostic_text_finalizer (global_dc);
+ original_text_finalizer = diagnostics::text_finalizer (global_dc);
switch (base_location)
{
case LINE_MAP_MAX_LOCATION_WITH_PACKED_RANGES + 1:
- diagnostic_text_finalizer (global_dc) = verify_unpacked_ranges;
+ diagnostics::text_finalizer (global_dc) = verify_unpacked_ranges;
break;
case LINE_MAP_MAX_LOCATION_WITH_COLS + 1:
- diagnostic_text_finalizer (global_dc) = verify_no_columns;
+ diagnostics::text_finalizer (global_dc) = verify_no_columns;
break;
default:
diff --git a/gcc/testsuite/gcc.dg/pr109267-1.c b/gcc/testsuite/gcc.dg/pr109267-1.c
new file mode 100644
index 0000000..e762e59
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109267-1.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* PR middle-end/109267 */
+
+int f(void)
+{
+ __builtin_unreachable();
+}
+
+/* This unreachable should be changed to be a trap. */
+
+/* { dg-final { scan-tree-dump-times "__builtin_unreachable trap \\\(" 1 "optimized" { target trap } } } */
+/* { dg-final { scan-tree-dump-times "goto <" 1 "optimized" { target { ! trap } } } } */
+/* { dg-final { scan-tree-dump-not "__builtin_unreachable \\\(" "optimized"} } */
diff --git a/gcc/testsuite/gcc.dg/pr109267-2.c b/gcc/testsuite/gcc.dg/pr109267-2.c
new file mode 100644
index 0000000..6cd1419
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109267-2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+/* PR middle-end/109267 */
+void g(void);
+int f(int *t)
+{
+ g();
+ __builtin_unreachable();
+}
+
+/* The unreachable should stay a unreachable. */
+/* { dg-final { scan-tree-dump-not "__builtin_unreachable trap \\\(" "optimized"} } */
+/* { dg-final { scan-tree-dump-times "__builtin_unreachable \\\(" 1 "optimized"} } */
diff --git a/gcc/testsuite/gcc.dg/pr121202.c b/gcc/testsuite/gcc.dg/pr121202.c
new file mode 100644
index 0000000..30ecf4a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr121202.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -fno-tree-copy-prop" } */
+
+int a, b, c;
+int e(int f, int g) { return f >> g; }
+int h(int f) { return a > 1 ? 0 : f << a; }
+int main() {
+ while (c--)
+ b = e(h(1), a);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr121216.c b/gcc/testsuite/gcc.dg/pr121216.c
new file mode 100644
index 0000000..a695b40
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr121216.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+int foo (void)
+{
+ const char *key = "obscurelevelofabstraction";
+ const char reverse_key[__builtin_strlen(key)] = {'\0'}; /* { dg-error "variable-sized object may not be initialized except with an empty initializer" } */
+ return __builtin_strlen(reverse_key);
+}
diff --git a/gcc/testsuite/gcc.dg/pr87600-2.c b/gcc/testsuite/gcc.dg/pr87600-2.c
index 808ebe1..822afe0 100644
--- a/gcc/testsuite/gcc.dg/pr87600-2.c
+++ b/gcc/testsuite/gcc.dg/pr87600-2.c
@@ -23,22 +23,3 @@ test1 (void)
asm ("blah %0 %1" : "=r" (var1) : "0" (var2)); /* { dg-error "invalid hard register usage between output operand and matching constraint operand" } */
return var1;
}
-
-long
-test2 (void)
-{
- register long var1 asm (REG1);
- register long var2 asm (REG1);
- asm ("blah %0 %1" : "=&r" (var1) : "r" (var2)); /* { dg-error "invalid hard register usage between earlyclobber operand and input operand" } */
- return var1;
-}
-
-long
-test3 (void)
-{
- register long var1 asm (REG1);
- register long var2 asm (REG1);
- long var3;
- asm ("blah %0 %1" : "=&r" (var1), "=r" (var3) : "1" (var2)); /* { dg-error "invalid hard register usage between earlyclobber operand and input operand" } */
- return var1 + var3;
-}
diff --git a/gcc/testsuite/gcc.dg/pr87600-3.c b/gcc/testsuite/gcc.dg/pr87600-3.c
new file mode 100644
index 0000000..4f43a5f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr87600-3.c
@@ -0,0 +1,26 @@
+/* PR rtl-optimization/87600 */
+/* { dg-do compile { target aarch64*-*-* arm*-*-* i?86-*-* powerpc*-*-* s390*-*-* x86_64-*-* } } */
+/* { dg-options "-O2" } */
+
+#include "pr87600.h"
+
+/* The following are all invalid uses of local register variables. */
+
+long
+test2 (void)
+{
+ register long var1 asm (REG1);
+ register long var2 asm (REG1);
+ asm ("blah %0 %1" : "=&r" (var1) : "r" (var2)); /* { dg-error "invalid hard register usage between earlyclobber operand and input operand" } */
+ return var1;
+}
+
+long
+test3 (void)
+{
+ register long var1 asm (REG1);
+ register long var2 asm (REG1);
+ long var3;
+ asm ("blah %0 %1" : "=&r" (var1), "=r" (var3) : "1" (var2)); /* { dg-error "invalid hard register usage between earlyclobber operand and input operand" } */
+ return var1 + var3;
+}
diff --git a/gcc/testsuite/gcc.dg/sarif-output/include-chain-2.h b/gcc/testsuite/gcc.dg/sarif-output/include-chain-2.h
index 382ac02..f60fb33 100644
--- a/gcc/testsuite/gcc.dg/sarif-output/include-chain-2.h
+++ b/gcc/testsuite/gcc.dg/sarif-output/include-chain-2.h
@@ -1,4 +1,4 @@
-/* Generate a warning with a diagnostic_path within a header. */
+/* Generate a warning with a diagnostic path within a header. */
void test (void *ptr)
{
diff --git a/gcc/testsuite/gcc.dg/torture/pr121194.c b/gcc/testsuite/gcc.dg/torture/pr121194.c
new file mode 100644
index 0000000..20f5ff7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr121194.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+
+int a, b, c, d;
+void e() {
+ int *f = &b;
+ for (a = 0; a < 8; a++) {
+ *f = 0;
+ for (c = 0; c < 2; c++)
+ *f = *f == 0;
+ }
+}
+int main() {
+ e();
+ int *g = &b;
+ *g = *g == (d == 0);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1b.c b/gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1b.c
index dd53295..79ba529 100644
--- a/gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1b.c
+++ b/gcc/testsuite/gcc.dg/tree-prof/afdo-crossmodule-1b.c
@@ -1,3 +1,8 @@
+/* { dg-require-effective-target lto } */
+/* { dg-additional-sources "afdo-crossmodule-1.c" } */
+/* { dg-options "-O3 -flto -fdump-ipa-afdo_offline -fdump-tree-einline-details" } */
+/* { dg-require-profiling "-fauto-profile" } */
+
extern int foo2 ();
int bar (int (*fooptr) (int (*)()))
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cmp-2.c b/gcc/testsuite/gcc.dg/tree-ssa/cmp-2.c
new file mode 100644
index 0000000..9b02901
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cmp-2.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-forwprop" } */
+
+/* PR tree-optimization/110949 */
+/* Transform `(cmp) - 1` into `-icmp`. */
+
+int f1(int a)
+{
+ int t = a == 115;
+ return t - 1;
+}
+
+/* { dg-final { scan-tree-dump " != 115" "forwprop1" } } */
+/* { dg-final { scan-tree-dump-not " == 115" "forwprop1" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/max-bitcmp-1.c b/gcc/testsuite/gcc.dg/tree-ssa/max-bitcmp-1.c
new file mode 100644
index 0000000..81b5a27
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/max-bitcmp-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-forwprop -fdump-tree-optimized" } */
+
+/* PR tree-optimization/95906 */
+/* this should become MAX_EXPR<a,b> */
+
+int f2(int a, int b)
+{
+ int cmp = -(a > b);
+ return (cmp & a) | (~cmp & b);
+}
+
+/* we should not end up with -_2 */
+/* we should not end up and & nor a `+ -1` */
+/* In optimized we should have a max. */
+/* { dg-final { scan-tree-dump-not " -\[a-zA-Z_\]" "forwprop1" } } */
+/* { dg-final { scan-tree-dump-not " & " "forwprop1" } } */
+/* { dg-final { scan-tree-dump-not " . -1" "forwprop1" } } */
+/* { dg-final { scan-tree-dump-times "MAX_EXPR " 1 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr117423.c b/gcc/testsuite/gcc.dg/tree-ssa/pr117423.c
new file mode 100644
index 0000000..a5d3b29
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr117423.c
@@ -0,0 +1,49 @@
+/* { dg-do run } */
+/* { dg-options "-O1" } */
+
+struct s4 {
+ int _0;
+};
+struct s1 {
+ unsigned char _4;
+ long _1;
+};
+struct s2 {
+ union {
+ struct s3 {
+ unsigned char _1;
+ struct s4 _0;
+ } var_0;
+ struct s1 var_1;
+ } DATA;
+};
+int f1(int arg0) { return arg0 > 12345; }
+__attribute__((noinline))
+struct s4 f2(int arg0) {
+ struct s4 rv = {arg0};
+ return rv;
+}
+struct s2 f3(int arg0) {
+ struct s2 rv;
+ struct s1 var6 = {0};
+ struct s4 var7;
+ if (f1(arg0)) {
+ rv.DATA.var_1 = var6;
+ return rv;
+ } else {
+ rv.DATA.var_0._1 = 2;
+ var7 = f2(arg0);
+ rv.DATA.var_0._0 = var7;
+ return rv;
+ }
+}
+int main() {
+ if (f3(12345).DATA.var_0._0._0 == 12345)
+ ;
+ else
+ __builtin_abort();
+ if (f3(12344).DATA.var_0._0._0 == 12344)
+ ;
+ else
+ __builtin_abort();
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr119085.c b/gcc/testsuite/gcc.dg/tree-ssa/pr119085.c
new file mode 100644
index 0000000..e9811ce
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr119085.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-options "-O1" } */
+
+struct with_hole {
+ int x;
+ long y;
+};
+struct without_hole {
+ int x;
+ int y;
+};
+union u {
+ struct with_hole with_hole;
+ struct without_hole without_hole;
+};
+
+void __attribute__((noinline))
+test (union u *up, union u u)
+{
+ union u u2;
+ volatile int f = 0;
+ u2 = u;
+ if (f)
+ u2.with_hole = u.with_hole;
+ *up = u2;
+}
+
+int main(void)
+{
+ union u u;
+ union u u2;
+ u2.without_hole.y = -1;
+ test (&u, u2);
+ if (u.without_hole.y != -1)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr81627.c b/gcc/testsuite/gcc.dg/tree-ssa/pr81627.c
index 9ba43be..ef35b29 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr81627.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr81627.c
@@ -4,6 +4,7 @@
int a, b, c, d[6], e = 3, f;
void abort (void);
+void fn1 () __attribute__((noinline));
void fn1 ()
{
for (b = 1; b < 5; b++)
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-23.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-23.c
new file mode 100644
index 0000000..f632dc8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-sink-23.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-sink1-details" } */
+
+struct S {
+ int* x;
+ int* y;
+};
+
+void __attribute__((noreturn)) bar(const struct S* s);
+
+void foo(int a, int b) {
+ struct S s;
+ s.x = &a;
+ s.y = &b;
+ if (a < b) {
+ bar(&s);
+ }
+}
+
+/* { dg-final { scan-tree-dump "Sinking.*s.y" "sink1" } } */
+/* { dg-final { scan-tree-dump "Sinking.*s.x" "sink1" } } */
diff --git a/gcc/testsuite/gcc.dg/uninit-pr120924.c b/gcc/testsuite/gcc.dg/uninit-pr120924.c
new file mode 100644
index 0000000..bfc8ae9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/uninit-pr120924.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wmaybe-uninitialized" } */
+
+int foo(int);
+enum {
+ BPF_TRACE_RAW_TP,
+ BPF_MODIFY_RETURN,
+ BPF_LSM_MAC,
+ BPF_TRACE_ITER,
+ BPF_LSM_CGROUP
+};
+int btf_get_kernel_prefix_kind_prefix, obj_1, attach_name___trans_tmp_1;
+char attach_name_fn_name;
+void attach_name(int attach_type)
+{
+ int mod_len;
+ char mod_name = attach_name_fn_name;
+ if (attach_name_fn_name)
+ mod_len = mod_name;
+ for (; obj_1;) {
+ if (mod_name && foo(mod_len))
+ continue;
+ switch (attach_type) {
+ case BPF_TRACE_RAW_TP:
+ case BPF_LSM_MAC:
+ case BPF_LSM_CGROUP:
+ btf_get_kernel_prefix_kind_prefix = 1;
+ case BPF_TRACE_ITER:
+ attach_name_fn_name = 2;
+ }
+ if (attach_name___trans_tmp_1)
+ return;
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/vect/pr116125.c b/gcc/testsuite/gcc.dg/vect/pr116125.c
index eab9efd..1b882ec 100644
--- a/gcc/testsuite/gcc.dg/vect/pr116125.c
+++ b/gcc/testsuite/gcc.dg/vect/pr116125.c
@@ -17,12 +17,12 @@ main (void)
{
check_vect ();
- struct st a[9] = {};
+ struct st a[10] = {};
- // input a = 0, 0, 0, 0, 0, 0, 0, 0, 0
+ // input a = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
mem_overlap (&a[1], a);
- // output a = 0, 1, 2, 3, 4, 5, 6, 7, 8
+ // output a = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
if (a[2].num == 2)
return 0;
else
diff --git a/gcc/testsuite/gcc.dg/vect/pr121126.c b/gcc/testsuite/gcc.dg/vect/pr121126.c
new file mode 100644
index 0000000..ae6603b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr121126.c
@@ -0,0 +1,30 @@
+/* { dg-additional-options "--param vect-partial-vector-usage=2" } */
+
+#include "tree-vect.h"
+
+unsigned char a;
+unsigned b;
+int r[11];
+static void __attribute__((noipa))
+c(int e, unsigned s[][11][11])
+{
+ for (int u = -(e ? 2000424973 : 0) - 2294542319; u < 7; u += 4)
+ for (int x = 0; x < 300000011; x += 4)
+ for (int y = 0; y < (0 < s[u][4][1]) + 11; y += 3) {
+ a = a ?: 1;
+ b = r[2];
+ }
+}
+long long ab;
+int e = 1;
+unsigned s[11][11][11];
+int main()
+{
+ check_vect ();
+ for (int t = 0; t < 11; ++t)
+ r[t] = 308100;
+ c(e,s);
+ ab = b;
+ if (ab != 308100)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/gcc.dg/vect/slp-28.c b/gcc/testsuite/gcc.dg/vect/slp-28.c
index 67b7be2..1f98787 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-28.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-28.c
@@ -59,8 +59,8 @@ main1 ()
abort ();
}
- /* Not vectorizable because of data dependencies: distance 3 is greater than
- the actual VF with SLP (2), but the analysis fail to detect that for now. */
+ /* Dependence distance 3 is greater than the actual VF with SLP (2),
+ thus vectorizable. */
for (i = 3; i < N/4; i++)
{
in3[i*4] = in3[(i-3)*4] + 5;
@@ -91,7 +91,6 @@ int main (void)
return 0;
}
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { ! vect32 } } } } */
-/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" { target vect32 } } } */
-/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 1 "vect" { target { ! vect32 } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 2 "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-127.c b/gcc/testsuite/gcc.dg/vect/vect-127.c
new file mode 100644
index 0000000..8b913dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-127.c
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-require-effective-target vect_int }
+
+void foo (int *p)
+{
+ for (int i = 0; i < 1024; ++i)
+ {
+ int a0 = p[2*i + 0];
+ int a1 = p[2*i + 1];
+ p[2*i + 4] = a0;
+ p[2*i + 5] = a1;
+ }
+}
+
+/* { dg-final { scan-tree-dump "loop vectorized using 16 byte vectors" "vect" { target { vect128 && vect_hw_misalign } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-reduc-cond-1.c b/gcc/testsuite/gcc.dg/vect/vect-reduc-cond-1.c
index d8356b4..258f17e 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-reduc-cond-1.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-reduc-cond-1.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_condition } */
#include <stdarg.h>
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/vect-reduc-cond-2.c b/gcc/testsuite/gcc.dg/vect/vect-reduc-cond-2.c
index 80c1dba..126a50f 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-reduc-cond-2.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-reduc-cond-2.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_condition } */
/* { dg-additional-options "-fdump-tree-ifcvt-details" } */
#include <stdarg.h>
diff --git a/gcc/testsuite/gcc.target/aarch64/asm-hard-reg-1.c b/gcc/testsuite/gcc.target/aarch64/asm-hard-reg-1.c
new file mode 100644
index 0000000..7441dd7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/asm-hard-reg-1.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+/* Ensure that we error out in case no hard regs are available for an operand
+ with constraint y. The position/order of the y-constrained operand does not
+ matter. */
+
+void
+test (void)
+{
+ int x, a, b, c, d, e, f, g, h;
+
+ __asm__ __volatile__ ("" :
+ "={v0}" (a),
+ "={v1}" (b),
+ "={v2}" (c),
+ "={v3}" (d),
+ "={v4}" (e),
+ "={v5}" (f),
+ "={v6}" (g),
+ "={v7}" (h));
+
+ __asm__ __volatile__ ("" : /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ "=y" (x),
+ "={v0}" (a),
+ "={v1}" (b),
+ "={v2}" (c),
+ "={v3}" (d),
+ "={v4}" (e),
+ "={v5}" (f),
+ "={v6}" (g),
+ "={v7}" (h));
+
+ __asm__ __volatile__ ("" : /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ "={v0}" (a),
+ "={v1}" (b),
+ "={v2}" (c),
+ "={v3}" (d),
+ "=y" (x),
+ "={v4}" (e),
+ "={v5}" (f),
+ "={v6}" (g),
+ "={v7}" (h));
+
+ __asm__ __volatile__ ("" : /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ "={v0}" (a),
+ "={v1}" (b),
+ "={v2}" (c),
+ "={v3}" (d),
+ "={v4}" (e),
+ "={v5}" (f),
+ "={v6}" (g),
+ "={v7}" (h),
+ "=y" (x));
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/asm-hard-reg-2.c b/gcc/testsuite/gcc.target/aarch64/asm-hard-reg-2.c
new file mode 100644
index 0000000..7434063
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/asm-hard-reg-2.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=armv8-a+sve" } */
+
+/* Test register pairs. */
+
+#include <arm_sve.h>
+
+void
+test (void)
+{
+ svuint32x2_t x, y;
+ svuint32x4_t z;
+
+ __asm__ __volatile__ ("" : "={z4}" (x), "={z6}" (y));
+ __asm__ __volatile__ ("" : "={z5}" (x), "={z6}" (y)); /* { dg-error "multiple outputs to hard register: v6" } */
+ __asm__ __volatile__ ("" : "={z4}" (z), "={z6}" (y)); /* { dg-error "multiple outputs to hard register: v6" } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/inszero_split_1.c b/gcc/testsuite/gcc.target/aarch64/inszero_split_1.c
new file mode 100644
index 0000000..5c739bd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/inszero_split_1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-O2" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/* Avoid INS from WZR register when optimizing for speed. */
+
+#include <arm_neon.h>
+
+/*
+** foo:
+** movi? [vdz]([0-9]+)\.?(?:[0-9]*[bhsd])?, #?0
+** ins v0.h\[2\], v(\1).h\[0\]
+** ret
+*/
+uint16x8_t foo(uint16x8_t a) {
+ a[2] = 0;
+ return a;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/simd/mf8_data_1.c b/gcc/testsuite/gcc.target/aarch64/simd/mf8_data_1.c
index a3fd9b8..79d1ccf 100644
--- a/gcc/testsuite/gcc.target/aarch64/simd/mf8_data_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/simd/mf8_data_1.c
@@ -1016,7 +1016,12 @@ mfloat8x8_t test_set_lane3(mfloat8x8_t a, const mfloat8_t *ptr)
/*
** test_set_lane4:
+** (
** ins v0.b\[6\], wzr
+** |
+** movi? [vdz]([0-9]+)\.?(?:[0-9]*[bhsd])?, #?0
+** ins v0.b\[6\], v(\1).b\[0\]
+** )
** ret
*/
mfloat8x8_t test_set_lane4(mfloat8x8_t a)
@@ -1056,7 +1061,12 @@ mfloat8x16_t test_setq_lane3(mfloat8x16_t a, const mfloat8_t *ptr)
/*
** test_setq_lane4:
+** (
** ins v0.b\[14\], wzr
+** |
+** movi? [vdz]([0-9]+)\.?(?:[0-9]*[bhsd])?, #?0
+** ins v0.b\[14\], v(\1).b\[0\]
+** )
** ret
*/
mfloat8x16_t test_setq_lane4(mfloat8x16_t a)
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/mask_load_2.c b/gcc/testsuite/gcc.target/aarch64/sve/mask_load_2.c
new file mode 100644
index 0000000..66d9510
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/mask_load_2.c
@@ -0,0 +1,23 @@
+// { dg-do compile }
+// { dg-options "-march=armv8-a+sve -msve-vector-bits=128 -O3" }
+
+typedef struct Array {
+ int elems[3];
+} Array;
+
+int loop(Array **pp, int len, int idx) {
+ int nRet = 0;
+
+ #pragma GCC unroll 0
+ for (int i = 0; i < len; i++) {
+ Array *p = pp[i];
+ if (p) {
+ nRet += p->elems[idx];
+ }
+ }
+
+ return nRet;
+}
+
+// { dg-final { scan-assembler-times {ld1w\tz[0-9]+\.d, p[0-7]/z} 1 } }
+// { dg-final { scan-assembler-times {add\tz[0-9]+\.s, p[0-7]/m} 1 } }
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmax_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmax_1.c
new file mode 100644
index 0000000..e6aa047
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmax_1.c
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize" } */
+
+#include <stdint.h>
+
+#define b_i b[i]
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##RHS (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i], RHS) > c[i]) \
+ out[i] = 3; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1)
+
+TEST_ALL (__builtin_fmaxf16, _Float16, uint64_t, 32)
+
+TEST_ALL (__builtin_fmaxf16, _Float16, uint32_t, 64)
+
+TEST_ALL (__builtin_fmaxf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 6 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 7 } } */
+
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmax_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmax_2.c
new file mode 100644
index 0000000..87125a6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmax_2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include "unpacked_builtin_fmax_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 9 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 7 } } */
+
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmin_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmin_1.c
new file mode 100644
index 0000000..b9fded0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmin_1.c
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048" } */
+
+#include <stdint.h>
+
+#define b_i b[i]
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##RHS (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i], RHS) > c[i]) \
+ out[i] = 3; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1)
+
+TEST_ALL (__builtin_fminf16, _Float16, uint64_t, 32)
+
+TEST_ALL (__builtin_fminf16, _Float16, uint32_t, 64)
+
+TEST_ALL (__builtin_fminf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 6 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 7 } } */
+
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmin_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmin_2.c
new file mode 100644
index 0000000..5923b67
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_builtin_fmin_2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include "unpacked_builtin_fmin_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 9 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 7 } } */
+
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_builtin_fmax_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_builtin_fmax_1.c
new file mode 100644
index 0000000..d328b37
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_builtin_fmax_1.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+#define c_i c[i]
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS, MERGE) \
+ void \
+ f_##TYPE0##_##TYPE1##_##RHS##_##MERGE (TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c, \
+ TYPE1 *__restrict p) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i], (TYPE0)RHS) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, c_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1, b_i)
+
+TEST_ALL (__builtin_fmaxf16, _Float16, uint64_t, 32)
+
+TEST_ALL (__builtin_fmaxf16, _Float16, uint32_t, 64)
+
+TEST_ALL (__builtin_fmaxf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 13 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 13 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 13 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_builtin_fmin_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_builtin_fmin_1.c
new file mode 100644
index 0000000..1821f03
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_builtin_fmin_1.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+#define c_i c[i]
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS, MERGE) \
+ void \
+ f_##TYPE0##_##TYPE1##_##RHS##_##MERGE (TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c, \
+ TYPE1 *__restrict p) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i], (TYPE0)RHS) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, c_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1, b_i)
+
+TEST_ALL (__builtin_fminf16, _Float16, uint64_t, 32)
+
+TEST_ALL (__builtin_fminf16, _Float16, uint32_t, 64)
+
+TEST_ALL (__builtin_fminf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 13 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 13 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 13 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_cvtf_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_cvtf_1.c
new file mode 100644
index 0000000..fa4dd15
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_cvtf_1.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define COND_CVT(TYPE0, TYPE1, TYPE2, COUNT) \
+ void \
+ test_##TYPE0##_##TYPE1##_##TYPE2 (TYPE0 *__restrict out, \
+ TYPE1 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE2 *__restrict p) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? (TYPE0)a[i] : b[i]; \
+ }
+
+#define TEST_CVTF(PFX, T) \
+ T (_Float16, PFX##int16_t, uint64_t, 32) \
+ T (_Float16, PFX##int16_t, uint32_t, 64) \
+ T (_Float16, PFX##int32_t, uint64_t, 32) \
+ T (_Float16, PFX##int32_t, uint32_t, 64) \
+ T (_Float16, PFX##int64_t, uint64_t, 32) \
+ T (float, PFX##int32_t, uint64_t, 32) \
+ T (float, PFX##int64_t, uint64_t, 32)
+
+#define TEST_ALL(T) \
+ TEST_CVTF (, T) \
+ TEST_CVTF (u, T)
+
+TEST_ALL (COND_CVT)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 8 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 6 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 8 } } */
+
+/* { dg-final { scan-assembler-times {\tscvtf\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tucvtf\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tscvtf\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tucvtf\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tscvtf\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.d\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tucvtf\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.d\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tscvtf\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tucvtf\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tscvtf\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.d\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tucvtf\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.d\n} 1 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fabs_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fabs_1.c
new file mode 100644
index 0000000..d959aa9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fabs_1.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, MERGE) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##MERGE (TYPE1 *__restrict p, \
+ TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i]) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i)
+
+TEST_ALL (__builtin_fabsf16, _Float16, uint64_t, 32)
+
+TEST_ALL (__builtin_fabsf16, _Float16, uint32_t, 64)
+
+TEST_ALL (__builtin_fabsf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfabs\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfabs\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fadd_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fadd_1.c
new file mode 100644
index 0000000..666cf89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fadd_1.c
@@ -0,0 +1,62 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+#define c_i c[i]
+#define imm_p5 0.5
+
+#define ADD(A, B) A + B
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, NAME, RHS, MERGE) \
+ void \
+ f_##TYPE0##_##TYPE1##_##NAME##_##MERGE (TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c, \
+ TYPE1 *__restrict p) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i], (TYPE0)RHS) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, b[i], a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, b[i], b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, b[i], c_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, one, 1, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, one, 1, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, none, -1, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, none, -1, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, p5, 0.5, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, p5, 0.5, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, np5, -0.5, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, np5, -0.5, b_i)
+
+TEST_ALL (ADD, _Float16, uint64_t, 32)
+
+TEST_ALL (ADD, _Float16, uint32_t, 64)
+
+TEST_ALL (ADD, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 19 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 19 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 19 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 5 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 10 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fcvt_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fcvt_1.c
new file mode 100644
index 0000000..3caae19
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fcvt_1.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define COND_CVT(TYPE0, TYPE1, TYPE2, COUNT) \
+ void \
+ test_##TYPE0##_##TYPE1##_##TYPE2 (TYPE0 *__restrict out, \
+ TYPE1 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE2 *__restrict p) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? (TYPE0)a[i] : b[i]; \
+ }
+
+#define TEST_FCVT(T) \
+ T (_Float16, float, uint64_t, 32) \
+ T (_Float16, float, uint32_t, 64) \
+ T (_Float16, double, uint64_t, 32) \
+ T (float, double, uint64_t, 32) \
+ T (float, _Float16, uint64_t, 32) \
+ T (float, _Float16, uint32_t, 64) \
+ T (double, _Float16, uint64_t,32) \
+ T (double, float, uint64_t, 32)
+
+TEST_FCVT (COND_CVT)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 4 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 4 } } */
+
+/* { dg-final { scan-assembler-times {\tfcvt\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.d\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfcvt\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.d\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfcvt\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfcvt\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.h\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfcvt\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfcvt\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fcvtz_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fcvtz_1.c
new file mode 100644
index 0000000..426d3af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fcvtz_1.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define COND_CVT(TYPE0, TYPE1, TYPE2, COUNT) \
+ void \
+ test_##TYPE0##_##TYPE1##_##TYPE2 (TYPE0 *__restrict out, \
+ TYPE1 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE2 *__restrict p) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? (TYPE0)a[i] : b[i]; \
+ }
+
+#define TEST_FCVTZ(PFX, T) \
+ T (PFX##int16_t, _Float16, uint64_t, 32) \
+ T (PFX##int16_t, _Float16, uint32_t, 64) \
+ T (PFX##int32_t, _Float16, uint64_t, 32) \
+ T (PFX##int32_t, _Float16, uint32_t, 64) \
+ T (PFX##int64_t, _Float16, uint64_t, 32) \
+ T (PFX##int32_t, float, uint64_t, 32) \
+ T (PFX##int64_t, float, uint64_t, 32) \
+ T (PFX##int32_t, double, uint64_t, 32)
+
+#define TEST_ALL(T) \
+ TEST_FCVTZ (, T) \
+ TEST_FCVTZ (u, T)
+
+TEST_ALL (COND_CVT)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 10 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 6 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 8 } } */
+
+/* { dg-final { scan-assembler-times {\tfcvtzs\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfcvtzu\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfcvtzs\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfcvtzu\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfcvtzs\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.h\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfcvtzu\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.h\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfcvtzs\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfcvtzu\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfcvtzs\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfcvtzu\tz[0-9]+\.d, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfcvtzs\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.d\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfcvtzu\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.d\n} 1 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fdiv_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fdiv_1.c
new file mode 100644
index 0000000..ec5653e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fdiv_1.c
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+#define c_i c[i]
+
+#define DIV(A, B) A / B
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS, MERGE) \
+ void \
+ f_##TYPE0##_##TYPE1##_##RHS##_##MERGE (TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c, \
+ TYPE1 *__restrict p) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i], (TYPE0)RHS) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, c_i)
+
+TEST_ALL (DIV, _Float16, uint64_t, 32)
+
+TEST_ALL (DIV, _Float16, uint32_t, 64)
+
+TEST_ALL (DIV, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 7 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfdivr\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfdiv\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfdivr\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfdiv\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fmaxnm_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fmaxnm_1.c
new file mode 100644
index 0000000..d34872f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fmaxnm_1.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -moverride=sve_width=2048 -fno-signed-zeros -ffinite-math-only -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+#define c_i c[i]
+
+#define MAX(A, B) (A > B) ? A : B
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS, MERGE) \
+ void \
+ f_##TYPE0##_##TYPE1##_##RHS##_##MERGE (TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c, \
+ TYPE1 *__restrict p) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i], (TYPE0)RHS) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, c_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1, b_i)
+
+TEST_ALL (MAX, _Float16, uint64_t, 32)
+
+TEST_ALL (MAX, _Float16, uint32_t, 64)
+
+TEST_ALL (MAX, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 13 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 13 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 13 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fminnm_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fminnm_1.c
new file mode 100644
index 0000000..d6c3c38
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fminnm_1.c
@@ -0,0 +1,53 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -moverride=sve_width=2048 -fno-signed-zeros -ffinite-math-only -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+#define c_i c[i]
+
+#define MIN(A, B) (A < B) ? A : B
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS, MERGE) \
+ void \
+ f_##TYPE0##_##TYPE1##_##RHS##_##MERGE (TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c, \
+ TYPE1 *__restrict p) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i], (TYPE0)RHS) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, c_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1, b_i)
+
+TEST_ALL (MIN, _Float16, uint64_t, 32)
+
+TEST_ALL (MIN, _Float16, uint32_t, 64)
+
+TEST_ALL (MIN, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 13 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 13 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 13 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fmul_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fmul_1.c
new file mode 100644
index 0000000..1ae7678
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fmul_1.c
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+#define c_i c[i]
+#define imm_p5 0.5
+
+#define MUL(A, B) A * B
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS, MERGE) \
+ void \
+ f_##TYPE0##_##TYPE1##_##RHS##_##MERGE (TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c, \
+ TYPE1 *__restrict p) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i], (TYPE0)RHS) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, c_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, imm_p5, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, imm_p5, b_i)
+
+TEST_ALL (MUL, _Float16, uint64_t, 32)
+
+TEST_ALL (MUL, _Float16, uint32_t, 64)
+
+TEST_ALL (MUL, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 10 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 10 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 10 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fneg_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fneg_1.c
new file mode 100644
index 0000000..7280f4e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fneg_1.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+
+#define NEG(X) -X
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, MERGE) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##MERGE (TYPE1 *__restrict p, \
+ TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i]) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i)
+
+TEST_ALL (NEG, _Float16, uint64_t, 32)
+
+TEST_ALL (NEG, _Float16, uint32_t, 64)
+
+TEST_ALL (NEG, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfneg\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfneg\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinta_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinta_1.c
new file mode 100644
index 0000000..ed4efb6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinta_1.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, MERGE) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##MERGE (TYPE1 *__restrict p, \
+ TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i]) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i)
+
+TEST_ALL (__builtin_roundf16, _Float16, uint64_t, 32)
+
+TEST_ALL (__builtin_roundf16, _Float16, uint32_t, 64)
+
+TEST_ALL (__builtin_roundf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfrinta\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfrinta\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinta_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinta_2.c
new file mode 100644
index 0000000..f20e2e6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinta_2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -mtune=generic -ftree-vectorize" } */
+
+#include "unpacked_cond_frinta_1.c"
+
+/* Test that we don't drop SELs without -fno-trapping-math. */
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-9]+\.d} 4 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfrinta\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfrinta\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 4 } } */
+
+/* { dg-final { scan-assembler-times {\tsel\t} 6 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinti_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinti_1.c
new file mode 100644
index 0000000..d682d15
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frinti_1.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, MERGE) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##MERGE (TYPE1 *__restrict p, \
+ TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i]) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i)
+
+TEST_ALL (__builtin_nearbyintf16, _Float16, uint64_t, 32)
+
+TEST_ALL (__builtin_nearbyintf16, _Float16, uint32_t, 64)
+
+TEST_ALL (__builtin_nearbyintf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfrinti\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfrinti\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintm_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintm_1.c
new file mode 100644
index 0000000..7d429b3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintm_1.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, MERGE) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##MERGE (TYPE1 *__restrict p, \
+ TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i]) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i)
+
+TEST_ALL (__builtin_floorf16, _Float16, uint64_t, 32)
+
+TEST_ALL (__builtin_floorf16, _Float16, uint32_t, 64)
+
+TEST_ALL (__builtin_floorf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfrintm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintp_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintp_1.c
new file mode 100644
index 0000000..c6d0c8c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintp_1.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, MERGE) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##MERGE (TYPE1 *__restrict p, \
+ TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i]) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i)
+
+TEST_ALL (__builtin_ceilf16, _Float16, uint64_t, 32)
+
+TEST_ALL (__builtin_ceilf16, _Float16, uint32_t, 64)
+
+TEST_ALL (__builtin_ceilf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintp\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfrintp\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintx_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintx_1.c
new file mode 100644
index 0000000..b8afef1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintx_1.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, MERGE) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##MERGE (TYPE1 *__restrict p, \
+ TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i]) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i)
+
+TEST_ALL (__builtin_rintf16, _Float16, uint64_t, 32)
+
+TEST_ALL (__builtin_rintf16, _Float16, uint32_t, 64)
+
+TEST_ALL (__builtin_rintf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfrintx\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintz_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintz_1.c
new file mode 100644
index 0000000..d55279b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_frintz_1.c
@@ -0,0 +1,37 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, MERGE) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##MERGE (TYPE1 *__restrict p, \
+ TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i]) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i)
+
+TEST_ALL (__builtin_truncf16, _Float16, uint64_t, 32)
+
+TEST_ALL (__builtin_truncf16, _Float16, uint32_t, 64)
+
+TEST_ALL (__builtin_truncf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintz\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfrintz\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fsubr_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fsubr_1.c
new file mode 100644
index 0000000..eafd169
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_cond_fsubr_1.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include <stdint.h>
+
+#define a_i a[i]
+#define b_i b[i]
+#define c_i c[i]
+#define imm_p5 0.5
+
+#define SUBR(A, B) B - A
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS, MERGE) \
+ void \
+ f_##TYPE0##_##TYPE1##_##RHS##_##MERGE (TYPE0 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c, \
+ TYPE1 *__restrict p) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ out[i] = p[i] ? FN (a[i], (TYPE0)RHS) : MERGE; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, c_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, imm_p5, a_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, imm_p5, b_i)
+
+TEST_ALL (SUBR, _Float16, uint64_t, 32)
+
+TEST_ALL (SUBR, _Float16, uint32_t, 64)
+
+TEST_ALL (SUBR, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 13 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 13 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 13 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 3 } } */
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tmovprfx\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 6 } } */
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 4 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 4 } } */
+
+/* { dg-final { scan-assembler-not {\tsel\t} } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fabs_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fabs_1.c
new file mode 100644
index 0000000..f09cfe8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fabs_1.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize" } */
+
+#include <stdint.h>
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1 (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i]) > b[i]) \
+ out[i] = 3; \
+ }
+
+TEST_FN (__builtin_fabsf16, _Float16, uint64_t, 32)
+
+TEST_FN (__builtin_fabsf16, _Float16, uint32_t, 64)
+
+TEST_FN (__builtin_fabsf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfabs\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfabs\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_1.c
new file mode 100644
index 0000000..9675f56
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_1.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048" } */
+
+#include <stdint.h>
+
+#define ADD(A, B) A + B
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, NAME, RHS) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##NAME (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i], (TYPE0)RHS) > c[i]) \
+ out[i] = 3; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i, b[i]) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, p5, 0.5) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, np5, -0.5) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, one, 1) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, none, -1)
+
+TEST_ALL (ADD, _Float16, uint64_t, 32)
+
+TEST_ALL (ADD, _Float16, uint32_t, 64)
+
+TEST_ALL (ADD, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 5 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 10 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 11 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 11 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 11 } } */
+
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_2.c
new file mode 100644
index 0000000..7a74efd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fadd_2.c
@@ -0,0 +1,26 @@
+/* { dg-do compile }*/
+/* { dg-options "-O2 -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include "unpacked_fadd_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 12 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 11 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 11 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 11 } } */
+
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.s, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.h, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfadd\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_1.c
new file mode 100644
index 0000000..78d0d9c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_1.c
@@ -0,0 +1,38 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048" } */
+
+#include <stdint.h>
+
+#define b_i b[i]
+#define DIV(A, B) A / B
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##RHS (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i], (TYPE0)RHS) > c[i]) \
+ out[i] = 3; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i)
+
+TEST_ALL (DIV, _Float16, uint64_t, 32)
+
+TEST_ALL (DIV, _Float16, uint32_t, 64)
+
+TEST_ALL (DIV, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 1 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfdivr?\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfdivr?\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_2.c
new file mode 100644
index 0000000..a8f70e1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include "unpacked_fdiv_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfdivr?\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfdivr?\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_3.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_3.c
new file mode 100644
index 0000000..ecd088f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fdiv_3.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-Ofast -moverride=sve_width=2048 -mlow-precision-div" } */
+
+#include "unpacked_fdiv_1.c"
+
+/* { dg-final { scan-assembler-not {\tfrecpe\tz[0-9]+\.h} } } */
+/* { dg-final { scan-assembler-not {\tfrecps\tz[0-9]+\.h} } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tfrecpe\tz[0-9]+\.s} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrecps\tz[0-9]+\.s} 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmaxnm_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmaxnm_1.c
new file mode 100644
index 0000000..5239e4b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmaxnm_1.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-signed-zeros -ffinite-math-only -moverride=sve_width=2048" } */
+
+#include <stdint.h>
+
+#define b_i b[i]
+#define MAX(A, B) (A > B) ? A : B
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##RHS (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (c[i] = FN (a[i], RHS)) \
+ out[i] = 3; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1)
+
+TEST_ALL (MAX, _Float16, uint64_t, 32)
+
+TEST_ALL (MAX, _Float16, uint32_t, 64)
+
+TEST_ALL (MAX, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 6 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 4 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 4 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 4 } } */
+
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmaxnm_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmaxnm_2.c
new file mode 100644
index 0000000..11aa7c0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmaxnm_2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-signed-zeros -ffinite-math-only -fno-trapping-math -moverride=sve_width=2048" } */
+
+#include "unpacked_fmaxnm_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 9 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 4 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 4 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 4 } } */
+
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmaxnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fminnm_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fminnm_1.c
new file mode 100644
index 0000000..02a5f46
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fminnm_1.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-signed-zeros -ffinite-math-only -moverride=sve_width=2048" } */
+
+#include <stdint.h>
+
+#define b_i b[i]
+#define MIN(A, B) (A < B) ? A : B
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##RHS (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (c[i] = FN (a[i], RHS) ) \
+ out[i] = 3; \
+ }
+
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 0) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1)
+
+TEST_ALL (MIN, _Float16, uint64_t, 32)
+
+TEST_ALL (MIN, _Float16, uint32_t, 64)
+
+TEST_ALL (MIN, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 6 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 4 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 4 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 4 } } */
+
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fminnm_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fminnm_2.c
new file mode 100644
index 0000000..81f583b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fminnm_2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-signed-zeros -ffinite-math-only -fno-trapping-math -moverride=sve_width=2048" } */
+
+#include "unpacked_fminnm_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 9 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 4 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 4 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 4 } } */
+
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.0\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.0\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfminnm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_1.c
new file mode 100644
index 0000000..a180a07
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_1.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048" } */
+
+#include <stdint.h>
+
+#define b_i b[i]
+#define immp5 0.5
+#define MUL(A, B) A * B
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##RHS (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i], (TYPE0)RHS) > c[i]) \
+ out[i] = 3; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, immp5)
+
+TEST_ALL (MUL, _Float16, uint64_t, 32)
+
+TEST_ALL (MUL, _Float16, uint32_t, 64)
+
+TEST_ALL (MUL, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 4 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 5 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 5 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 5 } } */
+
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_2.c
new file mode 100644
index 0000000..eb05600
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fmul_2.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include "unpacked_fmul_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 5 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 5 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 5 } } */
+
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.s, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.h, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfmul\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fneg_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fneg_1.c
new file mode 100644
index 0000000..d489ecb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fneg_1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize" } */
+
+#include <stdint.h>
+
+#define NEG(X) -X
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1 (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i]) > b[i]) \
+ out[i] = 3; \
+ }
+
+TEST_FN (NEG, _Float16, uint64_t, 32)
+
+TEST_FN (NEG, _Float16, uint32_t, 64)
+
+TEST_FN (NEG, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfneg\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfneg\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinta_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinta_1.c
new file mode 100644
index 0000000..3cbdef3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinta_1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize" } */
+
+#include <stdint.h>
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1 (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i]) > b[i]) \
+ out[i] = 3; \
+ }
+
+TEST_FN (__builtin_roundf16, _Float16, uint64_t, 32)
+
+TEST_FN (__builtin_roundf16, _Float16, uint32_t, 64)
+
+TEST_FN (__builtin_roundf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 1 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrinta\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrinta\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinta_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinta_2.c
new file mode 100644
index 0000000..4564686
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinta_2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include "unpacked_frinta_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrinta\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrinta\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinti_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinti_1.c
new file mode 100644
index 0000000..7645fed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinti_1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize" } */
+
+#include <stdint.h>
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1 (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i]) > b[i]) \
+ out[i] = 3; \
+ }
+
+TEST_FN (__builtin_nearbyintf16, _Float16, uint64_t, 32)
+
+TEST_FN (__builtin_nearbyintf16, _Float16, uint32_t, 64)
+
+TEST_FN (__builtin_nearbyintf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 1 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrinti\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrinti\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinti_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinti_2.c
new file mode 100644
index 0000000..eadce07
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frinti_2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include "unpacked_frinti_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrinti\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrinti\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintm_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintm_1.c
new file mode 100644
index 0000000..98f85fb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintm_1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize" } */
+
+#include <stdint.h>
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1 (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i]) > b[i]) \
+ out[i] = 3; \
+ }
+
+TEST_FN (__builtin_floorf16, _Float16, uint64_t, 32)
+
+TEST_FN (__builtin_floorf16, _Float16, uint32_t, 64)
+
+TEST_FN (__builtin_floorf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 1 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrintm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintm_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintm_2.c
new file mode 100644
index 0000000..56988be
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintm_2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include "unpacked_frintm_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintm\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrintm\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintp_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintp_1.c
new file mode 100644
index 0000000..f233697
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintp_1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize" } */
+
+#include <stdint.h>
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1 (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i]) > b[i]) \
+ out[i] = 3; \
+ }
+
+TEST_FN (__builtin_ceilf16, _Float16, uint64_t, 32)
+
+TEST_FN (__builtin_ceilf16, _Float16, uint32_t, 64)
+
+TEST_FN (__builtin_ceilf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 1 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintp\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrintp\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintp_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintp_2.c
new file mode 100644
index 0000000..c24c632
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintp_2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include "unpacked_frintp_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintp\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrintp\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintx_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintx_1.c
new file mode 100644
index 0000000..73403a5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintx_1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize" } */
+
+#include <stdint.h>
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1 (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i]) > b[i]) \
+ out[i] = 3; \
+ }
+
+TEST_FN (__builtin_rintf16, _Float16, uint64_t, 32)
+
+TEST_FN (__builtin_rintf16, _Float16, uint32_t, 64)
+
+TEST_FN (__builtin_rintf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 1 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrintx\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintx_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintx_2.c
new file mode 100644
index 0000000..e8b8924
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintx_2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include "unpacked_frintx_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintx\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrintx\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintz_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintz_1.c
new file mode 100644
index 0000000..7377843
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintz_1.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize" } */
+
+#include <stdint.h>
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1 (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i]) > b[i]) \
+ out[i] = 3; \
+ }
+
+TEST_FN (__builtin_truncf16, _Float16, uint64_t, 32)
+
+TEST_FN (__builtin_truncf16, _Float16, uint32_t, 64)
+
+TEST_FN (__builtin_truncf32, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 1 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintz\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrintz\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintz_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintz_2.c
new file mode 100644
index 0000000..1779122
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_frintz_2.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048 -ftree-vectorize -fno-trapping-math" } */
+
+#include "unpacked_frintz_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 3 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 2 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 2 } } */
+
+/* { dg-final { scan-assembler-times {\tfrintz\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfrintz\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_1.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_1.c
new file mode 100644
index 0000000..2cc8ec2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_1.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -moverride=sve_width=2048" } */
+
+#include <stdint.h>
+
+#define b_i b[i]
+#define immp5 0.5
+#define SUBR(A, B) B - A
+
+#define TEST_FN(FN, TYPE0, TYPE1, COUNT, RHS) \
+ void \
+ f_##FN##_##TYPE0##_##TYPE1##_##RHS (TYPE1 *__restrict out, \
+ TYPE0 *__restrict a, \
+ TYPE0 *__restrict b, \
+ TYPE0 *__restrict c) \
+ { \
+ for (unsigned int i = 0; i < COUNT; i++) \
+ if (FN (a[i], (TYPE0)RHS) > c[i]) \
+ out[i] = 3; \
+ }
+
+#define TEST_ALL(FN, TYPE0, TYPE1, COUNT) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, b_i) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, immp5) \
+ TEST_FN (FN, TYPE0, TYPE1, COUNT, 1)
+
+TEST_ALL (SUBR, _Float16, uint64_t, 32)
+
+TEST_ALL (SUBR, _Float16, uint32_t, 64)
+
+TEST_ALL (SUBR, float, uint64_t, 32)
+
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.s} 3 } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.d} 6 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 7 } } */
+
+/* { dg-final { scan-assembler-times {\tfsubr?\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfsubr?\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_2.c b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_2.c
new file mode 100644
index 0000000..de9325c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/unpacked_fsubr_2.c
@@ -0,0 +1,20 @@
+/* { dg-do compile }*/
+/* { dg-options "-O2 -moverride=sve_width=2048 -fno-trapping-math" } */
+
+#include "unpacked_fsubr_1.c"
+
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.s} } } */
+/* { dg-final { scan-assembler-not {\tptrue\tp[0-7]\.d} } } */
+/* { dg-final { scan-assembler-times {\tptrue\tp[0-7]\.b} 6 } } */
+
+/* { dg-final { scan-assembler-times {\tld1w\tz[0-9]+\.d} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.s} 7 } } */
+/* { dg-final { scan-assembler-times {\tld1h\tz[0-9]+\.d} 7 } } */
+
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.s, z[0-9]+\.s, z[0-9]+\.s\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #0.5\n} 1 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.s, p[0-7]/m, z[0-9]+\.s, #1.0\n} 1 } } */
+
+/* { dg-final { scan-assembler-times {\tfsub\tz[0-9]+\.h, z[0-9]+\.h, z[0-9]+\.h\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #0.5\n} 2 } } */
+/* { dg-final { scan-assembler-times {\tfsubr\tz[0-9]+\.h, p[0-7]/m, z[0-9]+\.h, #1.0\n} 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/vec-set-zero.c b/gcc/testsuite/gcc.target/aarch64/vec-set-zero.c
index b34b902c..ba4696e 100644
--- a/gcc/testsuite/gcc.target/aarch64/vec-set-zero.c
+++ b/gcc/testsuite/gcc.target/aarch64/vec-set-zero.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2" } */
+/* { dg-options "-Os" } */
#include "arm_neon.h"
diff --git a/gcc/testsuite/gcc.target/i386/asm-hard-reg-1.c b/gcc/testsuite/gcc.target/i386/asm-hard-reg-1.c
new file mode 100644
index 0000000..8080f56
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/asm-hard-reg-1.c
@@ -0,0 +1,80 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+void
+test (void)
+{
+ int x, y;
+
+ __asm__ __volatile__ ("" : "=a" (x), "={rbx}" (y));
+ __asm__ __volatile__ ("" : "=a" (x), "={rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "=a" (x) : "{rax}" (y));
+ __asm__ __volatile__ ("" : "=&a" (x) : "{rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "a" (x), "{rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "={rbx}" (x), "=a" (y));
+ __asm__ __volatile__ ("" : "={rax}" (x), "=a" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "={rax}" (x) : "a" (y));
+ __asm__ __volatile__ ("" : "=&{rax}" (x) : "a" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "{rax}" (x), "a" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "=b" (x), "={rax}" (y));
+ __asm__ __volatile__ ("" : "=b" (x), "={rbx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "=b" (x) : "{rbx}" (y));
+ __asm__ __volatile__ ("" : "=&b" (x) : "{rbx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "b" (x), "{rbx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "={rax}" (x), "=b" (y));
+ __asm__ __volatile__ ("" : "={rbx}" (x), "=b" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "={rbx}" (x) : "b" (y));
+ __asm__ __volatile__ ("" : "=&{rbx}" (x) : "b" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "{rbx}" (x), "b" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "=c" (x), "={rax}" (y));
+ __asm__ __volatile__ ("" : "=c" (x), "={rcx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "=c" (x) : "{rcx}" (y));
+ __asm__ __volatile__ ("" : "=&c" (x) : "{rcx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "c" (x), "{rcx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "={rax}" (x), "=c" (y));
+ __asm__ __volatile__ ("" : "={rcx}" (x), "=c" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "={rcx}" (x) : "c" (y));
+ __asm__ __volatile__ ("" : "=&{rcx}" (x) : "c" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "{rcx}" (x), "c" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "=d" (x), "={rax}" (y));
+ __asm__ __volatile__ ("" : "=d" (x), "={rdx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "=d" (x) : "{rdx}" (y));
+ __asm__ __volatile__ ("" : "=&d" (x) : "{rdx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "d" (x), "{rdx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "={rax}" (x), "=d" (y));
+ __asm__ __volatile__ ("" : "={rdx}" (x), "=d" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "={rdx}" (x) : "d" (y));
+ __asm__ __volatile__ ("" : "=&{rdx}" (x) : "d" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "{rdx}" (x), "d" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "=S" (x), "={rax}" (y));
+ __asm__ __volatile__ ("" : "=S" (x), "={rsi}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "=S" (x) : "{rsi}" (y));
+ __asm__ __volatile__ ("" : "=&S" (x) : "{rsi}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "S" (x), "{rsi}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "={rax}" (x), "=S" (y));
+ __asm__ __volatile__ ("" : "={rsi}" (x), "=S" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "={rsi}" (x) : "S" (y));
+ __asm__ __volatile__ ("" : "=&{rsi}" (x) : "S" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "{rsi}" (x), "S" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "=D" (x), "={rax}" (y));
+ __asm__ __volatile__ ("" : "=D" (x), "={rdi}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "=D" (x) : "{rdi}" (y));
+ __asm__ __volatile__ ("" : "=&D" (x) : "{rdi}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "D" (x), "{rdi}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "={rax}" (x), "=D" (y));
+ __asm__ __volatile__ ("" : "={rdi}" (x), "=D" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "={rdi}" (x) : "D" (y));
+ __asm__ __volatile__ ("" : "=&{rdi}" (x) : "D" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "{rdi}" (x), "D" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+}
diff --git a/gcc/testsuite/gcc.target/i386/asm-hard-reg-2.c b/gcc/testsuite/gcc.target/i386/asm-hard-reg-2.c
new file mode 100644
index 0000000..b35cf53
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/asm-hard-reg-2.c
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+void
+test (void)
+{
+ int x, y, yy;
+#ifdef __x86_64__
+ int z __attribute__ ((mode (TI)));
+#else
+ long z;
+#endif
+
+ __asm__ __volatile__ ("" : "=A" (z), "={rbx}" (y));
+ __asm__ __volatile__ ("" : "=A" (z), "={rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "=A" (z), "={rdx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "=A" (z) : "{rax}" (y));
+ __asm__ __volatile__ ("" : "=A" (z) : "{rdx}" (y));
+ __asm__ __volatile__ ("" : "=&A" (z) : "{rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "=&A" (z) : "{rdx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "A" (z), "{rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "A" (z), "{rdx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ __asm__ __volatile__ ("" : "={rbx}" (y), "=A" (z));
+ __asm__ __volatile__ ("" : "={rax}" (y), "=A" (z)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "={rdx}" (y), "=A" (z)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "={rax}" (y) : "A" (z));
+ __asm__ __volatile__ ("" : "={rdx}" (y) : "A" (z));
+ __asm__ __volatile__ ("" : "=&{rax}" (y) : "A" (z)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "=&{rdx}" (y) : "A" (z)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "{rax}" (y), "A" (z)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" :: "{rdx}" (y), "A" (z)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+
+ /* Note, we do not error for */
+ __asm__ __volatile__ ("" : "=A" (x), "={rax}" (y));
+ __asm__ __volatile__ ("" : "=A" (x), "={rdx}" (y));
+ /* This is due to how constraint A is implemented. RA has the freedom to
+ choose between rax or rdx for operand 0 since x fits into a single
+ register and does not require a register pair. Of course, we error out if
+ rax and rdx are taken by other operands as in the following: */
+ __asm__ __volatile__ ("" : "=A" (x), "={rax}" (y), "={rdx}" (yy)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ __asm__ __volatile__ ("" : "=A" (x), "={rdx}" (y), "={rax}" (yy)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/vsx-builtin-7.c b/gcc/testsuite/gcc.target/powerpc/vsx-builtin-7.c
index 5095d50..312043b 100644
--- a/gcc/testsuite/gcc.target/powerpc/vsx-builtin-7.c
+++ b/gcc/testsuite/gcc.target/powerpc/vsx-builtin-7.c
@@ -1,8 +1,16 @@
/* { dg-do compile { target { powerpc*-*-* } } } */
/* { dg-skip-if "" { powerpc*-*-darwin* } } */
-/* { dg-options "-O2 -mdejagnu-cpu=power7 -fno-inline-functions" } */
+/* { dg-options "-O2 -mdejagnu-cpu=power7 -fno-inline-functions -fno-ipa-icf" } */
/* { dg-require-effective-target powerpc_vsx } */
+/* PR testsuite/119382
+ Note: Added -fno-ipa-icf to disable Interprocedural Identical Code
+ Folding (ICF). Without this, insert_di_0_v2 is merged with insert_di_0
+ due to improved alias analysis introduced in commit r15-7961-gdc47161c1f32c3.
+ This results in the compiler replacing insert_di_0_v2 with a tail call to
+ insert_di_0, altering expected test behavior. Disabling ICF ensures correct
+ execution of the test. */
+
/* Test simple extract/insert/slat operations. Make sure all types are
supported with various options. */
diff --git a/gcc/testsuite/gcc.target/pru/pragma-ctable_entry-2.c b/gcc/testsuite/gcc.target/pru/pragma-ctable_entry-2.c
new file mode 100644
index 0000000..a1c707d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/pru/pragma-ctable_entry-2.c
@@ -0,0 +1,22 @@
+/* Test for base addresses with bit 31 set (PR121124). */
+
+/* { dg-do compile } */
+/* { dg-options "-O1" } */
+
+/* -O1 in the options is significant. Without it LBCO/SBCO operations may
+ not be optimized to the respective instructions. */
+
+
+#pragma ctable_entry 12 0x80beef00
+
+unsigned int
+test_ctable (unsigned int val1, unsigned int val2)
+{
+ ((volatile unsigned short int *)0x80beef00)[0] = val2;
+ ((volatile unsigned int *)0x80beef00)[val1] = val2;
+ return ((volatile unsigned int *)0x80beef00)[5];
+}
+
+/* { dg-final { scan-assembler "sbco\\tr15.b\[012\]?, 12, 0, 2" } } */
+/* { dg-final { scan-assembler "sbco\\tr15.b0, 12, r14, 4" } } */
+/* { dg-final { scan-assembler "lbco\\tr14.b0, 12, 20, 4" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c b/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c
index 81ebf5f..15cc3ee 100644
--- a/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c
+++ b/gcc/testsuite/gcc.target/riscv/interrupt-conflict-mode.c
@@ -1,7 +1,7 @@
/* Verify proper errors are generated for conflicted interrupt type. */
/* { dg-do compile } */
/* { dg-options "" } */
-void __attribute__ ((interrupt ("user")))
+void __attribute__ ((interrupt ("supervisor")))
foo(void);
void __attribute__ ((interrupt ("machine")))
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-rnmi.c b/gcc/testsuite/gcc.target/riscv/interrupt-rnmi.c
new file mode 100644
index 0000000..f340108
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/interrupt-rnmi.c
@@ -0,0 +1,11 @@
+/* Verify the return instruction is mnret. */
+/* { dg-do compile } */
+/* { dg-options "-march=rv32gc_smrnmi" { target { rv32 } } } */
+/* { dg-options "-march=rv64gc_smrnmi" { target { rv64 } } } */
+
+void __attribute__ ((interrupt ("rnmi")))
+foo (void)
+{
+}
+
+/* { dg-final { scan-assembler {\mmnret} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/interrupt-umode.c b/gcc/testsuite/gcc.target/riscv/interrupt-umode.c
deleted file mode 100644
index 042abf0..0000000
--- a/gcc/testsuite/gcc.target/riscv/interrupt-umode.c
+++ /dev/null
@@ -1,8 +0,0 @@
-/* Verify the return instruction is mret. */
-/* { dg-do compile } */
-/* { dg-options "" } */
-void __attribute__ ((interrupt ("user")))
-foo (void)
-{
-}
-/* { dg-final { scan-assembler {\muret} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i32.c
index 138124c..31d3b43 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i32.c
@@ -6,7 +6,7 @@
#define NT int16_t
#define WT int32_t
-DEF_AVG_1(NT, WT, avg_ceil)
+DEF_AVG_1_WRAP(NT, WT, avg_ceil)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*0} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i64.c
index 30438c9..7f30b9e 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i16-from-i64.c
@@ -6,7 +6,7 @@
#define NT int16_t
#define WT int64_t
-DEF_AVG_1(NT, WT, avg_ceil)
+DEF_AVG_1_WRAP(NT, WT, avg_ceil)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*0} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i32-from-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i32-from-i64.c
index 2e9cfa5..2e06d0a 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i32-from-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i32-from-i64.c
@@ -6,7 +6,7 @@
#define NT int32_t
#define WT int64_t
-DEF_AVG_1(NT, WT, avg_ceil)
+DEF_AVG_1_WRAP(NT, WT, avg_ceil)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*0} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i64-from-i128.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i64-from-i128.c
new file mode 100644
index 0000000..ca23066
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i64-from-i128.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d" } */
+
+#include "avg.h"
+
+#define NT int64_t
+#define WT int128_t
+
+DEF_AVG_1_WRAP(NT, WT, avg_ceil)
+
+/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*0} 1 } } */
+/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i16.c
index 2ebf294..dda84a6 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i16.c
@@ -6,7 +6,7 @@
#define NT int8_t
#define WT int16_t
-DEF_AVG_1(NT, WT, avg_ceil)
+DEF_AVG_1_WRAP(NT, WT, avg_ceil)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*0} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i32.c
index 64fec913..dfd2bb3 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i32.c
@@ -6,7 +6,7 @@
#define NT int8_t
#define WT int32_t
-DEF_AVG_1(NT, WT, avg_ceil)
+DEF_AVG_1_WRAP(NT, WT, avg_ceil)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*0} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i64.c
index a72642c..d1060cc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-1-i8-from-i64.c
@@ -6,7 +6,7 @@
#define NT int8_t
#define WT int64_t
-DEF_AVG_1(NT, WT, avg_ceil)
+DEF_AVG_1_WRAP(NT, WT, avg_ceil)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*0} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-run-1-i64-from-i128.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-run-1-i64-from-i128.c
new file mode 100644
index 0000000..ee5330c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_ceil-run-1-i64-from-i128.c
@@ -0,0 +1,16 @@
+/* { dg-do run { target { riscv_v && rv64 } } } */
+/* { dg-additional-options "-std=c99 -O3 -Wno-pedantic" } */
+
+#include "avg.h"
+#include "avg_data.h"
+
+#define WT int128_t
+#define NT int64_t
+#define NAME avg_ceil
+
+DEF_AVG_1_WRAP(NT, WT, NAME)
+
+#define TEST_DATA TEST_AVG_DATA_WRAP(NT, NAME)
+#define TEST_RUN(NT, WT, NAME, a, b, out, n) RUN_AVG_1_WRAP(NT, WT, NAME, a, b, out, n)
+
+#include "avg_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_data.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_data.h
index a4a4536..49103f3 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_data.h
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_data.h
@@ -345,8 +345,8 @@ int64_t TEST_AVG_DATA(int64_t, avg_ceil)[][3][N] =
},
{
9223372036854775806ull, 9223372036854775806ull, 9223372036854775806ull, 9223372036854775806ull,
- 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
-2ull, -2ull, -2ull, -2ull,
+ 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
-9223372036854775807ull, -9223372036854775807ull, -9223372036854775807ull, -9223372036854775807ull,
},
{
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i32.c
index 16ba967..fc7943c 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i32.c
@@ -6,7 +6,7 @@
#define NT int16_t
#define WT int32_t
-DEF_AVG_0(NT, WT, avg_floor)
+DEF_AVG_0_WRAP(NT, WT, avg_floor)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*2} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i64.c
index b229b4b..e02e5df 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i16-from-i64.c
@@ -6,7 +6,7 @@
#define NT int16_t
#define WT int64_t
-DEF_AVG_0(NT, WT, avg_floor)
+DEF_AVG_0_WRAP(NT, WT, avg_floor)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*2} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i32-from-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i32-from-i64.c
index 5f946bb..e36e424 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i32-from-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i32-from-i64.c
@@ -6,7 +6,7 @@
#define NT int32_t
#define WT int64_t
-DEF_AVG_0(NT, WT, avg_floor)
+DEF_AVG_0_WRAP(NT, WT, avg_floor)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*2} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i64-from-i128.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i64-from-i128.c
index c94dfc2..3e2d97d 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i64-from-i128.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i64-from-i128.c
@@ -6,7 +6,7 @@
#define NT int64_t
#define WT int128_t
-DEF_AVG_0(NT, WT, avg_floor)
+DEF_AVG_0_WRAP(NT, WT, avg_floor)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*2} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i16.c
index 5d9297a..cdbb299 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i16.c
@@ -6,7 +6,7 @@
#define NT int8_t
#define WT int16_t
-DEF_AVG_0(NT, WT, avg_floor)
+DEF_AVG_0_WRAP(NT, WT, avg_floor)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*2} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i32.c
index 5c5d4ea..53508b0 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i32.c
@@ -6,7 +6,7 @@
#define NT int8_t
#define WT int32_t
-DEF_AVG_0(NT, WT, avg_floor)
+DEF_AVG_0_WRAP(NT, WT, avg_floor)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*2} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i64.c
index f297953..9a6d1a2 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/avg_floor-1-i8-from-i64.c
@@ -6,7 +6,7 @@
#define NT int8_t
#define WT int64_t
-DEF_AVG_0(NT, WT, avg_floor)
+DEF_AVG_0_WRAP(NT, WT, avg_floor)
/* { dg-final { scan-assembler-times {csrwi\s*vxrm,\s*2} 1 } } */
/* { dg-final { scan-assembler-times {vaadd.vv} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/repeat-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/repeat-6.c
index 4dc5703..0fa1ea0 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/repeat-6.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/repeat-6.c
@@ -72,7 +72,7 @@ f_vnx128qi (int8_t *out)
*(vnx128qi *) out = v;
}
-/* { dg-final { scan-assembler-times {vmv.v.x\tv[0-9]+,\s*[a-x0-9]+} 6 } } */
+/* { dg-final { scan-assembler-times {vmv.v.x\tv[0-9]+,\s*[a-x0-9]+} 7 } } */
/* { dg-final { scan-assembler-times {slli\t[a-x0-9]+,\s*[a-x0-9]+,\s*8} 6 } } */
/* { dg-final { scan-assembler-times {or\t[a-x0-9]+,\s*[a-x0-9]+,\s*[a-x0-9]+} 6 } } */
/* { dg-final { scan-assembler-times {vslide1down\.vx\tv[0-9]+,\s*v[0-9]+,\s*[a-x0-9]+} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c
index b17fd8e..811f26c 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c
@@ -13,6 +13,8 @@ DEF_VF_MULOP_ACC_CASE_0 (_Float16, +, -, nacc)
DEF_VF_MULOP_ACC_CASE_0 (_Float16, -, -, nsac)
DEF_VF_MULOP_WIDEN_CASE_0 (_Float16, float, +, +, acc)
DEF_VF_MULOP_WIDEN_CASE_0 (_Float16, float, -, +, sac)
+DEF_VF_MULOP_WIDEN_CASE_0 (_Float16, float, +, -, nacc)
+DEF_VF_MULOP_WIDEN_CASE_0 (_Float16, float, -, -, nsac)
/* { dg-final { scan-assembler-times {vfmadd.vf} 1 } } */
/* { dg-final { scan-assembler-times {vfmsub.vf} 1 } } */
@@ -24,3 +26,5 @@ DEF_VF_MULOP_WIDEN_CASE_0 (_Float16, float, -, +, sac)
/* { dg-final { scan-assembler-times {vfnmsac.vf} 1 } } */
/* { dg-final { scan-assembler-times {vfwmacc.vf} 1 } } */
/* { dg-final { scan-assembler-times {vfwmsac.vf} 1 } } */
+/* { dg-final { scan-assembler-times {vfwnmacc.vf} 1 } } */
+/* { dg-final { scan-assembler-times {vfwnmsac.vf} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c
index efd887d..ca82ead 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c
@@ -13,6 +13,8 @@ DEF_VF_MULOP_ACC_CASE_0 (float, +, -, nacc)
DEF_VF_MULOP_ACC_CASE_0 (float, -, -, nsac)
DEF_VF_MULOP_WIDEN_CASE_0 (float, double, +, +, acc)
DEF_VF_MULOP_WIDEN_CASE_0 (float, double, -, +, sac)
+DEF_VF_MULOP_WIDEN_CASE_0 (float, double, +, -, nacc)
+DEF_VF_MULOP_WIDEN_CASE_0 (float, double, -, -, nsac)
/* { dg-final { scan-assembler-times {vfmadd.vf} 1 } } */
/* { dg-final { scan-assembler-times {vfmsub.vf} 1 } } */
@@ -24,3 +26,5 @@ DEF_VF_MULOP_WIDEN_CASE_0 (float, double, -, +, sac)
/* { dg-final { scan-assembler-times {vfnmsac.vf} 1 } } */
/* { dg-final { scan-assembler-times {vfwmacc.vf} 1 } } */
/* { dg-final { scan-assembler-times {vfwmsac.vf} 1 } } */
+/* { dg-final { scan-assembler-times {vfwnmacc.vf} 1 } } */
+/* { dg-final { scan-assembler-times {vfwnmsac.vf} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c
index 84987a9..3a39303 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c
@@ -13,5 +13,7 @@
/* { dg-final { scan-assembler-not {vfnmsac.vf} } } */
/* { dg-final { scan-assembler-not {vfwmacc.vf} } } */
/* { dg-final { scan-assembler-not {vfwmsac.vf} } } */
-/* { dg-final { scan-assembler-times {fcvt.s.h} 2 } } */
-/* { dg-final { scan-assembler-times {vfmv.v.f} 10 } } */
+/* { dg-final { scan-assembler-not {vfwnmacc.vf} } } */
+/* { dg-final { scan-assembler-not {vfwnmsac.vf} } } */
+/* { dg-final { scan-assembler-times {fcvt.s.h} 4 } } */
+/* { dg-final { scan-assembler-times {vfmv.v.f} 12 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c
index dbd3d02..b4618bae 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c
@@ -13,5 +13,7 @@
/* { dg-final { scan-assembler-not {vfnmsac.vf} } } */
/* { dg-final { scan-assembler-not {vfwmacc.vf} } } */
/* { dg-final { scan-assembler-not {vfwmsac.vf} } } */
-/* { dg-final { scan-assembler-times {fcvt.d.s} 2 } } */
-/* { dg-final { scan-assembler-times {vfmv.v.f} 10 } } */
+/* { dg-final { scan-assembler-not {vfwnmacc.vf} } } */
+/* { dg-final { scan-assembler-not {vfwnmsac.vf} } } */
+/* { dg-final { scan-assembler-times {fcvt.d.s} 4 } } */
+/* { dg-final { scan-assembler-times {vfmv.v.f} 12 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c
index 5f0d758..58afaa4 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c
@@ -13,6 +13,8 @@ DEF_VF_MULOP_ACC_CASE_1 (_Float16, +, -, nacc, VF_MULOP_ACC_BODY_X128)
DEF_VF_MULOP_ACC_CASE_1 (_Float16, -, -, nsac, VF_MULOP_ACC_BODY_X128)
DEF_VF_MULOP_WIDEN_CASE_1 (_Float16, float, +, +, acc)
DEF_VF_MULOP_WIDEN_CASE_1 (_Float16, float, -, +, sac)
+DEF_VF_MULOP_WIDEN_CASE_1 (_Float16, float, +, -, nacc)
+DEF_VF_MULOP_WIDEN_CASE_1 (_Float16, float, -, -, nsac)
/* { dg-final { scan-assembler {vfmadd.vf} } } */
/* { dg-final { scan-assembler {vfmsub.vf} } } */
@@ -24,3 +26,5 @@ DEF_VF_MULOP_WIDEN_CASE_1 (_Float16, float, -, +, sac)
/* { dg-final { scan-assembler {vfnmsac.vf} } } */
/* { dg-final { scan-assembler {vfwmacc.vf} } } */
/* { dg-final { scan-assembler {vfwmsac.vf} } } */
+/* { dg-final { scan-assembler {vfwnmacc.vf} } } */
+/* { dg-final { scan-assembler {vfwnmsac.vf} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c
index 951b0ef..0e95774 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c
@@ -13,6 +13,8 @@ DEF_VF_MULOP_ACC_CASE_1 (float, +, -, nacc, VF_MULOP_ACC_BODY_X128)
DEF_VF_MULOP_ACC_CASE_1 (float, -, -, nsac, VF_MULOP_ACC_BODY_X128)
DEF_VF_MULOP_WIDEN_CASE_1 (float, double, +, +, acc)
DEF_VF_MULOP_WIDEN_CASE_1 (float, double, -, +, sac)
+DEF_VF_MULOP_WIDEN_CASE_1 (float, double, +, -, nacc)
+DEF_VF_MULOP_WIDEN_CASE_1 (float, double, -, -, nsac)
/* { dg-final { scan-assembler {vfmadd.vf} } } */
/* { dg-final { scan-assembler {vfmsub.vf} } } */
@@ -24,3 +26,5 @@ DEF_VF_MULOP_WIDEN_CASE_1 (float, double, -, +, sac)
/* { dg-final { scan-assembler {vfnmsac.vf} } } */
/* { dg-final { scan-assembler {vfwmacc.vf} } } */
/* { dg-final { scan-assembler {vfwmsac.vf} } } */
+/* { dg-final { scan-assembler {vfwnmacc.vf} } } */
+/* { dg-final { scan-assembler {vfwnmsac.vf} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c
index a4edd92..559df6c 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c
@@ -13,4 +13,6 @@
/* { dg-final { scan-assembler-not {vfnmsac.vf} } } */
/* { dg-final { scan-assembler-not {vfwmacc.vf} } } */
/* { dg-final { scan-assembler-not {vfwmsac.vf} } } */
+/* { dg-final { scan-assembler-not {vfwnmacc.vf} } } */
+/* { dg-final { scan-assembler-not {vfwnmsac.vf} } } */
/* { dg-final { scan-assembler {fcvt.s.h} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c
index 4eb28e5..03f9c5a 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c
@@ -13,4 +13,6 @@
/* { dg-final { scan-assembler-not {vfnmsac.vf} } } */
/* { dg-final { scan-assembler-not {vfwmacc.vf} } } */
/* { dg-final { scan-assembler-not {vfwmsac.vf} } } */
+/* { dg-final { scan-assembler-not {vfwnmacc.vf} } } */
+/* { dg-final { scan-assembler-not {vfwnmsac.vf} } } */
/* { dg-final { scan-assembler {fcvt.d.s} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmacc-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmacc-run-1-f16.c
index 982dd97..fd8aa30 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmacc-run-1-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmacc-run-1-f16.c
@@ -1,5 +1,9 @@
/* { dg-do run { target { riscv_v } } } */
-/* { dg-additional-options "-march=rv64gcv_zvfh --param=fpr2vr-cost=0" } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
#include "vf_mulop.h"
#include "vf_mulop_data.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c
index 400bbcd..8fd8552 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c
@@ -1,5 +1,9 @@
/* { dg-do run { target { riscv_v } } } */
-/* { dg-additional-options "-march=rv64gcv_zvfh --param=fpr2vr-cost=0" } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
#include "vf_mulop.h"
#include "vf_mulop_data.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsac-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsac-run-1-f16.c
index 21c1860..e91fd15 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsac-run-1-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsac-run-1-f16.c
@@ -1,5 +1,9 @@
/* { dg-do run { target { riscv_v } } } */
-/* { dg-additional-options "-march=rv64gcv_zvfh --param=fpr2vr-cost=0" } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
#include "vf_mulop.h"
#include "vf_mulop_data.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c
index 163b5bd..ca7e0db 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c
@@ -1,5 +1,9 @@
/* { dg-do run { target { riscv_v } } } */
-/* { dg-additional-options "-march=rv64gcv_zvfh --param=fpr2vr-cost=0" } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
#include "vf_mulop.h"
#include "vf_mulop_data.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmacc-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmacc-run-1-f16.c
index 71f350f..b38e800 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmacc-run-1-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmacc-run-1-f16.c
@@ -1,5 +1,9 @@
/* { dg-do run { target { riscv_v } } } */
-/* { dg-additional-options "-march=rv64gcv_zvfh --param=fpr2vr-cost=0" } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
#include "vf_mulop.h"
#include "vf_mulop_data.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmadd-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmadd-run-1-f16.c
index e252e0d..fef5d77 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmadd-run-1-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmadd-run-1-f16.c
@@ -1,5 +1,9 @@
/* { dg-do run { target { riscv_v } } } */
-/* { dg-additional-options "-march=rv64gcv_zvfh --param=fpr2vr-cost=0" } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
#include "vf_mulop.h"
#include "vf_mulop_data.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsac-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsac-run-1-f16.c
index 439fd3e..7951d40 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsac-run-1-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsac-run-1-f16.c
@@ -1,5 +1,9 @@
/* { dg-do run { target { riscv_v } } } */
-/* { dg-additional-options "-march=rv64gcv_zvfh --param=fpr2vr-cost=0" } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
#include "vf_mulop.h"
#include "vf_mulop_data.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsub-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsub-run-1-f16.c
index b9d66ba..d0def86 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsub-run-1-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfnmsub-run-1-f16.c
@@ -1,5 +1,9 @@
/* { dg-do run { target { riscv_v } } } */
-/* { dg-additional-options "-march=rv64gcv_zvfh --param=fpr2vr-cost=0" } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
#include "vf_mulop.h"
#include "vf_mulop_data.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmacc-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmacc-run-1-f16.c
index d78cf73..d4c527a 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmacc-run-1-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmacc-run-1-f16.c
@@ -1,5 +1,9 @@
/* { dg-do run { target { riscv_v } } } */
-/* { dg-additional-options "-march=rv64gcv_zvfh --param=fpr2vr-cost=0" } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
#include "vf_mulop.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmsac-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmsac-run-1-f16.c
index 6422bba..abce2f2 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmsac-run-1-f16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwmsac-run-1-f16.c
@@ -1,5 +1,9 @@
/* { dg-do run { target { riscv_v } } } */
-/* { dg-additional-options "-march=rv64gcv_zvfh --param=fpr2vr-cost=0" } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
#include "vf_mulop.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmacc-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmacc-run-1-f16.c
new file mode 100644
index 0000000..ddf49d5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmacc-run-1-f16.c
@@ -0,0 +1,21 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+#define T1 _Float16
+#define T2 float
+#define NAME nacc
+#define OP +
+#define NEG -
+
+DEF_VF_MULOP_WIDEN_CASE_0_WRAP (T1, T2, OP, NEG, NAME)
+
+#define TEST_RUN(T1, T2, NAME, out, in, f, n) RUN_VF_MULOP_WIDEN_CASE_0_WRAP(T1, T2, NAME, out, in, f, n)
+#define LIMIT -32768
+
+#include "vf_mulop_widen_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmacc-run-1-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmacc-run-1-f32.c
new file mode 100644
index 0000000..851c335
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmacc-run-1-f32.c
@@ -0,0 +1,17 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+#define T1 float
+#define T2 double
+#define NAME nacc
+#define OP +
+#define NEG -
+
+DEF_VF_MULOP_WIDEN_CASE_0_WRAP (T1, T2, OP, NEG, NAME)
+
+#define TEST_RUN(T1, T2, NAME, out, in, f, n) RUN_VF_MULOP_WIDEN_CASE_0_WRAP(T1, T2, NAME, out, in, f, n)
+#define LIMIT -2147483648
+
+#include "vf_mulop_widen_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmsac-run-1-f16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmsac-run-1-f16.c
new file mode 100644
index 0000000..a874991
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmsac-run-1-f16.c
@@ -0,0 +1,21 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-require-effective-target riscv_v_ok } */
+/* { dg-require-effective-target riscv_zvfh } */
+/* { dg-add-options "riscv_v" } */
+/* { dg-add-options "riscv_zvfh" } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+#define T1 _Float16
+#define T2 float
+#define NAME nsac
+#define OP -
+#define NEG -
+
+DEF_VF_MULOP_WIDEN_CASE_0_WRAP (T1, T2, OP, NEG, NAME)
+
+#define TEST_RUN(T1, T2, NAME, out, in, f, n) RUN_VF_MULOP_WIDEN_CASE_0_WRAP(T1, T2, NAME, out, in, f, n)
+#define LIMIT -32768
+
+#include "vf_mulop_widen_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmsac-run-1-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmsac-run-1-f32.c
new file mode 100644
index 0000000..9eacace
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfwnmsac-run-1-f32.c
@@ -0,0 +1,17 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+#define T1 float
+#define T2 double
+#define NAME nsac
+#define OP -
+#define NEG -
+
+DEF_VF_MULOP_WIDEN_CASE_0_WRAP (T1, T2, OP, NEG, NAME)
+
+#define TEST_RUN(T1, T2, NAME, out, in, f, n) RUN_VF_MULOP_WIDEN_CASE_0_WRAP(T1, T2, NAME, out, in, f, n)
+#define LIMIT -2147483648
+
+#include "vf_mulop_widen_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c
index 83515ee..f84d7f5 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-times {vmin.vx} 2 } } */
/* { dg-final { scan-assembler-times {vsadd.vx} 1 } } */
/* { dg-final { scan-assembler-times {vssub.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vaadd.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c
index 1488fe1..70b6743 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-times {vmin.vx} 2 } } */
/* { dg-final { scan-assembler-times {vsadd.vx} 1 } } */
/* { dg-final { scan-assembler-times {vssub.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vaadd.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c
index 342ea18..986fa4c 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-times {vmin.vx} 2 } } */
/* { dg-final { scan-assembler-times {vsadd.vx} 1 } } */
/* { dg-final { scan-assembler-times {vssub.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vaadd.vx} 1 { target { no-opts "-O3 -mrvv-vector-bits=zvl -mrvv-max-lmul=m2" "-O3 -mrvv-vector-bits=zvl -mrvv-max-lmul=m4" } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c
index 583f917..c479295 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-times {vmin.vx} 2 } } */
/* { dg-final { scan-assembler-times {vsadd.vx} 1 } } */
/* { dg-final { scan-assembler-times {vssub.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vaadd.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c
index b064748..cb62e0f 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u16.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-times {vminu.vx} 2 } } */
/* { dg-final { scan-assembler-times {vsaddu.vx} 1 } } */
/* { dg-final { scan-assembler-times {vssubu.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vaaddu.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c
index e334bb3..e2a5dbb 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u32.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-times {vminu.vx} 2 } } */
/* { dg-final { scan-assembler-times {vsaddu.vx} 1 } } */
/* { dg-final { scan-assembler-times {vssubu.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vaaddu.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u64.c
index 3e8ca05..e7b1ef0 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u64.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-times {vminu.vx} 2 } } */
/* { dg-final { scan-assembler-times {vsaddu.vx} 1 } } */
/* { dg-final { scan-assembler-times {vssubu.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vaaddu.vx} 1 { target { no-opts "-O3 -mrvv-vector-bits=zvl -mrvv-max-lmul=m2" "-O3 -mrvv-vector-bits=zvl -mrvv-max-lmul=m4" } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u8.c
index 1f995cd..559887e 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-u8.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-times {vminu.vx} 2 } } */
/* { dg-final { scan-assembler-times {vsaddu.vx} 1 } } */
/* { dg-final { scan-assembler-times {vssubu.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vaaddu.vx} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c
index 78d3e0b..05801a9 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-not {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler-not {vaadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c
index e7bcfe5..f05f091 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-not {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler-not {vaadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c
index f9f1e39..adf9ccb 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-not {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler-not {vaadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c
index 80d6aaa..8b3f5bc 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-not {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler-not {vaadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u16.c
index f7fae37..365e650 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u16.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-not {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler-not {vssubu.vx} } } */
+/* { dg-final { scan-assembler-not {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u32.c
index b111a4e..c8fd42a 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u32.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-not {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler-not {vssubu.vx} } } */
+/* { dg-final { scan-assembler-not {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u64.c
index 4640d16..bdb76b4 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u64.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-not {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler-not {vssubu.vx} } } */
+/* { dg-final { scan-assembler-not {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u8.c
index 58341ad..fc9c101 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-u8.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-not {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler-not {vssubu.vx} } } */
+/* { dg-final { scan-assembler-not {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c
index 6bf2a35..741f431 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-not {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler-not {vaadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c
index 5432706..1741c22 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-not {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler-not {vaadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c
index a2099fd..d326357 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-not {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler-not {vaadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c
index 1daede9..3137dc0 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c
@@ -20,3 +20,4 @@ TEST_BINARY_VX_SIGNED_0(T)
/* { dg-final { scan-assembler-not {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler-not {vaadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u16.c
index 406b999..121daeb 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u16.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-not {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler-not {vssubu.vx} } } */
+/* { dg-final { scan-assembler-not {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u32.c
index 6792b6b..9616e7f 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u32.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-not {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler-not {vssubu.vx} } } */
+/* { dg-final { scan-assembler-not {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u64.c
index 692a709..cf985f0 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u64.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-not {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler-not {vssubu.vx} } } */
+/* { dg-final { scan-assembler-not {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u8.c
index 4e30498..3bb382d 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-u8.c
@@ -19,3 +19,4 @@ TEST_BINARY_VX_UNSIGNED_0(T)
/* { dg-final { scan-assembler-not {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler-not {vssubu.vx} } } */
+/* { dg-final { scan-assembler-not {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i16.c
index d79a9f2..86c8040 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i16.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -34,3 +35,9 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmin.vx} } } */
/* { dg-final { scan-assembler {vsadd.vx} } } */
/* { dg-final { scan-assembler {vssub.vx} } } */
+/* { dg-final { scan-assembler {vaadd.vx} { target { any-opts {
+ "-mrvv-vector-bits=scalable -mrvv-max-lmul=m1"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m1"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m2"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m4"
+ } } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i32.c
index 940f596..e2d1613 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i32.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X4)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X4)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -34,3 +35,8 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmin.vx} } } */
/* { dg-final { scan-assembler {vsadd.vx} } } */
/* { dg-final { scan-assembler {vssub.vx} } } */
+/* { dg-final { scan-assembler {vaadd.vx} { target { any-opts {
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m1"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m2"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m4"
+ } } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i64.c
index 22a64f6..06ffa15 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i64.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -34,3 +35,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler {vaadd.vx} { target { no-opts "-O3 -mrvv-vector-bits=zvl -mrvv-max-lmul=m2" "-O3 -mrvv-vector-bits=zvl -mrvv-max-lmul=m4" } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i8.c
index 3286b1a..cb086aa 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i8.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -34,3 +35,8 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmin.vx} } } */
/* { dg-final { scan-assembler {vsadd.vx} } } */
/* { dg-final { scan-assembler {vssub.vx} } } */
+/* { dg-final { scan-assembler {vaadd.vx} { target { any-opts {
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m1"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m2"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m4"
+ } } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c
index afb5a85..c851f23 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u16.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -32,3 +33,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vminu.vx} } } */
/* { dg-final { scan-assembler {vsaddu.vx} } } */
/* { dg-final { scan-assembler {vssubu.vx} } } */
+/* { dg-final { scan-assembler {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c
index a907e9b..b7805c1 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u32.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X4)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X4)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -31,3 +32,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmaxu.vx} } } */
/* { dg-final { scan-assembler {vminu.vx} } } */
/* { dg-final { scan-assembler {vssubu.vx} } } */
+/* { dg-final { scan-assembler {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c
index efabf99..8295dc2 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u64.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -32,3 +33,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler-not {vssubu.vx} } } */
+/* { dg-final { scan-assembler {vaaddu.vx} { target { no-opts "-O3 -mrvv-vector-bits=zvl -mrvv-max-lmul=m2" "-O3 -mrvv-vector-bits=zvl -mrvv-max-lmul=m4" } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u8.c
index 7b2b088..d214da9 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-u8.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -32,3 +33,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vminu.vx} } } */
/* { dg-final { scan-assembler {vsaddu.vx} } } */
/* { dg-final { scan-assembler {vssubu.vx} } } */
+/* { dg-final { scan-assembler {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i16.c
index b92db10..7c7bf09 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i16.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -34,3 +35,8 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmin.vx} } } */
/* { dg-final { scan-assembler {vsadd.vx} } } */
/* { dg-final { scan-assembler {vssub.vx} } } */
+/* { dg-final { scan-assembler {vaadd.vx} { target { any-opts {
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m1"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m2"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m4"
+ } } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i32.c
index 0870cde..6d161bd 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i32.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X4)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X4)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -34,3 +35,8 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler {vaadd.vx} { target { no-opts {
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m1"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m2"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m4"
+ } } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i64.c
index a4d60e9..0409012 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i64.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -34,3 +35,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler-not {vaadd.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i8.c
index ec069a3..ed437319 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i8.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -34,3 +35,8 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmin.vx} } } */
/* { dg-final { scan-assembler {vsadd.vx} } } */
/* { dg-final { scan-assembler {vssub.vx} } } */
+/* { dg-final { scan-assembler {vaadd.vx} { target { no-opts {
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m1"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m2"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m4"
+ } } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u16.c
index da1b1be..b7c7ad4 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u16.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -32,3 +33,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vminu.vx} } } */
/* { dg-final { scan-assembler {vsaddu.vx} } } */
/* { dg-final { scan-assembler {vssubu.vx} } } */
+/* { dg-final { scan-assembler {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u32.c
index b7ec6c9..dd9c845 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u32.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X4)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X4)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -32,3 +33,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler {vssubu.vx} } } */
+/* { dg-final { scan-assembler {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u64.c
index dce78b1..1fda062 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u64.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -32,3 +33,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler-not {vssubu.vx} } } */
+/* { dg-final { scan-assembler-not {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u8.c
index c5c6fb8..725a55b 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-u8.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -32,3 +33,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vminu.vx} } } */
/* { dg-final { scan-assembler {vsaddu.vx} } } */
/* { dg-final { scan-assembler {vssubu.vx} } } */
+/* { dg-final { scan-assembler {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i16.c
index 473c31b..1e18342 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i16.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -34,3 +35,8 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmin.vx} } } */
/* { dg-final { scan-assembler {vsadd.vx} } } */
/* { dg-final { scan-assembler {vssub.vx} } } */
+/* { dg-final { scan-assembler {vaadd.vx} { target { any-opts {
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m1"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m2"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m4"
+ } } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i32.c
index 6ae84c1..fd6e47c 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i32.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X4)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X4)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -34,3 +35,8 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler {vaadd.vx} { target { any-opts {
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m1"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m2"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m4"
+ } } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i64.c
index 794f506..399d0f5 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i64.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler-not {vsub.vx} } } */
@@ -34,3 +35,8 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler-not {vmin.vx} } } */
/* { dg-final { scan-assembler-not {vsadd.vx} } } */
/* { dg-final { scan-assembler-not {vssub.vx} } } */
+/* { dg-final { scan-assembler {vaadd.vx} { target { any-opts {
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m1"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m2"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m4"
+ } } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i8.c
index 77bcdeb..98567a3 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i8.c
@@ -20,6 +20,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -34,3 +35,8 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_S_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vmin.vx} } } */
/* { dg-final { scan-assembler {vsadd.vx} } } */
/* { dg-final { scan-assembler {vssub.vx} } } */
+/* { dg-final { scan-assembler {vaadd.vx} { target { any-opts {
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m1"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m2"
+ "-mrvv-vector-bits=zvl -mrvv-max-lmul=m4"
+ } } } } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u16.c
index 5952a7c..3a215ea 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u16.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u16.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -32,3 +33,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vminu.vx} } } */
/* { dg-final { scan-assembler {vsaddu.vx} } } */
/* { dg-final { scan-assembler {vssubu.vx} } } */
+/* { dg-final { scan-assembler {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u32.c
index 5bbc585..ac4d100 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u32.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u32.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X4)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X4)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X4)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -32,3 +33,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler {vssubu.vx} } } */
+/* { dg-final { scan-assembler {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u64.c
index 255ae62..5eb0ed6 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u64.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u64.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler-not {vsub.vx} } } */
@@ -32,3 +33,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler-not {vminu.vx} } } */
/* { dg-final { scan-assembler-not {vsaddu.vx} } } */
/* { dg-final { scan-assembler-not {vssubu.vx} } } */
+/* { dg-final { scan-assembler-not {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u8.c
index 63cd449..8b404b6 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-u8.c
@@ -19,6 +19,7 @@ DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_0_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, MIN_FUNC_1_WARP(T), min, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_ADD_FUNC_WRAP(T), sat_add, VX_BINARY_FUNC_BODY_X8)
DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BODY_X8)
+DEF_VX_BINARY_CASE_3_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor, VX_BINARY_FUNC_BODY_X8)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -32,3 +33,4 @@ DEF_VX_BINARY_CASE_3_WRAP(T, SAT_U_SUB_FUNC_WRAP(T), sat_sub, VX_BINARY_FUNC_BOD
/* { dg-final { scan-assembler {vminu.vx} } } */
/* { dg-final { scan-assembler {vsaddu.vx} } } */
/* { dg-final { scan-assembler {vssubu.vx} } } */
+/* { dg-final { scan-assembler {vaaddu.vx} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i16.c
new file mode 100644
index 0000000..2b87321
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i16.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -mrvv-vector-bits=zvl --param=gpr2vr-cost=0 " } */
+
+#define VL 8
+
+#include "vx-fixed-vxrm.h"
+
+#define VT vint16m1_t
+#define T int16_t
+#define ELEM_SIZE 16
+#define SUFFIX i16
+#define FUNC __riscv_vaadd_vv_i16m1
+
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNU, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNE, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RDN, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_ROD, FUNC)
+
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,0} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,1} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,2} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,3} 1 } } */
+/* { dg-final { scan-assembler-times {vaadd.vx} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i32.c
new file mode 100644
index 0000000..b95699b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i32.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -mrvv-vector-bits=zvl --param=gpr2vr-cost=0 " } */
+
+#define VL 4
+
+#include "vx-fixed-vxrm.h"
+
+#define VT vint32m1_t
+#define T int32_t
+#define ELEM_SIZE 32
+#define SUFFIX i32
+#define FUNC __riscv_vaadd_vv_i32m1
+
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNU, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNE, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RDN, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_ROD, FUNC)
+
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,0} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,1} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,2} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,3} 1 } } */
+/* { dg-final { scan-assembler-times {vaadd.vx} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i64.c
new file mode 100644
index 0000000..48b6010
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i64.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -mrvv-vector-bits=zvl --param=gpr2vr-cost=0 " } */
+
+#define VL 2
+
+#include "vx-fixed-vxrm.h"
+
+#define VT vint64m1_t
+#define T int64_t
+#define ELEM_SIZE 64
+#define SUFFIX i64
+#define FUNC __riscv_vaadd_vv_i64m1
+
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNU, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNE, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RDN, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_ROD, FUNC)
+
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,0} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,1} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,2} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,3} 1 } } */
+/* { dg-final { scan-assembler-times {vaadd.vx} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i8.c
new file mode 100644
index 0000000..d07a625
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-i8.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -mrvv-vector-bits=zvl --param=gpr2vr-cost=0 " } */
+
+#define VL 16
+
+#include "vx-fixed-vxrm.h"
+
+#define VT vint8m1_t
+#define T int8_t
+#define ELEM_SIZE 8
+#define SUFFIX i8
+#define FUNC __riscv_vaadd_vv_i8m1
+
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNU, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNE, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RDN, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_ROD, FUNC)
+
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,0} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,1} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,2} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,3} 1 } } */
+/* { dg-final { scan-assembler-times {vaadd.vx} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u16.c
new file mode 100644
index 0000000..bd36429
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u16.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -mrvv-vector-bits=zvl --param=gpr2vr-cost=0 " } */
+
+#define VL 8
+
+#include "vx-fixed-vxrm.h"
+
+#define VT vuint16m1_t
+#define T uint16_t
+#define ELEM_SIZE 16
+#define SUFFIX u16
+#define FUNC __riscv_vaaddu_vv_u16m1
+
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNU, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNE, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RDN, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_ROD, FUNC)
+
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,0} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,1} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,2} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,3} 1 } } */
+/* { dg-final { scan-assembler-times {vaaddu.vx} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u32.c
new file mode 100644
index 0000000..f023a76
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u32.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -mrvv-vector-bits=zvl --param=gpr2vr-cost=0 " } */
+
+#define VL 4
+
+#include "vx-fixed-vxrm.h"
+
+#define VT vuint32m1_t
+#define T uint32_t
+#define ELEM_SIZE 32
+#define SUFFIX u32
+#define FUNC __riscv_vaaddu_vv_u32m1
+
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNU, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNE, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RDN, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_ROD, FUNC)
+
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,0} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,1} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,2} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,3} 1 } } */
+/* { dg-final { scan-assembler-times {vaaddu.vx} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u64.c
new file mode 100644
index 0000000..d9a37ae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u64.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -mrvv-vector-bits=zvl --param=gpr2vr-cost=0 " } */
+
+#define VL 2
+
+#include "vx-fixed-vxrm.h"
+
+#define VT vuint64m1_t
+#define T uint64_t
+#define ELEM_SIZE 64
+#define SUFFIX u64
+#define FUNC __riscv_vaaddu_vv_u64m1
+
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNU, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNE, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RDN, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_ROD, FUNC)
+
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,0} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,1} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,2} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,3} 1 } } */
+/* { dg-final { scan-assembler-times {vaaddu.vx} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u8.c
new file mode 100644
index 0000000..328e5d4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm-1-u8.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -mrvv-vector-bits=zvl --param=gpr2vr-cost=0 " } */
+
+#define VL 16
+
+#include "vx-fixed-vxrm.h"
+
+#define VT vuint8m1_t
+#define T uint8_t
+#define ELEM_SIZE 8
+#define SUFFIX u8
+#define FUNC __riscv_vaaddu_vv_u8m1
+
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNU, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RNE, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_RDN, FUNC)
+DEF_FIXED_BINARY_VX_WRAP(VT, T, ELEM_SIZE, SUFFIX, __RISCV_VXRM_ROD, FUNC)
+
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,0} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,1} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,2} 1 } } */
+/* { dg-final { scan-assembler-times {csrwi\s+vxrm,3} 1 } } */
+/* { dg-final { scan-assembler-times {vaaddu.vx} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm.h
new file mode 100644
index 0000000..438c7ab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-fixed-vxrm.h
@@ -0,0 +1,28 @@
+#ifndef HAVE_DEFINED_VX_FIXED_VXRM_H
+#define HAVE_DEFINED_VX_FIXED_VXRM_H
+
+#include <riscv_vector.h>
+
+int64_t go[VL] = {};
+int64_t ga[VL] = {};
+
+#define DEF_FIXED_BINARY_VX(VT, T, ES, SX, VXRM, FUNC) \
+void __attribute__((noinline)) \
+test_fixed_binary_##VT##_##VXRM##_##FUNC##_vx () { \
+ VT a = __riscv_vle##ES##_v_##SX##m1((T *)ga, VL); \
+ VT b; \
+ T *bp = (T *)&b; \
+ \
+ for (int i = 0; i < VL; i++) { \
+ bp[i] = 123; \
+ } \
+ \
+ VT d = FUNC (a, b, VXRM, VL); \
+ \
+ __riscv_vse##ES##_v_##SX##m1((T *)&go, d, VL); \
+}
+
+#define DEF_FIXED_BINARY_VX_WRAP(VT, T, ES, SX, VXRM, FUNC) \
+ DEF_FIXED_BINARY_VX(VT, T, ES, SX, VXRM, FUNC)
+
+#endif
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h
index 6d4d720..b7c0f79 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary.h
@@ -3,6 +3,14 @@
#include <stdint.h>
+#undef HAS_INT128
+
+#if __riscv_xlen == 64
+#define HAS_INT128
+typedef unsigned __int128 uint128_t;
+typedef signed __int128 int128_t;
+#endif
+
#define DEF_VX_BINARY_CASE_0(T, OP, NAME) \
void \
test_vx_binary_##NAME##_##T##_case_0 (T * restrict out, T * restrict in, \
@@ -340,37 +348,62 @@ DEF_SAT_S_SUB(int64_t, uint64_t, INT64_MIN, INT64_MAX)
#define SAT_S_SUB_FUNC(T) test_##T##_sat_sub
#define SAT_S_SUB_FUNC_WRAP(T) SAT_S_SUB_FUNC(T)
-#define TEST_BINARY_VX_SIGNED_0(T) \
- DEF_VX_BINARY_CASE_0_WRAP(T, +, add) \
- DEF_VX_BINARY_CASE_0_WRAP(T, -, sub) \
- DEF_VX_BINARY_REVERSE_CASE_0_WRAP(T, -, rsub) \
- DEF_VX_BINARY_CASE_0_WRAP(T, &, and) \
- DEF_VX_BINARY_CASE_0_WRAP(T, |, or) \
- DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) \
- DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) \
- DEF_VX_BINARY_CASE_0_WRAP(T, /, div) \
- DEF_VX_BINARY_CASE_0_WRAP(T, %, rem) \
- DEF_VX_BINARY_CASE_2_WRAP(T, MAX_FUNC_0_WARP(T), max) \
- DEF_VX_BINARY_CASE_2_WRAP(T, MAX_FUNC_1_WARP(T), max) \
- DEF_VX_BINARY_CASE_2_WRAP(T, MIN_FUNC_0_WARP(T), min) \
- DEF_VX_BINARY_CASE_2_WRAP(T, MIN_FUNC_1_WARP(T), min) \
- DEF_VX_BINARY_CASE_2_WRAP(T, SAT_S_ADD_FUNC(T), sat_add) \
- DEF_VX_BINARY_CASE_2_WRAP(T, SAT_S_SUB_FUNC(T), sat_sub) \
-
-#define TEST_BINARY_VX_UNSIGNED_0(T) \
- DEF_VX_BINARY_CASE_0_WRAP(T, +, add) \
- DEF_VX_BINARY_CASE_0_WRAP(T, -, sub) \
- DEF_VX_BINARY_REVERSE_CASE_0_WRAP(T, -, rsub) \
- DEF_VX_BINARY_CASE_0_WRAP(T, &, and) \
- DEF_VX_BINARY_CASE_0_WRAP(T, |, or) \
- DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) \
- DEF_VX_BINARY_CASE_0_WRAP(T, /, div) \
- DEF_VX_BINARY_CASE_0_WRAP(T, %, rem) \
- DEF_VX_BINARY_CASE_2_WRAP(T, MAX_FUNC_0_WARP(T), max) \
- DEF_VX_BINARY_CASE_2_WRAP(T, MAX_FUNC_1_WARP(T), max) \
- DEF_VX_BINARY_CASE_2_WRAP(T, MIN_FUNC_0_WARP(T), min) \
- DEF_VX_BINARY_CASE_2_WRAP(T, MIN_FUNC_1_WARP(T), min) \
- DEF_VX_BINARY_CASE_2_WRAP(T, SAT_U_ADD_FUNC(T), sat_add) \
- DEF_VX_BINARY_CASE_2_WRAP(T, SAT_U_SUB_FUNC(T), sat_sub) \
+#define DEF_AVG_FLOOR(NT, WT) \
+NT \
+test_##NT##_avg_floor(NT x, NT y) \
+{ \
+ return (NT)(((WT)x + (WT)y) >> 1); \
+}
+
+DEF_AVG_FLOOR(uint8_t, uint16_t)
+DEF_AVG_FLOOR(uint16_t, uint32_t)
+DEF_AVG_FLOOR(uint32_t, uint64_t)
+
+DEF_AVG_FLOOR(int8_t, int16_t)
+DEF_AVG_FLOOR(int16_t, int32_t)
+DEF_AVG_FLOOR(int32_t, int64_t)
+
+#ifdef HAS_INT128
+ DEF_AVG_FLOOR(uint64_t, uint128_t)
+ DEF_AVG_FLOOR(int64_t, int128_t)
+#endif
+
+#define AVG_FLOOR_FUNC(T) test_##T##_avg_floor
+#define AVG_FLOOR_FUNC_WRAP(T) AVG_FLOOR_FUNC(T)
+
+#define TEST_BINARY_VX_SIGNED_0(T) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, +, add) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, -, sub) \
+ DEF_VX_BINARY_REVERSE_CASE_0_WRAP(T, -, rsub) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, |, or) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, /, div) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, %, rem) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, MAX_FUNC_0_WARP(T), max) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, MAX_FUNC_1_WARP(T), max) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, MIN_FUNC_0_WARP(T), min) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, MIN_FUNC_1_WARP(T), min) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, SAT_S_ADD_FUNC(T), sat_add) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, SAT_S_SUB_FUNC(T), sat_sub) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor) \
+
+#define TEST_BINARY_VX_UNSIGNED_0(T) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, +, add) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, -, sub) \
+ DEF_VX_BINARY_REVERSE_CASE_0_WRAP(T, -, rsub) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, &, and) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, |, or) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, ^, xor) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, /, div) \
+ DEF_VX_BINARY_CASE_0_WRAP(T, %, rem) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, MAX_FUNC_0_WARP(T), max) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, MAX_FUNC_1_WARP(T), max) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, MIN_FUNC_0_WARP(T), min) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, MIN_FUNC_1_WARP(T), min) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, SAT_U_ADD_FUNC(T), sat_add) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, SAT_U_SUB_FUNC(T), sat_sub) \
+ DEF_VX_BINARY_CASE_2_WRAP(T, AVG_FLOOR_FUNC_WRAP(T), avg_floor) \
#endif
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h
index 47f6128..6847309 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h
@@ -4906,4 +4906,396 @@ int64_t TEST_BINARY_DATA(int64_t, sat_sub)[][3][N] =
},
};
+uint8_t TEST_BINARY_DATA(uint8_t, avg_floor)[][3][N] =
+{
+ {
+ { 0 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 4, 4, 4, 4,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 2, 2, 2, 2,
+ },
+ },
+ {
+ { 127 },
+ {
+ 127, 127, 127, 127,
+ 128, 128, 128, 128,
+ 255, 255, 255, 255,
+ 1, 1, 1, 1,
+ },
+ {
+ 127, 127, 127, 127,
+ 127, 127, 127, 127,
+ 191, 191, 191, 191,
+ 64, 64, 64, 64,
+ },
+ },
+ {
+ { 255 },
+ {
+ 0, 0, 0, 0,
+ 255, 255, 255, 255,
+ 254, 254, 254, 254,
+ 1, 1, 1, 1,
+ },
+ {
+ 127, 127, 127, 127,
+ 255, 255, 255, 255,
+ 254, 254, 254, 254,
+ 128, 128, 128, 128,
+ },
+ },
+};
+
+uint16_t TEST_BINARY_DATA(uint16_t, avg_floor)[][3][N] =
+{
+ {
+ { 0 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 4, 4, 4, 4,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 2, 2, 2, 2,
+ },
+ },
+ {
+ { 32767 },
+ {
+ 32767, 32767, 32767, 32767,
+ 32768, 32768, 32768, 32768,
+ 65535, 65535, 65535, 65535,
+ 1, 1, 1, 1,
+ },
+ {
+ 32767, 32767, 32767, 32767,
+ 32767, 32767, 32767, 32767,
+ 49151, 49151, 49151, 49151,
+ 16384, 16384, 16384, 16384,
+ },
+ },
+ {
+ { 65535 },
+ {
+ 0, 0, 0, 0,
+ 65535, 65535, 65535, 65535,
+ 65534, 65534, 65534, 65534,
+ 1, 1, 1, 1,
+ },
+ {
+ 32767, 32767, 32767, 32767,
+ 65535, 65535, 65535, 65535,
+ 65534, 65534, 65534, 65534,
+ 32768, 32768, 32768, 32768,
+ },
+ },
+};
+
+uint32_t TEST_BINARY_DATA(uint32_t, avg_floor)[][3][N] =
+{
+ {
+ { 0 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 4, 4, 4, 4,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 2, 2, 2, 2,
+ },
+ },
+ {
+ { 2147483647 },
+ {
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ 2147483648, 2147483648, 2147483648, 2147483648,
+ 4294967295, 4294967295, 4294967295, 4294967295,
+ 1, 1, 1, 1,
+ },
+ {
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ 3221225471, 3221225471, 3221225471, 3221225471,
+ 1073741824, 1073741824, 1073741824, 1073741824,
+ },
+ },
+ {
+ { 4294967295 },
+ {
+ 0, 0, 0, 0,
+ 4294967295, 4294967295, 4294967295, 4294967295,
+ 4294967294, 4294967294, 4294967294, 4294967294,
+ 1, 1, 1, 1,
+ },
+ {
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ 4294967295, 4294967295, 4294967295, 4294967295,
+ 4294967294, 4294967294, 4294967294, 4294967294,
+ 2147483648, 2147483648, 2147483648, 2147483648,
+ },
+ },
+};
+
+uint64_t TEST_BINARY_DATA(uint64_t, avg_floor)[][3][N] =
+{
+ {
+ { 0 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 4, 4, 4, 4,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 2, 2, 2, 2,
+ },
+ },
+ {
+ { 9223372036854775807ull },
+ {
+ 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
+ 9223372036854775808ull, 9223372036854775808ull, 9223372036854775808ull, 9223372036854775808ull,
+ 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull,
+ 1, 1, 1, 1,
+ },
+ {
+ 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
+ 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
+ 13835058055282163711ull, 13835058055282163711ull, 13835058055282163711ull, 13835058055282163711ull,
+ 4611686018427387904ull, 4611686018427387904ull, 4611686018427387904ull, 4611686018427387904ull,
+ },
+ },
+ {
+ { 18446744073709551615ull },
+ {
+ 0, 0, 0, 0,
+ 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull,
+ 18446744073709551614ull, 18446744073709551614ull, 18446744073709551614ull, 18446744073709551614ull,
+ 1, 1, 1, 1,
+ },
+ {
+ 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
+ 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull, 18446744073709551615ull,
+ 18446744073709551614ull, 18446744073709551614ull, 18446744073709551614ull, 18446744073709551614ull,
+ 9223372036854775808ull, 9223372036854775808ull, 9223372036854775808ull, 9223372036854775808ull,
+ },
+ },
+};
+
+int8_t TEST_BINARY_DATA(int8_t, avg_floor)[][3][N] =
+{
+ {
+ { 0 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 4, 4, 4, 4,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 2, 2, 2, 2,
+ },
+ },
+ {
+ { 127 },
+ {
+ 127, 127, 127, 127,
+ -128, -128, -128, -128,
+ -127, -127, -127, -127,
+ 1, 1, 1, 1,
+ },
+ {
+ 127, 127, 127, 127,
+ -1, -1, -1, -1,
+ 0, 0, 0, 0,
+ 64, 64, 64, 64,
+ },
+ },
+ {
+ {-128 },
+ {
+ 0, 0, 0, 0,
+ -128, -128, -128, -128,
+ 126, 126, 126, 126,
+ 127, 127, 127, 127,
+ },
+ {
+ -64, -64, -64, -64,
+ -128, -128, -128, -128,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ },
+ },
+};
+
+int16_t TEST_BINARY_DATA(int16_t, avg_floor)[][3][N] =
+{
+ {
+ { 0 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 4, 4, 4, 4,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 2, 2, 2, 2,
+ },
+ },
+ {
+ { 32767 },
+ {
+ 32767, 32767, 32767, 32767,
+ -32768, -32768, -32768, -32768,
+ -32767, -32767, -32767, -32767,
+ 1, 1, 1, 1,
+ },
+ {
+ 32767, 32767, 32767, 32767,
+ -1, -1, -1, -1,
+ 0, 0, 0, 0,
+ 16384, 16384, 16384, 16384,
+ },
+ },
+ {
+ {-32768 },
+ {
+ 0, 0, 0, 0,
+ -32768, -32768, -32768, -32768,
+ 32766, 32766, 32766, 32766,
+ 32767, 32767, 32767, 32767,
+ },
+ {
+ -16384, -16384, -16384, -16384,
+ -32768, -32768, -32768, -32768,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ },
+ },
+};
+
+int32_t TEST_BINARY_DATA(int32_t, avg_floor)[][3][N] =
+{
+ {
+ { 0 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 4, 4, 4, 4,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 2, 2, 2, 2,
+ },
+ },
+ {
+ { 2147483647 },
+ {
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ -2147483648, -2147483648, -2147483648, -2147483648,
+ -2147483647, -2147483647, -2147483647, -2147483647,
+ 1, 1, 1, 1,
+ },
+ {
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ -1, -1, -1, -1,
+ 0, 0, 0, 0,
+ 1073741824, 1073741824, 1073741824, 1073741824,
+ },
+ },
+ {
+ {-2147483648 },
+ {
+ 0, 0, 0, 0,
+ -2147483648, -2147483648, -2147483648, -2147483648,
+ 2147483646, 2147483646, 2147483646, 2147483646,
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ },
+ {
+ -1073741824, -1073741824, -1073741824, -1073741824,
+ -2147483648, -2147483648, -2147483648, -2147483648,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ },
+ },
+};
+
+int64_t TEST_BINARY_DATA(int64_t, avg_floor)[][3][N] =
+{
+ {
+ { 0 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 4, 4, 4, 4,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 2, 2, 2, 2,
+ },
+ },
+ {
+ { 9223372036854775807ull },
+ {
+ 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
+ -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull,
+ -9223372036854775807ull, -9223372036854775807ull, -9223372036854775807ull, -9223372036854775807ull,
+ 1, 1, 1, 1,
+ },
+ {
+ 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
+ -1, -1, -1, -1,
+ 0, 0, 0, 0,
+ 4611686018427387904ull, 4611686018427387904ull, 4611686018427387904ull, 4611686018427387904ull,
+ },
+ },
+ {
+ {-9223372036854775808ull },
+ {
+ 0, 0, 0, 0,
+ -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull,
+ 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
+ 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull, 9223372036854775807ull,
+ },
+ {
+ -4611686018427387904ull, -4611686018427387904ull, -4611686018427387904ull, -4611686018427387904ull,
+ -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull,
+ -1, -1, -1, -1,
+ -1, -1, -1, -1,
+ },
+ },
+};
+
#endif
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i16.c
new file mode 100644
index 0000000..0307b3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i16.c
@@ -0,0 +1,17 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T int16_t
+#define NAME avg_floor
+#define FUNC AVG_FLOOR_FUNC_WRAP(T)
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+
+DEF_VX_BINARY_CASE_2_WRAP(T, FUNC, NAME)
+
+#define TEST_RUN(T, NAME, out, in, x, n) \
+ RUN_VX_BINARY_CASE_2_WRAP(T, NAME, FUNC, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i32.c
new file mode 100644
index 0000000..d73325b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i32.c
@@ -0,0 +1,17 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T int32_t
+#define NAME avg_floor
+#define FUNC AVG_FLOOR_FUNC_WRAP(T)
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+
+DEF_VX_BINARY_CASE_2_WRAP(T, FUNC, NAME)
+
+#define TEST_RUN(T, NAME, out, in, x, n) \
+ RUN_VX_BINARY_CASE_2_WRAP(T, NAME, FUNC, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i64.c
new file mode 100644
index 0000000..481774b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i64.c
@@ -0,0 +1,17 @@
+/* { dg-do run { target { riscv_v && rv64 } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T int64_t
+#define NAME avg_floor
+#define FUNC AVG_FLOOR_FUNC_WRAP(T)
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+
+DEF_VX_BINARY_CASE_2_WRAP(T, FUNC, NAME)
+
+#define TEST_RUN(T, NAME, out, in, x, n) \
+ RUN_VX_BINARY_CASE_2_WRAP(T, NAME, FUNC, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i8.c
new file mode 100644
index 0000000..7de89ee
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-i8.c
@@ -0,0 +1,17 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T int8_t
+#define NAME avg_floor
+#define FUNC AVG_FLOOR_FUNC_WRAP(T)
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+
+DEF_VX_BINARY_CASE_2_WRAP(T, FUNC, NAME)
+
+#define TEST_RUN(T, NAME, out, in, x, n) \
+ RUN_VX_BINARY_CASE_2_WRAP(T, NAME, FUNC, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u16.c
new file mode 100644
index 0000000..73d1a57
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u16.c
@@ -0,0 +1,17 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T uint16_t
+#define NAME avg_floor
+#define FUNC AVG_FLOOR_FUNC_WRAP(T)
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+
+DEF_VX_BINARY_CASE_2_WRAP(T, FUNC, NAME)
+
+#define TEST_RUN(T, NAME, out, in, x, n) \
+ RUN_VX_BINARY_CASE_2_WRAP(T, NAME, FUNC, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u32.c
new file mode 100644
index 0000000..60a7aa4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u32.c
@@ -0,0 +1,17 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T uint32_t
+#define NAME avg_floor
+#define FUNC AVG_FLOOR_FUNC_WRAP(T)
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+
+DEF_VX_BINARY_CASE_2_WRAP(T, FUNC, NAME)
+
+#define TEST_RUN(T, NAME, out, in, x, n) \
+ RUN_VX_BINARY_CASE_2_WRAP(T, NAME, FUNC, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u64.c
new file mode 100644
index 0000000..803bcba
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u64.c
@@ -0,0 +1,17 @@
+/* { dg-do run { target { riscv_v && rv64 } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T uint64_t
+#define NAME avg_floor
+#define FUNC AVG_FLOOR_FUNC_WRAP(T)
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+
+DEF_VX_BINARY_CASE_2_WRAP(T, FUNC, NAME)
+
+#define TEST_RUN(T, NAME, out, in, x, n) \
+ RUN_VX_BINARY_CASE_2_WRAP(T, NAME, FUNC, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u8.c
new file mode 100644
index 0000000..f28147b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vaadd-run-1-u8.c
@@ -0,0 +1,17 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99 --param=gpr2vr-cost=0" } */
+
+#include "vx_binary.h"
+#include "vx_binary_data.h"
+
+#define T uint8_t
+#define NAME avg_floor
+#define FUNC AVG_FLOOR_FUNC_WRAP(T)
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+
+DEF_VX_BINARY_CASE_2_WRAP(T, FUNC, NAME)
+
+#define TEST_RUN(T, NAME, out, in, x, n) \
+ RUN_VX_BINARY_CASE_2_WRAP(T, NAME, FUNC, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-5.c b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-5.c
index 04dec7b..4f6785a 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-5.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-5.c
@@ -6,9 +6,9 @@
/*
** foo:
-** addi\t[a-x0-9]+,\s*[a-x0-9]+,100
+** ...
** vsetvli\tzero,a2,e64,m2,t[au],m[au]
-** vlse64.v\tv[0-9]+,0\([a-x0-9]+\),zero
+** vmv.s.x\tv[0-9]+.*
** vs2r.v\tv[0-9]+,0\([a-x0-9]+\)
** ret
*/
@@ -23,7 +23,7 @@ void foo (void *base, void *out, size_t vl)
** foo2:
** fld\tfa[0-9]+,\s*100\(a0\)
** vsetvli\tzero,a2,e64,m2,t[au],m[au]
-** vfmv\.v\.f\tv[0-9]+,\s*fa[0-9]+
+** vfmv\.s\.f\tv[0-9]+,\s*fa[0-9]+
** vs2r.v\tv[0-9]+,0\([a-x0-9]+\)
** ret
*/
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-6.c b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-6.c
index 0ebb92e..a8c9263c 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-6.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-6.c
@@ -23,7 +23,7 @@ void foo (void *base, void *out, size_t vl)
** foo2:
** fld\tfa[0-9]+,\s*100\(a0\)
** vsetvli\tzero,a2,e64,m2,t[au],m[au]
-** vfmv\.v\.f\tv[0-9]+,\s*fa[0-9]+
+** vfmv\.s\.f\tv[0-9]+,\s*fa[0-9]+
** vs2r.v\tv[0-9]+,0\([a-x0-9]+\)
** ret
*/
@@ -52,7 +52,7 @@ void foo3 (void *base, void *out, size_t vl)
/*
** foo4:
** ...
-** vfmv\.v\.f\tv[0-9]+,\s*fa[0-9]+
+** vfmv\.s\.f\tv[0-9]+,\s*fa[0-9]+
** ...
** ret
*/
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-7.c b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-7.c
index 512fa62..cf53aca 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-7.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-7.c
@@ -6,9 +6,9 @@
/*
** foo:
-** addi\t[a-x0-9]+,\s*[a-x0-9]+,100
+** ...
** vsetvli\tzero,a2,e64,m2,t[au],m[au]
-** vlse64.v\tv[0-9]+,0\([a-x0-9]+\),zero
+** vmv\.v\.x\tv[0-9]+,\s*a[0-9]+
** vs2r.v\tv[0-9]+,0\([a-x0-9]+\)
** ret
*/
@@ -37,7 +37,7 @@ void foo2 (void *base, void *out, size_t vl)
/*
** foo3:
** ...
-** vlse64.v\tv[0-9]+,0\([a-x0-9]+\),zero
+** vmv\.v\.x\tv[0-9]+,\s*a[0-9]+
** ...
** ret
*/
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-8.c b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-8.c
index d9d10f3..fd3b7c5 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-8.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-8.c
@@ -175,9 +175,8 @@ void foo12 (void *base, void *out, size_t vl)
/*
** foo13:
** ...
-** vmv.v.x\tv[0-9]+,\s*[a-x0-9]+
+** vlse64.v\tv[0-9]+,0\([a-x0-9]+\),zero
** ...
-** ret
*/
void foo13 (void *base, void *out, size_t vl)
{
@@ -189,7 +188,7 @@ void foo13 (void *base, void *out, size_t vl)
/*
** foo14:
** ...
-** vmv.v.x\tv[0-9]+,\s*[a-x0-9]+
+** vlse64.v\tv[0-9]+,0\([a-x0-9]+\),zero
** ...
*/
void foo14 (void *base, void *out, size_t vl)
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-9.c b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-9.c
index 80ee1b5..64c22dd 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-9.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/base/scalar_move-9.c
@@ -23,4 +23,3 @@ vuint64m2_t f3(vuint64m2_t var_17, uint64_t var_60, size_t vl)
/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*0,\s*e64,\s*m2,\s*t[au],\s*m[au]} 1 } } */
/* { dg-final { scan-assembler-times {vsetivli\s+zero,\s*1,\s*e64,\s*m2,\s*t[au],\s*m[au]} 1 } } */
-/* { dg-final { scan-assembler-times {sgtu} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/pr121073.c b/gcc/testsuite/gcc.target/riscv/rvv/pr121073.c
new file mode 100644
index 0000000..2789d0f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/pr121073.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -mrvv-vector-bits=zvl -fsigned-char -fno-strict-aliasing -fwrapv -Wno-stringop-overflow -Wno-aggressive-loop-optimizations" } */
+
+int a;
+unsigned char p[1][21];
+void init() {
+ for (int s = 0; s < 21; ++s)
+ for (int t = 0; t < 21; ++t)
+ p[s][t] = 39;
+ for (short t = 0; t < 9; t += -5077966496202321318LL + 28071)
+ a = p[3][t] && p[2][t];
+}
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_arith.h b/gcc/testsuite/gcc.target/riscv/sat/sat_arith.h
index 7e2c93e..e40902a 100644
--- a/gcc/testsuite/gcc.target/riscv/sat/sat_arith.h
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_arith.h
@@ -73,6 +73,22 @@ sat_u_add_##WT##_##T##_fmt_7(T x, T y) \
}
#define DEF_SAT_U_ADD_FMT_7_WRAP(WT, T) DEF_SAT_U_ADD_FMT_7(WT, T)
+#define DEF_SAT_U_ADD_FMT_8(T) \
+T __attribute__((noinline)) \
+sat_u_add_##T##_fmt_8(T x, T y) \
+{ \
+ return x <= (T)(x + y) ? (x + y) : -1; \
+}
+#define DEF_SAT_U_ADD_FMT_8_WRAP(T) DEF_SAT_U_ADD_FMT_8(T)
+
+#define DEF_SAT_U_ADD_FMT_9(T) \
+T __attribute__((noinline)) \
+sat_u_add_##T##_fmt_9(T x, T y) \
+{ \
+ return x > (T)(x + y) ? -1 : (x + y); \
+}
+#define DEF_SAT_U_ADD_FMT_9_WRAP(T) DEF_SAT_U_ADD_FMT_9(T)
+
#define RUN_SAT_U_ADD_FMT_1(T, x, y) sat_u_add_##T##_fmt_1(x, y)
#define RUN_SAT_U_ADD_FMT_1_WRAP(T, x, y) RUN_SAT_U_ADD_FMT_1(T, x, y)
#define RUN_SAT_U_ADD_FMT_2(T, x, y) sat_u_add_##T##_fmt_2(x, y)
@@ -97,6 +113,10 @@ sat_u_add_##WT##_##T##_fmt_7(T x, T y) \
sat_u_add_uint64_t_##T##_fmt_7(x, y)
#define RUN_SAT_U_ADD_FMT_7_FROM_U64_WRAP(T, x, y) \
RUN_SAT_U_ADD_FMT_7_FROM_U64(T, x, y)
+#define RUN_SAT_U_ADD_FMT_8(T, x, y) sat_u_add_##T##_fmt_8(x, y)
+#define RUN_SAT_U_ADD_FMT_8_WRAP(T, x, y) RUN_SAT_U_ADD_FMT_8(T, x, y)
+#define RUN_SAT_U_ADD_FMT_9(T, x, y) sat_u_add_##T##_fmt_9(x, y)
+#define RUN_SAT_U_ADD_FMT_9_WRAP(T, x, y) RUN_SAT_U_ADD_FMT_9(T, x, y)
#define DEF_SAT_U_ADD_IMM_FMT_1(T, IMM) \
T __attribute__((noinline)) \
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u16.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u16.c
new file mode 100644
index 0000000..a7062b5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u16.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fdump-tree-optimized" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_ADD_FMT_8(uint16_t)
+
+/* { dg-final { scan-tree-dump-times ".SAT_ADD " 1 "optimized" } } */
+/* { dg-final { scan-assembler-not "\.L\[0-9\]+" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u32.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u32.c
new file mode 100644
index 0000000..2e43c7f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u32.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fdump-tree-optimized" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_ADD_FMT_8(uint32_t)
+
+/* { dg-final { scan-tree-dump-times ".SAT_ADD " 1 "optimized" } } */
+/* { dg-final { scan-assembler-not "\.L\[0-9\]+" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u64.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u64.c
new file mode 100644
index 0000000..4ad18c1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u64.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fdump-tree-optimized" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_ADD_FMT_8(uint64_t)
+
+/* { dg-final { scan-tree-dump-times ".SAT_ADD " 1 "optimized" } } */
+/* { dg-final { scan-assembler-not "\.L\[0-9\]+" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u8.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u8.c
new file mode 100644
index 0000000..608d31b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-8-u8.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fdump-tree-optimized" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_ADD_FMT_8(uint8_t)
+
+/* { dg-final { scan-tree-dump-times ".SAT_ADD " 1 "optimized" } } */
+/* { dg-final { scan-assembler-not "\.L\[0-9\]+" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u16.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u16.c
new file mode 100644
index 0000000..b9766d1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u16.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fdump-tree-optimized" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_ADD_FMT_9(uint16_t)
+
+/* { dg-final { scan-tree-dump-times ".SAT_ADD " 1 "optimized" } } */
+/* { dg-final { scan-assembler-not "\.L\[0-9\]+" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u32.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u32.c
new file mode 100644
index 0000000..2456d39
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u32.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fdump-tree-optimized" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_ADD_FMT_9(uint32_t)
+
+/* { dg-final { scan-tree-dump-times ".SAT_ADD " 1 "optimized" } } */
+/* { dg-final { scan-assembler-not "\.L\[0-9\]+" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u64.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u64.c
new file mode 100644
index 0000000..0a0ff24
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u64.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fdump-tree-optimized" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_ADD_FMT_9(uint64_t)
+
+/* { dg-final { scan-tree-dump-times ".SAT_ADD " 1 "optimized" } } */
+/* { dg-final { scan-assembler-not "\.L\[0-9\]+" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u8.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u8.c
new file mode 100644
index 0000000..53879dd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-9-u8.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -fdump-tree-optimized" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_ADD_FMT_9(uint8_t)
+
+/* { dg-final { scan-tree-dump-times ".SAT_ADD " 1 "optimized" } } */
+/* { dg-final { scan-assembler-not "\.L\[0-9\]+" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u16.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u16.c
new file mode 100644
index 0000000..aaf13be
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u16.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { rv32 || rv64 } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+#include "sat_arith_data.h"
+
+#define T1 uint16_t
+#define DATA TEST_BINARY_DATA_WRAP(T1, usadd)
+#define T TEST_BINARY_STRUCT_DECL(T1, usadd)
+
+DEF_SAT_U_ADD_FMT_8_WRAP(T1)
+
+#define RUN_BINARY(x, y) RUN_SAT_U_ADD_FMT_8_WRAP(T1, x, y)
+
+#include "scalar_sat_binary_run_xxx.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u32.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u32.c
new file mode 100644
index 0000000..0ec8d90
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u32.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { rv32 || rv64 } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+#include "sat_arith_data.h"
+
+#define T1 uint32_t
+#define DATA TEST_BINARY_DATA_WRAP(T1, usadd)
+#define T TEST_BINARY_STRUCT_DECL(T1, usadd)
+
+DEF_SAT_U_ADD_FMT_8_WRAP(T1)
+
+#define RUN_BINARY(x, y) RUN_SAT_U_ADD_FMT_8_WRAP(T1, x, y)
+
+#include "scalar_sat_binary_run_xxx.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u64.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u64.c
new file mode 100644
index 0000000..f367f67
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u64.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { rv32 || rv64 } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+#include "sat_arith_data.h"
+
+#define T1 uint64_t
+#define DATA TEST_BINARY_DATA_WRAP(T1, usadd)
+#define T TEST_BINARY_STRUCT_DECL(T1, usadd)
+
+DEF_SAT_U_ADD_FMT_8_WRAP(T1)
+
+#define RUN_BINARY(x, y) RUN_SAT_U_ADD_FMT_8_WRAP(T1, x, y)
+
+#include "scalar_sat_binary_run_xxx.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u8.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u8.c
new file mode 100644
index 0000000..0fd4036
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-8-u8.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { rv32 || rv64 } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+#include "sat_arith_data.h"
+
+#define T1 uint8_t
+#define DATA TEST_BINARY_DATA_WRAP(T1, usadd)
+#define T TEST_BINARY_STRUCT_DECL(T1, usadd)
+
+DEF_SAT_U_ADD_FMT_8_WRAP(T1)
+
+#define RUN_BINARY(x, y) RUN_SAT_U_ADD_FMT_8_WRAP(T1, x, y)
+
+#include "scalar_sat_binary_run_xxx.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u16.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u16.c
new file mode 100644
index 0000000..4289e2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u16.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { rv32 || rv64 } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+#include "sat_arith_data.h"
+
+#define T1 uint16_t
+#define DATA TEST_BINARY_DATA_WRAP(T1, usadd)
+#define T TEST_BINARY_STRUCT_DECL(T1, usadd)
+
+DEF_SAT_U_ADD_FMT_9_WRAP(T1)
+
+#define RUN_BINARY(x, y) RUN_SAT_U_ADD_FMT_9_WRAP(T1, x, y)
+
+#include "scalar_sat_binary_run_xxx.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u32.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u32.c
new file mode 100644
index 0000000..d3dd52e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u32.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { rv32 || rv64 } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+#include "sat_arith_data.h"
+
+#define T1 uint32_t
+#define DATA TEST_BINARY_DATA_WRAP(T1, usadd)
+#define T TEST_BINARY_STRUCT_DECL(T1, usadd)
+
+DEF_SAT_U_ADD_FMT_9_WRAP(T1)
+
+#define RUN_BINARY(x, y) RUN_SAT_U_ADD_FMT_9_WRAP(T1, x, y)
+
+#include "scalar_sat_binary_run_xxx.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u64.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u64.c
new file mode 100644
index 0000000..a9f0964
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u64.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { rv32 || rv64 } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+#include "sat_arith_data.h"
+
+#define T1 uint64_t
+#define DATA TEST_BINARY_DATA_WRAP(T1, usadd)
+#define T TEST_BINARY_STRUCT_DECL(T1, usadd)
+
+DEF_SAT_U_ADD_FMT_9_WRAP(T1)
+
+#define RUN_BINARY(x, y) RUN_SAT_U_ADD_FMT_9_WRAP(T1, x, y)
+
+#include "scalar_sat_binary_run_xxx.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u8.c b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u8.c
new file mode 100644
index 0000000..91cdb7e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat/sat_u_add-run-9-u8.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { rv32 || rv64 } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+#include "sat_arith_data.h"
+
+#define T1 uint8_t
+#define DATA TEST_BINARY_DATA_WRAP(T1, usadd)
+#define T TEST_BINARY_STRUCT_DECL(T1, usadd)
+
+DEF_SAT_U_ADD_FMT_9_WRAP(T1)
+
+#define RUN_BINARY(x, y) RUN_SAT_U_ADD_FMT_9_WRAP(T1, x, y)
+
+#include "scalar_sat_binary_run_xxx.h"
diff --git a/gcc/testsuite/gcc.target/riscv/xtheadint-push-pop.c b/gcc/testsuite/gcc.target/riscv/xtheadint-push-pop.c
index dc5609c..167fa15 100644
--- a/gcc/testsuite/gcc.target/riscv/xtheadint-push-pop.c
+++ b/gcc/testsuite/gcc.target/riscv/xtheadint-push-pop.c
@@ -20,12 +20,6 @@ void func_machine (void)
/* { dg-final { scan-assembler-times {\mth\.ipop\M} 2 { target { rv32 } } } } */
-__attribute__ ((interrupt ("user")))
-void func_usr (void)
-{
- f ();
-}
-
__attribute__ ((interrupt ("supervisor")))
void func_supervisor (void)
{
diff --git a/gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c b/gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c
new file mode 100644
index 0000000..671c0ed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/asm-hard-reg-1.c
@@ -0,0 +1,103 @@
+/* { dg-do compile { target { lp64 } } } */
+/* { dg-options "-O2 -march=z13 -mzarch" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+
+/*
+** test_in_1:
+** foo %r2
+** br %r14
+*/
+
+int
+test_in_1 (int x)
+{
+ asm ("foo %0" :: "{r2}" (x));
+ return x;
+}
+
+/*
+** test_in_2:
+** lgr (%r[0-9]+),%r2
+** lr %r2,%r3
+** foo %r2
+** lgr %r2,\1
+** br %r14
+*/
+
+int
+test_in_2 (int x, int y)
+{
+ asm ("foo %0" :: "{r2}" (y));
+ return x;
+}
+
+/*
+** test_in_3:
+** stmg %r12,%r15,96\(%r15\)
+** lay %r15,-160\(%r15\)
+** lgr (%r[0-9]+),%r2
+** ahi %r2,1
+** lgfr %r2,%r2
+** brasl %r14,foo@PLT
+** lr %r3,%r2
+** lr %r2,\1
+** foo %r3,%r2
+** lgr %r2,\1
+** lmg %r12,%r15,256\(%r15\)
+** br %r14
+*/
+
+extern int foo (int);
+
+int
+test_in_3 (int x)
+{
+ asm ("foo %0,%1\n" :: "{r3}" (foo (x + 1)), "{r2}" (x));
+ return x;
+}
+
+/*
+** test_out_1:
+** foo %r3
+** lgfr %r2,%r3
+** br %r14
+*/
+
+int
+test_out_1 (void)
+{
+ int x;
+ asm ("foo %0" : "={r3}" (x));
+ return x;
+}
+
+/*
+** test_out_2:
+** lgr (%r[0-9]+),%r2
+** foo %r2
+** ark (%r[0-9]+),\1,%r2
+** lgfr %r2,\2
+** br %r14
+*/
+
+int
+test_out_2 (int x)
+{
+ int y;
+ asm ("foo %0" : "={r2}" (y));
+ return x + y;
+}
+
+/*
+** test_inout_1:
+** foo %r2
+** lgfr %r2,%r2
+** br %r14
+*/
+
+int
+test_inout_1 (int x)
+{
+ asm ("foo %0" : "+{r2}" (x));
+ return x;
+}
diff --git a/gcc/testsuite/gcc.target/s390/asm-hard-reg-2.c b/gcc/testsuite/gcc.target/s390/asm-hard-reg-2.c
new file mode 100644
index 0000000..a892fe8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/asm-hard-reg-2.c
@@ -0,0 +1,43 @@
+/* { dg-do compile { target { lp64 } } } */
+/* { dg-options "-O2 -march=z13 -mzarch" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+/* { dg-final { scan-assembler {\.LC0:\n\t\.long\t1078523331\n} } } */
+
+
+/*
+** test_float_into_gpr:
+** lrl %r4,.LC0
+** foo %r4
+** br %r14
+*/
+
+void
+test_float_into_gpr (void)
+{
+ // This is the counterpart to
+ // register float x asm ("r4") = 3.14f;
+ // asm ("foo %0" :: "r" (x));
+ // where the bit-pattern of 3.14f is loaded into GPR.
+ asm ("foo %0" :: "{r4}" (3.14f));
+}
+
+/*
+** test_float:
+** (
+** ldr %f4,%f0
+** ldr %f5,%f2
+** |
+** ldr %f5,%f2
+** ldr %f4,%f0
+** )
+** aebr %f5,%f4
+** ldr %f0,%f5
+** br %r14
+*/
+
+float
+test_float (float x, float y)
+{
+ asm ("aebr %0,%1" : "+{f5}" (y) : "{f4}" (x));
+ return y;
+}
diff --git a/gcc/testsuite/gcc.target/s390/asm-hard-reg-3.c b/gcc/testsuite/gcc.target/s390/asm-hard-reg-3.c
new file mode 100644
index 0000000..5df37b5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/asm-hard-reg-3.c
@@ -0,0 +1,42 @@
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-O2 -march=z13 -mzarch" } */
+/* { dg-final { check-function-bodies "**" "" "" } } */
+/* { dg-final { scan-assembler {\.LC0:\n\t\.long\t1074339512\n\t\.long\t1374389535\n} } } */
+
+/*
+** test_double_into_gpr:
+** lgrl %r4,.LC0
+** foo %r4
+** br %r14
+*/
+
+void
+test_double_into_gpr (void)
+{
+ // This is the counterpart to
+ // register double x asm ("r4") = 3.14;
+ // asm ("foo %0" :: "r" (x));
+ // where the bit-pattern of 3.14 is loaded into GPR.
+ asm ("foo %0" :: "{r4}" (3.14));
+}
+
+/*
+** test_double:
+** (
+** ldr %f4,%f0
+** ldr %f5,%f2
+** |
+** ldr %f5,%f2
+** ldr %f4,%f0
+** )
+** adbr %f5,%f4
+** ldr %f0,%f5
+** br %r14
+*/
+
+double
+test_double (double x, double y)
+{
+ asm ("adbr %0,%1" : "+{f5}" (y) : "{f4}" (x));
+ return y;
+}
diff --git a/gcc/testsuite/gcc.target/s390/asm-hard-reg-4.c b/gcc/testsuite/gcc.target/s390/asm-hard-reg-4.c
new file mode 100644
index 0000000..29927ce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/asm-hard-reg-4.c
@@ -0,0 +1,6 @@
+/* { dg-do run { target lp64 } } */
+/* { dg-options "-O2 -march=z13 -mzarch" } */
+
+/* Test TARGET_MD_ASM_ADJUST for z13 and long double. */
+
+#include "asm-hard-reg-longdouble.h"
diff --git a/gcc/testsuite/gcc.target/s390/asm-hard-reg-5.c b/gcc/testsuite/gcc.target/s390/asm-hard-reg-5.c
new file mode 100644
index 0000000..eaf34d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/asm-hard-reg-5.c
@@ -0,0 +1,6 @@
+/* { dg-do run { target lp64 } } */
+/* { dg-options "-O2 -march=z14 -mzarch" } */
+
+/* Test TARGET_MD_ASM_ADJUST for z14 and long double. */
+
+#include "asm-hard-reg-longdouble.h"
diff --git a/gcc/testsuite/gcc.target/s390/asm-hard-reg-6.c b/gcc/testsuite/gcc.target/s390/asm-hard-reg-6.c
new file mode 100644
index 0000000..d012966
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/asm-hard-reg-6.c
@@ -0,0 +1,152 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+void
+test (void)
+{
+ // GPRs
+ {
+ int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p;
+ __asm__ __volatile__ ("%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14"
+ : "=r" (a),
+ "=r" (b),
+ "=r" (c),
+ "=r" (d),
+ "=r" (e),
+ "=r" (f),
+ "=r" (g),
+ "=r" (h),
+ "=r" (i),
+ "=r" (j),
+ "=r" (k),
+ "=r" (l),
+ "=r" (m),
+ "=r" (n),
+ "=r" (o));
+ __asm__ __volatile__ ("%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14"
+ : "={r0}" (a),
+ "={r1}" (b),
+ "={r2}" (c),
+ "={r3}" (d),
+ "={r4}" (e),
+ "={r5}" (f),
+ "={r6}" (g),
+ "={r7}" (h),
+ "={r8}" (i),
+ "={r9}" (j),
+ "={r10}" (k),
+ "={r11}" (l),
+ "={r12}" (m),
+ "={r13}" (n),
+ "={r14}" (o));
+ __asm__ __volatile__ ("%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14 %15" /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ : "=r" (a),
+ "=r" (b),
+ "=r" (c),
+ "=r" (d),
+ "=r" (e),
+ "=r" (f),
+ "=r" (g),
+ "=r" (h),
+ "=r" (i),
+ "=r" (j),
+ "=r" (k),
+ "=r" (l),
+ "=r" (m),
+ "=r" (n),
+ "=r" (o),
+ "=r" (p));
+ __asm__ __volatile__ ("%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14 %15" /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ : "=r" (a),
+ "=r" (b),
+ "=r" (c),
+ "=r" (d),
+ "=r" (e),
+ "=r" (f),
+ "=r" (g),
+ "=r" (h),
+ "=r" (i),
+ "=r" (j),
+ "=r" (k),
+ "=r" (l),
+ "=r" (m),
+ "=r" (n),
+ "=r" (o),
+ "={r4}" (p));
+ }
+
+ // FPRs
+ {
+ float a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q;
+ __asm__ __volatile__ ("%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14 %15"
+ : "=f" (a),
+ "=f" (b),
+ "=f" (c),
+ "=f" (d),
+ "=f" (e),
+ "=f" (f),
+ "=f" (g),
+ "=f" (h),
+ "=f" (i),
+ "=f" (j),
+ "=f" (k),
+ "=f" (l),
+ "=f" (m),
+ "=f" (n),
+ "=f" (o),
+ "=f" (p));
+ __asm__ __volatile__ ("%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14 %15"
+ : "={f0}" (a),
+ "={f1}" (b),
+ "={f2}" (c),
+ "={f3}" (d),
+ "={f4}" (e),
+ "={f5}" (f),
+ "={f6}" (g),
+ "={f7}" (h),
+ "={f8}" (i),
+ "={f9}" (j),
+ "={f10}" (k),
+ "={f11}" (l),
+ "={f12}" (m),
+ "={f13}" (n),
+ "={f14}" (o),
+ "={f15}" (p));
+ __asm__ __volatile__ ("%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14 %15 %16" /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ : "=f" (a),
+ "=f" (b),
+ "=f" (c),
+ "=f" (d),
+ "=f" (e),
+ "=f" (f),
+ "=f" (g),
+ "=f" (h),
+ "=f" (i),
+ "=f" (j),
+ "=f" (k),
+ "=f" (l),
+ "=f" (m),
+ "=f" (n),
+ "=f" (o),
+ "=f" (p),
+ "=f" (q));
+ __asm__ __volatile__ ("%0 %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13 %14 %15 %16" /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */
+ : "=f" (a),
+ "=f" (b),
+ "=f" (c),
+ "=f" (d),
+ "=f" (e),
+ "=f" (f),
+ "=f" (g),
+ "=f" (h),
+ "=f" (i),
+ "=f" (j),
+ "=f" (k),
+ "=f" (l),
+ "=f" (m),
+ "=f" (n),
+ "=f" (o),
+ "=f" (p),
+ "={f4}" (q));
+ }
+}
diff --git a/gcc/testsuite/gcc.target/s390/asm-hard-reg-7.c b/gcc/testsuite/gcc.target/s390/asm-hard-reg-7.c
new file mode 100644
index 0000000..923c9d2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/asm-hard-reg-7.c
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=z13" } */
+
+/* Test register pairs. */
+
+void
+test (void)
+{
+ register double f0 __asm__ ("f0");
+ register double f2 __asm__ ("f2");
+ register long double f0f2 __asm__ ("f0");
+ double x;
+ long double y;
+
+ /* Outputs */
+ __asm__ __volatile__ ("" : "=r" (f0), "=r" (f0f2));
+ __asm__ __volatile__ ("" : "=r" (f0f2), "={f0}" (y)); /* { dg-error "multiple outputs to hard register: %f0" } */
+ __asm__ __volatile__ ("" : "={f0}" (x), "=r" (f0f2)); /* { dg-error "multiple outputs to hard register: %f0" } */
+
+ __asm__ __volatile__ ("" : "=r" (f2), "=r" (f0f2));
+ __asm__ __volatile__ ("" : "={f2}" (x), "={f0}" (y)); /* { dg-error "multiple outputs to hard register: %f2" } */
+ __asm__ __volatile__ ("" : "=r" (f2), "={f0}" (y)); /* { dg-error "multiple outputs to hard register: %f2" } */
+ __asm__ __volatile__ ("" : "={f2}" (x), "=r" (f0f2)); /* { dg-error "multiple outputs to hard register: %f2" } */
+
+ /* Inputs */
+ __asm__ __volatile__ ("" :: "r" (f0), "r" (f0f2));
+ __asm__ __volatile__ ("" :: "r" (f0f2), "{f0}" (y)); /* { dg-error "multiple inputs to hard register: %f0" } */
+ __asm__ __volatile__ ("" :: "{f0}" (x), "r" (f0f2)); /* { dg-error "multiple inputs to hard register: %f0" } */
+
+ __asm__ __volatile__ ("" :: "r" (f2), "r" (f0f2));
+ __asm__ __volatile__ ("" :: "{f2}" (x), "{f0}" (y)); /* { dg-error "multiple inputs to hard register: %f2" } */
+ __asm__ __volatile__ ("" :: "r" (f2), "{f0}" (y)); /* { dg-error "multiple inputs to hard register: %f2" } */
+ __asm__ __volatile__ ("" :: "{f2}" (x), "r" (f0f2)); /* { dg-error "multiple inputs to hard register: %f2" } */
+}
diff --git a/gcc/testsuite/gcc.target/s390/asm-hard-reg-longdouble.h b/gcc/testsuite/gcc.target/s390/asm-hard-reg-longdouble.h
new file mode 100644
index 0000000..9f4adad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/asm-hard-reg-longdouble.h
@@ -0,0 +1,18 @@
+__attribute__ ((noipa))
+long double
+test_longdouble (long double x)
+{
+ long double y;
+ asm ("sqxbr\t%0,%1" : "={f4}" (y) : "{f5}" (x));
+ return y;
+}
+
+int
+main (void)
+{
+ long double x = test_longdouble (42.L);
+ long double y = 6.48074069840786023096596743608799656681773277430814773408787249757445105002862106857719481922686100006103515625L;
+ if (x != y)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gfortran.dg/array_constructor_58.f90 b/gcc/testsuite/gfortran.dg/array_constructor_58.f90
new file mode 100644
index 0000000..1473be0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/array_constructor_58.f90
@@ -0,0 +1,17 @@
+!{ dg-do run }
+
+! Contributed by Federico Perini <federico.perini@gmail.com>
+! Check that PR fortran/119106 is fixed.
+
+program char_param_array
+implicit none
+character, parameter :: p(5) = ['1','2','3','4','5']
+character, save :: n(5) = ['1','2','3','4','5']
+integer :: i(10), j
+
+i = 4
+if (any([(n(i(j)),j=1,10)] /= '4')) stop 1 ! OK
+if (any([(p(i(j)),j=1,10)] /= '4')) stop 2 ! used to runtime out-of-bounds error
+
+end program char_param_array
+
diff --git a/gcc/testsuite/gfortran.dg/assign_13.f90 b/gcc/testsuite/gfortran.dg/assign_13.f90
new file mode 100644
index 0000000..262ade0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/assign_13.f90
@@ -0,0 +1,25 @@
+! { dg-do run }
+!
+! PR fortran/121185
+! The assignment to Y%X in CHECK_T was using a polymorphic array access on the
+! left hand side, using the virtual table of Y.
+
+program p
+ implicit none
+ type t
+ complex, allocatable :: x(:)
+ end type t
+ real :: trace = 2.
+ type(t) :: z
+ z%x = [1,2] * trace
+ call check_t (z)
+contains
+ subroutine check_t (y)
+ class(t) :: y
+ ! print *, y% x
+ if (any(y%x /= [2., 4.])) error stop 11
+ y%x = y%x / trace
+ ! print *, y% x
+ if (any(y%x /= [1., 2.])) error stop 12
+ end subroutine
+end
diff --git a/gcc/testsuite/gfortran.dg/assign_14.f90 b/gcc/testsuite/gfortran.dg/assign_14.f90
new file mode 100644
index 0000000..33b46b9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/assign_14.f90
@@ -0,0 +1,24 @@
+! { dg-do compile }
+! { dg-additional-options {-fdump-tree-original} }
+!
+! PR fortran/121185
+! Check that an intermediary variable is used to reference component a.
+! { dg-final { scan-tree-dump-not {->b->a} original } }
+
+program p
+ implicit none
+ type t
+ integer, allocatable :: a(:)
+ end type t
+ type u
+ type(t), allocatable :: b
+ end type u
+ type v
+ type(u), allocatable :: c
+ end type v
+ type(v) :: z
+ z%c = u()
+ z%c%b = t()
+ z%c%b%a = [1,2]
+ z%c%b%a = z%c%b%a * 2
+end
diff --git a/gcc/testsuite/gfortran.dg/function_charlen_4.f90 b/gcc/testsuite/gfortran.dg/function_charlen_4.f90
new file mode 100644
index 0000000..ed39aca
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/function_charlen_4.f90
@@ -0,0 +1,34 @@
+! { dg-do run }
+! { dg-options "-O2 -std=legacy -fdump-tree-optimized" }
+!
+! PR fortran/121203 - fix passing of character length of function to procedure
+
+program p
+ character(10), external :: f
+ call eval (f,"abc")
+ call eval2(f,"abc")
+contains
+ subroutine eval2(func,c_arg)
+ character(*) c_arg
+ character(*) func
+ external func
+ ! These tests should get optimized:
+ if (len (c_arg) /= 3) stop 1
+ if (len (func(c_arg)) /= 10) stop 2
+ end subroutine
+end
+
+character(10) function f(arg)
+ character(*) arg
+ f=arg
+end
+
+subroutine eval(func,c_arg)
+ character(*) c_arg
+ character(*) func
+ external func
+ if (len (c_arg) /= 3) error stop 3
+ if (len (func(c_arg)) /= 10) error stop 4
+end subroutine
+
+! { dg-final { scan-tree-dump-not "_gfortran_stop_numeric" "optimized" } }
diff --git a/gcc/testsuite/gfortran.dg/pointer_check_15.f90 b/gcc/testsuite/gfortran.dg/pointer_check_15.f90
new file mode 100644
index 0000000..13c6820
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pointer_check_15.f90
@@ -0,0 +1,46 @@
+! { dg-do run }
+! { dg-additional-options "-O -fcheck=pointer -fdump-tree-original" }
+!
+! PR fortran/121145
+! Erroneous runtime error: Proc-pointer actual argument 'ptr' is not associated
+!
+! Contributed by Federico Perini.
+
+module m
+ implicit none
+
+ abstract interface
+ subroutine fun(x)
+ real, intent(in) :: x
+ end subroutine fun
+ end interface
+
+contains
+
+ subroutine with_fun(sub)
+ procedure(fun), optional :: sub
+ if (present(sub)) stop 1
+ end subroutine
+
+ subroutine with_non_optional(sub)
+ procedure(fun) :: sub
+ end subroutine
+
+end module m
+
+program p
+ use m
+ implicit none
+
+ procedure(fun), pointer :: ptr1 => null()
+ procedure(fun), pointer :: ptr2 => null()
+
+ call with_fun()
+ call with_fun(sub=ptr1) ! no runtime check here
+
+ if (associated (ptr2)) then
+ call with_non_optional(sub=ptr2) ! runtime check here
+ end if
+end
+
+! { dg-final { scan-tree-dump-times "Proc-pointer actual argument .'ptr2.'" 1 "original" } }
diff --git a/gcc/testsuite/gm2/switches/pedantic-params/fail/arrayofchar.def b/gcc/testsuite/gm2/switches/pedantic-params/fail/arrayofchar.def
new file mode 100644
index 0000000..a24f7d3
--- /dev/null
+++ b/gcc/testsuite/gm2/switches/pedantic-params/fail/arrayofchar.def
@@ -0,0 +1,12 @@
+DEFINITION MODULE arrayofchar ;
+
+FROM FIO IMPORT File ;
+
+(*
+ Description: provides write procedures for ARRAY OF CHAR.
+*)
+
+PROCEDURE Write (f: File; str: ARRAY OF CHAR) ;
+PROCEDURE WriteLn (f: File) ;
+
+END arrayofchar.
diff --git a/gcc/testsuite/gm2/switches/pedantic-params/fail/arrayofchar.mod b/gcc/testsuite/gm2/switches/pedantic-params/fail/arrayofchar.mod
new file mode 100644
index 0000000..4e630a9
--- /dev/null
+++ b/gcc/testsuite/gm2/switches/pedantic-params/fail/arrayofchar.mod
@@ -0,0 +1,30 @@
+IMPLEMENTATION MODULE arrayofchar ;
+
+FROM FIO IMPORT WriteChar, WriteLine ;
+IMPORT StrLib ;
+
+
+(*
+ Write - writes a string to file f.
+*)
+
+PROCEDURE Write (f: File; a: ARRAY OF CHAR) ;
+VAR
+ len, i: CARDINAL ;
+BEGIN
+ len := StrLib.StrLen (a) ;
+ i := 0 ;
+ WHILE i < len DO
+ WriteChar (f, a[i]) ;
+ INC (i)
+ END
+END Write ;
+
+
+PROCEDURE WriteLn (f: File) ;
+BEGIN
+ WriteLine (f)
+END WriteLn ;
+
+
+END arrayofchar.
diff --git a/gcc/testsuite/lib/gcc-defs.exp b/gcc/testsuite/lib/gcc-defs.exp
index 2f8b7d4..d66c833 100644
--- a/gcc/testsuite/lib/gcc-defs.exp
+++ b/gcc/testsuite/lib/gcc-defs.exp
@@ -599,15 +599,16 @@ proc aarch64-arch-dg-options { args } {
set add_arch 1
set add_tune 1
+ set add_override 1
set checks_output [string equal [lindex $do_what 0] "compile"]
set options [lindex $args 1]
foreach option [split $options] {
switch -glob -- $option {
-march=* { set add_arch 0 }
- -mcpu=* { set add_arch 0; set add_tune 0 }
- -mtune=* { set add_tune 0 }
- -moverride=* { set add_tune 0 }
+ -mcpu=* { set add_arch 0; set add_tune 0; set add_override 0}
+ -mtune=* { set add_tune 0; set add_override 0 }
+ -moverride=* { set add_override 0 }
-save-temps { set checks_output 1 }
--save-temps { set checks_output 1 }
-fdump* { set checks_output 1 }
@@ -619,9 +620,14 @@ proc aarch64-arch-dg-options { args } {
append options " $aarch64_default_testing_arch"
}
- if { $add_tune && $checks_output } {
+ if { $checks_output } {
# Turn off any default tuning and codegen tweaks.
- append options " -mtune=generic -moverride=tune=none"
+ if { $add_tune } {
+ append options " -mtune=generic"
+ }
+ if { $add_override } {
+ append options " -moverride=tune=none"
+ }
}
uplevel 1 aarch64-old-dg-options [lreplace $args 1 1 $options]
diff --git a/gcc/testsuite/lib/gcc-dg.exp b/gcc/testsuite/lib/gcc-dg.exp
index 312c4b8..859a943 100644
--- a/gcc/testsuite/lib/gcc-dg.exp
+++ b/gcc/testsuite/lib/gcc-dg.exp
@@ -1338,8 +1338,8 @@ proc dg-missed { args } {
}
# Look for messages with 'note: ' prefixes.
-# In addition to standard compiler diagnostics ('DK_NOTE', 'inform' functions,
-# "for additional details on an error message"),
+# In addition to standard compiler diagnostics (diagnostics::kind::note,
+# 'inform' functions, "for additional details on an error message"),
# this also includes output from '-fopt-info' for 'MSG_NOTE':
# a general optimization info.
# By default, any *excess* notes are pruned, meaning their appearance doesn't
diff --git a/gcc/testsuite/lib/sarif.py b/gcc/testsuite/lib/sarif.py
index 06d05c0..d75a87e 100644
--- a/gcc/testsuite/lib/sarif.py
+++ b/gcc/testsuite/lib/sarif.py
@@ -30,7 +30,7 @@ def get_result_by_index(sarif, idx):
return results[idx]
def get_state_graph(events, event_idx):
- graph = events[event_idx]['properties']['gcc/diagnostic_event/state_graph']
+ graph = events[event_idx]['properties']['gcc/diagnostics/paths/event/state_graph']
if 0:
print(graph)
assert graph is not None
diff --git a/gcc/testsuite/lib/scanasm.exp b/gcc/testsuite/lib/scanasm.exp
index a2311de..51952a6 100644
--- a/gcc/testsuite/lib/scanasm.exp
+++ b/gcc/testsuite/lib/scanasm.exp
@@ -896,6 +896,10 @@ proc configure_check-function-bodies { config } {
set up_config(fluff) {^\s*(?://)}
} elseif { [istarget *-*-darwin*] } {
set up_config(fluff) {^\s*(?:\.|//|@)|^L[0-9ABCESV]}
+ } elseif { [istarget s390*-*-*] } {
+ # Additionally to the defaults skip lines beginning with a # resulting
+ # from inline asm.
+ set up_config(fluff) {^\s*(?:\.|//|@|$|#)}
} else {
# Skip lines beginning with labels ('.L[...]:') or other directives
# ('.align', '.cfi_startproc', '.quad [...]', '.text', etc.), '//' or
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 65d2e67..e375b1e 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1017,6 +1017,18 @@ proc check_effective_target_label_values {} {
return 1
}
+
+# Return 1 if builtin_trap expands not into a call but an instruction,
+# 0 otherwise.
+proc check_effective_target_trap { } {
+ return [check_no_messages_and_pattern trap "!\\(call" rtl-expand {
+ void foo ()
+ {
+ return __builtin_trap ();
+ }
+ } "" ]
+}
+
# Return 1 if builtin_return_address and builtin_frame_address are
# supported, 0 otherwise.
@@ -2428,7 +2440,7 @@ proc check_effective_target_riscv_v_misalign_ok { } {
= {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
asm ("vsetivli zero,7,e8,m1,ta,ma");
asm ("addi a7,%0,1" : : "r" (a) : "a7" );
- asm ("vle8.v v8,0(a7)" : : : "v8");
+ asm ("vle16.v v8,0(a7)" : : : "v8");
return 0; } } "-march=${gcc_march}"] } {
return 1
}
@@ -2685,6 +2697,14 @@ proc remove_options_for_riscv_zvbb { flags } {
return [add_options_for_riscv_z_ext zvbb $flags]
}
+proc add_options_for_riscv_zvfh { flags } {
+ return [add_options_for_riscv_z_ext zvfh $flags]
+}
+
+proc remove_options_for_riscv_zvfh { flags } {
+ return [add_options_for_riscv_z_ext zvfh $flags]
+}
+
# Return 1 if the target is ia32 or x86_64.
proc check_effective_target_x86 { } {
diff --git a/gcc/text-art/style.cc b/gcc/text-art/style.cc
index ffc75b6..40886d6 100644
--- a/gcc/text-art/style.cc
+++ b/gcc/text-art/style.cc
@@ -29,7 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "text-art/selftests.h"
#include "text-art/types.h"
#include "color-macros.h"
-#include "diagnostic-color.h"
+#include "diagnostics/color.h"
using namespace text_art;
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 00a8ccb..70dbb3e 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -81,7 +81,8 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-utils.h"
#include "gcse.h"
#include "omp-offload.h"
-#include "edit-context.h"
+#include "diagnostics/changes.h"
+#include "diagnostics/file-cache.h"
#include "tree-pass.h"
#include "dumpfile.h"
#include "ipa-fnsummary.h"
@@ -230,7 +231,8 @@ announce_function (tree decl)
identifier_to_locale (lang_hooks.decl_printable_name (decl, 2)));
fflush (stderr);
pp_needs_newline (global_dc->get_reference_printer ()) = true;
- diagnostic_set_last_function (global_dc, (diagnostic_info *) NULL);
+ diagnostic_set_last_function (global_dc,
+ (diagnostics::diagnostic_info *) nullptr);
}
}
@@ -1017,7 +1019,7 @@ open_auxiliary_file (const char *ext)
/* Alternative diagnostics callback for reentered ICE reporting. */
static void
-internal_error_reentered (diagnostic_context *, const char *, va_list *)
+internal_error_reentered (diagnostics::context *, const char *, va_list *)
{
/* Flush the dump file if emergency_dump_function itself caused an ICE. */
if (dump_file)
@@ -1027,7 +1029,7 @@ internal_error_reentered (diagnostic_context *, const char *, va_list *)
/* Auxiliary callback for the diagnostics code. */
static void
-internal_error_function (diagnostic_context *, const char *, va_list *)
+internal_error_function (diagnostics::context *, const char *, va_list *)
{
global_dc->set_internal_error_callback (internal_error_reentered);
warn_if_plugins ();
@@ -1068,13 +1070,14 @@ general_init (const char *argv0, bool init_signals, unique_argv original_argv)
global_dc->set_original_argv (std::move (original_argv));
- global_dc->m_source_printing.enabled
+ auto &source_printing_opts = global_dc->get_source_printing_options ();
+ source_printing_opts.enabled
= global_options_init.x_flag_diagnostics_show_caret;
- global_dc->m_source_printing.show_event_links_p
+ source_printing_opts.show_event_links_p
= global_options_init.x_flag_diagnostics_show_event_links;
- global_dc->m_source_printing.show_labels_p
+ source_printing_opts.show_labels_p
= global_options_init.x_flag_diagnostics_show_labels;
- global_dc->m_source_printing.show_line_numbers_p
+ source_printing_opts.show_line_numbers_p
= global_options_init.x_flag_diagnostics_show_line_numbers;
global_dc->set_show_cwe (global_options_init.x_flag_diagnostics_show_cwe);
global_dc->set_show_rules (global_options_init.x_flag_diagnostics_show_rules);
@@ -1085,7 +1088,7 @@ general_init (const char *argv0, bool init_signals, unique_argv original_argv)
(global_options_init.x_flag_diagnostics_show_path_depths);
global_dc->set_show_option_requested
(global_options_init.x_flag_diagnostics_show_option);
- global_dc->m_source_printing.min_margin_width
+ source_printing_opts.min_margin_width
= global_options_init.x_diagnostics_minimum_margin_width;
global_dc->m_show_column
= global_options_init.x_flag_show_column;
@@ -1285,7 +1288,7 @@ process_options ()
input_location = saved_location;
if (flag_diagnostics_generate_patch)
- global_dc->create_edit_context ();
+ global_dc->initialize_fixits_change_set ();
/* Avoid any informative notes in the second run of -fcompare-debug. */
if (flag_compare_debug)
@@ -1748,11 +1751,13 @@ process_options ()
if (warn_coverage_mismatch
&& option_unspecified_p (OPT_Wcoverage_mismatch))
diagnostic_classify_diagnostic (global_dc, OPT_Wcoverage_mismatch,
- DK_ERROR, UNKNOWN_LOCATION);
+ diagnostics::kind::error,
+ UNKNOWN_LOCATION);
if (warn_coverage_invalid_linenum
&& option_unspecified_p (OPT_Wcoverage_invalid_line_number))
diagnostic_classify_diagnostic (global_dc, OPT_Wcoverage_invalid_line_number,
- DK_ERROR, UNKNOWN_LOCATION);
+ diagnostics::kind::error,
+ UNKNOWN_LOCATION);
}
/* Save the current optimization options. */
@@ -1815,6 +1820,10 @@ backend_init_target (void)
static void
backend_init (void)
{
+#if CHECKING_P
+ verify_reg_names_in_constraints ();
+#endif
+
init_emit_once ();
init_rtlanal ();
@@ -2385,11 +2394,11 @@ toplev::main (int argc, char **argv)
emit some diagnostics here. */
invoke_plugin_callbacks (PLUGIN_FINISH, NULL);
- if (auto edit_context_ptr = global_dc->get_edit_context ())
+ if (auto change_set_ptr = global_dc->get_fixits_change_set ())
{
pretty_printer pp;
pp_show_color (&pp) = pp_show_color (global_dc->get_reference_printer ());
- edit_context_ptr->print_diff (&pp, true);
+ change_set_ptr->print_diff (&pp, true);
pp_flush (&pp);
}
diff --git a/gcc/tree-cfgcleanup.cc b/gcc/tree-cfgcleanup.cc
index a34a51e..5aaa18d 100644
--- a/gcc/tree-cfgcleanup.cc
+++ b/gcc/tree-cfgcleanup.cc
@@ -47,6 +47,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-into-ssa.h"
#include "tree-cfgcleanup.h"
#include "gimple-pretty-print.h"
+#include "target.h"
/* The set of blocks in that at least one of the following changes happened:
@@ -1569,6 +1570,29 @@ execute_cleanup_cfg_post_optimizing (void)
cleanup_dead_labels ();
if (group_case_labels ())
todo |= TODO_cleanup_cfg;
+
+ basic_block bb = single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb);
+ /* If the first (and only) bb and the only non debug
+ statement is __builtin_unreachable call, then replace it with a trap
+ so the function is at least one instruction in size. */
+ if (!gsi_end_p (gsi)
+ && gimple_call_builtin_p (gsi_stmt (gsi), BUILT_IN_UNREACHABLE))
+ {
+ if (targetm.have_trap ())
+ {
+ gimple_call_set_fndecl (gsi_stmt (gsi), builtin_decl_implicit (BUILT_IN_UNREACHABLE_TRAP));
+ update_stmt (gsi_stmt (gsi));
+ }
+ /* If the target does not have a trap, convert it into an infinite loop. */
+ else
+ {
+ gsi_remove (&gsi, true);
+ make_single_succ_edge (bb, bb, EDGE_FALLTHRU);
+ fix_loop_structure (NULL);
+ }
+ }
+
if ((flag_compare_debug_opt || flag_compare_debug)
&& flag_dump_final_insns)
{
diff --git a/gcc/tree-diagnostic-client-data-hooks.cc b/gcc/tree-diagnostic-client-data-hooks.cc
index 84bd4b5..77eb292 100644
--- a/gcc/tree-diagnostic-client-data-hooks.cc
+++ b/gcc/tree-diagnostic-client-data-hooks.cc
@@ -1,4 +1,4 @@
-/* Implementation of diagnostic_client_data_hooks for the compilers
+/* Implementation of diagnostics::client_data_hooks for the compilers
(e.g. with knowledge of "tree", lang_hooks, and timevars).
Copyright (C) 2022-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -26,18 +26,18 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "diagnostic.h"
#include "tree-logical-location.h"
-#include "diagnostic-client-data-hooks.h"
-#include "diagnostic-format-sarif.h"
+#include "diagnostics/client-data-hooks.h"
+#include "diagnostics/sarif-sink.h"
#include "langhooks.h"
#include "plugin.h"
#include "timevar.h"
-/* Concrete class for supplying a diagnostic_context with information
+/* Concrete class for supplying a diagnostics::context with information
about a specific plugin within the client, when the client is the
compiler (i.e. a GCC plugin). */
class compiler_diagnostic_client_plugin_info
- : public diagnostic_client_plugin_info
+ : public diagnostics::client_plugin_info
{
public:
compiler_diagnostic_client_plugin_info (const plugin_name_args *args)
@@ -67,7 +67,7 @@ private:
/* Concrete subclass of client_version_info for use by compilers proper,
(i.e. using lang_hooks, and with knowledge of GCC plugins). */
-class compiler_version_info : public client_version_info
+class compiler_version_info : public diagnostics::client_version_info
{
public:
const char *get_tool_name () const final override
@@ -112,23 +112,26 @@ private:
}
};
-/* Subclass of diagnostic_client_data_hooks for use by compilers proper
+/* Subclass of diagnostics::client_data_hooks for use by compilers proper
i.e. with knowledge of "tree", access to langhooks, timevars etc. */
-class compiler_data_hooks : public diagnostic_client_data_hooks
+class compiler_data_hooks : public diagnostics::client_data_hooks
{
public:
- const client_version_info *get_any_version_info () const final override
+ const diagnostics::client_version_info *
+ get_any_version_info () const final override
{
return &m_version_info;
}
- const logical_location_manager *get_logical_location_manager () const final override
+ const diagnostics::logical_locations::manager *
+ get_logical_location_manager () const final override
{
return &m_logical_location_manager;
}
- logical_location_manager::key get_current_logical_location () const final override
+ diagnostics::logical_locations::key
+ get_current_logical_location () const final override
{
return m_logical_location_manager.key_from_tree (current_function_decl);
}
@@ -140,13 +143,13 @@ public:
}
void
- add_sarif_invocation_properties (sarif_object &invocation_obj)
+ add_sarif_invocation_properties (diagnostics::sarif_object &invocation_obj)
const final override
{
if (g_timer)
if (auto timereport_val = g_timer->make_json ())
{
- sarif_property_bag &bag_obj
+ auto &bag_obj
= invocation_obj.get_or_create_properties ();
bag_obj.set ("gcc/timeReport", std::move (timereport_val));
@@ -167,7 +170,7 @@ private:
/* Create a compiler_data_hooks (so that the class can be local
to this file). */
-std::unique_ptr<diagnostic_client_data_hooks>
+std::unique_ptr<diagnostics::client_data_hooks>
make_compiler_data_hooks ()
{
return std::make_unique<compiler_data_hooks> ();
diff --git a/gcc/tree-diagnostic.cc b/gcc/tree-diagnostic.cc
index 57c6715..3761fc0 100644
--- a/gcc/tree-diagnostic.cc
+++ b/gcc/tree-diagnostic.cc
@@ -27,29 +27,29 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pretty-print.h"
#include "gimple-pretty-print.h"
#include "tree-diagnostic.h"
-#include "diagnostic-client-data-hooks.h"
+#include "diagnostics/client-data-hooks.h"
#include "langhooks.h"
#include "intl.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/text-sink.h"
/* Prints out, if necessary, the name of the current function
that caused an error. */
void
-diagnostic_report_current_function (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic)
+diagnostic_report_current_function (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diag)
{
- location_t loc = diagnostic_location (diagnostic);
+ location_t loc = diagnostic_location (diag);
text_output.report_current_module (loc);
- lang_hooks.print_error_function (text_output, LOCATION_FILE (loc), diagnostic);
+ lang_hooks.print_error_function (text_output, LOCATION_FILE (loc), diag);
}
static void
-default_tree_diagnostic_text_starter (diagnostic_text_output_format &text_output,
- const diagnostic_info *diagnostic)
+default_tree_diagnostic_text_starter (diagnostics::text_sink &text_output,
+ const diagnostics::diagnostic_info *diag)
{
pretty_printer *const pp = text_output.get_printer ();
- diagnostic_report_current_function (text_output, diagnostic);
- pp_set_prefix (pp, text_output.build_prefix (*diagnostic));
+ diagnostic_report_current_function (text_output, diag);
+ pp_set_prefix (pp, text_output.build_prefix (*diag));
}
/* Default tree printer. Handles declarations only. */
@@ -110,8 +110,8 @@ default_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
to the DIAGNOSTIC location. */
static void
-set_inlining_locations (diagnostic_context *,
- diagnostic_info *diagnostic)
+set_inlining_locations (diagnostics::context *,
+ diagnostics::diagnostic_info *diagnostic)
{
location_t loc = diagnostic_location (diagnostic);
tree block = LOCATION_BLOCK (loc);
@@ -169,16 +169,16 @@ set_inlining_locations (diagnostic_context *,
/* Set if all locations are in a system header. */
diagnostic->m_iinfo.m_allsyslocs = nsyslocs == ilocs.length ();
- if (tree *ao = pp_ti_abstract_origin (&diagnostic->message))
+ if (tree *ao = pp_ti_abstract_origin (&diagnostic->m_message))
*ao = (tree)diagnostic->m_iinfo.m_ao;
}
/* Sets CONTEXT to use language independent diagnostics. */
void
-tree_diagnostics_defaults (diagnostic_context *context)
+tree_diagnostics_defaults (diagnostics::context *context)
{
- diagnostic_text_starter (context) = default_tree_diagnostic_text_starter;
- diagnostic_text_finalizer (context) = default_diagnostic_text_finalizer;
+ diagnostics::text_starter (context) = default_tree_diagnostic_text_starter;
+ diagnostics::text_finalizer (context) = diagnostics::default_text_finalizer;
context->set_format_decoder (default_tree_printer);
context->set_set_locations_callback (set_inlining_locations);
context->set_client_data_hooks (make_compiler_data_hooks ());
diff --git a/gcc/tree-diagnostic.h b/gcc/tree-diagnostic.h
index b138b8b..9315d35 100644
--- a/gcc/tree-diagnostic.h
+++ b/gcc/tree-diagnostic.h
@@ -48,10 +48,10 @@ along with GCC; see the file COPYING3. If not see
? diagnostic_abstract_origin (DI) \
: current_function_decl)
-void diagnostic_report_current_function (diagnostic_context *,
- const diagnostic_info *);
+void diagnostic_report_current_function (diagnostics::context *,
+ const diagnostics::diagnostic_info *);
-void tree_diagnostics_defaults (diagnostic_context *context);
+void tree_diagnostics_defaults (diagnostics::context *);
bool default_tree_printer (pretty_printer *, text_info *, const char *,
int, bool, bool, bool, bool *, pp_token_list &);
diff --git a/gcc/tree-logical-location.cc b/gcc/tree-logical-location.cc
index 1d0cc58..19bccd1 100644
--- a/gcc/tree-logical-location.cc
+++ b/gcc/tree-logical-location.cc
@@ -27,6 +27,8 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "intl.h"
+using namespace diagnostics::logical_locations;
+
static void
assert_valid_tree (const_tree node)
{
@@ -35,7 +37,8 @@ assert_valid_tree (const_tree node)
gcc_assert (TREE_CODE (node) != TRANSLATION_UNIT_DECL);
}
-/* class tree_logical_location_manager : public logical_location_manager. */
+/* class tree_logical_location_manager
+ : public diagnostics::logical_locations::manager. */
const char *
tree_logical_location_manager::get_short_name (key k) const
@@ -81,7 +84,7 @@ tree_logical_location_manager::get_internal_name (key k) const
return NULL;
}
-enum logical_location_kind
+enum kind
tree_logical_location_manager::get_kind (key k) const
{
tree node = tree_from_key (k);
@@ -90,18 +93,18 @@ tree_logical_location_manager::get_kind (key k) const
switch (TREE_CODE (node))
{
default:
- return logical_location_kind::unknown;
+ return kind::unknown;
case FUNCTION_DECL:
- return logical_location_kind::function;
+ return kind::function;
case PARM_DECL:
- return logical_location_kind::parameter;
+ return kind::parameter;
case VAR_DECL:
- return logical_location_kind::variable;
+ return kind::variable;
case NAMESPACE_DECL:
- return logical_location_kind::namespace_;
+ return kind::namespace_;
case RECORD_TYPE:
- return logical_location_kind::type;
+ return kind::type;
}
}
@@ -123,7 +126,7 @@ tree_logical_location_manager::get_name_for_path_output (key k) const
return label_text ();
}
-logical_location
+key
tree_logical_location_manager::get_parent (key k) const
{
tree node = tree_from_key (k);
@@ -132,16 +135,16 @@ tree_logical_location_manager::get_parent (key k) const
if (DECL_P (node))
{
if (!DECL_CONTEXT (node))
- return logical_location ();
+ return key ();
if (TREE_CODE (DECL_CONTEXT (node)) == TRANSLATION_UNIT_DECL)
- return logical_location ();
+ return key ();
return key_from_tree (DECL_CONTEXT (node));
}
else if (TYPE_P (node))
{
if (!TYPE_CONTEXT (node))
- return logical_location ();
+ return key ();
return key_from_tree (TYPE_CONTEXT (node));
}
- return logical_location ();
+ return key ();
}
diff --git a/gcc/tree-logical-location.h b/gcc/tree-logical-location.h
index 0d57888..2a7de37 100644
--- a/gcc/tree-logical-location.h
+++ b/gcc/tree-logical-location.h
@@ -21,29 +21,33 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_TREE_LOGICAL_LOCATION_H
#define GCC_TREE_LOGICAL_LOCATION_H
-#include "logical-location.h"
+#include "diagnostics/logical-locations.h"
-/* A subclass of logical_location_manager in which the keys are
- "tree".
+/* A subclass of diagnostics::logical_locations::manager in which the
+ keys are "tree".
Note that there is no integration with the garbage collector,
- and so logical_location instances can only be short-lived. */
-class tree_logical_location_manager : public logical_location_manager
+ and so key instances can only be short-lived. */
+class tree_logical_location_manager
+ : public diagnostics::logical_locations::manager
{
public:
+ using key = diagnostics::logical_locations::key;
+ using kind = diagnostics::logical_locations::kind;
+
const char *get_short_name (key) const final override;
const char *get_name_with_scope (key) const final override;
const char *get_internal_name (key) const final override;
- enum logical_location_kind get_kind (key) const final override;
+ kind get_kind (key) const final override;
label_text get_name_for_path_output (key) const final override;
key get_parent (key) const final override;
- static tree tree_from_key (logical_location k)
+ static tree tree_from_key (key k)
{
return const_cast<tree> (k.cast_to<const_tree> ());
}
- static logical_location key_from_tree (tree node)
+ static key key_from_tree (tree node)
{
- return logical_location::from_ptr (node);
+ return key::from_ptr (node);
}
};
diff --git a/gcc/tree-sra.cc b/gcc/tree-sra.cc
index 23236fc..032f277 100644
--- a/gcc/tree-sra.cc
+++ b/gcc/tree-sra.cc
@@ -2504,6 +2504,12 @@ sort_and_splice_var_accesses (tree var)
}
unscalarizable_region = true;
}
+ /* If there the same place is accessed with two incompatible
+ aggregate types, trying to base total scalarization on either of
+ them can be wrong. */
+ if (!first_scalar && !types_compatible_p (access->type, ac2->type))
+ bitmap_set_bit (cannot_scalarize_away_bitmap,
+ DECL_UID (access->base));
if (grp_same_access_path
&& (!ac2->grp_same_access_path
@@ -2889,7 +2895,10 @@ analyze_access_subtree (struct access *root, struct access *parent,
for (child = root->first_child; child; child = child->next_sibling)
{
- hole |= covered_to < child->offset;
+ if (totally)
+ covered_to = child->offset;
+ else
+ hole |= covered_to < child->offset;
sth_created |= analyze_access_subtree (child, root,
allow_replacements && !scalar
&& !root->grp_partial_lhs,
@@ -2900,6 +2909,8 @@ analyze_access_subtree (struct access *root, struct access *parent,
covered_to += child->size;
else
hole = true;
+ if (totally && !hole)
+ covered_to = limit;
}
if (allow_replacements && scalar && !root->first_child
@@ -2972,7 +2983,7 @@ analyze_access_subtree (struct access *root, struct access *parent,
root->grp_total_scalarization = 0;
}
- if (!hole || totally)
+ if (!hole)
root->grp_covered = 1;
else if (root->grp_write || comes_initialized_p (root->base))
root->grp_unscalarized_data = 1; /* not covered and written to */
diff --git a/gcc/tree-ssa-operands.cc b/gcc/tree-ssa-operands.cc
index 4eb9673..a5970ac 100644
--- a/gcc/tree-ssa-operands.cc
+++ b/gcc/tree-ssa-operands.cc
@@ -721,7 +721,7 @@ operands_scanner::get_asm_stmt_operands (gasm *stmt)
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
oconstraints[i] = constraint;
parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
- &allows_reg, &is_inout);
+ &allows_reg, &is_inout, nullptr);
/* This should have been split in gimplify_asm_expr. */
gcc_assert (!allows_reg || !is_inout);
@@ -740,7 +740,7 @@ operands_scanner::get_asm_stmt_operands (gasm *stmt)
tree link = gimple_asm_input_op (stmt, i);
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
parse_input_constraint (&constraint, 0, 0, noutputs, 0, oconstraints,
- &allows_mem, &allows_reg);
+ &allows_mem, &allows_reg, nullptr);
/* Memory operands are addressable. Note that STMT needs the
address of this operand. */
diff --git a/gcc/tree-ssa-sink.cc b/gcc/tree-ssa-sink.cc
index 959e0d5..2244e89f 100644
--- a/gcc/tree-ssa-sink.cc
+++ b/gcc/tree-ssa-sink.cc
@@ -356,37 +356,54 @@ statement_sink_location (gimple *stmt, basic_block frombb,
use = NULL;
- /* If stmt is a store the one and only use needs to be the VOP
- merging PHI node. */
+ /* If stmt is a store the one and only use needs to be a VUSE on
+ the live path. */
if (virtual_operand_p (DEF_FROM_PTR (def_p)))
{
+ tree lhs = gimple_get_lhs (stmt);
+ ao_ref ref;
+ ao_ref_init (&ref, lhs);
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, DEF_FROM_PTR (def_p))
{
gimple *use_stmt = USE_STMT (use_p);
/* A killing definition is not a use. */
- if ((gimple_has_lhs (use_stmt)
- && operand_equal_p (gimple_get_lhs (stmt),
- gimple_get_lhs (use_stmt), 0))
- || stmt_kills_ref_p (use_stmt, gimple_get_lhs (stmt)))
+ if (gimple_vdef (use_stmt)
+ && ((gimple_has_lhs (use_stmt)
+ && operand_equal_p (lhs,
+ gimple_get_lhs (use_stmt), 0))
+ || stmt_kills_ref_p (use_stmt, &ref)))
{
/* If use_stmt is or might be a nop assignment then USE_STMT
acts as a use as well as definition. */
if (stmt != use_stmt
- && ref_maybe_used_by_stmt_p (use_stmt,
- gimple_get_lhs (stmt)))
- return false;
+ && ref_maybe_used_by_stmt_p (use_stmt, &ref))
+ {
+ if (use && use != use_stmt)
+ return false;
+ use = use_stmt;
+ }
continue;
}
- if (gimple_code (use_stmt) != GIMPLE_PHI)
- return false;
-
- if (use
- && use != use_stmt)
- return false;
+ if (is_a <gphi *> (use_stmt)
+ || ref_maybe_used_by_stmt_p (use_stmt, &ref))
+ {
+ if (use && use != use_stmt)
+ return false;
+ use = use_stmt;
+ continue;
+ }
- use = use_stmt;
+ if (gimple_vdef (use_stmt))
+ {
+ if (stmt_may_clobber_ref_p_1 (use_stmt, &ref, false))
+ return false;
+ /* We do not look past VDEFs, so treat them as sink location. */
+ if (use && use != use_stmt)
+ return false;
+ use = use_stmt;
+ }
}
if (!use)
return false;
@@ -448,18 +465,26 @@ statement_sink_location (gimple *stmt, basic_block frombb,
break;
}
use = USE_STMT (one_use);
+ }
- if (gimple_code (use) != GIMPLE_PHI)
- {
- sinkbb = select_best_block (frombb, gimple_bb (use), stmt);
+ if (gimple_code (use) != GIMPLE_PHI)
+ {
+ sinkbb = select_best_block (frombb, gimple_bb (use), stmt);
- if (sinkbb == frombb)
- return false;
+ if (sinkbb == frombb)
+ return false;
- *togsi = gsi_after_labels (sinkbb);
+ /* The SSA update for sinking of stores cannot insert PHIs, the
+ sink location has to lead to exit without crossing any CFG
+ merge points to paths not dominated by the sink location. */
+ if (gimple_vdef (stmt)
+ && (!single_succ_p (sinkbb)
+ || single_succ (sinkbb)->index != EXIT_BLOCK))
+ return false;
- return true;
- }
+ *togsi = gsi_after_labels (sinkbb);
+
+ return true;
}
sinkbb = find_bb_for_arg (as_a <gphi *> (use), DEF_FROM_PTR (def_p));
diff --git a/gcc/tree-ssa-structalias.cc b/gcc/tree-ssa-structalias.cc
index fd22a94..0035e50 100644
--- a/gcc/tree-ssa-structalias.cc
+++ b/gcc/tree-ssa-structalias.cc
@@ -3068,7 +3068,7 @@ find_func_aliases (struct function *fn, gimple *origt)
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
oconstraints[i] = constraint;
parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
- &allows_reg, &is_inout);
+ &allows_reg, &is_inout, nullptr);
/* A memory constraint makes the address of the operand escape. */
if (!allows_reg && allows_mem)
@@ -3101,7 +3101,7 @@ find_func_aliases (struct function *fn, gimple *origt)
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
parse_input_constraint (&constraint, 0, 0, noutputs, 0, oconstraints,
- &allows_mem, &allows_reg);
+ &allows_mem, &allows_reg, nullptr);
/* A memory constraint makes the address of the operand escape. */
if (!allows_reg && allows_mem)
diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc
index c84cd29..3bf2852 100644
--- a/gcc/tree-vect-data-refs.cc
+++ b/gcc/tree-vect-data-refs.cc
@@ -3956,8 +3956,7 @@ vect_vfa_access_size (vec_info *vinfo, dr_vec_info *dr_info)
}
tree vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
int misalignment;
- if (STMT_VINFO_VEC_STMTS (stmt_vinfo).exists ()
- && ((misalignment = dr_misalignment (dr_info, vectype)), true)
+ if (((misalignment = dr_misalignment (dr_info, vectype)), true)
&& (vect_supportable_dr_alignment (vinfo, dr_info, vectype, misalignment)
== dr_explicit_realign_optimized))
{
@@ -4539,10 +4538,14 @@ vect_describe_gather_scatter_call (stmt_vec_info stmt_info,
info->ifn = gimple_call_internal_fn (call);
info->decl = NULL_TREE;
info->base = gimple_call_arg (call, 0);
- info->offset = gimple_call_arg (call, 1);
+ info->alias_ptr = gimple_call_arg
+ (call, internal_fn_alias_ptr_index (info->ifn));
+ info->offset = gimple_call_arg
+ (call, internal_fn_offset_index (info->ifn));
info->offset_dt = vect_unknown_def_type;
info->offset_vectype = NULL_TREE;
- info->scale = TREE_INT_CST_LOW (gimple_call_arg (call, 2));
+ info->scale = TREE_INT_CST_LOW (gimple_call_arg
+ (call, internal_fn_scale_index (info->ifn)));
info->element_type = TREE_TYPE (vectype);
info->memory_type = TREE_TYPE (DR_REF (dr));
}
@@ -4667,26 +4670,19 @@ vect_check_gather_scatter (stmt_vec_info stmt_info, loop_vec_info loop_vinfo,
if (off == NULL_TREE)
off = size_zero_node;
- /* If base is not loop invariant, either off is 0, then we start with just
- the constant offset in the loop invariant BASE and continue with base
- as OFF, otherwise give up.
- We could handle that case by gimplifying the addition of base + off
- into some SSA_NAME and use that as off, but for now punt. */
+ /* BASE must be loop invariant. If it is not invariant, but OFF is, then we
+ * can fix that by swapping BASE and OFF. */
if (!expr_invariant_in_loop_p (loop, base))
{
- if (!integer_zerop (off))
+ if (!expr_invariant_in_loop_p (loop, off))
return false;
- off = base;
- base = size_int (pbytepos);
- }
- /* Otherwise put base + constant offset into the loop invariant BASE
- and continue with OFF. */
- else
- {
- base = fold_convert (sizetype, base);
- base = size_binop (PLUS_EXPR, base, size_int (pbytepos));
+
+ std::swap (base, off);
}
+ base = fold_convert (sizetype, base);
+ base = size_binop (PLUS_EXPR, base, size_int (pbytepos));
+
/* OFF at this point may be either a SSA_NAME or some tree expression
from get_inner_reference. Try to peel off loop invariants from it
into BASE as long as possible. */
@@ -4864,9 +4860,17 @@ vect_check_gather_scatter (stmt_vec_info stmt_info, loop_vec_info loop_vinfo,
offset_vectype = NULL_TREE;
}
+ gcc_checking_assert (expr_invariant_in_loop_p (loop, base));
+ gcc_checking_assert (!expr_invariant_in_loop_p (loop, off));
+
info->ifn = ifn;
info->decl = decl;
info->base = base;
+
+ info->alias_ptr = build_int_cst
+ (reference_alias_ptr_type (DR_REF (dr)),
+ get_object_alignment (DR_REF (dr)));
+
info->offset = off;
info->offset_dt = vect_unknown_def_type;
info->offset_vectype = offset_vectype;
@@ -5056,7 +5060,7 @@ vect_find_stmt_data_reference (loop_p loop, gimple *stmt,
*/
opt_result
-vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf, bool *fatal)
+vect_analyze_data_refs (vec_info *vinfo, bool *fatal)
{
class loop *loop = NULL;
unsigned int i;
@@ -5075,7 +5079,6 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf, bool *fatal)
FOR_EACH_VEC_ELT (datarefs, i, dr)
{
enum { SG_NONE, GATHER, SCATTER } gatherscatter = SG_NONE;
- poly_uint64 vf;
gcc_assert (DR_REF (dr));
stmt_vec_info stmt_info = vinfo->lookup_stmt (DR_STMT (dr));
@@ -5267,11 +5270,6 @@ vect_analyze_data_refs (vec_info *vinfo, poly_uint64 *min_vf, bool *fatal)
stmt_info->stmt, vectype);
}
- /* Adjust the minimal vectorization factor according to the
- vector type. */
- vf = TYPE_VECTOR_SUBPARTS (vectype);
- *min_vf = upper_bound (*min_vf, vf);
-
/* Leave the BB vectorizer to pick the vector type later, based on
the final dataref group size and SLP node size. */
if (is_a <loop_vec_info> (vinfo))
@@ -5728,8 +5726,7 @@ vect_create_data_ref_ptr (vec_info *vinfo, stmt_vec_info stmt_info,
standard_iv_increment_position (loop, &incr_gsi, &insert_after);
create_iv (aggr_ptr_init, PLUS_EXPR,
- fold_convert (aggr_ptr_type, iv_step),
- aggr_ptr, loop, &incr_gsi, insert_after,
+ iv_step, aggr_ptr, loop, &incr_gsi, insert_after,
&indx_before_incr, &indx_after_incr);
incr = gsi_stmt (incr_gsi);
@@ -5757,7 +5754,7 @@ vect_create_data_ref_ptr (vec_info *vinfo, stmt_vec_info stmt_info,
{
standard_iv_increment_position (containing_loop, &incr_gsi,
&insert_after);
- create_iv (aptr, PLUS_EXPR, fold_convert (aggr_ptr_type, DR_STEP (dr)),
+ create_iv (aptr, PLUS_EXPR, DR_STEP (dr),
aggr_ptr, containing_loop, &incr_gsi, insert_after,
&indx_before_incr, &indx_after_incr);
incr = gsi_stmt (incr_gsi);
@@ -6080,204 +6077,6 @@ vect_store_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count,
}
-/* Function vect_permute_store_chain.
-
- Given a chain of interleaved stores in DR_CHAIN of LENGTH that must be
- a power of 2 or equal to 3, generate interleave_high/low stmts to reorder
- the data correctly for the stores. Return the final references for stores
- in RESULT_CHAIN.
-
- E.g., LENGTH is 4 and the scalar type is short, i.e., VF is 8.
- The input is 4 vectors each containing 8 elements. We assign a number to
- each element, the input sequence is:
-
- 1st vec: 0 1 2 3 4 5 6 7
- 2nd vec: 8 9 10 11 12 13 14 15
- 3rd vec: 16 17 18 19 20 21 22 23
- 4th vec: 24 25 26 27 28 29 30 31
-
- The output sequence should be:
-
- 1st vec: 0 8 16 24 1 9 17 25
- 2nd vec: 2 10 18 26 3 11 19 27
- 3rd vec: 4 12 20 28 5 13 21 30
- 4th vec: 6 14 22 30 7 15 23 31
-
- i.e., we interleave the contents of the four vectors in their order.
-
- We use interleave_high/low instructions to create such output. The input of
- each interleave_high/low operation is two vectors:
- 1st vec 2nd vec
- 0 1 2 3 4 5 6 7
- the even elements of the result vector are obtained left-to-right from the
- high/low elements of the first vector. The odd elements of the result are
- obtained left-to-right from the high/low elements of the second vector.
- The output of interleave_high will be: 0 4 1 5
- and of interleave_low: 2 6 3 7
-
-
- The permutation is done in log LENGTH stages. In each stage interleave_high
- and interleave_low stmts are created for each pair of vectors in DR_CHAIN,
- where the first argument is taken from the first half of DR_CHAIN and the
- second argument from it's second half.
- In our example,
-
- I1: interleave_high (1st vec, 3rd vec)
- I2: interleave_low (1st vec, 3rd vec)
- I3: interleave_high (2nd vec, 4th vec)
- I4: interleave_low (2nd vec, 4th vec)
-
- The output for the first stage is:
-
- I1: 0 16 1 17 2 18 3 19
- I2: 4 20 5 21 6 22 7 23
- I3: 8 24 9 25 10 26 11 27
- I4: 12 28 13 29 14 30 15 31
-
- The output of the second stage, i.e. the final result is:
-
- I1: 0 8 16 24 1 9 17 25
- I2: 2 10 18 26 3 11 19 27
- I3: 4 12 20 28 5 13 21 30
- I4: 6 14 22 30 7 15 23 31. */
-
-void
-vect_permute_store_chain (vec_info *vinfo, vec<tree> &dr_chain,
- unsigned int length,
- stmt_vec_info stmt_info,
- gimple_stmt_iterator *gsi,
- vec<tree> *result_chain)
-{
- tree vect1, vect2, high, low;
- gimple *perm_stmt;
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
- tree perm_mask_low, perm_mask_high;
- tree data_ref;
- tree perm3_mask_low, perm3_mask_high;
- unsigned int i, j, n, log_length = exact_log2 (length);
-
- result_chain->quick_grow (length);
- memcpy (result_chain->address (), dr_chain.address (),
- length * sizeof (tree));
-
- if (length == 3)
- {
- /* vect_grouped_store_supported ensures that this is constant. */
- unsigned int nelt = TYPE_VECTOR_SUBPARTS (vectype).to_constant ();
- unsigned int j0 = 0, j1 = 0, j2 = 0;
-
- vec_perm_builder sel (nelt, nelt, 1);
- sel.quick_grow (nelt);
- vec_perm_indices indices;
- for (j = 0; j < 3; j++)
- {
- int nelt0 = ((3 - j) * nelt) % 3;
- int nelt1 = ((3 - j) * nelt + 1) % 3;
- int nelt2 = ((3 - j) * nelt + 2) % 3;
-
- for (i = 0; i < nelt; i++)
- {
- if (3 * i + nelt0 < nelt)
- sel[3 * i + nelt0] = j0++;
- if (3 * i + nelt1 < nelt)
- sel[3 * i + nelt1] = nelt + j1++;
- if (3 * i + nelt2 < nelt)
- sel[3 * i + nelt2] = 0;
- }
- indices.new_vector (sel, 2, nelt);
- perm3_mask_low = vect_gen_perm_mask_checked (vectype, indices);
-
- for (i = 0; i < nelt; i++)
- {
- if (3 * i + nelt0 < nelt)
- sel[3 * i + nelt0] = 3 * i + nelt0;
- if (3 * i + nelt1 < nelt)
- sel[3 * i + nelt1] = 3 * i + nelt1;
- if (3 * i + nelt2 < nelt)
- sel[3 * i + nelt2] = nelt + j2++;
- }
- indices.new_vector (sel, 2, nelt);
- perm3_mask_high = vect_gen_perm_mask_checked (vectype, indices);
-
- vect1 = dr_chain[0];
- vect2 = dr_chain[1];
-
- /* Create interleaving stmt:
- low = VEC_PERM_EXPR <vect1, vect2,
- {j, nelt, *, j + 1, nelt + j + 1, *,
- j + 2, nelt + j + 2, *, ...}> */
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shuffle3_low");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, vect1,
- vect2, perm3_mask_low);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
-
- vect1 = data_ref;
- vect2 = dr_chain[2];
- /* Create interleaving stmt:
- low = VEC_PERM_EXPR <vect1, vect2,
- {0, 1, nelt + j, 3, 4, nelt + j + 1,
- 6, 7, nelt + j + 2, ...}> */
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shuffle3_high");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, vect1,
- vect2, perm3_mask_high);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- (*result_chain)[j] = data_ref;
- }
- }
- else
- {
- /* If length is not equal to 3 then only power of 2 is supported. */
- gcc_assert (pow2p_hwi (length));
-
- /* The encoding has 2 interleaved stepped patterns. */
- poly_uint64 nelt = TYPE_VECTOR_SUBPARTS (vectype);
- vec_perm_builder sel (nelt, 2, 3);
- sel.quick_grow (6);
- for (i = 0; i < 3; i++)
- {
- sel[i * 2] = i;
- sel[i * 2 + 1] = i + nelt;
- }
- vec_perm_indices indices (sel, 2, nelt);
- perm_mask_high = vect_gen_perm_mask_checked (vectype, indices);
-
- for (i = 0; i < 6; i++)
- sel[i] += exact_div (nelt, 2);
- indices.new_vector (sel, 2, nelt);
- perm_mask_low = vect_gen_perm_mask_checked (vectype, indices);
-
- for (i = 0, n = log_length; i < n; i++)
- {
- for (j = 0; j < length/2; j++)
- {
- vect1 = dr_chain[j];
- vect2 = dr_chain[j+length/2];
-
- /* Create interleaving stmt:
- high = VEC_PERM_EXPR <vect1, vect2, {0, nelt, 1, nelt+1,
- ...}> */
- high = make_temp_ssa_name (vectype, NULL, "vect_inter_high");
- perm_stmt = gimple_build_assign (high, VEC_PERM_EXPR, vect1,
- vect2, perm_mask_high);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- (*result_chain)[2*j] = high;
-
- /* Create interleaving stmt:
- low = VEC_PERM_EXPR <vect1, vect2,
- {nelt/2, nelt*3/2, nelt/2+1, nelt*3/2+1,
- ...}> */
- low = make_temp_ssa_name (vectype, NULL, "vect_inter_low");
- perm_stmt = gimple_build_assign (low, VEC_PERM_EXPR, vect1,
- vect2, perm_mask_low);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- (*result_chain)[2*j+1] = low;
- }
- memcpy (dr_chain.address (), result_chain->address (),
- length * sizeof (tree));
- }
- }
-}
-
/* Function vect_setup_realignment
This function is called when vectorizing an unaligned load using
@@ -6708,633 +6507,6 @@ vect_load_lanes_supported (tree vectype, unsigned HOST_WIDE_INT count,
return IFN_LAST;
}
-/* Function vect_permute_load_chain.
-
- Given a chain of interleaved loads in DR_CHAIN of LENGTH that must be
- a power of 2 or equal to 3, generate extract_even/odd stmts to reorder
- the input data correctly. Return the final references for loads in
- RESULT_CHAIN.
-
- E.g., LENGTH is 4 and the scalar type is short, i.e., VF is 8.
- The input is 4 vectors each containing 8 elements. We assign a number to each
- element, the input sequence is:
-
- 1st vec: 0 1 2 3 4 5 6 7
- 2nd vec: 8 9 10 11 12 13 14 15
- 3rd vec: 16 17 18 19 20 21 22 23
- 4th vec: 24 25 26 27 28 29 30 31
-
- The output sequence should be:
-
- 1st vec: 0 4 8 12 16 20 24 28
- 2nd vec: 1 5 9 13 17 21 25 29
- 3rd vec: 2 6 10 14 18 22 26 30
- 4th vec: 3 7 11 15 19 23 27 31
-
- i.e., the first output vector should contain the first elements of each
- interleaving group, etc.
-
- We use extract_even/odd instructions to create such output. The input of
- each extract_even/odd operation is two vectors
- 1st vec 2nd vec
- 0 1 2 3 4 5 6 7
-
- and the output is the vector of extracted even/odd elements. The output of
- extract_even will be: 0 2 4 6
- and of extract_odd: 1 3 5 7
-
-
- The permutation is done in log LENGTH stages. In each stage extract_even
- and extract_odd stmts are created for each pair of vectors in DR_CHAIN in
- their order. In our example,
-
- E1: extract_even (1st vec, 2nd vec)
- E2: extract_odd (1st vec, 2nd vec)
- E3: extract_even (3rd vec, 4th vec)
- E4: extract_odd (3rd vec, 4th vec)
-
- The output for the first stage will be:
-
- E1: 0 2 4 6 8 10 12 14
- E2: 1 3 5 7 9 11 13 15
- E3: 16 18 20 22 24 26 28 30
- E4: 17 19 21 23 25 27 29 31
-
- In order to proceed and create the correct sequence for the next stage (or
- for the correct output, if the second stage is the last one, as in our
- example), we first put the output of extract_even operation and then the
- output of extract_odd in RESULT_CHAIN (which is then copied to DR_CHAIN).
- The input for the second stage is:
-
- 1st vec (E1): 0 2 4 6 8 10 12 14
- 2nd vec (E3): 16 18 20 22 24 26 28 30
- 3rd vec (E2): 1 3 5 7 9 11 13 15
- 4th vec (E4): 17 19 21 23 25 27 29 31
-
- The output of the second stage:
-
- E1: 0 4 8 12 16 20 24 28
- E2: 2 6 10 14 18 22 26 30
- E3: 1 5 9 13 17 21 25 29
- E4: 3 7 11 15 19 23 27 31
-
- And RESULT_CHAIN after reordering:
-
- 1st vec (E1): 0 4 8 12 16 20 24 28
- 2nd vec (E3): 1 5 9 13 17 21 25 29
- 3rd vec (E2): 2 6 10 14 18 22 26 30
- 4th vec (E4): 3 7 11 15 19 23 27 31. */
-
-static void
-vect_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain,
- unsigned int length,
- stmt_vec_info stmt_info,
- gimple_stmt_iterator *gsi,
- vec<tree> *result_chain)
-{
- tree data_ref, first_vect, second_vect;
- tree perm_mask_even, perm_mask_odd;
- tree perm3_mask_low, perm3_mask_high;
- gimple *perm_stmt;
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
- unsigned int i, j, log_length = exact_log2 (length);
-
- result_chain->quick_grow (length);
- memcpy (result_chain->address (), dr_chain.address (),
- length * sizeof (tree));
-
- if (length == 3)
- {
- /* vect_grouped_load_supported ensures that this is constant. */
- unsigned nelt = TYPE_VECTOR_SUBPARTS (vectype).to_constant ();
- unsigned int k;
-
- vec_perm_builder sel (nelt, nelt, 1);
- sel.quick_grow (nelt);
- vec_perm_indices indices;
- for (k = 0; k < 3; k++)
- {
- for (i = 0; i < nelt; i++)
- if (3 * i + k < 2 * nelt)
- sel[i] = 3 * i + k;
- else
- sel[i] = 0;
- indices.new_vector (sel, 2, nelt);
- perm3_mask_low = vect_gen_perm_mask_checked (vectype, indices);
-
- for (i = 0, j = 0; i < nelt; i++)
- if (3 * i + k < 2 * nelt)
- sel[i] = i;
- else
- sel[i] = nelt + ((nelt + k) % 3) + 3 * (j++);
- indices.new_vector (sel, 2, nelt);
- perm3_mask_high = vect_gen_perm_mask_checked (vectype, indices);
-
- first_vect = dr_chain[0];
- second_vect = dr_chain[1];
-
- /* Create interleaving stmt (low part of):
- low = VEC_PERM_EXPR <first_vect, second_vect2, {k, 3 + k, 6 + k,
- ...}> */
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shuffle3_low");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, first_vect,
- second_vect, perm3_mask_low);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
-
- /* Create interleaving stmt (high part of):
- high = VEC_PERM_EXPR <first_vect, second_vect2, {k, 3 + k, 6 + k,
- ...}> */
- first_vect = data_ref;
- second_vect = dr_chain[2];
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shuffle3_high");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, first_vect,
- second_vect, perm3_mask_high);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- (*result_chain)[k] = data_ref;
- }
- }
- else
- {
- /* If length is not equal to 3 then only power of 2 is supported. */
- gcc_assert (pow2p_hwi (length));
-
- /* The encoding has a single stepped pattern. */
- poly_uint64 nelt = TYPE_VECTOR_SUBPARTS (vectype);
- vec_perm_builder sel (nelt, 1, 3);
- sel.quick_grow (3);
- for (i = 0; i < 3; ++i)
- sel[i] = i * 2;
- vec_perm_indices indices (sel, 2, nelt);
- perm_mask_even = vect_gen_perm_mask_checked (vectype, indices);
-
- for (i = 0; i < 3; ++i)
- sel[i] = i * 2 + 1;
- indices.new_vector (sel, 2, nelt);
- perm_mask_odd = vect_gen_perm_mask_checked (vectype, indices);
-
- for (i = 0; i < log_length; i++)
- {
- for (j = 0; j < length; j += 2)
- {
- first_vect = dr_chain[j];
- second_vect = dr_chain[j+1];
-
- /* data_ref = permute_even (first_data_ref, second_data_ref); */
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_perm_even");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR,
- first_vect, second_vect,
- perm_mask_even);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- (*result_chain)[j/2] = data_ref;
-
- /* data_ref = permute_odd (first_data_ref, second_data_ref); */
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_perm_odd");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR,
- first_vect, second_vect,
- perm_mask_odd);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- (*result_chain)[j/2+length/2] = data_ref;
- }
- memcpy (dr_chain.address (), result_chain->address (),
- length * sizeof (tree));
- }
- }
-}
-
-/* Function vect_shift_permute_load_chain.
-
- Given a chain of loads in DR_CHAIN of LENGTH 2 or 3, generate
- sequence of stmts to reorder the input data accordingly.
- Return the final references for loads in RESULT_CHAIN.
- Return true if successed, false otherwise.
-
- E.g., LENGTH is 3 and the scalar type is short, i.e., VF is 8.
- The input is 3 vectors each containing 8 elements. We assign a
- number to each element, the input sequence is:
-
- 1st vec: 0 1 2 3 4 5 6 7
- 2nd vec: 8 9 10 11 12 13 14 15
- 3rd vec: 16 17 18 19 20 21 22 23
-
- The output sequence should be:
-
- 1st vec: 0 3 6 9 12 15 18 21
- 2nd vec: 1 4 7 10 13 16 19 22
- 3rd vec: 2 5 8 11 14 17 20 23
-
- We use 3 shuffle instructions and 3 * 3 - 1 shifts to create such output.
-
- First we shuffle all 3 vectors to get correct elements order:
-
- 1st vec: ( 0 3 6) ( 1 4 7) ( 2 5)
- 2nd vec: ( 8 11 14) ( 9 12 15) (10 13)
- 3rd vec: (16 19 22) (17 20 23) (18 21)
-
- Next we unite and shift vector 3 times:
-
- 1st step:
- shift right by 6 the concatenation of:
- "1st vec" and "2nd vec"
- ( 0 3 6) ( 1 4 7) |( 2 5) _ ( 8 11 14) ( 9 12 15)| (10 13)
- "2nd vec" and "3rd vec"
- ( 8 11 14) ( 9 12 15) |(10 13) _ (16 19 22) (17 20 23)| (18 21)
- "3rd vec" and "1st vec"
- (16 19 22) (17 20 23) |(18 21) _ ( 0 3 6) ( 1 4 7)| ( 2 5)
- | New vectors |
-
- So that now new vectors are:
-
- 1st vec: ( 2 5) ( 8 11 14) ( 9 12 15)
- 2nd vec: (10 13) (16 19 22) (17 20 23)
- 3rd vec: (18 21) ( 0 3 6) ( 1 4 7)
-
- 2nd step:
- shift right by 5 the concatenation of:
- "1st vec" and "3rd vec"
- ( 2 5) ( 8 11 14) |( 9 12 15) _ (18 21) ( 0 3 6)| ( 1 4 7)
- "2nd vec" and "1st vec"
- (10 13) (16 19 22) |(17 20 23) _ ( 2 5) ( 8 11 14)| ( 9 12 15)
- "3rd vec" and "2nd vec"
- (18 21) ( 0 3 6) |( 1 4 7) _ (10 13) (16 19 22)| (17 20 23)
- | New vectors |
-
- So that now new vectors are:
-
- 1st vec: ( 9 12 15) (18 21) ( 0 3 6)
- 2nd vec: (17 20 23) ( 2 5) ( 8 11 14)
- 3rd vec: ( 1 4 7) (10 13) (16 19 22) READY
-
- 3rd step:
- shift right by 5 the concatenation of:
- "1st vec" and "1st vec"
- ( 9 12 15) (18 21) |( 0 3 6) _ ( 9 12 15) (18 21)| ( 0 3 6)
- shift right by 3 the concatenation of:
- "2nd vec" and "2nd vec"
- (17 20 23) |( 2 5) ( 8 11 14) _ (17 20 23)| ( 2 5) ( 8 11 14)
- | New vectors |
-
- So that now all vectors are READY:
- 1st vec: ( 0 3 6) ( 9 12 15) (18 21)
- 2nd vec: ( 2 5) ( 8 11 14) (17 20 23)
- 3rd vec: ( 1 4 7) (10 13) (16 19 22)
-
- This algorithm is faster than one in vect_permute_load_chain if:
- 1. "shift of a concatination" is faster than general permutation.
- This is usually so.
- 2. The TARGET machine can't execute vector instructions in parallel.
- This is because each step of the algorithm depends on previous.
- The algorithm in vect_permute_load_chain is much more parallel.
-
- The algorithm is applicable only for LOAD CHAIN LENGTH less than VF.
-*/
-
-static bool
-vect_shift_permute_load_chain (vec_info *vinfo, vec<tree> dr_chain,
- unsigned int length,
- stmt_vec_info stmt_info,
- gimple_stmt_iterator *gsi,
- vec<tree> *result_chain)
-{
- tree vect[3], vect_shift[3], data_ref, first_vect, second_vect;
- tree perm2_mask1, perm2_mask2, perm3_mask;
- tree select_mask, shift1_mask, shift2_mask, shift3_mask, shift4_mask;
- gimple *perm_stmt;
-
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
- machine_mode vmode = TYPE_MODE (vectype);
- unsigned int i;
- loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
-
- unsigned HOST_WIDE_INT nelt, vf;
- if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant (&nelt)
- || !LOOP_VINFO_VECT_FACTOR (loop_vinfo).is_constant (&vf))
- /* Not supported for variable-length vectors. */
- return false;
-
- vec_perm_builder sel (nelt, nelt, 1);
- sel.quick_grow (nelt);
-
- result_chain->quick_grow (length);
- memcpy (result_chain->address (), dr_chain.address (),
- length * sizeof (tree));
-
- if (pow2p_hwi (length) && vf > 4)
- {
- unsigned int j, log_length = exact_log2 (length);
- for (i = 0; i < nelt / 2; ++i)
- sel[i] = i * 2;
- for (i = 0; i < nelt / 2; ++i)
- sel[nelt / 2 + i] = i * 2 + 1;
- vec_perm_indices indices (sel, 2, nelt);
- if (!can_vec_perm_const_p (vmode, vmode, indices))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "shuffle of 2 fields structure is not \
- supported by target\n");
- return false;
- }
- perm2_mask1 = vect_gen_perm_mask_checked (vectype, indices);
-
- for (i = 0; i < nelt / 2; ++i)
- sel[i] = i * 2 + 1;
- for (i = 0; i < nelt / 2; ++i)
- sel[nelt / 2 + i] = i * 2;
- indices.new_vector (sel, 2, nelt);
- if (!can_vec_perm_const_p (vmode, vmode, indices))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "shuffle of 2 fields structure is not \
- supported by target\n");
- return false;
- }
- perm2_mask2 = vect_gen_perm_mask_checked (vectype, indices);
-
- /* Generating permutation constant to shift all elements.
- For vector length 8 it is {4 5 6 7 8 9 10 11}. */
- for (i = 0; i < nelt; i++)
- sel[i] = nelt / 2 + i;
- indices.new_vector (sel, 2, nelt);
- if (!can_vec_perm_const_p (vmode, vmode, indices))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "shift permutation is not supported by target\n");
- return false;
- }
- shift1_mask = vect_gen_perm_mask_checked (vectype, indices);
-
- /* Generating permutation constant to select vector from 2.
- For vector length 8 it is {0 1 2 3 12 13 14 15}. */
- for (i = 0; i < nelt / 2; i++)
- sel[i] = i;
- for (i = nelt / 2; i < nelt; i++)
- sel[i] = nelt + i;
- indices.new_vector (sel, 2, nelt);
- if (!can_vec_perm_const_p (vmode, vmode, indices))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "select is not supported by target\n");
- return false;
- }
- select_mask = vect_gen_perm_mask_checked (vectype, indices);
-
- for (i = 0; i < log_length; i++)
- {
- for (j = 0; j < length; j += 2)
- {
- first_vect = dr_chain[j];
- second_vect = dr_chain[j + 1];
-
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shuffle2");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR,
- first_vect, first_vect,
- perm2_mask1);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- vect[0] = data_ref;
-
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shuffle2");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR,
- second_vect, second_vect,
- perm2_mask2);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- vect[1] = data_ref;
-
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shift");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR,
- vect[0], vect[1], shift1_mask);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- (*result_chain)[j/2 + length/2] = data_ref;
-
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_select");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR,
- vect[0], vect[1], select_mask);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- (*result_chain)[j/2] = data_ref;
- }
- memcpy (dr_chain.address (), result_chain->address (),
- length * sizeof (tree));
- }
- return true;
- }
- if (length == 3 && vf > 2)
- {
- unsigned int k = 0, l = 0;
-
- /* Generating permutation constant to get all elements in rigth order.
- For vector length 8 it is {0 3 6 1 4 7 2 5}. */
- for (i = 0; i < nelt; i++)
- {
- if (3 * k + (l % 3) >= nelt)
- {
- k = 0;
- l += (3 - (nelt % 3));
- }
- sel[i] = 3 * k + (l % 3);
- k++;
- }
- vec_perm_indices indices (sel, 2, nelt);
- if (!can_vec_perm_const_p (vmode, vmode, indices))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "shuffle of 3 fields structure is not \
- supported by target\n");
- return false;
- }
- perm3_mask = vect_gen_perm_mask_checked (vectype, indices);
-
- /* Generating permutation constant to shift all elements.
- For vector length 8 it is {6 7 8 9 10 11 12 13}. */
- for (i = 0; i < nelt; i++)
- sel[i] = 2 * (nelt / 3) + (nelt % 3) + i;
- indices.new_vector (sel, 2, nelt);
- if (!can_vec_perm_const_p (vmode, vmode, indices))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "shift permutation is not supported by target\n");
- return false;
- }
- shift1_mask = vect_gen_perm_mask_checked (vectype, indices);
-
- /* Generating permutation constant to shift all elements.
- For vector length 8 it is {5 6 7 8 9 10 11 12}. */
- for (i = 0; i < nelt; i++)
- sel[i] = 2 * (nelt / 3) + 1 + i;
- indices.new_vector (sel, 2, nelt);
- if (!can_vec_perm_const_p (vmode, vmode, indices))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "shift permutation is not supported by target\n");
- return false;
- }
- shift2_mask = vect_gen_perm_mask_checked (vectype, indices);
-
- /* Generating permutation constant to shift all elements.
- For vector length 8 it is {3 4 5 6 7 8 9 10}. */
- for (i = 0; i < nelt; i++)
- sel[i] = (nelt / 3) + (nelt % 3) / 2 + i;
- indices.new_vector (sel, 2, nelt);
- if (!can_vec_perm_const_p (vmode, vmode, indices))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "shift permutation is not supported by target\n");
- return false;
- }
- shift3_mask = vect_gen_perm_mask_checked (vectype, indices);
-
- /* Generating permutation constant to shift all elements.
- For vector length 8 it is {5 6 7 8 9 10 11 12}. */
- for (i = 0; i < nelt; i++)
- sel[i] = 2 * (nelt / 3) + (nelt % 3) / 2 + i;
- indices.new_vector (sel, 2, nelt);
- if (!can_vec_perm_const_p (vmode, vmode, indices))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "shift permutation is not supported by target\n");
- return false;
- }
- shift4_mask = vect_gen_perm_mask_checked (vectype, indices);
-
- for (k = 0; k < 3; k++)
- {
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shuffle3");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR,
- dr_chain[k], dr_chain[k],
- perm3_mask);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- vect[k] = data_ref;
- }
-
- for (k = 0; k < 3; k++)
- {
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shift1");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR,
- vect[k % 3], vect[(k + 1) % 3],
- shift1_mask);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- vect_shift[k] = data_ref;
- }
-
- for (k = 0; k < 3; k++)
- {
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shift2");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR,
- vect_shift[(4 - k) % 3],
- vect_shift[(3 - k) % 3],
- shift2_mask);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- vect[k] = data_ref;
- }
-
- (*result_chain)[3 - (nelt % 3)] = vect[2];
-
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shift3");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, vect[0],
- vect[0], shift3_mask);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- (*result_chain)[nelt % 3] = data_ref;
-
- data_ref = make_temp_ssa_name (vectype, NULL, "vect_shift4");
- perm_stmt = gimple_build_assign (data_ref, VEC_PERM_EXPR, vect[1],
- vect[1], shift4_mask);
- vect_finish_stmt_generation (vinfo, stmt_info, perm_stmt, gsi);
- (*result_chain)[0] = data_ref;
- return true;
- }
- return false;
-}
-
-/* Function vect_transform_grouped_load.
-
- Given a chain of input interleaved data-refs (in DR_CHAIN), build statements
- to perform their permutation and ascribe the result vectorized statements to
- the scalar statements.
-*/
-
-void
-vect_transform_grouped_load (vec_info *vinfo, stmt_vec_info stmt_info,
- vec<tree> dr_chain,
- int size, gimple_stmt_iterator *gsi)
-{
- machine_mode mode;
- vec<tree> result_chain = vNULL;
-
- /* DR_CHAIN contains input data-refs that are a part of the interleaving.
- RESULT_CHAIN is the output of vect_permute_load_chain, it contains permuted
- vectors, that are ready for vector computation. */
- result_chain.create (size);
-
- /* If reassociation width for vector type is 2 or greater target machine can
- execute 2 or more vector instructions in parallel. Otherwise try to
- get chain for loads group using vect_shift_permute_load_chain. */
- mode = TYPE_MODE (STMT_VINFO_VECTYPE (stmt_info));
- if (targetm.sched.reassociation_width (VEC_PERM_EXPR, mode) > 1
- || pow2p_hwi (size)
- || !vect_shift_permute_load_chain (vinfo, dr_chain, size, stmt_info,
- gsi, &result_chain))
- vect_permute_load_chain (vinfo, dr_chain,
- size, stmt_info, gsi, &result_chain);
- vect_record_grouped_load_vectors (vinfo, stmt_info, result_chain);
- result_chain.release ();
-}
-
-/* RESULT_CHAIN contains the output of a group of grouped loads that were
- generated as part of the vectorization of STMT_INFO. Assign the statement
- for each vector to the associated scalar statement. */
-
-void
-vect_record_grouped_load_vectors (vec_info *, stmt_vec_info stmt_info,
- vec<tree> result_chain)
-{
- stmt_vec_info first_stmt_info = DR_GROUP_FIRST_ELEMENT (stmt_info);
- unsigned int i, gap_count;
- tree tmp_data_ref;
-
- /* Put a permuted data-ref in the VECTORIZED_STMT field.
- Since we scan the chain starting from it's first node, their order
- corresponds the order of data-refs in RESULT_CHAIN. */
- stmt_vec_info next_stmt_info = first_stmt_info;
- gap_count = 1;
- FOR_EACH_VEC_ELT (result_chain, i, tmp_data_ref)
- {
- if (!next_stmt_info)
- break;
-
- /* Skip the gaps. Loads created for the gaps will be removed by dead
- code elimination pass later. No need to check for the first stmt in
- the group, since it always exists.
- DR_GROUP_GAP is the number of steps in elements from the previous
- access (if there is no gap DR_GROUP_GAP is 1). We skip loads that
- correspond to the gaps. */
- if (next_stmt_info != first_stmt_info
- && gap_count < DR_GROUP_GAP (next_stmt_info))
- {
- gap_count++;
- continue;
- }
-
- /* ??? The following needs cleanup after the removal of
- DR_GROUP_SAME_DR_STMT. */
- if (next_stmt_info)
- {
- gimple *new_stmt = SSA_NAME_DEF_STMT (tmp_data_ref);
- /* We assume that if VEC_STMT is not NULL, this is a case of multiple
- copies, and we put the new vector statement last. */
- STMT_VINFO_VEC_STMTS (next_stmt_info).safe_push (new_stmt);
-
- next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
- gap_count = 1;
- }
- }
-}
-
/* Function vect_force_dr_alignment_p.
Returns whether the alignment of a DECL can be forced to be aligned
@@ -7362,13 +6534,14 @@ vect_can_force_dr_alignment_p (const_tree decl, poly_uint64 alignment)
alignment.
If CHECK_ALIGNED_ACCESSES is TRUE, check if the access is supported even
it is aligned, i.e., check if it is possible to vectorize it with different
- alignment. */
+ alignment. If GS_INFO is passed we are dealing with a gather/scatter. */
enum dr_alignment_support
vect_supportable_dr_alignment (vec_info *vinfo, dr_vec_info *dr_info,
- tree vectype, int misalignment)
+ tree vectype, int misalignment,
+ gather_scatter_info *gs_info)
{
- data_reference *dr = dr_info->dr;
+ data_reference *dr = dr_info ? dr_info->dr : nullptr;
stmt_vec_info stmt_info = dr_info->stmt;
machine_mode mode = TYPE_MODE (vectype);
loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
@@ -7380,14 +6553,6 @@ vect_supportable_dr_alignment (vec_info *vinfo, dr_vec_info *dr_info,
else if (dr_safe_speculative_read_required (stmt_info))
return dr_unaligned_unsupported;
- /* For now assume all conditional loads/stores support unaligned
- access without any special code. */
- if (gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt))
- if (gimple_call_internal_p (stmt)
- && (gimple_call_internal_fn (stmt) == IFN_MASK_LOAD
- || gimple_call_internal_fn (stmt) == IFN_MASK_STORE))
- return dr_unaligned_supported;
-
if (loop_vinfo)
{
vect_loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -7457,7 +6622,7 @@ vect_supportable_dr_alignment (vec_info *vinfo, dr_vec_info *dr_info,
}
} */
- if (DR_IS_READ (dr))
+ if (dr && DR_IS_READ (dr))
{
if (can_implement_p (vec_realign_load_optab, mode)
&& (!targetm.vectorize.builtin_mask_for_load
@@ -7485,10 +6650,43 @@ vect_supportable_dr_alignment (vec_info *vinfo, dr_vec_info *dr_info,
bool is_packed = false;
tree type = TREE_TYPE (DR_REF (dr));
+ bool is_gather_scatter = gs_info != nullptr;
if (misalignment == DR_MISALIGNMENT_UNKNOWN)
- is_packed = not_size_aligned (DR_REF (dr));
+ {
+ if (!is_gather_scatter || dr != nullptr)
+ is_packed = not_size_aligned (DR_REF (dr));
+ else
+ {
+ /* Gather-scatter accesses normally perform only component accesses
+ so alignment is irrelevant for them. Targets like riscv do care
+ about scalar alignment in vector accesses, though, so check scalar
+ alignment here. We determined the alias pointer as well as the
+ base alignment during pattern recognition and can re-use it here.
+
+ As we do not have an analyzed dataref we only know the alignment
+ of the reference itself and nothing about init, steps, etc.
+ For now don't try harder to determine misalignment and
+ just assume it is unknown. We consider the type packed if its
+ scalar alignment is lower than the natural alignment of a vector
+ element's type. */
+
+ gcc_assert (!GATHER_SCATTER_LEGACY_P (*gs_info));
+ gcc_assert (dr == nullptr);
+
+ tree inner_vectype = TREE_TYPE (vectype);
+
+ unsigned HOST_WIDE_INT scalar_align
+ = tree_to_uhwi (gs_info->alias_ptr);
+ unsigned HOST_WIDE_INT inner_vectype_sz
+ = tree_to_uhwi (TYPE_SIZE (inner_vectype));
+
+ bool is_misaligned = scalar_align < inner_vectype_sz;
+ is_packed = scalar_align > 1 && is_misaligned;
+ }
+ }
if (targetm.vectorize.support_vector_misalignment (mode, type, misalignment,
- is_packed))
+ is_packed,
+ is_gather_scatter))
return dr_unaligned_supported;
/* Unsupported. */
diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
index edad40c..2ee023f 100644
--- a/gcc/tree-vect-loop.cc
+++ b/gcc/tree-vect-loop.cc
@@ -191,12 +191,6 @@ vect_determine_vectype_for_stmt_1 (vec_info *vinfo, stmt_vec_info stmt_info,
if (stmt_vectype)
{
- if (known_le (TYPE_VECTOR_SUBPARTS (stmt_vectype), 1U))
- return opt_result::failure_at (STMT_VINFO_STMT (stmt_info),
- "not vectorized: unsupported "
- "data-type in %G",
- STMT_VINFO_STMT (stmt_info));
-
if (STMT_VINFO_VECTYPE (stmt_info))
/* The only case when a vectype had been already set is for stmts
that contain a data ref, or for "pattern-stmts" (stmts generated
@@ -303,8 +297,7 @@ vect_set_stmts_vectype (loop_vec_info loop_vinfo)
scalar_type);
vectype = get_vectype_for_scalar_type (loop_vinfo, scalar_type);
- if (!vectype
- || known_le (TYPE_VECTOR_SUBPARTS (vectype), 1U))
+ if (!vectype)
return opt_result::failure_at (phi,
"not vectorized: unsupported "
"data-type %T\n",
@@ -2380,7 +2373,6 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal,
opt_result ok = opt_result::success ();
int res;
unsigned int max_vf = MAX_VECTORIZATION_FACTOR;
- poly_uint64 min_vf = 2;
loop_vec_info orig_loop_vinfo = NULL;
/* If we are dealing with an epilogue then orig_loop_vinfo points to the
@@ -2427,7 +2419,7 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal,
/* Analyze the data references and also adjust the minimal
vectorization factor according to the loads and stores. */
- ok = vect_analyze_data_refs (loop_vinfo, &min_vf, &fatal);
+ ok = vect_analyze_data_refs (loop_vinfo, &fatal);
if (!ok)
{
if (dump_enabled_p ())
@@ -2492,9 +2484,6 @@ vect_analyze_loop_2 (loop_vec_info loop_vinfo, bool &fatal,
"bad data dependence.\n");
return ok;
}
- if (max_vf != MAX_VECTORIZATION_FACTOR
- && maybe_lt (max_vf, min_vf))
- return opt_result::failure_at (vect_location, "bad data dependence.\n");
LOOP_VINFO_MAX_VECT_FACTOR (loop_vinfo) = max_vf;
ok = vect_set_stmts_vectype (loop_vinfo);
@@ -2894,7 +2883,7 @@ again:
continue;
vinfo = DR_GROUP_FIRST_ELEMENT (vinfo);
unsigned int size = DR_GROUP_SIZE (vinfo);
- tree vectype = STMT_VINFO_VECTYPE (vinfo);
+ tree vectype = SLP_TREE_VECTYPE (SLP_INSTANCE_TREE (instance));
if (vect_store_lanes_supported (vectype, size, false) == IFN_LAST
&& ! known_eq (TYPE_VECTOR_SUBPARTS (vectype), 1U)
&& ! vect_grouped_store_supported (vectype, size))
@@ -2908,7 +2897,7 @@ again:
vinfo = DR_GROUP_FIRST_ELEMENT (vinfo);
bool single_element_p = !DR_GROUP_NEXT_ELEMENT (vinfo);
size = DR_GROUP_SIZE (vinfo);
- vectype = STMT_VINFO_VECTYPE (vinfo);
+ vectype = SLP_TREE_VECTYPE (node);
if (vect_load_lanes_supported (vectype, size, false) == IFN_LAST
&& ! vect_grouped_load_supported (vectype, single_element_p,
size))
@@ -6700,7 +6689,7 @@ vectorize_fold_left_reduction (loop_vec_info loop_vinfo,
vec_loop_lens *lens)
{
class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
- tree vectype_out = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype_out = SLP_TREE_VECTYPE (slp_node);
internal_fn mask_reduc_fn = get_masked_reduction_fn (reduc_fn, vectype_in);
gcc_assert (!nested_in_vect_loop_p (loop, stmt_info));
@@ -7087,14 +7076,13 @@ vectorizable_lane_reducing (loop_vec_info loop_vinfo, stmt_vec_info stmt_info,
for (int i = 0; i < (int) gimple_num_ops (stmt) - 1; i++)
{
- stmt_vec_info def_stmt_info;
slp_tree slp_op;
tree op;
tree vectype;
enum vect_def_type dt;
- if (!vect_is_simple_use (loop_vinfo, stmt_info, slp_node, i, &op,
- &slp_op, &dt, &vectype, &def_stmt_info))
+ if (!vect_is_simple_use (loop_vinfo, slp_node, i, &op,
+ &slp_op, &dt, &vectype))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -7521,7 +7509,7 @@ vectorizable_reduction (loop_vec_info loop_vinfo,
stmt_vec_info def_stmt_info;
enum vect_def_type dt;
- if (!vect_is_simple_use (loop_vinfo, stmt_info, slp_for_stmt_info,
+ if (!vect_is_simple_use (loop_vinfo, slp_for_stmt_info,
i + opno_adjust, &op.ops[i], &slp_op[i], &dt,
&vectype_op[i], &def_stmt_info))
{
@@ -8192,7 +8180,7 @@ vect_transform_reduction (loop_vec_info loop_vinfo,
stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
slp_tree slp_node)
{
- tree vectype_out = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype_out = SLP_TREE_VECTYPE (slp_node);
class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
unsigned vec_num;
@@ -8219,7 +8207,7 @@ vect_transform_reduction (loop_vec_info loop_vinfo,
tree vectype_in = STMT_VINFO_REDUC_VECTYPE_IN (stmt_info);
if (!vectype_in)
- vectype_in = STMT_VINFO_VECTYPE (stmt_info);
+ vectype_in = SLP_TREE_VECTYPE (slp_node);
vec_num = vect_get_num_copies (loop_vinfo, slp_node, vectype_in);
@@ -8284,7 +8272,7 @@ vect_transform_reduction (loop_vec_info loop_vinfo,
if (!cond_fn_p)
{
gcc_assert (reduc_index >= 0 && reduc_index <= 2);
- vect_get_vec_defs (loop_vinfo, stmt_info, slp_node, 1,
+ vect_get_vec_defs (loop_vinfo, slp_node,
single_defuse_cycle && reduc_index == 0
? NULL_TREE : op.ops[0], &vec_oprnds[0],
single_defuse_cycle && reduc_index == 1
@@ -8299,19 +8287,19 @@ vect_transform_reduction (loop_vec_info loop_vinfo,
vectype. */
gcc_assert (single_defuse_cycle
&& (reduc_index == 1 || reduc_index == 2));
- vect_get_vec_defs (loop_vinfo, stmt_info, slp_node, 1, op.ops[0],
- truth_type_for (vectype_in), &vec_oprnds[0],
+ vect_get_vec_defs (loop_vinfo, slp_node, op.ops[0],
+ &vec_oprnds[0],
reduc_index == 1 ? NULL_TREE : op.ops[1],
- NULL_TREE, &vec_oprnds[1],
+ &vec_oprnds[1],
reduc_index == 2 ? NULL_TREE : op.ops[2],
- NULL_TREE, &vec_oprnds[2]);
+ &vec_oprnds[2]);
}
/* For single def-use cycles get one copy of the vectorized reduction
definition. */
if (single_defuse_cycle)
{
- vect_get_vec_defs (loop_vinfo, stmt_info, slp_node, 1,
+ vect_get_vec_defs (loop_vinfo, slp_node,
reduc_index == 0 ? op.ops[0] : NULL_TREE,
&vec_oprnds[0],
reduc_index == 1 ? op.ops[1] : NULL_TREE,
@@ -8539,7 +8527,7 @@ vect_transform_cycle_phi (loop_vec_info loop_vinfo,
stmt_vec_info stmt_info,
slp_tree slp_node, slp_instance slp_node_instance)
{
- tree vectype_out = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype_out = SLP_TREE_VECTYPE (slp_node);
class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
int i;
bool nested_cycle = false;
@@ -8770,6 +8758,18 @@ vectorizable_lc_phi (loop_vec_info loop_vinfo,
"incompatible vector types for invariants\n");
return false;
}
+
+ /* ??? This can happen with data vs. mask uses of boolean. */
+ if (!useless_type_conversion_p (SLP_TREE_VECTYPE (slp_node),
+ SLP_TREE_VECTYPE
+ (SLP_TREE_CHILDREN (slp_node)[0])))
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "missed mask promotion\n");
+ return false;
+ }
+
STMT_VINFO_TYPE (stmt_info) = lc_phi_info_type;
return true;
}
@@ -8780,13 +8780,13 @@ vect_transform_lc_phi (loop_vec_info loop_vinfo,
slp_tree slp_node)
{
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype = SLP_TREE_VECTYPE (slp_node);
tree scalar_dest = gimple_phi_result (stmt_info->stmt);
basic_block bb = gimple_bb (stmt_info->stmt);
edge e = single_pred_edge (bb);
tree vec_dest = vect_create_destination_var (scalar_dest, vectype);
auto_vec<tree> vec_oprnds;
- vect_get_vec_defs (loop_vinfo, stmt_info, slp_node, 1,
+ vect_get_vec_defs (loop_vinfo, slp_node,
gimple_phi_arg_def (stmt_info->stmt, 0), &vec_oprnds);
for (unsigned i = 0; i < vec_oprnds.length (); i++)
{
@@ -8803,7 +8803,7 @@ vect_transform_lc_phi (loop_vec_info loop_vinfo,
bool
vectorizable_phi (vec_info *,
- stmt_vec_info stmt_info, gimple **vec_stmt,
+ stmt_vec_info stmt_info,
slp_tree slp_node, stmt_vector_for_cost *cost_vec)
{
if (!is_a <gphi *> (stmt_info->stmt) || !slp_node)
@@ -8814,7 +8814,7 @@ vectorizable_phi (vec_info *,
tree vectype = SLP_TREE_VECTYPE (slp_node);
- if (!vec_stmt) /* transformation not required. */
+ if (cost_vec) /* transformation not required. */
{
slp_tree child;
unsigned i;
@@ -8945,8 +8945,7 @@ vectorizable_phi (vec_info *,
bool
vectorizable_recurr (loop_vec_info loop_vinfo, stmt_vec_info stmt_info,
- gimple **vec_stmt, slp_tree slp_node,
- stmt_vector_for_cost *cost_vec)
+ slp_tree slp_node, stmt_vector_for_cost *cost_vec)
{
if (!loop_vinfo || !is_a<gphi *> (stmt_info->stmt))
return false;
@@ -8957,14 +8956,10 @@ vectorizable_recurr (loop_vec_info loop_vinfo, stmt_vec_info stmt_info,
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_first_order_recurrence)
return false;
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
- unsigned ncopies;
- if (slp_node)
- ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
- else
- ncopies = vect_get_num_copies (loop_vinfo, vectype);
+ tree vectype = SLP_TREE_VECTYPE (slp_node);
+ unsigned ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
poly_int64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
- unsigned dist = slp_node ? SLP_TREE_LANES (slp_node) : 1;
+ unsigned dist = SLP_TREE_LANES (slp_node);
/* We need to be able to make progress with a single vector. */
if (maybe_gt (dist * 2, nunits))
{
@@ -8982,48 +8977,30 @@ vectorizable_recurr (loop_vec_info loop_vinfo, stmt_vec_info stmt_info,
sel.quick_push (nunits - dist + i);
vec_perm_indices indices (sel, 2, nunits);
- if (!vec_stmt) /* transformation not required. */
+ if (cost_vec) /* transformation not required. */
{
if (!can_vec_perm_const_p (TYPE_MODE (vectype), TYPE_MODE (vectype),
indices))
return false;
- if (slp_node)
- {
- /* We eventually need to set a vector type on invariant
- arguments. */
- unsigned j;
- slp_tree child;
- FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (slp_node), j, child)
- if (!vect_maybe_update_slp_op_vectype
- (child, SLP_TREE_VECTYPE (slp_node)))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "incompatible vector types for "
- "invariants\n");
- return false;
- }
- }
+ /* We eventually need to set a vector type on invariant
+ arguments. */
+ unsigned j;
+ slp_tree child;
+ FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (slp_node), j, child)
+ if (!vect_maybe_update_slp_op_vectype (child, vectype))
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "incompatible vector types for "
+ "invariants\n");
+ return false;
+ }
/* Verify we have set up compatible types. */
edge le = loop_latch_edge (LOOP_VINFO_LOOP (loop_vinfo));
- tree latch_vectype = NULL_TREE;
- if (slp_node)
- {
- slp_tree latch_def = SLP_TREE_CHILDREN (slp_node)[le->dest_idx];
- latch_vectype = SLP_TREE_VECTYPE (latch_def);
- }
- else
- {
- tree latch_def = PHI_ARG_DEF_FROM_EDGE (phi, le);
- if (TREE_CODE (latch_def) == SSA_NAME)
- {
- stmt_vec_info latch_def_info = loop_vinfo->lookup_def (latch_def);
- latch_def_info = vect_stmt_to_vectorize (latch_def_info);
- latch_vectype = STMT_VINFO_VECTYPE (latch_def_info);
- }
- }
+ slp_tree latch_def = SLP_TREE_CHILDREN (slp_node)[le->dest_idx];
+ tree latch_vectype = SLP_TREE_VECTYPE (latch_def);
if (!types_compatible_p (latch_vectype, vectype))
return false;
@@ -9031,9 +9008,6 @@ vectorizable_recurr (loop_vec_info loop_vinfo, stmt_vec_info stmt_info,
for each copy. With SLP the prologue value is explicitly
represented and costed separately. */
unsigned prologue_cost = 0;
- if (!slp_node)
- prologue_cost = record_stmt_cost (cost_vec, 1, scalar_to_vec,
- stmt_info, 0, vect_prologue);
unsigned inside_cost = record_stmt_cost (cost_vec, ncopies, vector_stmt,
stmt_info, 0, vect_body);
if (dump_enabled_p ())
@@ -9085,14 +9059,9 @@ vectorizable_recurr (loop_vec_info loop_vinfo, stmt_vec_info stmt_info,
NULL, perm);
vect_finish_stmt_generation (loop_vinfo, stmt_info, vperm, &gsi2);
- if (slp_node)
- slp_node->push_vec_def (vperm);
- else
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (vperm);
+ slp_node->push_vec_def (vperm);
}
- if (!slp_node)
- *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
return true;
}
@@ -9404,7 +9373,7 @@ vect_update_nonlinear_iv (gimple_seq* stmts, tree vectype,
static bool
vectorizable_nonlinear_induction (loop_vec_info loop_vinfo,
stmt_vec_info stmt_info,
- gimple **vec_stmt, slp_tree slp_node,
+ slp_tree slp_node,
stmt_vector_for_cost *cost_vec)
{
class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
@@ -9560,7 +9529,7 @@ vectorizable_nonlinear_induction (loop_vec_info loop_vinfo,
gcc_unreachable ();
}
- if (!vec_stmt) /* transformation not required. */
+ if (cost_vec) /* transformation not required. */
{
unsigned inside_cost = 0, prologue_cost = 0;
/* loop cost for vec_loop. Neg induction doesn't have any
@@ -9715,8 +9684,7 @@ vectorizable_nonlinear_induction (loop_vec_info loop_vinfo,
bool
vectorizable_induction (loop_vec_info loop_vinfo,
stmt_vec_info stmt_info,
- gimple **vec_stmt, slp_tree slp_node,
- stmt_vector_for_cost *cost_vec)
+ slp_tree slp_node, stmt_vector_for_cost *cost_vec)
{
class loop *loop = LOOP_VINFO_LOOP (loop_vinfo);
bool nested_in_vect_loop = false;
@@ -9750,7 +9718,7 @@ vectorizable_induction (loop_vec_info loop_vinfo,
/* Handle nonlinear induction in a separate place. */
if (induction_type != vect_step_op_add)
return vectorizable_nonlinear_induction (loop_vinfo, stmt_info,
- vec_stmt, slp_node, cost_vec);
+ slp_node, cost_vec);
tree vectype = SLP_TREE_VECTYPE (slp_node);
poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
@@ -9854,7 +9822,7 @@ vectorizable_induction (loop_vec_info loop_vinfo,
}
}
- if (!vec_stmt) /* transformation not required. */
+ if (cost_vec) /* transformation not required. */
{
unsigned inside_cost = 0, prologue_cost = 0;
/* We eventually need to set a vector type on invariant
@@ -10286,9 +10254,8 @@ vectorizable_induction (loop_vec_info loop_vinfo,
helper function for vectorizable_live_operation. */
static tree
-vectorizable_live_operation_1 (loop_vec_info loop_vinfo,
- stmt_vec_info stmt_info, basic_block exit_bb,
- tree vectype, int ncopies, slp_tree slp_node,
+vectorizable_live_operation_1 (loop_vec_info loop_vinfo, basic_block exit_bb,
+ tree vectype, slp_tree slp_node,
tree bitsize, tree bitstart, tree vec_lhs,
tree lhs_type, gimple_stmt_iterator *exit_gsi)
{
@@ -10319,8 +10286,7 @@ vectorizable_live_operation_1 (loop_vec_info loop_vinfo,
where VEC_LHS is the vectorized live-out result and MASK is
the loop mask for the final iteration. */
- gcc_assert (ncopies == 1
- && (!slp_node || SLP_TREE_LANES (slp_node) == 1));
+ gcc_assert (SLP_TREE_LANES (slp_node) == 1);
gimple_seq tem = NULL;
gimple_stmt_iterator gsi = gsi_last (tem);
tree len = vect_get_loop_len (loop_vinfo, &gsi,
@@ -10355,8 +10321,8 @@ vectorizable_live_operation_1 (loop_vec_info loop_vinfo,
where VEC_LHS is the vectorized live-out result and MASK is
the loop mask for the final iteration. */
- gcc_assert (!slp_node || SLP_TREE_LANES (slp_node) == 1);
- tree scalar_type = TREE_TYPE (STMT_VINFO_VECTYPE (stmt_info));
+ gcc_assert (SLP_TREE_LANES (slp_node) == 1);
+ tree scalar_type = TREE_TYPE (vectype);
gimple_seq tem = NULL;
gimple_stmt_iterator gsi = gsi_last (tem);
tree mask = vect_get_loop_mask (loop_vinfo, &gsi,
@@ -10402,11 +10368,8 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info,
loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
imm_use_iterator imm_iter;
tree lhs, lhs_type, bitsize;
- tree vectype = (slp_node
- ? SLP_TREE_VECTYPE (slp_node)
- : STMT_VINFO_VECTYPE (stmt_info));
+ tree vectype = SLP_TREE_VECTYPE (slp_node);
poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
- int ncopies;
gimple *use_stmt;
use_operand_p use_p;
auto_vec<tree> vec_oprnds;
@@ -10425,7 +10388,7 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info,
return true;
/* For SLP reductions we vectorize the epilogue for all involved stmts
together. */
- if (slp_node && !REDUC_GROUP_FIRST_ELEMENT (stmt_info) && slp_index != 0)
+ if (!REDUC_GROUP_FIRST_ELEMENT (stmt_info) && slp_index != 0)
return true;
stmt_vec_info reduc_info = info_for_reduction (loop_vinfo, stmt_info);
gcc_assert (reduc_info->is_reduc_info);
@@ -10443,7 +10406,7 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info,
block, but we have to find an alternate exit first. */
if (LOOP_VINFO_EARLY_BREAKS (loop_vinfo))
{
- slp_tree phis_node = slp_node ? slp_node_instance->reduc_phis : NULL;
+ slp_tree phis_node = slp_node_instance->reduc_phis;
for (auto exit : get_loop_exit_edges (LOOP_VINFO_LOOP (loop_vinfo)))
if (exit != LOOP_VINFO_IV_EXIT (loop_vinfo))
{
@@ -10474,32 +10437,24 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info,
return true;
}
- if (slp_node)
- ncopies = 1;
- else
- ncopies = vect_get_num_copies (loop_vinfo, vectype);
-
- if (slp_node)
- {
- gcc_assert (slp_index >= 0);
+ gcc_assert (slp_index >= 0);
- /* Get the last occurrence of the scalar index from the concatenation of
- all the slp vectors. Calculate which slp vector it is and the index
- within. */
- int num_scalar = SLP_TREE_LANES (slp_node);
- int num_vec = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
- poly_uint64 pos = (num_vec * nunits) - num_scalar + slp_index;
+ /* Get the last occurrence of the scalar index from the concatenation of
+ all the slp vectors. Calculate which slp vector it is and the index
+ within. */
+ int num_scalar = SLP_TREE_LANES (slp_node);
+ int num_vec = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
+ poly_uint64 pos = (num_vec * nunits) - num_scalar + slp_index;
- /* Calculate which vector contains the result, and which lane of
- that vector we need. */
- if (!can_div_trunc_p (pos, nunits, &vec_entry, &vec_index))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "Cannot determine which vector holds the"
- " final result.\n");
- return false;
- }
+ /* Calculate which vector contains the result, and which lane of
+ that vector we need. */
+ if (!can_div_trunc_p (pos, nunits, &vec_entry, &vec_index))
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "Cannot determine which vector holds the"
+ " final result.\n");
+ return false;
}
if (!vec_stmt_p)
@@ -10507,7 +10462,7 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info,
/* No transformation required. */
if (loop_vinfo && LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
{
- if (slp_node && SLP_TREE_LANES (slp_node) != 1)
+ if (SLP_TREE_LANES (slp_node) != 1)
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -10516,8 +10471,7 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info,
"the loop.\n");
LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
}
- else if (ncopies > 1
- || (slp_node && SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) > 1))
+ else if (SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) > 1)
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -10527,8 +10481,6 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info,
}
else
{
- gcc_assert (ncopies == 1
- && (!slp_node || SLP_TREE_LANES (slp_node) == 1));
if (direct_internal_fn_supported_p (IFN_EXTRACT_LAST, vectype,
OPTIMIZE_FOR_SPEED))
vect_record_loop_mask (loop_vinfo,
@@ -10570,40 +10522,21 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info,
bitsize = vector_element_bits_tree (vectype);
/* Get the vectorized lhs of STMT and the lane to use (counted in bits). */
- tree vec_lhs, vec_lhs0, bitstart;
- gimple *vec_stmt, *vec_stmt0;
- if (slp_node)
- {
- gcc_assert (!loop_vinfo
- || ((!LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
- && !LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo))
- || SLP_TREE_LANES (slp_node) == 1));
+ gcc_assert (!loop_vinfo
+ || ((!LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
+ && !LOOP_VINFO_FULLY_WITH_LENGTH_P (loop_vinfo))
+ || SLP_TREE_LANES (slp_node) == 1));
- /* Get the correct slp vectorized stmt. */
- vec_lhs = SLP_TREE_VEC_DEFS (slp_node)[vec_entry];
- vec_stmt = SSA_NAME_DEF_STMT (vec_lhs);
+ /* Get the correct slp vectorized stmt. */
+ tree vec_lhs = SLP_TREE_VEC_DEFS (slp_node)[vec_entry];
+ gimple *vec_stmt = SSA_NAME_DEF_STMT (vec_lhs);
- /* In case we need to early break vectorize also get the first stmt. */
- vec_lhs0 = SLP_TREE_VEC_DEFS (slp_node)[0];
- vec_stmt0 = SSA_NAME_DEF_STMT (vec_lhs0);
+ /* In case we need to early break vectorize also get the first stmt. */
+ tree vec_lhs0 = SLP_TREE_VEC_DEFS (slp_node)[0];
- /* Get entry to use. */
- bitstart = bitsize_int (vec_index);
- bitstart = int_const_binop (MULT_EXPR, bitsize, bitstart);
- }
- else
- {
- /* For multiple copies, get the last copy. */
- vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info).last ();
- vec_lhs = gimple_get_lhs (vec_stmt);
-
- /* In case we need to early break vectorize also get the first stmt. */
- vec_stmt0 = STMT_VINFO_VEC_STMTS (stmt_info)[0];
- vec_lhs0 = gimple_get_lhs (vec_stmt0);
-
- /* Get the last lane in the vector. */
- bitstart = int_const_binop (MULT_EXPR, bitsize, bitsize_int (nunits - 1));
- }
+ /* Get entry to use. */
+ tree bitstart = bitsize_int (vec_index);
+ bitstart = int_const_binop (MULT_EXPR, bitsize, bitstart);
if (loop_vinfo)
{
@@ -10652,8 +10585,8 @@ vectorizable_live_operation (vec_info *vinfo, stmt_vec_info stmt_info,
gimple_stmt_iterator exit_gsi;
tree new_tree
- = vectorizable_live_operation_1 (loop_vinfo, stmt_info,
- e->dest, vectype, ncopies,
+ = vectorizable_live_operation_1 (loop_vinfo,
+ e->dest, vectype,
slp_node, bitsize,
tmp_bitstart, tmp_vec_lhs,
lhs_type, &exit_gsi);
diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
index 0f6d6b7..f0ddbf9 100644
--- a/gcc/tree-vect-patterns.cc
+++ b/gcc/tree-vect-patterns.cc
@@ -6042,12 +6042,14 @@ vect_recog_gather_scatter_pattern (vec_info *vinfo,
tree vec_els
= vect_get_mask_load_else (elsval, TREE_TYPE (gs_vectype));
- pattern_stmt = gimple_build_call_internal (gs_info.ifn, 6, base,
+ pattern_stmt = gimple_build_call_internal (gs_info.ifn, 7, base,
+ gs_info.alias_ptr,
offset, scale, zero, mask,
vec_els);
}
else
- pattern_stmt = gimple_build_call_internal (gs_info.ifn, 4, base,
+ pattern_stmt = gimple_build_call_internal (gs_info.ifn, 5, base,
+ gs_info.alias_ptr,
offset, scale, zero);
tree lhs = gimple_get_lhs (stmt_info->stmt);
tree load_lhs = vect_recog_temp_ssa_var (TREE_TYPE (lhs), NULL);
@@ -6057,12 +6059,13 @@ vect_recog_gather_scatter_pattern (vec_info *vinfo,
{
tree rhs = vect_get_store_rhs (stmt_info);
if (mask != NULL)
- pattern_stmt = gimple_build_call_internal (gs_info.ifn, 5,
- base, offset, scale, rhs,
- mask);
+ pattern_stmt = gimple_build_call_internal (gs_info.ifn, 6,
+ base, gs_info.alias_ptr,
+ offset, scale, rhs, mask);
else
- pattern_stmt = gimple_build_call_internal (gs_info.ifn, 4,
- base, offset, scale, rhs);
+ pattern_stmt = gimple_build_call_internal (gs_info.ifn, 5,
+ base, gs_info.alias_ptr,
+ offset, scale, rhs);
}
gimple_call_set_nothrow (pattern_stmt, true);
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index fe67d4d..c0636d8 100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -507,19 +507,21 @@ vect_def_types_match (enum vect_def_type dta, enum vect_def_type dtb)
&& (dtb == vect_external_def || dtb == vect_constant_def)));
}
+#define GATHER_SCATTER_OFFSET (-3)
+
static const int no_arg_map[] = { 0 };
static const int arg0_map[] = { 1, 0 };
-static const int arg1_map[] = { 1, 1 };
+static const int arg2_map[] = { 1, 2 };
static const int arg2_arg3_map[] = { 2, 2, 3 };
-static const int arg1_arg3_map[] = { 2, 1, 3 };
-static const int arg1_arg4_arg5_map[] = { 3, 1, 4, 5 };
-static const int arg1_arg3_arg4_map[] = { 3, 1, 3, 4 };
+static const int arg2_arg4_map[] = { 2, 2, 4 };
+static const int arg2_arg5_arg6_map[] = { 3, 2, 5, 6 };
+static const int arg2_arg4_arg5_map[] = { 3, 2, 4, 5 };
static const int arg3_arg2_map[] = { 2, 3, 2 };
static const int op1_op0_map[] = { 2, 1, 0 };
-static const int off_map[] = { 1, -3 };
-static const int off_op0_map[] = { 2, -3, 0 };
-static const int off_arg2_arg3_map[] = { 3, -3, 2, 3 };
-static const int off_arg3_arg2_map[] = { 3, -3, 3, 2 };
+static const int off_map[] = { 1, GATHER_SCATTER_OFFSET };
+static const int off_op0_map[] = { 2, GATHER_SCATTER_OFFSET, 0 };
+static const int off_arg2_arg3_map[] = { 3, GATHER_SCATTER_OFFSET, 2, 3 };
+static const int off_arg3_arg2_map[] = { 3, GATHER_SCATTER_OFFSET, 3, 2 };
static const int mask_call_maps[6][7] = {
{ 1, 1, },
{ 2, 1, 2, },
@@ -568,18 +570,18 @@ vect_get_operand_map (const gimple *stmt, bool gather_scatter_p = false,
return gather_scatter_p ? off_arg2_arg3_map : arg2_arg3_map;
case IFN_GATHER_LOAD:
- return arg1_map;
+ return arg2_map;
case IFN_MASK_GATHER_LOAD:
case IFN_MASK_LEN_GATHER_LOAD:
- return arg1_arg4_arg5_map;
+ return arg2_arg5_arg6_map;
case IFN_SCATTER_STORE:
- return arg1_arg3_map;
+ return arg2_arg4_map;
case IFN_MASK_SCATTER_STORE:
case IFN_MASK_LEN_SCATTER_STORE:
- return arg1_arg3_arg4_map;
+ return arg2_arg4_arg5_map;
case IFN_MASK_STORE:
return gather_scatter_p ? off_arg3_arg2_map : arg3_arg2_map;
@@ -691,7 +693,7 @@ vect_get_and_check_slp_defs (vec_info *vinfo, unsigned char swap,
{
oprnd_info = (*oprnds_info)[i];
int opno = map ? map[i] : int (i);
- if (opno == -3)
+ if (opno == GATHER_SCATTER_OFFSET)
{
gcc_assert (STMT_VINFO_GATHER_SCATTER_P (stmt_info));
if (!is_a <loop_vec_info> (vinfo)
@@ -5239,7 +5241,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size,
if (STMT_VINFO_STRIDED_P (stmt_vinfo)
|| compare_step_with_zero (vinfo, stmt_vinfo) <= 0
|| vect_load_lanes_supported
- (STMT_VINFO_VECTYPE (stmt_vinfo),
+ (SLP_TREE_VECTYPE (load_node),
DR_GROUP_SIZE (stmt_vinfo), masked) == IFN_LAST
/* ??? During SLP re-discovery with a single lane
a masked grouped load will appear permuted and
@@ -5260,7 +5262,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned max_tree_size,
|| SLP_TREE_LANES (load_node) == group_size
|| (vect_slp_prefer_store_lanes_p
(vinfo, stmt_vinfo,
- STMT_VINFO_VECTYPE (stmt_vinfo), masked,
+ SLP_TREE_VECTYPE (load_node), masked,
group_size, SLP_TREE_LANES (load_node))));
}
@@ -7586,20 +7588,25 @@ vect_make_slp_decision (loop_vec_info loop_vinfo)
hash_set<slp_tree> visited;
FOR_EACH_VEC_ELT (slp_instances, i, instance)
{
- /* FORNOW: SLP if you can. */
+ slp_tree root = SLP_INSTANCE_TREE (instance);
+
/* All unroll factors have the form:
GET_MODE_SIZE (vinfo->vector_mode) * X
for some rational X, so they must have a common multiple. */
- vect_update_slp_vf_for_node (SLP_INSTANCE_TREE (instance),
- unrolling_factor, visited);
+ vect_update_slp_vf_for_node (root, unrolling_factor, visited);
/* Mark all the stmts that belong to INSTANCE as PURE_SLP stmts. Later we
call vect_detect_hybrid_slp () to find stmts that need hybrid SLP and
loop-based vectorization. Such stmts will be marked as HYBRID. */
- vect_mark_slp_stmts (loop_vinfo, SLP_INSTANCE_TREE (instance));
- decided_to_slp++;
+ vect_mark_slp_stmts (loop_vinfo, root);
+
+ /* If all instances ended up with vector(1) T roots make sure to
+ not vectorize. RVV for example relies on loop vectorization
+ when some instances are essentially kept scalar. See PR121048. */
+ if (known_gt (TYPE_VECTOR_SUBPARTS (SLP_TREE_VECTYPE (root)), 1U))
+ decided_to_slp++;
}
LOOP_VINFO_SLP_UNROLLING_FACTOR (loop_vinfo) = unrolling_factor;
@@ -8643,7 +8650,7 @@ vect_slp_analyze_operations (vec_info *vinfo)
|| (SLP_INSTANCE_KIND (instance) == slp_inst_kind_gcond
&& !vectorizable_early_exit (vinfo,
SLP_INSTANCE_ROOT_STMTS (instance)[0],
- NULL, NULL,
+ NULL,
SLP_INSTANCE_TREE (instance),
&cost_vec)))
{
@@ -9565,14 +9572,13 @@ vect_slp_analyze_bb_1 (bb_vec_info bb_vinfo, int n_stmts, bool &fatal,
slp_instance instance;
int i;
- poly_uint64 min_vf = 2;
/* The first group of checks is independent of the vector size. */
fatal = true;
/* Analyze the data references. */
- if (!vect_analyze_data_refs (bb_vinfo, &min_vf, NULL))
+ if (!vect_analyze_data_refs (bb_vinfo, NULL))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -11366,7 +11372,11 @@ vect_schedule_slp_node (vec_info *vinfo,
&& !SSA_NAME_IS_DEFAULT_DEF (def))
{
gimple *stmt = SSA_NAME_DEF_STMT (def);
- if (!last_stmt)
+ if (gimple_uid (stmt) == -1u)
+ /* If the stmt is not inside the region do not
+ use it as possible insertion point. */
+ ;
+ else if (!last_stmt)
last_stmt = stmt;
else if (vect_stmt_dominates_stmt_p (last_stmt, stmt))
last_stmt = stmt;
@@ -11671,10 +11681,9 @@ vectorize_slp_instance_root_stmt (vec_info *vinfo, slp_tree node, slp_instance i
auto root_stmt_info = instance->root_stmts[0];
auto last_stmt = STMT_VINFO_STMT (vect_orig_stmt (root_stmt_info));
gimple_stmt_iterator rgsi = gsi_for_stmt (last_stmt);
- gimple *vec_stmt = NULL;
gcc_assert (!SLP_TREE_VEC_DEFS (node).is_empty ());
bool res = vectorizable_early_exit (vinfo, root_stmt_info, &rgsi,
- &vec_stmt, node, NULL);
+ node, NULL);
gcc_assert (res);
return;
}
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index f0d3105..aa2657a 100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -62,14 +62,6 @@ along with GCC; see the file COPYING3. If not see
/* For lang_hooks.types.type_for_mode. */
#include "langhooks.h"
-/* Return the vectorized type for the given statement. */
-
-tree
-stmt_vectype (class _stmt_vec_info *stmt_info)
-{
- return STMT_VINFO_VECTYPE (stmt_info);
-}
-
/* Return TRUE iff the given statement is in an inner loop relative to
the loop being vectorized. */
bool
@@ -901,13 +893,11 @@ vect_mark_stmts_to_be_vectorized (loop_vec_info loop_vinfo, bool *fatal)
/* Function vect_model_simple_cost.
- Models cost for simple operations, i.e. those that only emit ncopies of a
- single op. Right now, this does not account for multiple insns that could
- be generated for the single vector op. We will handle that shortly. */
+ Models cost for simple operations, i.e. those that only emit N operations
+ of the same KIND. */
static void
-vect_model_simple_cost (vec_info *, int ncopies, enum vect_def_type *dt,
- int ndts, slp_tree node,
+vect_model_simple_cost (vec_info *, int n, slp_tree node,
stmt_vector_for_cost *cost_vec,
vect_cost_for_stmt kind = vector_stmt)
{
@@ -915,22 +905,10 @@ vect_model_simple_cost (vec_info *, int ncopies, enum vect_def_type *dt,
gcc_assert (cost_vec != NULL);
- /* ??? Somehow we need to fix this at the callers. */
- if (node)
- ncopies = SLP_TREE_NUMBER_OF_VEC_STMTS (node);
-
- if (!node)
- /* Cost the "broadcast" of a scalar operand in to a vector operand.
- Use scalar_to_vec to cost the broadcast, as elsewhere in the vector
- cost model. */
- for (int i = 0; i < ndts; i++)
- if (dt[i] == vect_constant_def || dt[i] == vect_external_def)
- prologue_cost += record_stmt_cost (cost_vec, 1, scalar_to_vec,
- node, 0, vect_prologue);
+ n *= SLP_TREE_NUMBER_OF_VEC_STMTS (node);
/* Pass the inside-of-loop statements to the target-specific cost model. */
- inside_cost += record_stmt_cost (cost_vec, ncopies, kind,
- node, 0, vect_body);
+ inside_cost += record_stmt_cost (cost_vec, n, kind, node, 0, vect_body);
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
@@ -1269,130 +1247,23 @@ vect_init_vector (vec_info *vinfo, stmt_vec_info stmt_info, tree val, tree type,
}
-/* Function vect_get_vec_defs_for_operand.
-
- OP is an operand in STMT_VINFO. This function returns a vector of
- NCOPIES defs that will be used in the vectorized stmts for STMT_VINFO.
-
- In the case that OP is an SSA_NAME which is defined in the loop, then
- STMT_VINFO_VEC_STMTS of the defining stmt holds the relevant defs.
-
- In case OP is an invariant or constant, a new stmt that creates a vector def
- needs to be introduced. VECTYPE may be used to specify a required type for
- vector invariant. */
-
-void
-vect_get_vec_defs_for_operand (vec_info *vinfo, stmt_vec_info stmt_vinfo,
- unsigned ncopies,
- tree op, vec<tree> *vec_oprnds, tree vectype)
-{
- gimple *def_stmt;
- enum vect_def_type dt;
- bool is_simple_use;
- loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
-
- if (dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location,
- "vect_get_vec_defs_for_operand: %T\n", op);
-
- stmt_vec_info def_stmt_info;
- is_simple_use = vect_is_simple_use (op, loop_vinfo, &dt,
- &def_stmt_info, &def_stmt);
- gcc_assert (is_simple_use);
- if (def_stmt && dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location, " def_stmt = %G", def_stmt);
-
- vec_oprnds->create (ncopies);
- if (dt == vect_constant_def || dt == vect_external_def)
- {
- tree stmt_vectype = STMT_VINFO_VECTYPE (stmt_vinfo);
- tree vector_type;
-
- if (vectype)
- vector_type = vectype;
- else if (VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (op))
- && VECTOR_BOOLEAN_TYPE_P (stmt_vectype))
- vector_type = truth_type_for (stmt_vectype);
- else
- vector_type = get_vectype_for_scalar_type (loop_vinfo, TREE_TYPE (op));
-
- gcc_assert (vector_type);
- /* A masked load can have a default SSA definition as else operand.
- We should "vectorize" this instead of creating a duplicate from the
- scalar default. */
- tree vop;
- if (TREE_CODE (op) == SSA_NAME
- && SSA_NAME_IS_DEFAULT_DEF (op)
- && VAR_P (SSA_NAME_VAR (op)))
- vop = get_or_create_ssa_default_def (cfun,
- create_tmp_var (vector_type));
- else
- vop = vect_init_vector (vinfo, stmt_vinfo, op, vector_type, NULL);
- while (ncopies--)
- vec_oprnds->quick_push (vop);
- }
- else
- {
- def_stmt_info = vect_stmt_to_vectorize (def_stmt_info);
- gcc_assert (STMT_VINFO_VEC_STMTS (def_stmt_info).length () == ncopies);
- for (unsigned i = 0; i < ncopies; ++i)
- vec_oprnds->quick_push (gimple_get_lhs
- (STMT_VINFO_VEC_STMTS (def_stmt_info)[i]));
- }
-}
-
-
/* Get vectorized definitions for OP0 and OP1. */
void
-vect_get_vec_defs (vec_info *vinfo, stmt_vec_info stmt_info, slp_tree slp_node,
- unsigned ncopies,
- tree op0, tree vectype0, vec<tree> *vec_oprnds0,
- tree op1, tree vectype1, vec<tree> *vec_oprnds1,
- tree op2, tree vectype2, vec<tree> *vec_oprnds2,
- tree op3, tree vectype3, vec<tree> *vec_oprnds3)
-{
- if (slp_node)
- {
- if (op0)
- vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_oprnds0);
- if (op1)
- vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[1], vec_oprnds1);
- if (op2)
- vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[2], vec_oprnds2);
- if (op3)
- vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[3], vec_oprnds3);
- }
- else
- {
- if (op0)
- vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
- op0, vec_oprnds0, vectype0);
- if (op1)
- vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
- op1, vec_oprnds1, vectype1);
- if (op2)
- vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
- op2, vec_oprnds2, vectype2);
- if (op3)
- vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
- op3, vec_oprnds3, vectype3);
- }
-}
-
-void
-vect_get_vec_defs (vec_info *vinfo, stmt_vec_info stmt_info, slp_tree slp_node,
- unsigned ncopies,
+vect_get_vec_defs (vec_info *, slp_tree slp_node,
tree op0, vec<tree> *vec_oprnds0,
tree op1, vec<tree> *vec_oprnds1,
tree op2, vec<tree> *vec_oprnds2,
tree op3, vec<tree> *vec_oprnds3)
{
- vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
- op0, NULL_TREE, vec_oprnds0,
- op1, NULL_TREE, vec_oprnds1,
- op2, NULL_TREE, vec_oprnds2,
- op3, NULL_TREE, vec_oprnds3);
+ if (op0)
+ vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_oprnds0);
+ if (op1)
+ vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[1], vec_oprnds1);
+ if (op2)
+ vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[2], vec_oprnds2);
+ if (op3)
+ vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[3], vec_oprnds3);
}
/* Helper function called by vect_finish_replace_stmt and
@@ -1566,8 +1437,7 @@ check_load_store_for_partial_vectors (loop_vec_info loop_vinfo, tree vectype,
bool is_load = (vls_type == VLS_LOAD);
if (memory_access_type == VMAT_LOAD_STORE_LANES)
{
- if (slp_node)
- nvectors /= group_size;
+ nvectors /= group_size;
internal_fn ifn
= (is_load ? vect_load_lanes_supported (vectype, group_size, true,
elsvals)
@@ -1622,8 +1492,7 @@ check_load_store_for_partial_vectors (loop_vec_info loop_vinfo, tree vectype,
return;
}
- if (memory_access_type != VMAT_CONTIGUOUS
- && memory_access_type != VMAT_CONTIGUOUS_PERMUTE)
+ if (memory_access_type != VMAT_CONTIGUOUS)
{
/* Element X of the data must come from iteration i * VF + X of the
scalar loop. We need more work to support other mappings. */
@@ -1734,7 +1603,7 @@ prepare_vec_mask (loop_vec_info loop_vinfo, tree mask_type, tree loop_mask,
else values will be stored in the vector ELSVALS points to. */
static bool
-vect_truncate_gather_scatter_offset (stmt_vec_info stmt_info,
+vect_truncate_gather_scatter_offset (stmt_vec_info stmt_info, tree vectype,
loop_vec_info loop_vinfo, bool masked_p,
gather_scatter_info *gs_info,
vec<int> *elsvals)
@@ -1752,7 +1621,6 @@ vect_truncate_gather_scatter_offset (stmt_vec_info stmt_info,
}
/* Get the number of bits in an element. */
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
scalar_mode element_mode = SCALAR_TYPE_MODE (TREE_TYPE (vectype));
unsigned int element_bits = GET_MODE_BITSIZE (element_mode);
@@ -1803,6 +1671,9 @@ vect_truncate_gather_scatter_offset (stmt_vec_info stmt_info,
/* Logically the sum of DR_BASE_ADDRESS, DR_INIT and DR_OFFSET,
but we don't need to store that here. */
gs_info->base = NULL_TREE;
+ gs_info->alias_ptr = build_int_cst
+ (reference_alias_ptr_type (DR_REF (dr)),
+ get_object_alignment (DR_REF (dr)));
gs_info->element_type = TREE_TYPE (vectype);
gs_info->offset = fold_convert (offset_type, step);
gs_info->offset_dt = vect_constant_def;
@@ -1829,14 +1700,14 @@ vect_truncate_gather_scatter_offset (stmt_vec_info stmt_info,
else values will be stored in the vector ELSVALS points to. */
static bool
-vect_use_strided_gather_scatters_p (stmt_vec_info stmt_info,
+vect_use_strided_gather_scatters_p (stmt_vec_info stmt_info, tree vectype,
loop_vec_info loop_vinfo, bool masked_p,
gather_scatter_info *gs_info,
vec<int> *elsvals)
{
if (!vect_check_gather_scatter (stmt_info, loop_vinfo, gs_info, elsvals)
|| gs_info->ifn == IFN_LAST)
- return vect_truncate_gather_scatter_offset (stmt_info, loop_vinfo,
+ return vect_truncate_gather_scatter_offset (stmt_info, vectype, loop_vinfo,
masked_p, gs_info, elsvals);
tree old_offset_type = TREE_TYPE (gs_info->offset);
@@ -2106,7 +1977,7 @@ get_group_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
separated by the stride, until we have a complete vector.
Fall back to scalar accesses if that isn't possible. */
*memory_access_type = VMAT_STRIDED_SLP;
- else
+ else if (!STMT_VINFO_GATHER_SCATTER_P (stmt_info))
{
int cmp = compare_step_with_zero (vinfo, stmt_info);
if (cmp < 0)
@@ -2349,19 +2220,73 @@ get_group_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
allows us to use contiguous accesses. */
if ((*memory_access_type == VMAT_ELEMENTWISE
|| *memory_access_type == VMAT_STRIDED_SLP)
+ && !STMT_VINFO_GATHER_SCATTER_P (stmt_info)
&& single_element_p
&& SLP_TREE_LANES (slp_node) == 1
&& loop_vinfo
- && vect_use_strided_gather_scatters_p (stmt_info, loop_vinfo,
+ && vect_use_strided_gather_scatters_p (stmt_info, vectype, loop_vinfo,
masked_p, gs_info, elsvals))
*memory_access_type = VMAT_GATHER_SCATTER;
+ else if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
+ {
+ tree offset;
+ slp_tree offset_node;
+ *memory_access_type = VMAT_GATHER_SCATTER;
+ if (!vect_check_gather_scatter (stmt_info, loop_vinfo, gs_info,
+ elsvals))
+ gcc_unreachable ();
+ /* When using internal functions, we rely on pattern recognition
+ to convert the type of the offset to the type that the target
+ requires, with the result being a call to an internal function.
+ If that failed for some reason (e.g. because another pattern
+ took priority), just handle cases in which the offset already
+ has the right type. */
+ else if (GATHER_SCATTER_IFN_P (*gs_info)
+ && !is_gimple_call (stmt_info->stmt)
+ && !tree_nop_conversion_p (TREE_TYPE (gs_info->offset),
+ TREE_TYPE (gs_info->offset_vectype)))
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "%s offset requires a conversion\n",
+ vls_type == VLS_LOAD ? "gather" : "scatter");
+ return false;
+ }
+ else if (!vect_is_simple_use (vinfo, slp_node, 0, &offset, &offset_node,
+ &gs_info->offset_dt,
+ &gs_info->offset_vectype))
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "%s index use not simple.\n",
+ vls_type == VLS_LOAD ? "gather" : "scatter");
+ return false;
+ }
+ else if (GATHER_SCATTER_EMULATED_P (*gs_info))
+ {
+ if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant ()
+ || !TYPE_VECTOR_SUBPARTS (gs_info->offset_vectype).is_constant ()
+ || VECTOR_BOOLEAN_TYPE_P (gs_info->offset_vectype)
+ || !constant_multiple_p (TYPE_VECTOR_SUBPARTS
+ (gs_info->offset_vectype),
+ TYPE_VECTOR_SUBPARTS (vectype)))
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "unsupported vector types for emulated "
+ "gather.\n");
+ return false;
+ }
+ }
+ }
if (*memory_access_type == VMAT_CONTIGUOUS_DOWN
|| *memory_access_type == VMAT_CONTIGUOUS_REVERSE)
*poffset = neg_ldst_offset;
- if (*memory_access_type == VMAT_GATHER_SCATTER
- || *memory_access_type == VMAT_ELEMENTWISE
+ if (*memory_access_type == VMAT_ELEMENTWISE
+ || (*memory_access_type == VMAT_GATHER_SCATTER
+ && GATHER_SCATTER_LEGACY_P (*gs_info))
|| *memory_access_type == VMAT_STRIDED_SLP
|| *memory_access_type == VMAT_INVARIANT)
{
@@ -2370,10 +2295,15 @@ get_group_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
}
else
{
- *misalignment = dr_misalignment (first_dr_info, vectype, *poffset);
+ if (*memory_access_type == VMAT_GATHER_SCATTER
+ && !first_dr_info)
+ *misalignment = DR_MISALIGNMENT_UNKNOWN;
+ else
+ *misalignment = dr_misalignment (first_dr_info, vectype, *poffset);
*alignment_support_scheme
- = vect_supportable_dr_alignment (vinfo, first_dr_info, vectype,
- *misalignment);
+ = vect_supportable_dr_alignment
+ (vinfo, first_dr_info, vectype, *misalignment,
+ *memory_access_type == VMAT_GATHER_SCATTER ? gs_info : nullptr);
}
if (vls_type != VLS_LOAD && first_stmt_info == stmt_info)
@@ -2443,58 +2373,12 @@ get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
*misalignment = DR_MISALIGNMENT_UNKNOWN;
*poffset = 0;
- if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
- {
- *memory_access_type = VMAT_GATHER_SCATTER;
- if (!vect_check_gather_scatter (stmt_info, loop_vinfo, gs_info,
- elsvals))
- gcc_unreachable ();
- /* When using internal functions, we rely on pattern recognition
- to convert the type of the offset to the type that the target
- requires, with the result being a call to an internal function.
- If that failed for some reason (e.g. because another pattern
- took priority), just handle cases in which the offset already
- has the right type. */
- else if (gs_info->ifn != IFN_LAST
- && !is_gimple_call (stmt_info->stmt)
- && !tree_nop_conversion_p (TREE_TYPE (gs_info->offset),
- TREE_TYPE (gs_info->offset_vectype)))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "%s offset requires a conversion\n",
- vls_type == VLS_LOAD ? "gather" : "scatter");
- return false;
- }
- slp_tree offset_node = SLP_TREE_CHILDREN (slp_node)[0];
- gs_info->offset_dt = SLP_TREE_DEF_TYPE (offset_node);
- gs_info->offset_vectype = SLP_TREE_VECTYPE (offset_node);
- if (gs_info->ifn == IFN_LAST && !gs_info->decl)
- {
- if (!TYPE_VECTOR_SUBPARTS (vectype).is_constant ()
- || !TYPE_VECTOR_SUBPARTS (gs_info->offset_vectype).is_constant ()
- || VECTOR_BOOLEAN_TYPE_P (gs_info->offset_vectype)
- || !constant_multiple_p (TYPE_VECTOR_SUBPARTS
- (gs_info->offset_vectype),
- TYPE_VECTOR_SUBPARTS (vectype)))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "unsupported vector types for emulated "
- "gather.\n");
- return false;
- }
- }
- /* Gather-scatter accesses perform only component accesses, alignment
- is irrelevant for them. */
- *alignment_support_scheme = dr_unaligned_supported;
- }
- else if (!get_group_load_store_type (vinfo, stmt_info, vectype, slp_node,
- masked_p,
- vls_type, memory_access_type, poffset,
- alignment_support_scheme,
- misalignment, gs_info, lanes_ifn,
- elsvals))
+ if (!get_group_load_store_type (vinfo, stmt_info, vectype, slp_node,
+ masked_p,
+ vls_type, memory_access_type, poffset,
+ alignment_support_scheme,
+ misalignment, gs_info, lanes_ifn,
+ elsvals))
return false;
if ((*memory_access_type == VMAT_ELEMENTWISE
@@ -2528,17 +2412,18 @@ get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
"alignment. With non-contiguous memory vectorization"
" could read out of bounds at %G ",
STMT_VINFO_STMT (stmt_info));
- if (inbounds)
- LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true;
- else
- return false;
+ if (inbounds)
+ LOOP_VINFO_MUST_USE_PARTIAL_VECTORS_P (loop_vinfo) = true;
+ else
+ return false;
}
/* If this DR needs alignment for correctness, we must ensure the target
alignment is a constant power-of-two multiple of the amount read per
vector iteration or force masking. */
if (dr_safe_speculative_read_required (stmt_info)
- && *alignment_support_scheme == dr_aligned)
+ && (*alignment_support_scheme == dr_aligned
+ && *memory_access_type != VMAT_GATHER_SCATTER))
{
/* We can only peel for loops, of course. */
gcc_checking_assert (loop_vinfo);
@@ -2665,7 +2550,7 @@ get_load_store_type (vec_info *vinfo, stmt_vec_info stmt_info,
to the mask in *MASK_NODE if MASK_NODE is not NULL. */
static bool
-vect_check_scalar_mask (vec_info *vinfo, stmt_vec_info stmt_info,
+vect_check_scalar_mask (vec_info *vinfo,
slp_tree slp_node, unsigned mask_index,
tree *mask, slp_tree *mask_node,
vect_def_type *mask_dt_out, tree *mask_vectype_out)
@@ -2673,7 +2558,7 @@ vect_check_scalar_mask (vec_info *vinfo, stmt_vec_info stmt_info,
enum vect_def_type mask_dt;
tree mask_vectype;
slp_tree mask_node_1;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node, mask_index,
+ if (!vect_is_simple_use (vinfo, slp_node, mask_index,
mask, &mask_node_1, &mask_dt, &mask_vectype))
{
if (dump_enabled_p ())
@@ -2693,8 +2578,7 @@ vect_check_scalar_mask (vec_info *vinfo, stmt_vec_info stmt_info,
/* If the caller is not prepared for adjusting an external/constant
SLP mask vector type fail. */
- if (slp_node
- && !mask_node
+ if (!mask_node
&& SLP_TREE_DEF_TYPE (mask_node_1) != vect_internal_def)
{
if (dump_enabled_p ())
@@ -2703,7 +2587,7 @@ vect_check_scalar_mask (vec_info *vinfo, stmt_vec_info stmt_info,
return false;
}
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype = SLP_TREE_VECTYPE (slp_node);
if (!mask_vectype)
mask_vectype = get_mask_type_for_scalar_type (vinfo, TREE_TYPE (vectype),
mask_node_1);
@@ -2754,13 +2638,12 @@ vect_check_store_rhs (vec_info *vinfo, stmt_vec_info stmt_info,
&& internal_store_fn_p (gimple_call_internal_fn (call)))
op_no = internal_fn_stored_value_index (gimple_call_internal_fn (call));
}
- if (slp_node)
- op_no = vect_slp_child_index_for_operand
- (stmt_info->stmt, op_no, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
+ op_no = vect_slp_child_index_for_operand
+ (stmt_info->stmt, op_no, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
enum vect_def_type rhs_dt;
tree rhs_vectype;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node, op_no,
+ if (!vect_is_simple_use (vinfo, slp_node, op_no,
rhs, rhs_node, &rhs_dt, &rhs_vectype))
{
if (dump_enabled_p ())
@@ -2780,7 +2663,7 @@ vect_check_store_rhs (vec_info *vinfo, stmt_vec_info stmt_info,
return false;
}
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype = SLP_TREE_VECTYPE (slp_node);
if (rhs_vectype && !useless_type_conversion_p (vectype, rhs_vectype))
{
if (dump_enabled_p ())
@@ -2886,11 +2769,11 @@ vect_get_mask_load_else (int elsval, tree type)
static gimple *
vect_build_one_gather_load_call (vec_info *vinfo, stmt_vec_info stmt_info,
+ tree vectype,
gimple_stmt_iterator *gsi,
gather_scatter_info *gs_info,
tree ptr, tree offset, tree mask)
{
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
tree arglist = TYPE_ARG_TYPES (TREE_TYPE (gs_info->decl));
tree rettype = TREE_TYPE (TREE_TYPE (gs_info->decl));
tree srctype = TREE_VALUE (arglist); arglist = TREE_CHAIN (arglist);
@@ -3067,8 +2950,7 @@ vect_build_one_scatter_store_call (vec_info *vinfo, stmt_vec_info stmt_info,
containing loop. */
static void
-vect_get_gather_scatter_ops (loop_vec_info loop_vinfo,
- class loop *loop, stmt_vec_info stmt_info,
+vect_get_gather_scatter_ops (class loop *loop,
slp_tree slp_node, gather_scatter_info *gs_info,
tree *dataref_ptr, vec<tree> *vec_offset)
{
@@ -3081,16 +2963,7 @@ vect_get_gather_scatter_ops (loop_vec_info loop_vinfo,
new_bb = gsi_insert_seq_on_edge_immediate (pe, stmts);
gcc_assert (!new_bb);
}
- if (slp_node)
- vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_offset);
- else
- {
- unsigned ncopies
- = vect_get_num_copies (loop_vinfo, gs_info->offset_vectype);
- vect_get_vec_defs_for_operand (loop_vinfo, stmt_info, ncopies,
- gs_info->offset, vec_offset,
- gs_info->offset_vectype);
- }
+ vect_get_slp_defs (SLP_TREE_CHILDREN (slp_node)[0], vec_offset);
}
/* Prepare to implement a grouped or strided load or store using
@@ -3103,7 +2976,7 @@ vect_get_gather_scatter_ops (loop_vec_info loop_vinfo,
I * DR_STEP / SCALE. */
static void
-vect_get_strided_load_store_ops (stmt_vec_info stmt_info,
+vect_get_strided_load_store_ops (stmt_vec_info stmt_info, tree vectype,
loop_vec_info loop_vinfo,
gimple_stmt_iterator *gsi,
gather_scatter_info *gs_info,
@@ -3111,7 +2984,6 @@ vect_get_strided_load_store_ops (stmt_vec_info stmt_info,
vec_loop_lens *loop_lens)
{
struct data_reference *dr = STMT_VINFO_DATA_REF (stmt_info);
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
if (LOOP_VINFO_USING_SELECT_VL_P (loop_vinfo))
{
@@ -3236,29 +3108,17 @@ vect_get_data_ptr_increment (vec_info *vinfo, gimple_stmt_iterator *gsi,
static bool
vectorizable_bswap (vec_info *vinfo,
stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- gimple **vec_stmt, slp_tree slp_node,
+ slp_tree slp_node,
slp_tree *slp_op,
tree vectype_in, stmt_vector_for_cost *cost_vec)
{
tree op, vectype;
gcall *stmt = as_a <gcall *> (stmt_info->stmt);
- loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
- unsigned ncopies;
op = gimple_call_arg (stmt, 0);
- vectype = STMT_VINFO_VECTYPE (stmt_info);
+ vectype = SLP_TREE_VECTYPE (slp_node);
poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
- /* Multiple types in SLP are handled by creating the appropriate number of
- vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
- case of SLP. */
- if (slp_node)
- ncopies = 1;
- else
- ncopies = vect_get_num_copies (loop_vinfo, vectype);
-
- gcc_assert (ncopies >= 1);
-
if (TYPE_SIZE (vectype_in) != TYPE_SIZE (vectype))
{
if (dump_enabled_p ())
@@ -3288,10 +3148,9 @@ vectorizable_bswap (vec_info *vinfo,
if (!can_vec_perm_const_p (vmode, vmode, indices))
return false;
- if (! vec_stmt)
+ if (cost_vec)
{
- if (slp_node
- && !vect_maybe_update_slp_op_vectype (slp_op[0], vectype_in))
+ if (!vect_maybe_update_slp_op_vectype (slp_op[0], vectype_in))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -3304,8 +3163,7 @@ vectorizable_bswap (vec_info *vinfo,
record_stmt_cost (cost_vec,
1, vector_stmt, stmt_info, 0, vect_prologue);
record_stmt_cost (cost_vec,
- slp_node
- ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) : ncopies,
+ SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node),
vec_perm, stmt_info, 0, vect_body);
return true;
}
@@ -3314,8 +3172,7 @@ vectorizable_bswap (vec_info *vinfo,
/* Transform. */
vec<tree> vec_oprnds = vNULL;
- vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
- op, &vec_oprnds);
+ vect_get_vec_defs (vinfo, slp_node, op, &vec_oprnds);
/* Arguments are ready. create the new vector stmt. */
unsigned i;
tree vop;
@@ -3334,15 +3191,9 @@ vectorizable_bswap (vec_info *vinfo,
new_stmt = gimple_build_assign (tem, build1 (VIEW_CONVERT_EXPR,
vectype, tem2));
vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
- if (slp_node)
- slp_node->push_vec_def (new_stmt);
- else
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
+ slp_node->push_vec_def (new_stmt);
}
- if (!slp_node)
- *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
-
vec_oprnds.release ();
return true;
}
@@ -3382,14 +3233,14 @@ simple_integer_narrowing (tree vectype_out, tree vectype_in,
static bool
vectorizable_call (vec_info *vinfo,
stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- gimple **vec_stmt, slp_tree slp_node,
+ slp_tree slp_node,
stmt_vector_for_cost *cost_vec)
{
gcall *stmt;
tree vec_dest;
tree scalar_dest;
tree op;
- tree vec_oprnd0 = NULL_TREE, vec_oprnd1 = NULL_TREE;
+ tree vec_oprnd0 = NULL_TREE;
tree vectype_out, vectype_in;
poly_uint64 nunits_in;
poly_uint64 nunits_out;
@@ -3401,19 +3252,16 @@ vectorizable_call (vec_info *vinfo,
vect_unknown_def_type };
tree vectypes[ARRAY_SIZE (dt)] = {};
slp_tree slp_op[ARRAY_SIZE (dt)] = {};
- int ndts = ARRAY_SIZE (dt);
- int ncopies, j;
auto_vec<tree, 8> vargs;
enum { NARROW, NONE, WIDEN } modifier;
size_t i, nargs;
- tree lhs;
tree clz_ctz_arg1 = NULL_TREE;
if (!STMT_VINFO_RELEVANT_P (stmt_info) && !bb_vinfo)
return false;
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
- && ! vec_stmt)
+ && cost_vec)
return false;
/* Is STMT_INFO a vectorizable call? */
@@ -3433,7 +3281,7 @@ vectorizable_call (vec_info *vinfo,
gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt));
- vectype_out = STMT_VINFO_VECTYPE (stmt_info);
+ vectype_out = SLP_TREE_VECTYPE (slp_node);
/* Process function arguments. */
rhs_type = NULL_TREE;
@@ -3470,13 +3318,13 @@ vectorizable_call (vec_info *vinfo,
{
if ((int) i == mask_opno)
{
- if (!vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_opno,
+ if (!vect_check_scalar_mask (vinfo, slp_node, mask_opno,
&op, &slp_op[i], &dt[i], &vectypes[i]))
return false;
continue;
}
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
+ if (!vect_is_simple_use (vinfo, slp_node,
i, &op, &slp_op[i], &dt[i], &vectypes[i]))
{
if (dump_enabled_p ())
@@ -3512,7 +3360,7 @@ vectorizable_call (vec_info *vinfo,
from the scalar type. */
if (!vectype_in)
vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node);
- if (vec_stmt)
+ if (!cost_vec)
gcc_assert (vectype_in);
if (!vectype_in)
{
@@ -3532,13 +3380,14 @@ vectorizable_call (vec_info *vinfo,
return false;
}
- if (vect_emulated_vector_p (vectype_in) || vect_emulated_vector_p (vectype_out))
- {
+ if (vect_emulated_vector_p (vectype_in)
+ || vect_emulated_vector_p (vectype_out))
+ {
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
"use emulated vector type for call\n");
return false;
- }
+ }
/* FORNOW */
nunits_in = TYPE_VECTOR_SUBPARTS (vectype_in);
@@ -3593,7 +3442,7 @@ vectorizable_call (vec_info *vinfo,
if (ifn == IFN_LAST && !fndecl)
{
if (cfn == CFN_GOMP_SIMD_LANE
- && (!slp_node || SLP_TREE_LANES (slp_node) == 1)
+ && SLP_TREE_LANES (slp_node) == 1
&& loop_vinfo
&& LOOP_VINFO_LOOP (loop_vinfo)->simduid
&& TREE_CODE (gimple_call_arg (stmt, 0)) == SSA_NAME
@@ -3609,7 +3458,7 @@ vectorizable_call (vec_info *vinfo,
|| gimple_call_builtin_p (stmt, BUILT_IN_BSWAP32)
|| gimple_call_builtin_p (stmt, BUILT_IN_BSWAP64)
|| gimple_call_builtin_p (stmt, BUILT_IN_BSWAP128)))
- return vectorizable_bswap (vinfo, stmt_info, gsi, vec_stmt, slp_node,
+ return vectorizable_bswap (vinfo, stmt_info, gsi, slp_node,
slp_op, vectype_in, cost_vec);
else
{
@@ -3620,42 +3469,27 @@ vectorizable_call (vec_info *vinfo,
}
}
- if (slp_node)
- ncopies = 1;
- else if (modifier == NARROW && ifn == IFN_LAST)
- ncopies = vect_get_num_copies (loop_vinfo, vectype_out);
- else
- ncopies = vect_get_num_copies (loop_vinfo, vectype_in);
-
- /* Sanity check: make sure that at least one copy of the vectorized stmt
- needs to be generated. */
- gcc_assert (ncopies >= 1);
-
int reduc_idx = STMT_VINFO_REDUC_IDX (stmt_info);
internal_fn cond_fn = get_conditional_internal_fn (ifn);
internal_fn cond_len_fn = get_len_internal_fn (ifn);
int len_opno = internal_fn_len_index (cond_len_fn);
vec_loop_masks *masks = (loop_vinfo ? &LOOP_VINFO_MASKS (loop_vinfo) : NULL);
vec_loop_lens *lens = (loop_vinfo ? &LOOP_VINFO_LENS (loop_vinfo) : NULL);
- if (!vec_stmt) /* transformation not required. */
+ if (cost_vec) /* transformation not required. */
{
- if (slp_node)
- for (i = 0; i < nargs; ++i)
- if (!vect_maybe_update_slp_op_vectype (slp_op[i],
- vectypes[i]
- ? vectypes[i] : vectype_in))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "incompatible vector types for invariants\n");
- return false;
- }
+ for (i = 0; i < nargs; ++i)
+ if (!vect_maybe_update_slp_op_vectype (slp_op[i],
+ vectypes[i]
+ ? vectypes[i] : vectype_in))
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "incompatible vector types for invariants\n");
+ return false;
+ }
STMT_VINFO_TYPE (stmt_info) = call_vec_info_type;
DUMP_VECT_SCOPE ("vectorizable_call");
- vect_model_simple_cost (vinfo, ncopies, dt, ndts, slp_node, cost_vec);
- if (ifn != IFN_LAST && modifier == NARROW && !slp_node)
- record_stmt_cost (cost_vec, ncopies / 2,
- vec_promote_demote, stmt_info, 0, vect_body);
+ vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
if (loop_vinfo
&& LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
@@ -3677,10 +3511,7 @@ vectorizable_call (vec_info *vinfo,
}
else
{
- unsigned int nvectors
- = (slp_node
- ? SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node)
- : ncopies);
+ unsigned int nvectors = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
tree scalar_mask = NULL_TREE;
if (mask_opno >= 0)
scalar_mask = gimple_call_arg (stmt_info->stmt, mask_opno);
@@ -3733,220 +3564,112 @@ vectorizable_call (vec_info *vinfo,
tree prev_res = NULL_TREE;
vargs.safe_grow (vect_nargs, true);
auto_vec<vec<tree> > vec_defs (nargs);
- for (j = 0; j < ncopies; ++j)
+
+ /* Build argument list for the vectorized call. */
+ if (cfn == CFN_GOMP_SIMD_LANE)
{
- /* Build argument list for the vectorized call. */
- if (slp_node)
+ for (i = 0; i < SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); ++i)
{
- if (cfn == CFN_GOMP_SIMD_LANE)
+ /* ??? For multi-lane SLP we'd need to build
+ { 0, 0, .., 1, 1, ... }. */
+ tree cst = build_index_vector (vectype_out,
+ i * nunits_out, 1);
+ tree new_var
+ = vect_get_new_ssa_name (vectype_out, vect_simple_var, "cst_");
+ gimple *init_stmt = gimple_build_assign (new_var, cst);
+ vect_init_vector_1 (vinfo, stmt_info, init_stmt, NULL);
+ new_temp = make_ssa_name (vec_dest);
+ gimple *new_stmt = gimple_build_assign (new_temp, new_var);
+ vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
+ slp_node->push_vec_def (new_stmt);
+ }
+ }
+ else
+ {
+ vec<tree> vec_oprnds0;
+ vect_get_slp_defs (vinfo, slp_node, &vec_defs);
+ vec_oprnds0 = vec_defs[0];
+
+ /* Arguments are ready. Create the new vector stmt. */
+ FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_oprnd0)
+ {
+ int varg = 0;
+ if (masked_loop_p && reduc_idx >= 0)
+ {
+ unsigned int vec_num = vec_oprnds0.length ();
+ vargs[varg++] = vect_get_loop_mask (loop_vinfo, gsi, masks,
+ vec_num, vectype_out, i);
+ }
+ size_t k;
+ for (k = 0; k < nargs; k++)
+ {
+ vec<tree> vec_oprndsk = vec_defs[k];
+ vargs[varg++] = vec_oprndsk[i];
+ }
+ if (masked_loop_p && reduc_idx >= 0)
+ vargs[varg++] = vargs[reduc_idx + 1];
+ if (clz_ctz_arg1)
+ vargs[varg++] = clz_ctz_arg1;
+
+ gimple *new_stmt;
+ if (modifier == NARROW)
{
- for (i = 0; i < SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node); ++i)
+ /* We don't define any narrowing conditional functions
+ at present. */
+ gcc_assert (mask_opno < 0);
+ tree half_res = make_ssa_name (vectype_in);
+ gcall *call = gimple_build_call_internal_vec (ifn, vargs);
+ gimple_call_set_lhs (call, half_res);
+ gimple_call_set_nothrow (call, true);
+ vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
+ if ((i & 1) == 0)
{
- /* ??? For multi-lane SLP we'd need to build
- { 0, 0, .., 1, 1, ... }. */
- tree cst = build_index_vector (vectype_out,
- i * nunits_out, 1);
- tree new_var
- = vect_get_new_ssa_name (vectype_out, vect_simple_var,
- "cst_");
- gimple *init_stmt = gimple_build_assign (new_var, cst);
- vect_init_vector_1 (vinfo, stmt_info, init_stmt, NULL);
- new_temp = make_ssa_name (vec_dest);
- gimple *new_stmt
- = gimple_build_assign (new_temp, new_var);
- vect_finish_stmt_generation (vinfo, stmt_info, new_stmt,
- gsi);
- slp_node->push_vec_def (new_stmt);
+ prev_res = half_res;
+ continue;
}
- continue;
+ new_temp = make_ssa_name (vec_dest);
+ new_stmt = vect_gimple_build (new_temp, convert_code,
+ prev_res, half_res);
+ vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
}
-
- vec<tree> vec_oprnds0;
- vect_get_slp_defs (vinfo, slp_node, &vec_defs);
- vec_oprnds0 = vec_defs[0];
-
- /* Arguments are ready. Create the new vector stmt. */
- FOR_EACH_VEC_ELT (vec_oprnds0, i, vec_oprnd0)
+ else
{
- int varg = 0;
- if (masked_loop_p && reduc_idx >= 0)
+ if (len_opno >= 0 && len_loop_p)
{
unsigned int vec_num = vec_oprnds0.length ();
- /* Always true for SLP. */
- gcc_assert (ncopies == 1);
- vargs[varg++] = vect_get_loop_mask (loop_vinfo,
- gsi, masks, vec_num,
- vectype_out, i);
+ tree len = vect_get_loop_len (loop_vinfo, gsi, lens,
+ vec_num, vectype_out, i, 1);
+ signed char biasval
+ = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
+ tree bias = build_int_cst (intQI_type_node, biasval);
+ vargs[len_opno] = len;
+ vargs[len_opno + 1] = bias;
}
- size_t k;
- for (k = 0; k < nargs; k++)
+ else if (mask_opno >= 0 && masked_loop_p)
{
- vec<tree> vec_oprndsk = vec_defs[k];
- vargs[varg++] = vec_oprndsk[i];
+ unsigned int vec_num = vec_oprnds0.length ();
+ tree mask = vect_get_loop_mask (loop_vinfo, gsi, masks,
+ vec_num, vectype_out, i);
+ vargs[mask_opno]
+ = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
+ vargs[mask_opno], gsi);
}
- if (masked_loop_p && reduc_idx >= 0)
- vargs[varg++] = vargs[reduc_idx + 1];
- if (clz_ctz_arg1)
- vargs[varg++] = clz_ctz_arg1;
- gimple *new_stmt;
- if (modifier == NARROW)
- {
- /* We don't define any narrowing conditional functions
- at present. */
- gcc_assert (mask_opno < 0);
- tree half_res = make_ssa_name (vectype_in);
- gcall *call
- = gimple_build_call_internal_vec (ifn, vargs);
- gimple_call_set_lhs (call, half_res);
- gimple_call_set_nothrow (call, true);
- vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
- if ((i & 1) == 0)
- {
- prev_res = half_res;
- continue;
- }
- new_temp = make_ssa_name (vec_dest);
- new_stmt = vect_gimple_build (new_temp, convert_code,
- prev_res, half_res);
- vect_finish_stmt_generation (vinfo, stmt_info,
- new_stmt, gsi);
- }
+ gcall *call;
+ if (ifn != IFN_LAST)
+ call = gimple_build_call_internal_vec (ifn, vargs);
else
- {
- if (len_opno >= 0 && len_loop_p)
- {
- unsigned int vec_num = vec_oprnds0.length ();
- /* Always true for SLP. */
- gcc_assert (ncopies == 1);
- tree len
- = vect_get_loop_len (loop_vinfo, gsi, lens, vec_num,
- vectype_out, i, 1);
- signed char biasval
- = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
- tree bias = build_int_cst (intQI_type_node, biasval);
- vargs[len_opno] = len;
- vargs[len_opno + 1] = bias;
- }
- else if (mask_opno >= 0 && masked_loop_p)
- {
- unsigned int vec_num = vec_oprnds0.length ();
- /* Always true for SLP. */
- gcc_assert (ncopies == 1);
- tree mask = vect_get_loop_mask (loop_vinfo,
- gsi, masks, vec_num,
- vectype_out, i);
- vargs[mask_opno] = prepare_vec_mask
- (loop_vinfo, TREE_TYPE (mask), mask,
- vargs[mask_opno], gsi);
- }
-
- gcall *call;
- if (ifn != IFN_LAST)
- call = gimple_build_call_internal_vec (ifn, vargs);
- else
- call = gimple_build_call_vec (fndecl, vargs);
- new_temp = make_ssa_name (vec_dest, call);
- gimple_call_set_lhs (call, new_temp);
- gimple_call_set_nothrow (call, true);
- vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
- new_stmt = call;
- }
- slp_node->push_vec_def (new_stmt);
- }
- continue;
- }
-
- int varg = 0;
- if (masked_loop_p && reduc_idx >= 0)
- vargs[varg++] = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies,
- vectype_out, j);
- for (i = 0; i < nargs; i++)
- {
- op = gimple_call_arg (stmt, i);
- if (j == 0)
- {
- vec_defs.quick_push (vNULL);
- vect_get_vec_defs_for_operand (vinfo, stmt_info, ncopies,
- op, &vec_defs[i],
- vectypes[i]);
- }
- vargs[varg++] = vec_defs[i][j];
- }
- if (masked_loop_p && reduc_idx >= 0)
- vargs[varg++] = vargs[reduc_idx + 1];
- if (clz_ctz_arg1)
- vargs[varg++] = clz_ctz_arg1;
-
- if (len_opno >= 0 && len_loop_p)
- {
- tree len = vect_get_loop_len (loop_vinfo, gsi, lens, ncopies,
- vectype_out, j, 1);
- signed char biasval
- = LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
- tree bias = build_int_cst (intQI_type_node, biasval);
- vargs[len_opno] = len;
- vargs[len_opno + 1] = bias;
- }
- else if (mask_opno >= 0 && masked_loop_p)
- {
- tree mask = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies,
- vectype_out, j);
- vargs[mask_opno]
- = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
- vargs[mask_opno], gsi);
- }
-
- gimple *new_stmt;
- if (cfn == CFN_GOMP_SIMD_LANE)
- {
- tree cst = build_index_vector (vectype_out, j * nunits_out, 1);
- tree new_var
- = vect_get_new_ssa_name (vectype_out, vect_simple_var, "cst_");
- gimple *init_stmt = gimple_build_assign (new_var, cst);
- vect_init_vector_1 (vinfo, stmt_info, init_stmt, NULL);
- new_temp = make_ssa_name (vec_dest);
- new_stmt = gimple_build_assign (new_temp, new_var);
- vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
- }
- else if (modifier == NARROW)
- {
- /* We don't define any narrowing conditional functions at
- present. */
- gcc_assert (mask_opno < 0);
- tree half_res = make_ssa_name (vectype_in);
- gcall *call = gimple_build_call_internal_vec (ifn, vargs);
- gimple_call_set_lhs (call, half_res);
- gimple_call_set_nothrow (call, true);
- vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
- if ((j & 1) == 0)
- {
- prev_res = half_res;
- continue;
+ call = gimple_build_call_vec (fndecl, vargs);
+ new_temp = make_ssa_name (vec_dest, call);
+ gimple_call_set_lhs (call, new_temp);
+ gimple_call_set_nothrow (call, true);
+ vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
+ new_stmt = call;
}
- new_temp = make_ssa_name (vec_dest);
- new_stmt = vect_gimple_build (new_temp, convert_code, prev_res,
- half_res);
- vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
- }
- else
- {
- gcall *call;
- if (ifn != IFN_LAST)
- call = gimple_build_call_internal_vec (ifn, vargs);
- else
- call = gimple_build_call_vec (fndecl, vargs);
- new_temp = make_ssa_name (vec_dest, call);
- gimple_call_set_lhs (call, new_temp);
- gimple_call_set_nothrow (call, true);
- vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
- new_stmt = call;
+ slp_node->push_vec_def (new_stmt);
}
-
- if (j == (modifier == NARROW ? 1 : 0))
- *vec_stmt = new_stmt;
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
}
+
for (i = 0; i < nargs; i++)
{
vec<tree> vec_oprndsi = vec_defs[i];
@@ -3958,73 +3681,36 @@ vectorizable_call (vec_info *vinfo,
auto_vec<vec<tree> > vec_defs (nargs);
/* We don't define any narrowing conditional functions at present. */
gcc_assert (mask_opno < 0);
- for (j = 0; j < ncopies; ++j)
- {
- /* Build argument list for the vectorized call. */
- if (j == 0)
- vargs.create (nargs * 2);
- else
- vargs.truncate (0);
- if (slp_node)
- {
- vec<tree> vec_oprnds0;
+ /* Build argument list for the vectorized call. */
+ vargs.create (nargs * 2);
- vect_get_slp_defs (vinfo, slp_node, &vec_defs);
- vec_oprnds0 = vec_defs[0];
+ vect_get_slp_defs (vinfo, slp_node, &vec_defs);
+ vec<tree> vec_oprnds0 = vec_defs[0];
- /* Arguments are ready. Create the new vector stmt. */
- for (i = 0; vec_oprnds0.iterate (i, &vec_oprnd0); i += 2)
- {
- size_t k;
- vargs.truncate (0);
- for (k = 0; k < nargs; k++)
- {
- vec<tree> vec_oprndsk = vec_defs[k];
- vargs.quick_push (vec_oprndsk[i]);
- vargs.quick_push (vec_oprndsk[i + 1]);
- }
- gcall *call;
- if (ifn != IFN_LAST)
- call = gimple_build_call_internal_vec (ifn, vargs);
- else
- call = gimple_build_call_vec (fndecl, vargs);
- new_temp = make_ssa_name (vec_dest, call);
- gimple_call_set_lhs (call, new_temp);
- gimple_call_set_nothrow (call, true);
- vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
- slp_node->push_vec_def (call);
- }
- continue;
- }
-
- for (i = 0; i < nargs; i++)
+ /* Arguments are ready. Create the new vector stmt. */
+ for (i = 0; vec_oprnds0.iterate (i, &vec_oprnd0); i += 2)
+ {
+ size_t k;
+ vargs.truncate (0);
+ for (k = 0; k < nargs; k++)
{
- op = gimple_call_arg (stmt, i);
- if (j == 0)
- {
- vec_defs.quick_push (vNULL);
- vect_get_vec_defs_for_operand (vinfo, stmt_info, 2 * ncopies,
- op, &vec_defs[i], vectypes[i]);
- }
- vec_oprnd0 = vec_defs[i][2*j];
- vec_oprnd1 = vec_defs[i][2*j+1];
-
- vargs.quick_push (vec_oprnd0);
- vargs.quick_push (vec_oprnd1);
+ vec<tree> vec_oprndsk = vec_defs[k];
+ vargs.quick_push (vec_oprndsk[i]);
+ vargs.quick_push (vec_oprndsk[i + 1]);
}
-
- gcall *new_stmt = gimple_build_call_vec (fndecl, vargs);
- new_temp = make_ssa_name (vec_dest, new_stmt);
- gimple_call_set_lhs (new_stmt, new_temp);
- vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
-
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
+ gcall *call;
+ if (ifn != IFN_LAST)
+ call = gimple_build_call_internal_vec (ifn, vargs);
+ else
+ call = gimple_build_call_vec (fndecl, vargs);
+ new_temp = make_ssa_name (vec_dest, call);
+ gimple_call_set_lhs (call, new_temp);
+ gimple_call_set_nothrow (call, true);
+ vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
+ slp_node->push_vec_def (call);
}
- if (!slp_node)
- *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
-
for (i = 0; i < nargs; i++)
{
vec<tree> vec_oprndsi = vec_defs[i];
@@ -4037,21 +3723,6 @@ vectorizable_call (vec_info *vinfo,
vargs.release ();
- /* The call in STMT might prevent it from being removed in dce.
- We however cannot remove it here, due to the way the ssa name
- it defines is mapped to the new definition. So just replace
- rhs of the statement with something harmless. */
-
- if (slp_node)
- return true;
-
- stmt_info = vect_orig_stmt (stmt_info);
- lhs = gimple_get_lhs (stmt_info->stmt);
-
- gassign *new_stmt
- = gimple_build_assign (lhs, build_zero_cst (TREE_TYPE (lhs)));
- vinfo->replace_stmt (gsi, stmt_info, new_stmt);
-
return true;
}
@@ -4145,12 +3816,12 @@ vect_simd_lane_linear (tree op, class loop *loop,
static bool
vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
gimple_stmt_iterator *gsi,
- gimple **vec_stmt, slp_tree slp_node,
- stmt_vector_for_cost *)
+ slp_tree slp_node,
+ stmt_vector_for_cost *cost_vec)
{
tree vec_dest;
tree scalar_dest;
- tree op, type;
+ tree op;
tree vec_oprnd0 = NULL_TREE;
tree vectype;
poly_uint64 nunits;
@@ -4162,7 +3833,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
auto_vec<simd_call_arg_info> arginfo;
vec<tree> vargs = vNULL;
size_t i, nargs;
- tree lhs, rtype, ratype;
+ tree rtype, ratype;
vec<constructor_elt, va_gc> *ret_ctor_elts = NULL;
int masked_call_offset = 0;
@@ -4192,7 +3863,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
return false;
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
- && ! vec_stmt)
+ && cost_vec)
return false;
if (gimple_call_lhs (stmt)
@@ -4201,7 +3872,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
gcc_checking_assert (!stmt_can_throw_internal (cfun, stmt));
- vectype = STMT_VINFO_VECTYPE (stmt_info);
+ vectype = SLP_TREE_VECTYPE (slp_node);
if (loop_vinfo && nested_in_vect_loop_p (loop, stmt_info))
return false;
@@ -4213,9 +3884,8 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
if (nargs == 0)
return false;
- vec<tree>& simd_clone_info = (slp_node ? SLP_TREE_SIMD_CLONE_INFO (slp_node)
- : STMT_VINFO_SIMD_CLONE_INFO (stmt_info));
- if (!vec_stmt)
+ vec<tree>& simd_clone_info = SLP_TREE_SIMD_CLONE_INFO (slp_node);
+ if (cost_vec)
simd_clone_info.truncate (0);
arginfo.reserve (nargs, true);
auto_vec<slp_tree> slp_op;
@@ -4231,10 +3901,10 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
thisarginfo.op = NULL_TREE;
thisarginfo.simd_lane_linear = false;
- int op_no = i + masked_call_offset;
- if (slp_node)
- op_no = vect_slp_child_index_for_operand (stmt, op_no, false);
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
+ int op_no = vect_slp_child_index_for_operand (stmt,
+ i + masked_call_offset,
+ false);
+ if (!vect_is_simple_use (vinfo, slp_node,
op_no, &op, &slp_op[i],
&thisarginfo.dt, &thisarginfo.vectype)
|| thisarginfo.dt == vect_uninitialized_def)
@@ -4252,10 +3922,9 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
at analysis time, handling conflicts via
vect_maybe_update_slp_op_vectype. At transform time
we have a vector type recorded for SLP. */
- gcc_assert (!vec_stmt
- || !slp_node
+ gcc_assert (cost_vec
|| thisarginfo.vectype != NULL_TREE);
- if (!vec_stmt)
+ if (cost_vec)
thisarginfo.vectype = get_vectype_for_scalar_type (vinfo,
TREE_TYPE (op),
slp_node);
@@ -4265,7 +3934,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
/* For linear arguments, the analyze phase should have saved
the base and step in {STMT_VINFO,SLP_TREE}_SIMD_CLONE_INFO. */
- if (vec_stmt
+ if (!cost_vec
&& i * 3 + 4 <= simd_clone_info.length ()
&& simd_clone_info[i * 3 + 2])
{
@@ -4289,7 +3958,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
thisarginfo.op, bias);
}
}
- else if (!vec_stmt
+ else if (cost_vec
&& thisarginfo.dt != vect_constant_def
&& thisarginfo.dt != vect_external_def
&& loop_vinfo
@@ -4309,7 +3978,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
linear too. */
if (POINTER_TYPE_P (TREE_TYPE (op))
&& !thisarginfo.linear_step
- && !vec_stmt
+ && cost_vec
&& thisarginfo.dt != vect_constant_def
&& thisarginfo.dt != vect_external_def
&& loop_vinfo
@@ -4320,10 +3989,10 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
}
poly_uint64 vf = loop_vinfo ? LOOP_VINFO_VECT_FACTOR (loop_vinfo) : 1;
- unsigned group_size = slp_node ? SLP_TREE_LANES (slp_node) : 1;
+ unsigned group_size = SLP_TREE_LANES (slp_node);
unsigned int badness = 0;
struct cgraph_node *bestn = NULL;
- if (vec_stmt)
+ if (!cost_vec)
bestn = cgraph_node::get (simd_clone_info[0]);
else
for (struct cgraph_node *n = node->simd_clones; n != NULL;
@@ -4350,7 +4019,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
if (n->simdclone->inbranch)
this_badness += 8192;
- /* If STMT_VINFO_VECTYPE has not been set yet pass the general vector
+ /* If SLP_TREE_VECTYPE has not been set yet pass the general vector
mode, which for targets that use it will determine what ISA we can
vectorize this code with. */
machine_mode vector_mode = vinfo->vector_mode;
@@ -4535,10 +4204,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
fndecl = bestn->decl;
nunits = bestn->simdclone->simdlen;
- if (slp_node)
- ncopies = vector_unroll_factor (vf * group_size, nunits);
- else
- ncopies = vector_unroll_factor (vf, nunits);
+ ncopies = vector_unroll_factor (vf * group_size, nunits);
/* If the function isn't const, only allow it in simd loops where user
has asserted that at least nunits consecutive iterations can be
@@ -4551,17 +4217,16 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
needs to be generated. */
gcc_assert (ncopies >= 1);
- if (!vec_stmt) /* transformation not required. */
+ if (cost_vec) /* transformation not required. */
{
- if (slp_node)
- for (unsigned i = 0; i < nargs; ++i)
- if (!vect_maybe_update_slp_op_vectype (slp_op[i], arginfo[i].vectype))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "incompatible vector types for invariants\n");
- return false;
- }
+ for (unsigned i = 0; i < nargs; ++i)
+ if (!vect_maybe_update_slp_op_vectype (slp_op[i], arginfo[i].vectype))
+ {
+ if (dump_enabled_p ())
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
+ "incompatible vector types for invariants\n");
+ return false;
+ }
/* When the original call is pure or const but the SIMD ABI dictates
an aggregate return we will have to use a virtual definition and
in a loop eventually even need to add a virtual PHI. That's
@@ -4573,7 +4238,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
/* ??? For SLP code-gen we end up inserting after the last
vector argument def rather than at the original call position
so automagic virtual operand updating doesn't work. */
- if (gimple_vuse (stmt) && slp_node)
+ if (gimple_vuse (stmt))
vinfo->any_known_not_updated_vssa = true;
simd_clone_info.safe_push (bestn->decl);
for (i = 0; i < bestn->simdclone->nargs; i++)
@@ -4619,7 +4284,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
STMT_VINFO_TYPE (stmt_info) = call_simd_clone_vec_info_type;
DUMP_VECT_SCOPE ("vectorizable_simd_clone_call");
-/* vect_model_simple_cost (vinfo, ncopies, dt, slp_node, cost_vec); */
+/* vect_model_simple_cost (vinfo, 1, slp_node, cost_vec); */
return true;
}
@@ -4647,13 +4312,8 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
auto_vec<vec<tree> > vec_oprnds;
auto_vec<unsigned> vec_oprnds_i;
vec_oprnds_i.safe_grow_cleared (nargs, true);
- if (slp_node)
- {
- vec_oprnds.reserve_exact (nargs);
- vect_get_slp_defs (vinfo, slp_node, &vec_oprnds);
- }
- else
- vec_oprnds.safe_grow_cleared (nargs, true);
+ vec_oprnds.reserve_exact (nargs);
+ vect_get_slp_defs (vinfo, slp_node, &vec_oprnds);
for (j = 0; j < ncopies; ++j)
{
poly_uint64 callee_nelements;
@@ -4688,10 +4348,6 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
gcc_assert ((k & (k - 1)) == 0);
if (m == 0)
{
- if (!slp_node)
- vect_get_vec_defs_for_operand (vinfo, stmt_info,
- ncopies * o / k, op,
- &vec_oprnds[i]);
vec_oprnds_i[i] = 0;
vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
}
@@ -4728,11 +4384,6 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
{
if (m == 0 && l == 0)
{
- if (!slp_node)
- vect_get_vec_defs_for_operand (vinfo, stmt_info,
- k * o * ncopies,
- op,
- &vec_oprnds[i]);
vec_oprnds_i[i] = 0;
vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
}
@@ -4796,14 +4447,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
/* The SIMD clone function has the same number of
elements as the current function. */
if (m == 0)
- {
- if (!slp_node)
- vect_get_vec_defs_for_operand (vinfo, stmt_info,
- o * ncopies,
- op,
- &vec_oprnds[i]);
- vec_oprnds_i[i] = 0;
- }
+ vec_oprnds_i[i] = 0;
vec_oprnd0 = vec_oprnds[i][vec_oprnds_i[i]++];
if (loop_vinfo
&& LOOP_VINFO_FULLY_MASKED_P (loop_vinfo))
@@ -4854,14 +4498,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
for (m = j * o; m < (j + 1) * o; m++)
{
if (m == 0)
- {
- if (!slp_node)
- vect_get_vec_defs_for_operand (vinfo, stmt_info,
- o * ncopies,
- op,
- &vec_oprnds[i]);
- vec_oprnds_i[i] = 0;
- }
+ vec_oprnds_i[i] = 0;
if (maybe_lt (atype_subparts,
TYPE_VECTOR_SUBPARTS (arginfo[i].vectype)))
{
@@ -5096,13 +4733,8 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
new_stmt = gimple_build_assign (make_ssa_name (vectype), t);
vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
- if (j == 0 && l == 0)
- *vec_stmt = new_stmt;
- if (slp_node)
- SLP_TREE_VEC_DEFS (slp_node)
- .quick_push (gimple_assign_lhs (new_stmt));
- else
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
+ SLP_TREE_VEC_DEFS (slp_node)
+ .quick_push (gimple_assign_lhs (new_stmt));
}
if (ratype)
@@ -5145,13 +4777,8 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
= gimple_build_assign (make_ssa_name (vec_dest), vec_oprnd0);
vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
- if ((unsigned) j == k - 1)
- *vec_stmt = new_stmt;
- if (slp_node)
- SLP_TREE_VEC_DEFS (slp_node)
- .quick_push (gimple_assign_lhs (new_stmt));
- else
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
+ SLP_TREE_VEC_DEFS (slp_node)
+ .quick_push (gimple_assign_lhs (new_stmt));
continue;
}
else if (ratype)
@@ -5172,12 +4799,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
}
}
- if (j == 0)
- *vec_stmt = new_stmt;
- if (slp_node)
- SLP_TREE_VEC_DEFS (slp_node).quick_push (gimple_get_lhs (new_stmt));
- else
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
+ SLP_TREE_VEC_DEFS (slp_node).quick_push (gimple_get_lhs (new_stmt));
}
for (i = 0; i < nargs; ++i)
@@ -5190,26 +4812,6 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info,
/* Mark the clone as no longer being a candidate for GC. */
bestn->gc_candidate = false;
- /* The call in STMT might prevent it from being removed in dce.
- We however cannot remove it here, due to the way the ssa name
- it defines is mapped to the new definition. So just replace
- rhs of the statement with something harmless. */
-
- if (slp_node)
- return true;
-
- gimple *new_stmt;
- if (scalar_dest)
- {
- type = TREE_TYPE (scalar_dest);
- lhs = gimple_call_lhs (vect_orig_stmt (stmt_info)->stmt);
- new_stmt = gimple_build_assign (lhs, build_zero_cst (type));
- }
- else
- new_stmt = gimple_build_nop ();
- vinfo->replace_stmt (gsi, vect_orig_stmt (stmt_info), new_stmt);
- unlink_stmt_vdef (stmt);
-
return true;
}
@@ -5280,12 +4882,8 @@ vect_create_vectorized_demotion_stmts (vec_info *vinfo, vec<tree> *vec_oprnds,
else
{
/* This is the last step of the conversion sequence. Store the
- vectors in SLP_NODE or in vector info of the scalar statement
- (or in STMT_VINFO_RELATED_STMT chain). */
- if (slp_node)
- slp_node->push_vec_def (new_stmt);
- else
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
+ vectors in SLP_NODE. */
+ slp_node->push_vec_def (new_stmt);
}
}
@@ -5430,7 +5028,7 @@ vect_create_half_widening_stmts (vec_info *vinfo,
static bool
vectorizable_conversion (vec_info *vinfo,
stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- gimple **vec_stmt, slp_tree slp_node,
+ slp_tree slp_node,
stmt_vector_for_cost *cost_vec)
{
tree vec_dest, cvt_op = NULL_TREE;
@@ -5441,7 +5039,6 @@ vectorizable_conversion (vec_info *vinfo,
code_helper codecvt1 = ERROR_MARK, codecvt2 = ERROR_MARK;
tree new_temp;
enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
- int ndts = 2;
poly_uint64 nunits_in;
poly_uint64 nunits_out;
tree vectype_out, vectype_in;
@@ -5473,7 +5070,7 @@ vectorizable_conversion (vec_info *vinfo,
return false;
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
- && ! vec_stmt)
+ && cost_vec)
return false;
gimple* stmt = stmt_info->stmt;
@@ -5517,7 +5114,7 @@ vectorizable_conversion (vec_info *vinfo,
/* Check the operands of the operation. */
slp_tree slp_op0, slp_op1 = NULL;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
+ if (!vect_is_simple_use (vinfo, slp_node,
0, &op0, &slp_op0, &dt[0], &vectype_in))
{
if (dump_enabled_p ())
@@ -5556,7 +5153,7 @@ vectorizable_conversion (vec_info *vinfo,
op1 = is_gimple_assign (stmt) ? gimple_assign_rhs2 (stmt) :
gimple_call_arg (stmt, 0);
tree vectype1_in;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1,
+ if (!vect_is_simple_use (vinfo, slp_node, 1,
&op1, &slp_op1, &dt[1], &vectype1_in))
{
if (dump_enabled_p ())
@@ -5574,7 +5171,7 @@ vectorizable_conversion (vec_info *vinfo,
from the scalar type. */
if (!vectype_in)
vectype_in = get_vectype_for_scalar_type (vinfo, rhs_type, slp_node);
- if (vec_stmt)
+ if (!cost_vec)
gcc_assert (vectype_in);
if (!vectype_in)
{
@@ -5817,7 +5414,7 @@ vectorizable_conversion (vec_info *vinfo,
LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo) = false;
}
- if (!vec_stmt) /* transformation not required. */
+ if (cost_vec) /* transformation not required. */
{
if (!vect_maybe_update_slp_op_vectype (slp_op0, vectype_in)
|| !vect_maybe_update_slp_op_vectype (slp_op1, vectype_in))
@@ -5832,7 +5429,7 @@ vectorizable_conversion (vec_info *vinfo,
{
STMT_VINFO_TYPE (stmt_info) = type_conversion_vec_info_type;
vect_model_simple_cost (vinfo, (1 + multi_step_cvt),
- dt, ndts, slp_node, cost_vec);
+ slp_node, cost_vec);
}
else if (modifier == NARROW_SRC || modifier == NARROW_DST)
{
@@ -5903,8 +5500,7 @@ vectorizable_conversion (vec_info *vinfo,
switch (modifier)
{
case NONE:
- vect_get_vec_defs (vinfo, stmt_info, slp_node, 1,
- op0, vectype_in, &vec_oprnds0);
+ vect_get_vec_defs (vinfo, slp_node, op0, &vec_oprnds0);
/* vec_dest is intermediate type operand when multi_step_cvt. */
if (multi_step_cvt)
{
@@ -5939,10 +5535,9 @@ vectorizable_conversion (vec_info *vinfo,
of elements that we can fit in a vectype (nunits), we have to
generate more than one vector stmt - i.e - we need to "unroll"
the vector stmt by a factor VF/nunits. */
- vect_get_vec_defs (vinfo, stmt_info, slp_node, 1,
- op0, vectype_in, &vec_oprnds0,
+ vect_get_vec_defs (vinfo, slp_node, op0, &vec_oprnds0,
code == WIDEN_LSHIFT_EXPR ? NULL_TREE : op1,
- vectype_in, &vec_oprnds1);
+ &vec_oprnds1);
if (code == WIDEN_LSHIFT_EXPR)
{
int oprnds_size = vec_oprnds0.length ();
@@ -5993,8 +5588,7 @@ vectorizable_conversion (vec_info *vinfo,
of elements that we can fit in a vectype (nunits), we have to
generate more than one vector stmt - i.e - we need to "unroll"
the vector stmt by a factor VF/nunits. */
- vect_get_vec_defs (vinfo, stmt_info, slp_node, 1,
- op0, vectype_in, &vec_oprnds0);
+ vect_get_vec_defs (vinfo, slp_node, op0, &vec_oprnds0);
/* Arguments are ready. Create the new vector stmts. */
if (cvt_type && modifier == NARROW_DST)
FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
@@ -6073,17 +5667,14 @@ vect_nop_conversion_p (stmt_vec_info stmt_info)
static bool
vectorizable_assignment (vec_info *vinfo,
stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- gimple **vec_stmt, slp_tree slp_node,
+ slp_tree slp_node,
stmt_vector_for_cost *cost_vec)
{
tree vec_dest;
tree scalar_dest;
tree op;
- loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
tree new_temp;
enum vect_def_type dt[1] = {vect_unknown_def_type};
- int ndts = 1;
- int ncopies;
int i;
vec<tree> vec_oprnds = vNULL;
tree vop;
@@ -6095,7 +5686,7 @@ vectorizable_assignment (vec_info *vinfo,
return false;
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
- && ! vec_stmt)
+ && cost_vec)
return false;
/* Is vectorizable assignment? */
@@ -6116,21 +5707,11 @@ vectorizable_assignment (vec_info *vinfo,
|| CONVERT_EXPR_CODE_P (code)))
return false;
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype = SLP_TREE_VECTYPE (slp_node);
poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
- /* Multiple types in SLP are handled by creating the appropriate number of
- vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
- case of SLP. */
- if (slp_node)
- ncopies = 1;
- else
- ncopies = vect_get_num_copies (loop_vinfo, vectype);
-
- gcc_assert (ncopies >= 1);
-
slp_tree slp_op;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0, &op, &slp_op,
+ if (!vect_is_simple_use (vinfo, slp_node, 0, &op, &slp_op,
&dt[0], &vectype_in))
{
if (dump_enabled_p ())
@@ -6187,10 +5768,9 @@ vectorizable_assignment (vec_info *vinfo,
return false;
}
- if (!vec_stmt) /* transformation not required. */
+ if (cost_vec) /* transformation not required. */
{
- if (slp_node
- && !vect_maybe_update_slp_op_vectype (slp_op, vectype_in))
+ if (!vect_maybe_update_slp_op_vectype (slp_op, vectype_in))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -6200,7 +5780,7 @@ vectorizable_assignment (vec_info *vinfo,
STMT_VINFO_TYPE (stmt_info) = assignment_vec_info_type;
DUMP_VECT_SCOPE ("vectorizable_assignment");
if (!vect_nop_conversion_p (stmt_info))
- vect_model_simple_cost (vinfo, ncopies, dt, ndts, slp_node, cost_vec);
+ vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
return true;
}
@@ -6212,7 +5792,7 @@ vectorizable_assignment (vec_info *vinfo,
vec_dest = vect_create_destination_var (scalar_dest, vectype);
/* Handle use. */
- vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies, op, &vec_oprnds);
+ vect_get_vec_defs (vinfo, slp_node, op, &vec_oprnds);
/* Arguments are ready. create the new vector stmt. */
FOR_EACH_VEC_ELT (vec_oprnds, i, vop)
@@ -6224,13 +5804,8 @@ vectorizable_assignment (vec_info *vinfo,
new_temp = make_ssa_name (vec_dest, new_stmt);
gimple_assign_set_lhs (new_stmt, new_temp);
vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
- if (slp_node)
- slp_node->push_vec_def (new_stmt);
- else
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
+ slp_node->push_vec_def (new_stmt);
}
- if (!slp_node)
- *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
vec_oprnds.release ();
return true;
@@ -6272,7 +5847,7 @@ vect_supportable_shift (vec_info *vinfo, enum tree_code code, tree scalar_type)
static bool
vectorizable_shift (vec_info *vinfo,
stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- gimple **vec_stmt, slp_tree slp_node,
+ slp_tree slp_node,
stmt_vector_for_cost *cost_vec)
{
tree vec_dest;
@@ -6280,7 +5855,6 @@ vectorizable_shift (vec_info *vinfo,
tree op0, op1 = NULL;
tree vec_oprnd1 = NULL_TREE;
tree vectype;
- loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
enum tree_code code;
machine_mode vec_mode;
tree new_temp;
@@ -6288,12 +5862,10 @@ vectorizable_shift (vec_info *vinfo,
int icode;
machine_mode optab_op2_mode;
enum vect_def_type dt[2] = {vect_unknown_def_type, vect_unknown_def_type};
- int ndts = 2;
poly_uint64 nunits_in;
poly_uint64 nunits_out;
tree vectype_out;
tree op1_vectype;
- int ncopies;
int i;
vec<tree> vec_oprnds0 = vNULL;
vec<tree> vec_oprnds1 = vNULL;
@@ -6308,7 +5880,7 @@ vectorizable_shift (vec_info *vinfo,
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
&& STMT_VINFO_DEF_TYPE (stmt_info) != vect_nested_cycle
- && ! vec_stmt)
+ && cost_vec)
return false;
/* Is STMT a vectorizable binary/unary operation? */
@@ -6326,7 +5898,7 @@ vectorizable_shift (vec_info *vinfo,
return false;
scalar_dest = gimple_assign_lhs (stmt);
- vectype_out = STMT_VINFO_VECTYPE (stmt_info);
+ vectype_out = SLP_TREE_VECTYPE (slp_node);
if (!type_has_mode_precision_p (TREE_TYPE (scalar_dest)))
{
if (dump_enabled_p ())
@@ -6336,7 +5908,7 @@ vectorizable_shift (vec_info *vinfo,
}
slp_tree slp_op0;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
+ if (!vect_is_simple_use (vinfo, slp_node,
0, &op0, &slp_op0, &dt[0], &vectype))
{
if (dump_enabled_p ())
@@ -6348,7 +5920,7 @@ vectorizable_shift (vec_info *vinfo,
from the scalar type. */
if (!vectype)
vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0), slp_node);
- if (vec_stmt)
+ if (!cost_vec)
gcc_assert (vectype);
if (!vectype)
{
@@ -6365,7 +5937,7 @@ vectorizable_shift (vec_info *vinfo,
stmt_vec_info op1_def_stmt_info;
slp_tree slp_op1;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1, &op1, &slp_op1,
+ if (!vect_is_simple_use (vinfo, slp_node, 1, &op1, &slp_op1,
&dt[1], &op1_vectype, &op1_def_stmt_info))
{
if (dump_enabled_p ())
@@ -6374,23 +5946,13 @@ vectorizable_shift (vec_info *vinfo,
return false;
}
- /* Multiple types in SLP are handled by creating the appropriate number of
- vectorized stmts for each SLP node. Hence, NCOPIES is always 1 in
- case of SLP. */
- if (slp_node)
- ncopies = 1;
- else
- ncopies = vect_get_num_copies (loop_vinfo, vectype);
-
- gcc_assert (ncopies >= 1);
-
/* Determine whether the shift amount is a vector, or scalar. If the
shift/rotate amount is a vector, use the vector/vector shift optabs. */
if ((dt[1] == vect_internal_def
|| dt[1] == vect_induction_def
|| dt[1] == vect_nested_cycle)
- && (!slp_node || SLP_TREE_LANES (slp_node) == 1))
+ && SLP_TREE_LANES (slp_node) == 1)
scalar_shift_arg = false;
else if (dt[1] == vect_constant_def
|| dt[1] == vect_external_def
@@ -6399,29 +5961,26 @@ vectorizable_shift (vec_info *vinfo,
/* In SLP, need to check whether the shift count is the same,
in loops if it is a constant or invariant, it is always
a scalar shift. */
- if (slp_node)
- {
- vec<stmt_vec_info> stmts = SLP_TREE_SCALAR_STMTS (slp_node);
- stmt_vec_info slpstmt_info;
+ vec<stmt_vec_info> stmts = SLP_TREE_SCALAR_STMTS (slp_node);
+ stmt_vec_info slpstmt_info;
- FOR_EACH_VEC_ELT (stmts, k, slpstmt_info)
- if (slpstmt_info)
- {
- gassign *slpstmt = as_a <gassign *> (slpstmt_info->stmt);
- if (!operand_equal_p (gimple_assign_rhs2 (slpstmt), op1, 0))
- scalar_shift_arg = false;
- }
+ FOR_EACH_VEC_ELT (stmts, k, slpstmt_info)
+ if (slpstmt_info)
+ {
+ gassign *slpstmt = as_a <gassign *> (slpstmt_info->stmt);
+ if (!operand_equal_p (gimple_assign_rhs2 (slpstmt), op1, 0))
+ scalar_shift_arg = false;
+ }
- /* For internal SLP defs we have to make sure we see scalar stmts
- for all vector elements.
- ??? For different vectors we could resort to a different
- scalar shift operand but code-generation below simply always
- takes the first. */
- if (dt[1] == vect_internal_def
- && maybe_ne (nunits_out * SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node),
- stmts.length ()))
- scalar_shift_arg = false;
- }
+ /* For internal SLP defs we have to make sure we see scalar stmts
+ for all vector elements.
+ ??? For different vectors we could resort to a different
+ scalar shift operand but code-generation below simply always
+ takes the first. */
+ if (dt[1] == vect_internal_def
+ && maybe_ne (nunits_out * SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node),
+ stmts.length ()))
+ scalar_shift_arg = false;
/* If the shift amount is computed by a pattern stmt we cannot
use the scalar amount directly thus give up and use a vector
@@ -6455,8 +6014,7 @@ vectorizable_shift (vec_info *vinfo,
TYPE_VECTOR_SUBPARTS (vectype))
|| TYPE_MODE (op1_vectype) != TYPE_MODE (vectype));
if (incompatible_op1_vectype_p
- && (!slp_node
- || SLP_TREE_DEF_TYPE (slp_op1) != vect_constant_def
+ && (SLP_TREE_DEF_TYPE (slp_op1) != vect_constant_def
|| slp_op1->refcnt != 1))
{
if (dump_enabled_p ())
@@ -6537,16 +6095,15 @@ vectorizable_shift (vec_info *vinfo,
if (vect_emulated_vector_p (vectype))
return false;
- if (!vec_stmt) /* transformation not required. */
+ if (cost_vec) /* transformation not required. */
{
- if (slp_node
- && (!vect_maybe_update_slp_op_vectype (slp_op0, vectype)
- || ((!scalar_shift_arg || dt[1] == vect_internal_def)
- && (!incompatible_op1_vectype_p
- || dt[1] == vect_constant_def)
- && !vect_maybe_update_slp_op_vectype
- (slp_op1,
- incompatible_op1_vectype_p ? vectype : op1_vectype))))
+ if (!vect_maybe_update_slp_op_vectype (slp_op0, vectype)
+ || ((!scalar_shift_arg || dt[1] == vect_internal_def)
+ && (!incompatible_op1_vectype_p
+ || dt[1] == vect_constant_def)
+ && !vect_maybe_update_slp_op_vectype
+ (slp_op1,
+ incompatible_op1_vectype_p ? vectype : op1_vectype)))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -6554,24 +6111,20 @@ vectorizable_shift (vec_info *vinfo,
return false;
}
/* Now adjust the constant shift amount in place. */
- if (slp_node
- && incompatible_op1_vectype_p
+ if (incompatible_op1_vectype_p
&& dt[1] == vect_constant_def)
- {
- for (unsigned i = 0;
- i < SLP_TREE_SCALAR_OPS (slp_op1).length (); ++i)
- {
- SLP_TREE_SCALAR_OPS (slp_op1)[i]
- = fold_convert (TREE_TYPE (vectype),
- SLP_TREE_SCALAR_OPS (slp_op1)[i]);
- gcc_assert ((TREE_CODE (SLP_TREE_SCALAR_OPS (slp_op1)[i])
- == INTEGER_CST));
- }
- }
+ for (unsigned i = 0;
+ i < SLP_TREE_SCALAR_OPS (slp_op1).length (); ++i)
+ {
+ SLP_TREE_SCALAR_OPS (slp_op1)[i]
+ = fold_convert (TREE_TYPE (vectype),
+ SLP_TREE_SCALAR_OPS (slp_op1)[i]);
+ gcc_assert ((TREE_CODE (SLP_TREE_SCALAR_OPS (slp_op1)[i])
+ == INTEGER_CST));
+ }
STMT_VINFO_TYPE (stmt_info) = shift_vec_info_type;
DUMP_VECT_SCOPE ("vectorizable_shift");
- vect_model_simple_cost (vinfo, ncopies, dt,
- scalar_shift_arg ? 1 : ndts, slp_node, cost_vec);
+ vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
return true;
}
@@ -6581,15 +6134,6 @@ vectorizable_shift (vec_info *vinfo,
dump_printf_loc (MSG_NOTE, vect_location,
"transform binary/unary operation.\n");
- if (incompatible_op1_vectype_p && !slp_node)
- {
- gcc_assert (!scalar_shift_arg && was_scalar_shift_arg);
- op1 = fold_convert (TREE_TYPE (vectype), op1);
- if (dt[1] != vect_constant_def)
- op1 = vect_init_vector (vinfo, stmt_info, op1,
- TREE_TYPE (vectype), NULL);
- }
-
/* Handle def. */
vec_dest = vect_create_destination_var (scalar_dest, vectype);
@@ -6606,7 +6150,7 @@ vectorizable_shift (vec_info *vinfo,
dump_printf_loc (MSG_NOTE, vect_location,
"operand 1 using scalar mode.\n");
vec_oprnd1 = op1;
- vec_oprnds1.create (slp_node ? slp_node->vec_stmts_size : ncopies);
+ vec_oprnds1.create (SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node));
vec_oprnds1.quick_push (vec_oprnd1);
/* Store vec_oprnd1 for every vector stmt to be created.
We check during the analysis that all the shift arguments
@@ -6614,11 +6158,11 @@ vectorizable_shift (vec_info *vinfo,
TODO: Allow different constants for different vector
stmts generated for an SLP instance. */
for (k = 0;
- k < (slp_node ? slp_node->vec_stmts_size - 1 : ncopies - 1); k++)
+ k < SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node) - 1; k++)
vec_oprnds1.quick_push (vec_oprnd1);
}
}
- else if (!scalar_shift_arg && slp_node && incompatible_op1_vectype_p)
+ else if (!scalar_shift_arg && incompatible_op1_vectype_p)
{
if (was_scalar_shift_arg)
{
@@ -6646,7 +6190,7 @@ vectorizable_shift (vec_info *vinfo,
/* vec_oprnd1 is available if operand 1 should be of a scalar-type
(a special case for certain kind of vector shifts); otherwise,
operand 1 should be of a vector type (the usual case). */
- vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
+ vect_get_vec_defs (vinfo, slp_node,
op0, &vec_oprnds0,
vec_oprnd1 ? NULL_TREE : op1, &vec_oprnds1);
@@ -6674,15 +6218,9 @@ vectorizable_shift (vec_info *vinfo,
new_temp = make_ssa_name (vec_dest, new_stmt);
gimple_assign_set_lhs (new_stmt, new_temp);
vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
- if (slp_node)
- slp_node->push_vec_def (new_stmt);
- else
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
+ slp_node->push_vec_def (new_stmt);
}
- if (!slp_node)
- *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
-
vec_oprnds0.release ();
vec_oprnds1.release ();
@@ -6700,7 +6238,7 @@ vectorizable_shift (vec_info *vinfo,
static bool
vectorizable_operation (vec_info *vinfo,
stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- gimple **vec_stmt, slp_tree slp_node,
+ slp_tree slp_node,
stmt_vector_for_cost *cost_vec)
{
tree vec_dest;
@@ -6716,7 +6254,6 @@ vectorizable_operation (vec_info *vinfo,
bool target_support_p;
enum vect_def_type dt[3]
= {vect_unknown_def_type, vect_unknown_def_type, vect_unknown_def_type};
- int ndts = 3;
poly_uint64 nunits_in;
poly_uint64 nunits_out;
tree vectype_out;
@@ -6731,7 +6268,7 @@ vectorizable_operation (vec_info *vinfo,
return false;
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
- && ! vec_stmt)
+ && cost_vec)
return false;
/* Is STMT a vectorizable binary/unary operation? */
@@ -6798,7 +6335,7 @@ vectorizable_operation (vec_info *vinfo,
}
slp_tree slp_op0;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
+ if (!vect_is_simple_use (vinfo, slp_node,
0, &op0, &slp_op0, &dt[0], &vectype))
{
if (dump_enabled_p ())
@@ -6832,7 +6369,7 @@ vectorizable_operation (vec_info *vinfo,
vectype = get_vectype_for_scalar_type (vinfo, TREE_TYPE (op0),
slp_node);
}
- if (vec_stmt)
+ if (!cost_vec)
gcc_assert (vectype);
if (!vectype)
{
@@ -6854,7 +6391,7 @@ vectorizable_operation (vec_info *vinfo,
slp_tree slp_op1 = NULL, slp_op2 = NULL;
if (op_type == binary_op || op_type == ternary_op)
{
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
+ if (!vect_is_simple_use (vinfo, slp_node,
1, &op1, &slp_op1, &dt[1], &vectype2))
{
if (dump_enabled_p ())
@@ -6872,7 +6409,7 @@ vectorizable_operation (vec_info *vinfo,
}
if (op_type == ternary_op)
{
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
+ if (!vect_is_simple_use (vinfo, slp_node,
2, &op2, &slp_op2, &dt[2], &vectype3))
{
if (dump_enabled_p ())
@@ -6938,7 +6475,7 @@ vectorizable_operation (vec_info *vinfo,
|| !target_support_p)
&& maybe_ne (GET_MODE_SIZE (vec_mode), UNITS_PER_WORD))
/* Check only during analysis. */
- || (!vec_stmt && !vect_can_vectorize_without_simd_p (code)))
+ || (cost_vec && !vect_can_vectorize_without_simd_p (code)))
{
if (dump_enabled_p ())
dump_printf (MSG_NOTE, "using word mode not possible.\n");
@@ -6967,7 +6504,7 @@ vectorizable_operation (vec_info *vinfo,
bool mask_out_inactive = ((!is_invariant && gimple_could_trap_p (stmt))
|| reduc_idx >= 0);
- if (!vec_stmt) /* transformation not required. */
+ if (cost_vec) /* transformation not required. */
{
if (loop_vinfo
&& LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo)
@@ -7006,7 +6543,7 @@ vectorizable_operation (vec_info *vinfo,
STMT_VINFO_TYPE (stmt_info) = op_vec_info_type;
DUMP_VECT_SCOPE ("vectorizable_operation");
- vect_model_simple_cost (vinfo, 1, dt, ndts, slp_node, cost_vec);
+ vect_model_simple_cost (vinfo, 1, slp_node, cost_vec);
if (using_emulated_vectors_p)
{
/* The above vect_model_simple_cost call handles constants
@@ -7066,7 +6603,7 @@ vectorizable_operation (vec_info *vinfo,
else
vec_dest = vect_create_destination_var (scalar_dest, vectype_out);
- vect_get_vec_defs (vinfo, stmt_info, slp_node, 1,
+ vect_get_vec_defs (vinfo, slp_node,
op0, &vec_oprnds0, op1, &vec_oprnds1, op2, &vec_oprnds2);
/* Arguments are ready. Create the new vector stmt. */
FOR_EACH_VEC_ELT (vec_oprnds0, i, vop0)
@@ -7949,17 +7486,16 @@ check_scan_store (vec_info *vinfo, stmt_vec_info stmt_info, tree vectype,
static bool
vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
- slp_tree slp_node, gimple_stmt_iterator *gsi,
- gimple **vec_stmt, int ncopies)
+ slp_tree slp_node, gimple_stmt_iterator *gsi)
{
loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
dr_vec_info *dr_info = STMT_VINFO_DR_INFO (stmt_info);
tree ref_type = reference_alias_ptr_type (DR_REF (dr_info->dr));
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype = SLP_TREE_VECTYPE (slp_node);
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
- "transform scan store. ncopies = %d\n", ncopies);
+ "transform scan store.\n");
gimple *stmt = STMT_VINFO_STMT (stmt_info);
tree rhs = gimple_assign_rhs1 (stmt);
@@ -8070,8 +7606,8 @@ vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
/* We want to lookup the vector operands of the reduction, not those
of the store - for SLP we have to use the proper SLP node for the
lookup, which should be the single child of the scan store. */
- vect_get_vec_defs (vinfo, stmt_info, SLP_TREE_CHILDREN (slp_node)[0],
- ncopies, rhs1, &vec_oprnds2, rhs2, &vec_oprnds3);
+ vect_get_vec_defs (vinfo, SLP_TREE_CHILDREN (slp_node)[0],
+ rhs1, &vec_oprnds2, rhs2, &vec_oprnds3);
/* ??? For SLP we do not key the def on 'rhs1' or 'rhs2' but get
them in SLP child order. So we have to swap here with logic
similar to above. */
@@ -8085,7 +7621,7 @@ vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
std::swap (vec_oprnds2[i], vec_oprnds3[i]);;
}
else
- vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
+ vect_get_vec_defs (vinfo, slp_node,
rhs2, &vec_oprnds3);
for (unsigned j = 0; j < vec_oprnds3.length (); j++)
{
@@ -8106,11 +7642,6 @@ vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
vect_copy_ref_info (data_ref, DR_REF (load1_dr_info->dr));
gimple *g = gimple_build_assign (vec_oprnd2, data_ref);
vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
- if (! slp_node)
- {
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
- *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
- }
}
tree v = vec_oprnd2;
@@ -8124,11 +7655,6 @@ vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
? zero_vec : vec_oprnd1, v,
perms[i]);
vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
- if (! slp_node)
- {
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
- *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
- }
if (zero_vec && use_whole_vector[i] == scan_store_kind_lshift_cond)
{
@@ -8145,8 +7671,6 @@ vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
new_temp, vec_oprnd1);
vect_finish_stmt_generation (vinfo, stmt_info,
g, gsi);
- if (! slp_node)
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
new_temp = new_temp2;
}
@@ -8164,8 +7688,6 @@ vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
tree new_temp2 = make_ssa_name (vectype);
g = gimple_build_assign (new_temp2, code, v, new_temp);
vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
- if (! slp_node)
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
v = new_temp2;
}
@@ -8173,8 +7695,6 @@ vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
tree new_temp = make_ssa_name (vectype);
gimple *g = gimple_build_assign (new_temp, code, orig, v);
vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
- if (! slp_node)
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
tree last_perm_arg = new_temp;
/* For exclusive scan, new_temp computed above is the exclusive scan
@@ -8185,16 +7705,12 @@ vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
last_perm_arg = make_ssa_name (vectype);
g = gimple_build_assign (last_perm_arg, code, new_temp, vec_oprnd2);
vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
- if (! slp_node)
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
}
orig = make_ssa_name (vectype);
g = gimple_build_assign (orig, VEC_PERM_EXPR, last_perm_arg,
last_perm_arg, perms[units_log2]);
vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
- if (! slp_node)
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
if (!inscan_var_store)
{
@@ -8204,8 +7720,6 @@ vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
vect_copy_ref_info (data_ref, DR_REF (dr_info->dr));
g = gimple_build_assign (data_ref, new_temp);
vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
- if (! slp_node)
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
}
}
@@ -8221,8 +7735,6 @@ vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
vect_copy_ref_info (data_ref, DR_REF (dr_info->dr));
gimple *g = gimple_build_assign (data_ref, orig);
vect_finish_stmt_generation (vinfo, stmt_info, g, gsi);
- if (! slp_node)
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (g);
}
return true;
}
@@ -8239,7 +7751,7 @@ vectorizable_scan_store (vec_info *vinfo, stmt_vec_info stmt_info,
static bool
vectorizable_store (vec_info *vinfo,
stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- gimple **vec_stmt, slp_tree slp_node,
+ slp_tree slp_node,
stmt_vector_for_cost *cost_vec)
{
tree data_ref;
@@ -8270,7 +7782,7 @@ vectorizable_store (vec_info *vinfo,
return false;
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
- && ! vec_stmt)
+ && cost_vec)
return false;
/* Is vectorizable store? */
@@ -8307,7 +7819,7 @@ vectorizable_store (vec_info *vinfo,
mask_index = vect_slp_child_index_for_operand
(call, mask_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
if (mask_index >= 0
- && !vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_index,
+ && !vect_check_scalar_mask (vinfo, slp_node, mask_index,
&mask, &mask_node, &mask_dt,
&mask_vectype))
return false;
@@ -8382,7 +7894,8 @@ vectorizable_store (vec_info *vinfo,
}
else if (memory_access_type != VMAT_LOAD_STORE_LANES
&& (memory_access_type != VMAT_GATHER_SCATTER
- || (gs_info.decl && !VECTOR_BOOLEAN_TYPE_P (mask_vectype))))
+ || (GATHER_SCATTER_LEGACY_P (gs_info)
+ && !VECTOR_BOOLEAN_TYPE_P (mask_vectype))))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -8390,8 +7903,7 @@ vectorizable_store (vec_info *vinfo,
return false;
}
else if (memory_access_type == VMAT_GATHER_SCATTER
- && gs_info.ifn == IFN_LAST
- && !gs_info.decl)
+ && GATHER_SCATTER_EMULATED_P (gs_info))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -8423,14 +7935,14 @@ vectorizable_store (vec_info *vinfo,
group_size = vec_num = 1;
}
- if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1 && !vec_stmt)
+ if (STMT_VINFO_SIMD_LANE_ACCESS_P (stmt_info) > 1 && cost_vec)
{
if (!check_scan_store (vinfo, stmt_info, vectype, rhs_dt, slp_node, mask,
memory_access_type))
return false;
}
- bool costing_p = !vec_stmt;
+ bool costing_p = cost_vec;
if (costing_p) /* transformation not required. */
{
STMT_VINFO_MEMORY_ACCESS_TYPE (stmt_info) = memory_access_type;
@@ -8456,7 +7968,6 @@ vectorizable_store (vec_info *vinfo,
if (dump_enabled_p ()
&& memory_access_type != VMAT_ELEMENTWISE
- && memory_access_type != VMAT_GATHER_SCATTER
&& memory_access_type != VMAT_STRIDED_SLP
&& memory_access_type != VMAT_INVARIANT
&& alignment_support_scheme != dr_aligned)
@@ -8493,8 +8004,7 @@ vectorizable_store (vec_info *vinfo,
return true;
}
- return vectorizable_scan_store (vinfo, stmt_info, slp_node,
- gsi, vec_stmt, 1);
+ return vectorizable_scan_store (vinfo, stmt_info, slp_node, gsi);
}
/* FORNOW */
@@ -8690,15 +8200,13 @@ vectorizable_store (vec_info *vinfo,
}
alias_off = build_int_cst (ref_type, 0);
- stmt_vec_info next_stmt_info = first_stmt_info;
auto_vec<tree> vec_oprnds;
/* For costing some adjacent vector stores, we'd like to cost with
the total number of them once instead of cost each one by one. */
unsigned int n_adjacent_stores = 0;
running_off = offvar;
if (!costing_p)
- vect_get_vec_defs (vinfo, next_stmt_info, slp_node, ncopies, op,
- &vec_oprnds);
+ vect_get_vec_defs (vinfo, slp_node, op, &vec_oprnds);
unsigned int group_el = 0;
unsigned HOST_WIDE_INT elsz
= tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
@@ -8833,7 +8341,8 @@ vectorizable_store (vec_info *vinfo,
{
aggr_type = elem_type;
if (!costing_p)
- vect_get_strided_load_store_ops (stmt_info, loop_vinfo, gsi, &gs_info,
+ vect_get_strided_load_store_ops (stmt_info, vectype, loop_vinfo,
+ gsi, &gs_info,
&bump, &vec_offset, loop_lens);
}
else
@@ -8855,39 +8364,6 @@ vectorizable_store (vec_info *vinfo,
more than one vector stmt - i.e - we need to "unroll" the
vector stmt by a factor VF/nunits. */
- /* In case of interleaving (non-unit grouped access):
-
- S1: &base + 2 = x2
- S2: &base = x0
- S3: &base + 1 = x1
- S4: &base + 3 = x3
-
- We create vectorized stores starting from base address (the access of the
- first stmt in the chain (S2 in the above example), when the last store stmt
- of the chain (S4) is reached:
-
- VS1: &base = vx2
- VS2: &base + vec_size*1 = vx0
- VS3: &base + vec_size*2 = vx1
- VS4: &base + vec_size*3 = vx3
-
- Then permutation statements are generated:
-
- VS5: vx5 = VEC_PERM_EXPR < vx0, vx3, {0, 8, 1, 9, 2, 10, 3, 11} >
- VS6: vx6 = VEC_PERM_EXPR < vx0, vx3, {4, 12, 5, 13, 6, 14, 7, 15} >
- ...
-
- And they are put in STMT_VINFO_VEC_STMT of the corresponding scalar stmts
- (the order of the data-refs in the output of vect_permute_store_chain
- corresponds to the order of scalar stmts in the interleaving chain - see
- the documentation of vect_permute_store_chain()).
-
- In case of both multiple types and interleaving, above vector stores and
- permutation stmts are created for every copy. The result vector stmts are
- put in STMT_VINFO_VEC_STMT for the first copy and in the corresponding
- STMT_VINFO_RELATED_STMT for the next copies.
- */
-
auto_vec<tree> dr_chain (group_size);
auto_vec<tree> vec_masks;
tree vec_mask = NULL;
@@ -9073,8 +8549,7 @@ vectorizable_store (vec_info *vinfo,
vect_get_slp_defs (mask_node, &vec_masks);
if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
- vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info,
- slp_node, &gs_info,
+ vect_get_gather_scatter_ops (loop, slp_node, &gs_info,
&dataref_ptr, &vec_offsets);
else
dataref_ptr
@@ -9117,7 +8592,7 @@ vectorizable_store (vec_info *vinfo,
final_mask, vec_mask, gsi);
}
- if (gs_info.ifn != IFN_LAST)
+ if (GATHER_SCATTER_IFN_P (gs_info))
{
if (costing_p)
{
@@ -9157,30 +8632,37 @@ vectorizable_store (vec_info *vinfo,
{
if (VECTOR_TYPE_P (TREE_TYPE (vec_offset)))
call = gimple_build_call_internal (
- IFN_MASK_LEN_SCATTER_STORE, 7, dataref_ptr,
+ IFN_MASK_LEN_SCATTER_STORE, 8, dataref_ptr,
+ gs_info.alias_ptr,
vec_offset, scale, vec_oprnd, final_mask, final_len,
bias);
else
/* Non-vector offset indicates that prefer to take
MASK_LEN_STRIDED_STORE instead of the
- IFN_MASK_SCATTER_STORE with direct stride arg. */
+ IFN_MASK_SCATTER_STORE with direct stride arg.
+ Similar to the gather case we have checked the
+ alignment for a scatter already and assume
+ that the strided store has the same requirements. */
call = gimple_build_call_internal (
IFN_MASK_LEN_STRIDED_STORE, 6, dataref_ptr,
vec_offset, vec_oprnd, final_mask, final_len, bias);
}
else if (final_mask)
call = gimple_build_call_internal
- (IFN_MASK_SCATTER_STORE, 5, dataref_ptr,
+ (IFN_MASK_SCATTER_STORE, 6, dataref_ptr,
+ gs_info.alias_ptr,
vec_offset, scale, vec_oprnd, final_mask);
else
- call = gimple_build_call_internal (IFN_SCATTER_STORE, 4,
- dataref_ptr, vec_offset,
+ call = gimple_build_call_internal (IFN_SCATTER_STORE, 5,
+ dataref_ptr,
+ gs_info.alias_ptr,
+ vec_offset,
scale, vec_oprnd);
gimple_call_set_nothrow (call, true);
vect_finish_stmt_generation (vinfo, stmt_info, call, gsi);
new_stmt = call;
}
- else if (gs_info.decl)
+ else if (GATHER_SCATTER_LEGACY_P (gs_info))
{
/* The builtin decls path for scatter is legacy, x86 only. */
gcc_assert (nunits.is_constant ()
@@ -9377,7 +8859,6 @@ vectorizable_store (vec_info *vinfo,
gcc_assert (memory_access_type == VMAT_CONTIGUOUS
|| memory_access_type == VMAT_CONTIGUOUS_DOWN
- || memory_access_type == VMAT_CONTIGUOUS_PERMUTE
|| memory_access_type == VMAT_CONTIGUOUS_REVERSE);
unsigned inside_cost = 0, prologue_cost = 0;
@@ -9390,45 +8871,11 @@ vectorizable_store (vec_info *vinfo,
if (!costing_p)
{
/* Get vectorized arguments for SLP_NODE. */
- vect_get_vec_defs (vinfo, stmt_info, slp_node, 1, op,
- &vec_oprnds, mask, &vec_masks);
+ vect_get_vec_defs (vinfo, slp_node, op, &vec_oprnds, mask, &vec_masks);
vec_oprnd = vec_oprnds[0];
if (mask)
vec_mask = vec_masks[0];
}
- else
- {
- /* For interleaved stores we collect vectorized defs for all the
- stores in the group in DR_CHAIN. DR_CHAIN is then used as an
- input to vect_permute_store_chain().
-
- If the store is not grouped, DR_GROUP_SIZE is 1, and DR_CHAIN
- is of size 1. */
- stmt_vec_info next_stmt_info = first_stmt_info;
- for (i = 0; i < group_size; i++)
- {
- /* Since gaps are not supported for interleaved stores,
- DR_GROUP_SIZE is the exact number of stmts in the chain.
- Therefore, NEXT_STMT_INFO can't be NULL_TREE. In case
- that there is no interleaving, DR_GROUP_SIZE is 1,
- and only one iteration of the loop will be executed. */
- op = vect_get_store_rhs (next_stmt_info);
- if (!costing_p)
- {
- vect_get_vec_defs_for_operand (vinfo, next_stmt_info,
- 1, op, gvec_oprnds[i]);
- vec_oprnd = (*gvec_oprnds[i])[0];
- dr_chain.quick_push (vec_oprnd);
- }
- next_stmt_info = DR_GROUP_NEXT_ELEMENT (next_stmt_info);
- }
- if (mask && !costing_p)
- {
- vect_get_vec_defs_for_operand (vinfo, stmt_info, 1,
- mask, &vec_masks, mask_vectype);
- vec_mask = vec_masks[0];
- }
- }
/* We should have catched mismatched types earlier. */
gcc_assert (costing_p
@@ -9455,25 +8902,7 @@ vectorizable_store (vec_info *vinfo,
simd_lane_access_p, bump);
new_stmt = NULL;
- if (grouped_store)
- {
- /* Permute. */
- gcc_assert (memory_access_type == VMAT_CONTIGUOUS_PERMUTE);
- if (costing_p)
- {
- int group_size = DR_GROUP_SIZE (first_stmt_info);
- int nstmts = ceil_log2 (group_size) * group_size;
- inside_cost += record_stmt_cost (cost_vec, nstmts, vec_perm,
- slp_node, 0, vect_body);
- if (dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location, "vect_model_store_cost: "
- "strided group_size = %d .\n", group_size);
- }
- else
- vect_permute_store_chain (vinfo, dr_chain, group_size, stmt_info,
- gsi, &result_chain);
- }
-
+ gcc_assert (!grouped_store);
for (i = 0; i < vec_num; i++)
{
if (!costing_p)
@@ -9826,7 +9255,7 @@ hoist_defs_of_uses (gimple *stmt, class loop *loop, bool hoist_p)
static bool
vectorizable_load (vec_info *vinfo,
stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- gimple **vec_stmt, slp_tree slp_node,
+ slp_tree slp_node,
stmt_vector_for_cost *cost_vec)
{
tree scalar_dest;
@@ -9870,7 +9299,7 @@ vectorizable_load (vec_info *vinfo,
return false;
if (STMT_VINFO_DEF_TYPE (stmt_info) != vect_internal_def
- && ! vec_stmt)
+ && cost_vec)
return false;
if (!STMT_VINFO_DATA_REF (stmt_info))
@@ -9919,7 +9348,7 @@ vectorizable_load (vec_info *vinfo,
mask_index = vect_slp_child_index_for_operand
(call, mask_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
if (mask_index >= 0
- && !vect_check_scalar_mask (vinfo, stmt_info, slp_node, mask_index,
+ && !vect_check_scalar_mask (vinfo, slp_node, mask_index,
&mask, &slp_op, &mask_dt, &mask_vectype))
return false;
@@ -9928,12 +9357,12 @@ vectorizable_load (vec_info *vinfo,
els_index = vect_slp_child_index_for_operand
(call, els_index, STMT_VINFO_GATHER_SCATTER_P (stmt_info));
if (els_index >= 0
- && !vect_is_simple_use (vinfo, stmt_info, slp_node, els_index,
+ && !vect_is_simple_use (vinfo, slp_node, els_index,
&els, &els_op, &els_dt, &els_vectype))
return false;
}
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype = SLP_TREE_VECTYPE (slp_node);
poly_uint64 nunits = TYPE_VECTOR_SUBPARTS (vectype);
if (loop_vinfo)
@@ -10091,8 +9520,7 @@ vectorizable_load (vec_info *vinfo,
return false;
}
else if (memory_access_type == VMAT_GATHER_SCATTER
- && gs_info.ifn == IFN_LAST
- && !gs_info.decl)
+ && GATHER_SCATTER_EMULATED_P (gs_info))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -10109,7 +9537,7 @@ vectorizable_load (vec_info *vinfo,
}
}
- bool costing_p = !vec_stmt;
+ bool costing_p = cost_vec;
if (costing_p) /* transformation not required. */
{
@@ -10642,7 +10070,6 @@ vectorizable_load (vec_info *vinfo,
vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
}
- gcc_assert (alignment_support_scheme);
vec_loop_masks *loop_masks
= (loop_vinfo && LOOP_VINFO_FULLY_MASKED_P (loop_vinfo)
? &LOOP_VINFO_MASKS (loop_vinfo)
@@ -10662,10 +10089,12 @@ vectorizable_load (vec_info *vinfo,
/* Targets with store-lane instructions must not require explicit
realignment. vect_supportable_dr_alignment always returns either
- dr_aligned or dr_unaligned_supported for masked operations. */
+ dr_aligned or dr_unaligned_supported for (non-length) masked
+ operations. */
gcc_assert ((memory_access_type != VMAT_LOAD_STORE_LANES
&& !mask
&& !loop_masks)
+ || memory_access_type == VMAT_GATHER_SCATTER
|| alignment_support_scheme == dr_aligned
|| alignment_support_scheme == dr_unaligned_supported);
@@ -10701,39 +10130,6 @@ vectorizable_load (vec_info *vinfo,
S2: z = x + 1 - -
*/
- /* In case of interleaving (non-unit grouped access):
-
- S1: x2 = &base + 2
- S2: x0 = &base
- S3: x1 = &base + 1
- S4: x3 = &base + 3
-
- Vectorized loads are created in the order of memory accesses
- starting from the access of the first stmt of the chain:
-
- VS1: vx0 = &base
- VS2: vx1 = &base + vec_size*1
- VS3: vx3 = &base + vec_size*2
- VS4: vx4 = &base + vec_size*3
-
- Then permutation statements are generated:
-
- VS5: vx5 = VEC_PERM_EXPR < vx0, vx1, { 0, 2, ..., i*2 } >
- VS6: vx6 = VEC_PERM_EXPR < vx0, vx1, { 1, 3, ..., i*2+1 } >
- ...
-
- And they are put in STMT_VINFO_VEC_STMT of the corresponding scalar stmts
- (the order of the data-refs in the output of vect_permute_load_chain
- corresponds to the order of scalar stmts in the interleaving chain - see
- the documentation of vect_permute_load_chain()).
- The generation of permutation stmts and recording them in
- STMT_VINFO_VEC_STMT is done in vect_transform_grouped_load().
-
- In case of both multiple types and interleaving, the vector loads and
- permutation stmts above are created for every copy. The result vector
- stmts are put in STMT_VINFO_VEC_STMT for the first copy and in the
- corresponding STMT_VINFO_RELATED_STMT for the next copies. */
-
/* If the data reference is aligned (dr_aligned) or potentially unaligned
on a target that supports unaligned accesses (dr_unaligned_supported)
we generate the following code:
@@ -10824,7 +10220,8 @@ vectorizable_load (vec_info *vinfo,
{
aggr_type = elem_type;
if (!costing_p)
- vect_get_strided_load_store_ops (stmt_info, loop_vinfo, gsi, &gs_info,
+ vect_get_strided_load_store_ops (stmt_info, vectype, loop_vinfo,
+ gsi, &gs_info,
&bump, &vec_offset, loop_lens);
}
else
@@ -11010,8 +10407,6 @@ vectorizable_load (vec_info *vinfo,
if (memory_access_type == VMAT_GATHER_SCATTER)
{
- gcc_assert (alignment_support_scheme == dr_aligned
- || alignment_support_scheme == dr_unaligned_supported);
gcc_assert (!grouped_load && !slp_perm);
unsigned int inside_cost = 0, prologue_cost = 0;
@@ -11020,8 +10415,7 @@ vectorizable_load (vec_info *vinfo,
if (!costing_p)
{
if (STMT_VINFO_GATHER_SCATTER_P (stmt_info))
- vect_get_gather_scatter_ops (loop_vinfo, loop, stmt_info,
- slp_node, &gs_info, &dataref_ptr,
+ vect_get_gather_scatter_ops (loop, slp_node, &gs_info, &dataref_ptr,
&vec_offsets);
else
dataref_ptr
@@ -11054,7 +10448,7 @@ vectorizable_load (vec_info *vinfo,
/* 2. Create the vector-load in the loop. */
unsigned HOST_WIDE_INT align;
- if (gs_info.ifn != IFN_LAST)
+ if (GATHER_SCATTER_IFN_P (gs_info))
{
if (costing_p)
{
@@ -11100,7 +10494,8 @@ vectorizable_load (vec_info *vinfo,
{
if (VECTOR_TYPE_P (TREE_TYPE (vec_offset)))
call = gimple_build_call_internal (IFN_MASK_LEN_GATHER_LOAD,
- 8, dataref_ptr,
+ 9, dataref_ptr,
+ gs_info.alias_ptr,
vec_offset, scale, zero,
final_mask, vec_els,
final_len, bias);
@@ -11115,18 +10510,20 @@ vectorizable_load (vec_info *vinfo,
}
else if (final_mask)
call = gimple_build_call_internal (IFN_MASK_GATHER_LOAD,
- 6, dataref_ptr,
+ 7, dataref_ptr,
+ gs_info.alias_ptr,
vec_offset, scale,
zero, final_mask, vec_els);
else
- call = gimple_build_call_internal (IFN_GATHER_LOAD, 4,
- dataref_ptr, vec_offset,
- scale, zero);
+ call = gimple_build_call_internal (IFN_GATHER_LOAD, 5,
+ dataref_ptr,
+ gs_info.alias_ptr,
+ vec_offset, scale, zero);
gimple_call_set_nothrow (call, true);
new_stmt = call;
data_ref = NULL_TREE;
}
- else if (gs_info.decl)
+ else if (GATHER_SCATTER_LEGACY_P (gs_info))
{
/* The builtin decls path for gather is legacy, x86 only. */
gcc_assert (!final_len && nunits.is_constant ());
@@ -11143,7 +10540,7 @@ vectorizable_load (vec_info *vinfo,
if (known_eq (nunits, offset_nunits))
{
new_stmt = vect_build_one_gather_load_call
- (vinfo, stmt_info, gsi, &gs_info,
+ (vinfo, stmt_info, vectype, gsi, &gs_info,
dataref_ptr, vec_offsets[i], final_mask);
data_ref = NULL_TREE;
}
@@ -11153,7 +10550,7 @@ vectorizable_load (vec_info *vinfo,
lanes but the builtins will produce full vectype
data with just the lower lanes filled. */
new_stmt = vect_build_one_gather_load_call
- (vinfo, stmt_info, gsi, &gs_info,
+ (vinfo, stmt_info, vectype, gsi, &gs_info,
dataref_ptr, vec_offsets[2 * i], final_mask);
tree low = make_ssa_name (vectype);
gimple_set_lhs (new_stmt, low);
@@ -11192,7 +10589,8 @@ vectorizable_load (vec_info *vinfo,
}
new_stmt = vect_build_one_gather_load_call
- (vinfo, stmt_info, gsi, &gs_info, dataref_ptr,
+ (vinfo, stmt_info, vectype, gsi, &gs_info,
+ dataref_ptr,
vec_offsets[2 * i + 1], final_mask);
tree high = make_ssa_name (vectype);
gimple_set_lhs (new_stmt, high);
@@ -11235,7 +10633,7 @@ vectorizable_load (vec_info *vinfo,
new_stmt, gsi);
}
new_stmt = vect_build_one_gather_load_call
- (vinfo, stmt_info, gsi, &gs_info,
+ (vinfo, stmt_info, vectype, gsi, &gs_info,
dataref_ptr, vec_offset, final_mask);
data_ref = NULL_TREE;
}
@@ -11816,18 +11214,12 @@ vectorizable_load (vec_info *vinfo,
alignment support schemes. */
if (costing_p)
{
- /* For VMAT_CONTIGUOUS_PERMUTE if it's grouped load, we
- only need to take care of the first stmt, whose
- stmt_info is first_stmt_info, vec_num iterating on it
- will cover the cost for the remaining, it's consistent
- with transforming. For the prologue cost for realign,
+ /* For the prologue cost for realign,
we only need to count it once for the whole group. */
bool first_stmt_info_p = first_stmt_info == stmt_info;
bool add_realign_cost = first_stmt_info_p && i == 0;
if (memory_access_type == VMAT_CONTIGUOUS
- || memory_access_type == VMAT_CONTIGUOUS_REVERSE
- || (memory_access_type == VMAT_CONTIGUOUS_PERMUTE
- && (!grouped_load || first_stmt_info_p)))
+ || memory_access_type == VMAT_CONTIGUOUS_REVERSE)
{
/* Leave realign cases alone to keep them simple. */
if (alignment_support_scheme == dr_explicit_realign_optimized
@@ -11915,7 +11307,7 @@ vectorizable_load (vec_info *vinfo,
}
/* Collect vector loads and later create their permutation in
- vect_transform_grouped_load (). */
+ vect_transform_slp_perm_load. */
if (!costing_p && (grouped_load || slp_perm))
dr_chain.quick_push (new_temp);
@@ -11984,8 +11376,7 @@ vectorizable_load (vec_info *vinfo,
if (costing_p)
{
gcc_assert (memory_access_type == VMAT_CONTIGUOUS
- || memory_access_type == VMAT_CONTIGUOUS_REVERSE
- || memory_access_type == VMAT_CONTIGUOUS_PERMUTE);
+ || memory_access_type == VMAT_CONTIGUOUS_REVERSE);
if (n_adjacent_loads > 0)
vect_get_load_cost (vinfo, stmt_info, slp_node, n_adjacent_loads,
alignment_support_scheme, misalignment, false,
@@ -12015,7 +11406,7 @@ vectorizable_load (vec_info *vinfo,
condition operands are supportable using vec_is_simple_use. */
static bool
-vect_is_simple_cond (tree cond, vec_info *vinfo, stmt_vec_info stmt_info,
+vect_is_simple_cond (tree cond, vec_info *vinfo,
slp_tree slp_node, tree *comp_vectype,
enum vect_def_type *dts, tree vectype)
{
@@ -12027,7 +11418,7 @@ vect_is_simple_cond (tree cond, vec_info *vinfo, stmt_vec_info stmt_info,
if (TREE_CODE (cond) == SSA_NAME
&& VECT_SCALAR_BOOLEAN_TYPE_P (TREE_TYPE (cond)))
{
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0, &cond,
+ if (!vect_is_simple_use (vinfo, slp_node, 0, &cond,
&slp_op, &dts[0], comp_vectype)
|| !*comp_vectype
|| !VECTOR_BOOLEAN_TYPE_P (*comp_vectype))
@@ -12043,7 +11434,7 @@ vect_is_simple_cond (tree cond, vec_info *vinfo, stmt_vec_info stmt_info,
if (TREE_CODE (lhs) == SSA_NAME)
{
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 0,
+ if (!vect_is_simple_use (vinfo, slp_node, 0,
&lhs, &slp_op, &dts[0], &vectype1))
return false;
}
@@ -12055,7 +11446,7 @@ vect_is_simple_cond (tree cond, vec_info *vinfo, stmt_vec_info stmt_info,
if (TREE_CODE (rhs) == SSA_NAME)
{
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1,
+ if (!vect_is_simple_use (vinfo, slp_node, 1,
&rhs, &slp_op, &dts[1], &vectype2))
return false;
}
@@ -12108,7 +11499,6 @@ vect_is_simple_cond (tree cond, vec_info *vinfo, stmt_vec_info stmt_info,
static bool
vectorizable_condition (vec_info *vinfo,
stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- gimple **vec_stmt,
slp_tree slp_node, stmt_vector_for_cost *cost_vec)
{
tree scalar_dest = NULL_TREE;
@@ -12124,9 +11514,6 @@ vectorizable_condition (vec_info *vinfo,
enum vect_def_type dts[4]
= {vect_unknown_def_type, vect_unknown_def_type,
vect_unknown_def_type, vect_unknown_def_type};
- int ndts = 4;
- int ncopies;
- int vec_num;
enum tree_code code, cond_code, bitop1 = NOP_EXPR, bitop2 = NOP_EXPR;
int i;
bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
@@ -12156,7 +11543,7 @@ vectorizable_condition (vec_info *vinfo,
= STMT_VINFO_REDUC_DEF (vect_orig_stmt (stmt_info)) != NULL;
if (for_reduction)
{
- if (slp_node && SLP_TREE_LANES (slp_node) > 1)
+ if (SLP_TREE_LANES (slp_node) > 1)
return false;
reduc_info = info_for_reduction (vinfo, stmt_info);
reduction_type = STMT_VINFO_REDUC_TYPE (reduc_info);
@@ -12170,38 +11557,25 @@ vectorizable_condition (vec_info *vinfo,
return false;
}
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype = SLP_TREE_VECTYPE (slp_node);
tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
- if (slp_node)
- {
- ncopies = 1;
- vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
- }
- else
- {
- ncopies = vect_get_num_copies (loop_vinfo, vectype);
- vec_num = 1;
- }
-
- gcc_assert (ncopies >= 1);
- if (for_reduction && ncopies > 1)
- return false; /* FORNOW */
+ int vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
cond_expr = gimple_assign_rhs1 (stmt);
gcc_assert (! COMPARISON_CLASS_P (cond_expr));
- if (!vect_is_simple_cond (cond_expr, vinfo, stmt_info, slp_node,
+ if (!vect_is_simple_cond (cond_expr, vinfo, slp_node,
&comp_vectype, &dts[0], vectype)
|| !comp_vectype)
return false;
unsigned op_adjust = COMPARISON_CLASS_P (cond_expr) ? 1 : 0;
slp_tree then_slp_node, else_slp_node;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 1 + op_adjust,
+ if (!vect_is_simple_use (vinfo, slp_node, 1 + op_adjust,
&then_clause, &then_slp_node, &dts[2], &vectype1))
return false;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node, 2 + op_adjust,
+ if (!vect_is_simple_use (vinfo, slp_node, 2 + op_adjust,
&else_clause, &else_slp_node, &dts[3], &vectype2))
return false;
@@ -12249,9 +11623,8 @@ vectorizable_condition (vec_info *vinfo,
}
/* ??? The vectorized operand query below doesn't allow swapping
this way for SLP. */
- if (slp_node)
- return false;
- std::swap (then_clause, else_clause);
+ return false;
+ /* std::swap (then_clause, else_clause); */
}
if (!masked && VECTOR_BOOLEAN_TYPE_P (comp_vectype))
@@ -12305,7 +11678,7 @@ vectorizable_condition (vec_info *vinfo,
return false;
}
- if (!vec_stmt)
+ if (cost_vec)
{
if (bitop1 != NOP_EXPR)
{
@@ -12336,14 +11709,13 @@ vectorizable_condition (vec_info *vinfo,
|| !expand_vec_cond_expr_p (vectype, vec_cmp_type))))
return false;
- if (slp_node
- && (!vect_maybe_update_slp_op_vectype
- (SLP_TREE_CHILDREN (slp_node)[0], comp_vectype)
- || (op_adjust == 1
- && !vect_maybe_update_slp_op_vectype
- (SLP_TREE_CHILDREN (slp_node)[1], comp_vectype))
- || !vect_maybe_update_slp_op_vectype (then_slp_node, vectype)
- || !vect_maybe_update_slp_op_vectype (else_slp_node, vectype)))
+ if (!vect_maybe_update_slp_op_vectype (SLP_TREE_CHILDREN (slp_node)[0],
+ comp_vectype)
+ || (op_adjust == 1
+ && !vect_maybe_update_slp_op_vectype
+ (SLP_TREE_CHILDREN (slp_node)[1], comp_vectype))
+ || !vect_maybe_update_slp_op_vectype (then_slp_node, vectype)
+ || !vect_maybe_update_slp_op_vectype (else_slp_node, vectype))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -12360,11 +11732,11 @@ vectorizable_condition (vec_info *vinfo,
vectype, OPTIMIZE_FOR_SPEED))
vect_record_loop_len (loop_vinfo,
&LOOP_VINFO_LENS (loop_vinfo),
- ncopies * vec_num, vectype, 1);
+ vec_num, vectype, 1);
else
vect_record_loop_mask (loop_vinfo,
&LOOP_VINFO_MASKS (loop_vinfo),
- ncopies * vec_num, vectype, NULL);
+ vec_num, vectype, NULL);
}
/* Extra inactive lanes should be safe for vect_nested_cycle. */
else if (STMT_VINFO_DEF_TYPE (reduc_info) != vect_nested_cycle)
@@ -12378,8 +11750,7 @@ vectorizable_condition (vec_info *vinfo,
}
STMT_VINFO_TYPE (stmt_info) = condition_vec_info_type;
- vect_model_simple_cost (vinfo, ncopies, dts, ndts, slp_node,
- cost_vec, kind);
+ vect_model_simple_cost (vinfo, 1, slp_node, cost_vec, kind);
return true;
}
@@ -12408,7 +11779,7 @@ vectorizable_condition (vec_info *vinfo,
masks = &LOOP_VINFO_MASKS (loop_vinfo);
else
{
- scalar_cond_masked_key cond (cond_expr, ncopies);
+ scalar_cond_masked_key cond (cond_expr, 1);
if (loop_vinfo->scalar_cond_masked_set.contains (cond))
masks = &LOOP_VINFO_MASKS (loop_vinfo);
else
@@ -12443,18 +11814,18 @@ vectorizable_condition (vec_info *vinfo,
/* Handle cond expr. */
if (masked)
- vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
- cond_expr, comp_vectype, &vec_oprnds0,
- then_clause, vectype, &vec_oprnds2,
+ vect_get_vec_defs (vinfo, slp_node,
+ cond_expr, &vec_oprnds0,
+ then_clause, &vec_oprnds2,
reduction_type != EXTRACT_LAST_REDUCTION
- ? else_clause : NULL, vectype, &vec_oprnds3);
+ ? else_clause : NULL, &vec_oprnds3);
else
- vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
- cond_expr0, comp_vectype, &vec_oprnds0,
- cond_expr1, comp_vectype, &vec_oprnds1,
- then_clause, vectype, &vec_oprnds2,
+ vect_get_vec_defs (vinfo, slp_node,
+ cond_expr0, &vec_oprnds0,
+ cond_expr1, &vec_oprnds1,
+ then_clause, &vec_oprnds2,
reduction_type != EXTRACT_LAST_REDUCTION
- ? else_clause : NULL, vectype, &vec_oprnds3);
+ ? else_clause : NULL, &vec_oprnds3);
if (reduction_type == EXTRACT_LAST_REDUCTION)
vec_else_clause = else_clause;
@@ -12571,7 +11942,7 @@ vectorizable_condition (vec_info *vinfo,
if (lens)
{
len = vect_get_loop_len (loop_vinfo, gsi, lens,
- vec_num * ncopies, vectype, i, 1);
+ vec_num, vectype, i, 1);
signed char biasval
= LOOP_VINFO_PARTIAL_LOAD_STORE_BIAS (loop_vinfo);
bias = build_int_cst (intQI_type_node, biasval);
@@ -12585,7 +11956,7 @@ vectorizable_condition (vec_info *vinfo,
if (masks)
{
tree loop_mask
- = vect_get_loop_mask (loop_vinfo, gsi, masks, vec_num * ncopies,
+ = vect_get_loop_mask (loop_vinfo, gsi, masks, vec_num,
vectype, i);
tree tmp2 = make_ssa_name (vec_cmp_type);
gassign *g
@@ -12637,15 +12008,9 @@ vectorizable_condition (vec_info *vinfo,
vec_then_clause, vec_else_clause);
vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
}
- if (slp_node)
- slp_node->push_vec_def (new_stmt);
- else
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
+ slp_node->push_vec_def (new_stmt);
}
- if (!slp_node)
- *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
-
vec_oprnds0.release ();
vec_oprnds1.release ();
vec_oprnds2.release ();
@@ -12665,18 +12030,15 @@ vectorizable_condition (vec_info *vinfo,
static bool
vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
stmt_vec_info stmt_info, tree_code code,
- gimple_stmt_iterator *gsi, gimple **vec_stmt,
+ gimple_stmt_iterator *gsi,
slp_tree slp_node, stmt_vector_for_cost *cost_vec)
{
tree lhs, rhs1, rhs2;
tree vectype1 = NULL_TREE, vectype2 = NULL_TREE;
tree vec_rhs1 = NULL_TREE, vec_rhs2 = NULL_TREE;
tree new_temp;
- loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
enum vect_def_type dts[2] = {vect_unknown_def_type, vect_unknown_def_type};
- int ndts = 2;
poly_uint64 nunits;
- int ncopies;
enum tree_code bitop1 = NOP_EXPR, bitop2 = NOP_EXPR;
int i;
bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
@@ -12694,22 +12056,15 @@ vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
mask_type = vectype;
nunits = TYPE_VECTOR_SUBPARTS (vectype);
- if (slp_node)
- ncopies = 1;
- else
- ncopies = vect_get_num_copies (loop_vinfo, vectype);
-
- gcc_assert (ncopies >= 1);
-
if (TREE_CODE_CLASS (code) != tcc_comparison)
return false;
slp_tree slp_rhs1, slp_rhs2;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
+ if (!vect_is_simple_use (vinfo, slp_node,
0, &rhs1, &slp_rhs1, &dts[0], &vectype1))
return false;
- if (!vect_is_simple_use (vinfo, stmt_info, slp_node,
+ if (!vect_is_simple_use (vinfo, slp_node,
1, &rhs2, &slp_rhs2, &dts[1], &vectype2))
return false;
@@ -12775,7 +12130,7 @@ vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
}
}
- if (!vec_stmt)
+ if (cost_vec)
{
if (bitop1 == NOP_EXPR)
{
@@ -12800,9 +12155,8 @@ vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
}
/* Put types on constant and invariant SLP children. */
- if (slp_node
- && (!vect_maybe_update_slp_op_vectype (slp_rhs1, vectype)
- || !vect_maybe_update_slp_op_vectype (slp_rhs2, vectype)))
+ if (!vect_maybe_update_slp_op_vectype (slp_rhs1, vectype)
+ || !vect_maybe_update_slp_op_vectype (slp_rhs2, vectype))
{
if (dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -12810,8 +12164,8 @@ vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
return false;
}
- vect_model_simple_cost (vinfo, ncopies * (1 + (bitop2 != NOP_EXPR)),
- dts, ndts, slp_node, cost_vec);
+ vect_model_simple_cost (vinfo, 1 + (bitop2 != NOP_EXPR),
+ slp_node, cost_vec);
return true;
}
@@ -12822,9 +12176,7 @@ vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
if (lhs)
mask = vect_create_destination_var (lhs, mask_type);
- vect_get_vec_defs (vinfo, stmt_info, slp_node, ncopies,
- rhs1, vectype, &vec_oprnds0,
- rhs2, vectype, &vec_oprnds1);
+ vect_get_vec_defs (vinfo, slp_node, rhs1, &vec_oprnds0, rhs2, &vec_oprnds1);
if (swap_p)
std::swap (vec_oprnds0, vec_oprnds1);
@@ -12863,15 +12215,9 @@ vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
vect_finish_stmt_generation (vinfo, stmt_info, new_stmt, gsi);
}
}
- if (slp_node)
- slp_node->push_vec_def (new_stmt);
- else
- STMT_VINFO_VEC_STMTS (stmt_info).safe_push (new_stmt);
+ slp_node->push_vec_def (new_stmt);
}
- if (!slp_node)
- *vec_stmt = STMT_VINFO_VEC_STMTS (stmt_info)[0];
-
vec_oprnds0.release ();
vec_oprnds1.release ();
@@ -12889,7 +12235,6 @@ vectorizable_comparison_1 (vec_info *vinfo, tree vectype,
static bool
vectorizable_comparison (vec_info *vinfo,
stmt_vec_info stmt_info, gimple_stmt_iterator *gsi,
- gimple **vec_stmt,
slp_tree slp_node, stmt_vector_for_cost *cost_vec)
{
bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo);
@@ -12905,12 +12250,12 @@ vectorizable_comparison (vec_info *vinfo,
return false;
enum tree_code code = gimple_assign_rhs_code (stmt);
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+ tree vectype = SLP_TREE_VECTYPE (slp_node);
if (!vectorizable_comparison_1 (vinfo, vectype, stmt_info, code, gsi,
- vec_stmt, slp_node, cost_vec))
+ slp_node, cost_vec))
return false;
- if (!vec_stmt)
+ if (cost_vec)
STMT_VINFO_TYPE (stmt_info) = comparison_vec_info_type;
return true;
@@ -12921,7 +12266,7 @@ vectorizable_comparison (vec_info *vinfo,
bool
vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info,
- gimple_stmt_iterator *gsi, gimple **vec_stmt,
+ gimple_stmt_iterator *gsi,
slp_tree slp_node, stmt_vector_for_cost *cost_vec)
{
loop_vec_info loop_vinfo = dyn_cast <loop_vec_info> (vinfo);
@@ -12939,48 +12284,17 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info,
auto code = gimple_cond_code (STMT_VINFO_STMT (stmt_info));
- tree vectype = NULL_TREE;
- slp_tree slp_op0;
- tree op0;
- enum vect_def_type dt0;
-
- /* Early break gcond kind SLP trees can be root only and have no children,
- for instance in the case where the argument is an external. If that's
- the case there is no operand to analyse use of. */
- if ((!slp_node || !SLP_TREE_CHILDREN (slp_node).is_empty ())
- && !vect_is_simple_use (vinfo, stmt_info, slp_node, 0, &op0, &slp_op0, &dt0,
- &vectype))
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "use not simple.\n");
- return false;
- }
-
/* For SLP we don't want to use the type of the operands of the SLP node, when
vectorizing using SLP slp_node will be the children of the gcond and we
want to use the type of the direct children which since the gcond is root
will be the current node, rather than a child node as vect_is_simple_use
assumes. */
- if (slp_node)
- vectype = SLP_TREE_VECTYPE (slp_node);
-
+ tree vectype = SLP_TREE_VECTYPE (slp_node);
if (!vectype)
return false;
machine_mode mode = TYPE_MODE (vectype);
- int ncopies, vec_num;
-
- if (slp_node)
- {
- ncopies = 1;
- vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
- }
- else
- {
- ncopies = vect_get_num_copies (loop_vinfo, vectype);
- vec_num = 1;
- }
+ int vec_num = SLP_TREE_NUMBER_OF_VEC_STMTS (slp_node);
vec_loop_masks *masks = &LOOP_VINFO_MASKS (loop_vinfo);
vec_loop_lens *lens = &LOOP_VINFO_LENS (loop_vinfo);
@@ -13010,7 +12324,7 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info,
exit_true_edge->dest);
/* Analyze only. */
- if (!vec_stmt)
+ if (cost_vec)
{
if (direct_optab_handler (cbranch_optab, mode) == CODE_FOR_nothing)
{
@@ -13022,31 +12336,17 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info,
return false;
}
- if (ncopies > 1
- && direct_optab_handler (ior_optab, mode) == CODE_FOR_nothing)
- {
- if (dump_enabled_p ())
- dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "can't vectorize early exit because the "
- "target does not support boolean vector IOR "
- "for type %T.\n",
- vectype);
- return false;
- }
-
if (!vectorizable_comparison_1 (vinfo, vectype, stmt_info, code, gsi,
- vec_stmt, slp_node, cost_vec))
+ slp_node, cost_vec))
return false;
if (LOOP_VINFO_CAN_USE_PARTIAL_VECTORS_P (loop_vinfo))
{
if (direct_internal_fn_supported_p (IFN_VCOND_MASK_LEN, vectype,
OPTIMIZE_FOR_SPEED))
- vect_record_loop_len (loop_vinfo, lens, ncopies * vec_num,
- vectype, 1);
+ vect_record_loop_len (loop_vinfo, lens, vec_num, vectype, 1);
else
- vect_record_loop_mask (loop_vinfo, masks, ncopies * vec_num,
- vectype, NULL);
+ vect_record_loop_mask (loop_vinfo, masks, vec_num, vectype, NULL);
}
return true;
@@ -13066,28 +12366,13 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info,
vectorized. It's not very clean to do this here, But the masking code below is
complex and this keeps it all in one place to ease fixes and backports. Once we
drop the non-SLP loop vect or split vectorizable_* this can be simplified. */
- if (!slp_node)
- {
- if (!vectorizable_comparison_1 (vinfo, vectype, stmt_info, code, gsi,
- vec_stmt, slp_node, cost_vec))
- gcc_unreachable ();
- }
gimple *stmt = STMT_VINFO_STMT (stmt_info);
basic_block cond_bb = gimple_bb (stmt);
gimple_stmt_iterator cond_gsi = gsi_last_bb (cond_bb);
auto_vec<tree> stmts;
-
- if (slp_node)
- stmts.safe_splice (SLP_TREE_VEC_DEFS (slp_node));
- else
- {
- auto vec_stmts = STMT_VINFO_VEC_STMTS (stmt_info);
- stmts.reserve_exact (vec_stmts.length ());
- for (auto stmt : vec_stmts)
- stmts.quick_push (gimple_assign_lhs (stmt));
- }
+ stmts.safe_splice (SLP_TREE_VEC_DEFS (slp_node));
/* If we're comparing against a previous forall we need to negate the resullts
before we do the final comparison or reduction. */
@@ -13126,7 +12411,7 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info,
for (unsigned i = 0; i < stmts.length (); i++)
{
tree stmt_mask
- = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies * vec_num,
+ = vect_get_loop_mask (loop_vinfo, gsi, masks, vec_num,
vectype, i);
stmt_mask
= prepare_vec_mask (loop_vinfo, TREE_TYPE (stmt_mask), stmt_mask,
@@ -13137,7 +12422,7 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info,
for (unsigned i = 0; i < stmts.length (); i++)
{
tree len_mask = vect_gen_loop_len_mask (loop_vinfo, gsi, &cond_gsi,
- lens, ncopies * vec_num,
+ lens, vec_num,
vectype, stmts[i], i, 1);
workset.quick_push (len_mask);
@@ -13162,13 +12447,13 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info,
if (masked_loop_p)
{
tree mask
- = vect_get_loop_mask (loop_vinfo, gsi, masks, ncopies, vectype, 0);
+ = vect_get_loop_mask (loop_vinfo, gsi, masks, 1, vectype, 0);
new_temp = prepare_vec_mask (loop_vinfo, TREE_TYPE (mask), mask,
new_temp, &cond_gsi);
}
else if (len_loop_p)
new_temp = vect_gen_loop_len_mask (loop_vinfo, gsi, &cond_gsi, lens,
- ncopies, vectype, new_temp, 0, 1);
+ 1, vectype, new_temp, 0, 1);
}
gcc_assert (new_temp);
@@ -13176,13 +12461,8 @@ vectorizable_early_exit (vec_info *vinfo, stmt_vec_info stmt_info,
gimple_cond_set_condition (cond_stmt, NE_EXPR, new_temp, cst);
update_stmt (orig_stmt);
- if (slp_node)
- SLP_TREE_VEC_DEFS (slp_node).truncate (0);
- else
- STMT_VINFO_VEC_STMTS (stmt_info).truncate (0);
-
- if (!slp_node)
- *vec_stmt = orig_stmt;
+ /* ??? */
+ SLP_TREE_VEC_DEFS (slp_node).truncate (0);
return true;
}
@@ -13310,58 +12590,58 @@ vect_analyze_stmt (vec_info *vinfo,
/* Prefer vectorizable_call over vectorizable_simd_clone_call so
-mveclibabi= takes preference over library functions with
the simd attribute. */
- ok = (vectorizable_call (vinfo, stmt_info, NULL, NULL, node, cost_vec)
- || vectorizable_simd_clone_call (vinfo, stmt_info, NULL, NULL, node,
+ ok = (vectorizable_call (vinfo, stmt_info, NULL, node, cost_vec)
+ || vectorizable_simd_clone_call (vinfo, stmt_info, NULL, node,
cost_vec)
|| vectorizable_conversion (vinfo, stmt_info,
- NULL, NULL, node, cost_vec)
+ NULL, node, cost_vec)
|| vectorizable_operation (vinfo, stmt_info,
- NULL, NULL, node, cost_vec)
+ NULL, node, cost_vec)
|| vectorizable_assignment (vinfo, stmt_info,
- NULL, NULL, node, cost_vec)
- || vectorizable_load (vinfo, stmt_info, NULL, NULL, node, cost_vec)
- || vectorizable_store (vinfo, stmt_info, NULL, NULL, node, cost_vec)
+ NULL, node, cost_vec)
+ || vectorizable_load (vinfo, stmt_info, NULL, node, cost_vec)
+ || vectorizable_store (vinfo, stmt_info, NULL, node, cost_vec)
|| vectorizable_lane_reducing (as_a <loop_vec_info> (vinfo),
stmt_info, node, cost_vec)
|| vectorizable_reduction (as_a <loop_vec_info> (vinfo), stmt_info,
node, node_instance, cost_vec)
|| vectorizable_induction (as_a <loop_vec_info> (vinfo), stmt_info,
- NULL, node, cost_vec)
- || vectorizable_shift (vinfo, stmt_info, NULL, NULL, node, cost_vec)
+ node, cost_vec)
+ || vectorizable_shift (vinfo, stmt_info, NULL, node, cost_vec)
|| vectorizable_condition (vinfo, stmt_info,
- NULL, NULL, node, cost_vec)
- || vectorizable_comparison (vinfo, stmt_info, NULL, NULL, node,
+ NULL, node, cost_vec)
+ || vectorizable_comparison (vinfo, stmt_info, NULL, node,
cost_vec)
|| vectorizable_lc_phi (as_a <loop_vec_info> (vinfo),
stmt_info, node)
|| vectorizable_recurr (as_a <loop_vec_info> (vinfo),
- stmt_info, NULL, node, cost_vec)
- || vectorizable_early_exit (vinfo, stmt_info, NULL, NULL, node,
+ stmt_info, node, cost_vec)
+ || vectorizable_early_exit (vinfo, stmt_info, NULL, node,
cost_vec));
else
{
if (bb_vinfo)
- ok = (vectorizable_call (vinfo, stmt_info, NULL, NULL, node, cost_vec)
+ ok = (vectorizable_call (vinfo, stmt_info, NULL, node, cost_vec)
|| vectorizable_simd_clone_call (vinfo, stmt_info,
- NULL, NULL, node, cost_vec)
- || vectorizable_conversion (vinfo, stmt_info, NULL, NULL, node,
+ NULL, node, cost_vec)
+ || vectorizable_conversion (vinfo, stmt_info, NULL, node,
cost_vec)
|| vectorizable_shift (vinfo, stmt_info,
- NULL, NULL, node, cost_vec)
+ NULL, node, cost_vec)
|| vectorizable_operation (vinfo, stmt_info,
- NULL, NULL, node, cost_vec)
- || vectorizable_assignment (vinfo, stmt_info, NULL, NULL, node,
+ NULL, node, cost_vec)
+ || vectorizable_assignment (vinfo, stmt_info, NULL, node,
cost_vec)
|| vectorizable_load (vinfo, stmt_info,
- NULL, NULL, node, cost_vec)
+ NULL, node, cost_vec)
|| vectorizable_store (vinfo, stmt_info,
- NULL, NULL, node, cost_vec)
+ NULL, node, cost_vec)
|| vectorizable_condition (vinfo, stmt_info,
- NULL, NULL, node, cost_vec)
- || vectorizable_comparison (vinfo, stmt_info, NULL, NULL, node,
+ NULL, node, cost_vec)
+ || vectorizable_comparison (vinfo, stmt_info, NULL, node,
cost_vec)
- || vectorizable_phi (vinfo, stmt_info, NULL, node, cost_vec)
- || vectorizable_early_exit (vinfo, stmt_info, NULL, NULL, node,
+ || vectorizable_phi (vinfo, stmt_info, node, cost_vec)
+ || vectorizable_early_exit (vinfo, stmt_info, NULL, node,
cost_vec));
}
@@ -13378,7 +12658,8 @@ vect_analyze_stmt (vec_info *vinfo,
need extra handling, except for vectorizable reductions. */
if (!bb_vinfo
&& STMT_VINFO_TYPE (stmt_info) != reduc_vec_info_type
- && STMT_VINFO_TYPE (stmt_info) != lc_phi_info_type
+ && (STMT_VINFO_TYPE (stmt_info) != lc_phi_info_type
+ || STMT_VINFO_DEF_TYPE (stmt_info) == vect_internal_def)
&& (!node->ldst_lanes || SLP_TREE_CODE (node) == VEC_PERM_EXPR)
&& !can_vectorize_live_stmts (as_a <loop_vec_info> (vinfo),
node, node_instance,
@@ -13402,57 +12683,49 @@ vect_transform_stmt (vec_info *vinfo,
slp_tree slp_node, slp_instance slp_node_instance)
{
bool is_store = false;
- gimple *vec_stmt = NULL;
bool done;
- gcc_assert (slp_node || !PURE_SLP_STMT (stmt_info));
+ gcc_assert (slp_node);
if (dump_enabled_p ())
dump_printf_loc (MSG_NOTE, vect_location,
"------>vectorizing statement: %G", stmt_info->stmt);
tree saved_vectype = STMT_VINFO_VECTYPE (stmt_info);
- if (slp_node)
- STMT_VINFO_VECTYPE (stmt_info) = SLP_TREE_VECTYPE (slp_node);
+ STMT_VINFO_VECTYPE (stmt_info) = SLP_TREE_VECTYPE (slp_node);
switch (STMT_VINFO_TYPE (stmt_info))
{
case type_demotion_vec_info_type:
case type_promotion_vec_info_type:
case type_conversion_vec_info_type:
- done = vectorizable_conversion (vinfo, stmt_info,
- gsi, &vec_stmt, slp_node, NULL);
+ done = vectorizable_conversion (vinfo, stmt_info, gsi, slp_node, NULL);
gcc_assert (done);
break;
case induc_vec_info_type:
done = vectorizable_induction (as_a <loop_vec_info> (vinfo),
- stmt_info, &vec_stmt, slp_node,
- NULL);
+ stmt_info, slp_node, NULL);
gcc_assert (done);
break;
case shift_vec_info_type:
- done = vectorizable_shift (vinfo, stmt_info,
- gsi, &vec_stmt, slp_node, NULL);
+ done = vectorizable_shift (vinfo, stmt_info, gsi, slp_node, NULL);
gcc_assert (done);
break;
case op_vec_info_type:
- done = vectorizable_operation (vinfo, stmt_info, gsi, &vec_stmt, slp_node,
- NULL);
+ done = vectorizable_operation (vinfo, stmt_info, gsi, slp_node, NULL);
gcc_assert (done);
break;
case assignment_vec_info_type:
- done = vectorizable_assignment (vinfo, stmt_info,
- gsi, &vec_stmt, slp_node, NULL);
+ done = vectorizable_assignment (vinfo, stmt_info, gsi, slp_node, NULL);
gcc_assert (done);
break;
case load_vec_info_type:
- done = vectorizable_load (vinfo, stmt_info, gsi, &vec_stmt, slp_node,
- NULL);
+ done = vectorizable_load (vinfo, stmt_info, gsi, slp_node, NULL);
gcc_assert (done);
break;
@@ -13468,32 +12741,28 @@ vect_transform_stmt (vec_info *vinfo,
;
else
{
- done = vectorizable_store (vinfo, stmt_info,
- gsi, &vec_stmt, slp_node, NULL);
+ done = vectorizable_store (vinfo, stmt_info, gsi, slp_node, NULL);
gcc_assert (done);
is_store = true;
}
break;
case condition_vec_info_type:
- done = vectorizable_condition (vinfo, stmt_info,
- gsi, &vec_stmt, slp_node, NULL);
+ done = vectorizable_condition (vinfo, stmt_info, gsi, slp_node, NULL);
gcc_assert (done);
break;
case comparison_vec_info_type:
- done = vectorizable_comparison (vinfo, stmt_info, gsi, &vec_stmt,
- slp_node, NULL);
+ done = vectorizable_comparison (vinfo, stmt_info, gsi, slp_node, NULL);
gcc_assert (done);
break;
case call_vec_info_type:
- done = vectorizable_call (vinfo, stmt_info,
- gsi, &vec_stmt, slp_node, NULL);
+ done = vectorizable_call (vinfo, stmt_info, gsi, slp_node, NULL);
break;
case call_simd_clone_vec_info_type:
- done = vectorizable_simd_clone_call (vinfo, stmt_info, gsi, &vec_stmt,
+ done = vectorizable_simd_clone_call (vinfo, stmt_info, gsi,
slp_node, NULL);
break;
@@ -13517,18 +12786,17 @@ vect_transform_stmt (vec_info *vinfo,
case recurr_info_type:
done = vectorizable_recurr (as_a <loop_vec_info> (vinfo),
- stmt_info, &vec_stmt, slp_node, NULL);
+ stmt_info, slp_node, NULL);
gcc_assert (done);
break;
case phi_info_type:
- done = vectorizable_phi (vinfo, stmt_info, &vec_stmt, slp_node, NULL);
+ done = vectorizable_phi (vinfo, stmt_info, slp_node, NULL);
gcc_assert (done);
break;
case loop_exit_ctrl_vec_info_type:
- done = vectorizable_early_exit (vinfo, stmt_info, gsi, &vec_stmt,
- slp_node, NULL);
+ done = vectorizable_early_exit (vinfo, stmt_info, gsi, slp_node, NULL);
gcc_assert (done);
break;
@@ -13543,12 +12811,8 @@ vect_transform_stmt (vec_info *vinfo,
done = true;
}
- if (!slp_node && vec_stmt)
- gcc_assert (STMT_VINFO_VEC_STMTS (stmt_info).exists ());
-
if (STMT_VINFO_TYPE (stmt_info) != store_vec_info_type
- && (!slp_node
- || !slp_node->ldst_lanes
+ && (!slp_node->ldst_lanes
|| SLP_TREE_CODE (slp_node) == VEC_PERM_EXPR))
{
/* Handle stmts whose DEF is used outside the loop-nest that is
@@ -13558,8 +12822,7 @@ vect_transform_stmt (vec_info *vinfo,
gcc_assert (done);
}
- if (slp_node)
- STMT_VINFO_VECTYPE (stmt_info) = saved_vectype;
+ STMT_VINFO_VECTYPE (stmt_info) = saved_vectype;
return is_store;
}
@@ -13994,123 +13257,49 @@ vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
/* Function vect_is_simple_use.
- Same as vect_is_simple_use but also determines the vector operand
- type of OPERAND and stores it to *VECTYPE. If the definition of
- OPERAND is vect_uninitialized_def, vect_constant_def or
- vect_external_def *VECTYPE will be set to NULL_TREE and the caller
- is responsible to compute the best suited vector type for the
- scalar operand. */
-
-bool
-vect_is_simple_use (tree operand, vec_info *vinfo, enum vect_def_type *dt,
- tree *vectype, stmt_vec_info *def_stmt_info_out,
- gimple **def_stmt_out)
-{
- stmt_vec_info def_stmt_info;
- gimple *def_stmt;
- if (!vect_is_simple_use (operand, vinfo, dt, &def_stmt_info, &def_stmt))
- return false;
-
- if (def_stmt_out)
- *def_stmt_out = def_stmt;
- if (def_stmt_info_out)
- *def_stmt_info_out = def_stmt_info;
-
- /* Now get a vector type if the def is internal, otherwise supply
- NULL_TREE and leave it up to the caller to figure out a proper
- type for the use stmt. */
- if (*dt == vect_internal_def
- || *dt == vect_induction_def
- || *dt == vect_reduction_def
- || *dt == vect_double_reduction_def
- || *dt == vect_nested_cycle
- || *dt == vect_first_order_recurrence)
- {
- *vectype = STMT_VINFO_VECTYPE (def_stmt_info);
- gcc_assert (*vectype != NULL_TREE);
- if (dump_enabled_p ())
- dump_printf_loc (MSG_NOTE, vect_location,
- "vect_is_simple_use: vectype %T\n", *vectype);
- }
- else if (*dt == vect_uninitialized_def
- || *dt == vect_constant_def
- || *dt == vect_external_def)
- *vectype = NULL_TREE;
- else
- gcc_unreachable ();
-
- return true;
-}
-
-/* Function vect_is_simple_use.
-
Same as vect_is_simple_use but determines the operand by operand
position OPERAND from either STMT or SLP_NODE, filling in *OP
and *SLP_DEF (when SLP_NODE is not NULL). */
bool
-vect_is_simple_use (vec_info *vinfo, stmt_vec_info stmt, slp_tree slp_node,
+vect_is_simple_use (vec_info *vinfo, slp_tree slp_node,
unsigned operand, tree *op, slp_tree *slp_def,
enum vect_def_type *dt,
tree *vectype, stmt_vec_info *def_stmt_info_out)
{
- if (slp_node)
- {
- slp_tree child = SLP_TREE_CHILDREN (slp_node)[operand];
- *slp_def = child;
- *vectype = SLP_TREE_VECTYPE (child);
- if (SLP_TREE_DEF_TYPE (child) == vect_internal_def)
- {
- /* ??? VEC_PERM nodes might be intermediate and their lane value
- have no representative (nor do we build a VEC_PERM stmt for
- the actual operation). Note for two-operator nodes we set
- a representative but leave scalar stmts empty as we'd only
- have one for a subset of lanes. Ideally no caller would
- require *op for internal defs. */
- if (SLP_TREE_REPRESENTATIVE (child))
- {
- *op = gimple_get_lhs (SLP_TREE_REPRESENTATIVE (child)->stmt);
- return vect_is_simple_use (*op, vinfo, dt, def_stmt_info_out);
- }
- else
- {
- gcc_assert (SLP_TREE_CODE (child) == VEC_PERM_EXPR);
- *op = error_mark_node;
- *dt = vect_internal_def;
- if (def_stmt_info_out)
- *def_stmt_info_out = NULL;
- return true;
- }
+ slp_tree child = SLP_TREE_CHILDREN (slp_node)[operand];
+ *slp_def = child;
+ *vectype = SLP_TREE_VECTYPE (child);
+ if (SLP_TREE_DEF_TYPE (child) == vect_internal_def)
+ {
+ /* ??? VEC_PERM nodes might be intermediate and their lane value
+ have no representative (nor do we build a VEC_PERM stmt for
+ the actual operation). Note for two-operator nodes we set
+ a representative but leave scalar stmts empty as we'd only
+ have one for a subset of lanes. Ideally no caller would
+ require *op for internal defs. */
+ if (SLP_TREE_REPRESENTATIVE (child))
+ {
+ *op = gimple_get_lhs (SLP_TREE_REPRESENTATIVE (child)->stmt);
+ return vect_is_simple_use (*op, vinfo, dt, def_stmt_info_out);
}
else
{
+ gcc_assert (SLP_TREE_CODE (child) == VEC_PERM_EXPR);
+ *op = error_mark_node;
+ *dt = vect_internal_def;
if (def_stmt_info_out)
*def_stmt_info_out = NULL;
- *op = SLP_TREE_SCALAR_OPS (child)[0];
- *dt = SLP_TREE_DEF_TYPE (child);
return true;
}
}
else
{
- *slp_def = NULL;
- if (gassign *ass = dyn_cast <gassign *> (stmt->stmt))
- {
- if (gimple_assign_rhs_code (ass) == COND_EXPR
- && COMPARISON_CLASS_P (gimple_assign_rhs1 (ass)))
- gcc_unreachable ();
- else if (gimple_assign_rhs_code (ass) == VIEW_CONVERT_EXPR)
- *op = TREE_OPERAND (gimple_assign_rhs1 (ass), 0);
- else
- *op = gimple_op (ass, operand + 1);
- }
- else if (gcond *cond = dyn_cast <gcond *> (stmt->stmt))
- *op = gimple_op (cond, operand);
- else if (gcall *call = dyn_cast <gcall *> (stmt->stmt))
- *op = gimple_call_arg (call, operand);
- else
- gcc_unreachable ();
- return vect_is_simple_use (*op, vinfo, dt, vectype, def_stmt_info_out);
+ if (def_stmt_info_out)
+ *def_stmt_info_out = NULL;
+ *op = SLP_TREE_SCALAR_OPS (child)[0];
+ *dt = SLP_TREE_DEF_TYPE (child);
+ return true;
}
}
diff --git a/gcc/tree-vectorizer.cc b/gcc/tree-vectorizer.cc
index 2f77e46..066c8a8 100644
--- a/gcc/tree-vectorizer.cc
+++ b/gcc/tree-vectorizer.cc
@@ -724,7 +724,6 @@ vec_info::new_stmt_vec_info (gimple *stmt)
STMT_VINFO_REDUC_IDX (res) = -1;
STMT_VINFO_SLP_VECT_ONLY (res) = false;
STMT_VINFO_SLP_VECT_ONLY_PATTERN (res) = false;
- STMT_VINFO_VEC_STMTS (res) = vNULL;
res->reduc_initial_values = vNULL;
res->reduc_scalar_results = vNULL;
@@ -790,8 +789,6 @@ vec_info::free_stmt_vec_info (stmt_vec_info stmt_info)
stmt_info->reduc_initial_values.release ();
stmt_info->reduc_scalar_results.release ();
- STMT_VINFO_SIMD_CLONE_INFO (stmt_info).release ();
- STMT_VINFO_VEC_STMTS (stmt_info).release ();
free (stmt_info);
}
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index 799d5fe..e8be608 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -184,11 +184,6 @@ enum vect_memory_access_type {
of invariants. */
VMAT_CONTIGUOUS_DOWN,
- /* A simple contiguous access in which the elements need to be permuted
- after loading or before storing. Only used for loop vectorization;
- SLP uses separate permutes. */
- VMAT_CONTIGUOUS_PERMUTE,
-
/* A simple contiguous access in which the elements need to be reversed
after loading or before storing. */
VMAT_CONTIGUOUS_REVERSE,
@@ -1359,9 +1354,6 @@ public:
/* The vector type to be used for the LHS of this statement. */
tree vectype;
- /* The vectorized stmts. */
- vec<gimple *> vec_stmts;
-
/* The following is relevant only for stmts that contain a non-scalar
data-ref (array/pointer/struct access). A GIMPLE stmt is expected to have
at most one such data-ref. */
@@ -1398,11 +1390,6 @@ public:
pattern statement. */
gimple_seq pattern_def_seq;
- /* Selected SIMD clone's function info. First vector element
- is SIMD clone's function decl, followed by a pair of trees (base + step)
- for linear arguments (pair of NULLs for other arguments). */
- vec<tree> simd_clone_info;
-
/* Classify the def of this stmt. */
enum vect_def_type def_type;
@@ -1557,6 +1544,10 @@ struct gather_scatter_info {
/* The loop-invariant base value. */
tree base;
+ /* The TBBA alias pointer the value of which determines the alignment
+ of the scalar accesses. */
+ tree alias_ptr;
+
/* The original scalar offset, which is a non-loop-invariant SSA_NAME. */
tree offset;
@@ -1583,7 +1574,6 @@ struct gather_scatter_info {
#define STMT_VINFO_RELEVANT(S) (S)->relevant
#define STMT_VINFO_LIVE_P(S) (S)->live
#define STMT_VINFO_VECTYPE(S) (S)->vectype
-#define STMT_VINFO_VEC_STMTS(S) (S)->vec_stmts
#define STMT_VINFO_VECTORIZABLE(S) (S)->vectorizable
#define STMT_VINFO_DATA_REF(S) ((S)->dr_aux.dr + 0)
#define STMT_VINFO_GATHER_SCATTER_P(S) (S)->gather_scatter_p
@@ -1614,7 +1604,6 @@ struct gather_scatter_info {
#define STMT_VINFO_IN_PATTERN_P(S) (S)->in_pattern_p
#define STMT_VINFO_RELATED_STMT(S) (S)->related_stmt
#define STMT_VINFO_PATTERN_DEF_SEQ(S) (S)->pattern_def_seq
-#define STMT_VINFO_SIMD_CLONE_INFO(S) (S)->simd_clone_info
#define STMT_VINFO_DEF_TYPE(S) (S)->def_type
#define STMT_VINFO_GROUPED_ACCESS(S) \
((S)->dr_aux.dr && DR_GROUP_FIRST_ELEMENT(S))
@@ -1655,6 +1644,14 @@ struct gather_scatter_info {
#define PURE_SLP_STMT(S) ((S)->slp_type == pure_slp)
#define STMT_SLP_TYPE(S) (S)->slp_type
+#define GATHER_SCATTER_LEGACY_P(info) ((info).decl != NULL_TREE \
+ && (info).ifn == IFN_LAST)
+#define GATHER_SCATTER_IFN_P(info) ((info).decl == NULL_TREE \
+ && (info).ifn != IFN_LAST)
+#define GATHER_SCATTER_EMULATED_P(info) ((info).decl == NULL_TREE \
+ && (info).ifn == IFN_LAST)
+
+
/* Contains the scalar or vector costs for a vec_info. */
class vector_costs
{
@@ -2422,10 +2419,7 @@ extern bool vect_chooses_same_modes_p (machine_mode, machine_mode);
extern bool vect_get_loop_mask_type (loop_vec_info);
extern bool vect_is_simple_use (tree, vec_info *, enum vect_def_type *,
stmt_vec_info * = NULL, gimple ** = NULL);
-extern bool vect_is_simple_use (tree, vec_info *, enum vect_def_type *,
- tree *, stmt_vec_info * = NULL,
- gimple ** = NULL);
-extern bool vect_is_simple_use (vec_info *, stmt_vec_info, slp_tree,
+extern bool vect_is_simple_use (vec_info *, slp_tree,
unsigned, tree *, slp_tree *,
enum vect_def_type *,
tree *, stmt_vec_info * = NULL);
@@ -2486,18 +2480,11 @@ extern void vect_finish_stmt_generation (vec_info *, stmt_vec_info, gimple *,
gimple_stmt_iterator *);
extern opt_result vect_mark_stmts_to_be_vectorized (loop_vec_info, bool *);
extern tree vect_get_store_rhs (stmt_vec_info);
-void vect_get_vec_defs_for_operand (vec_info *vinfo, stmt_vec_info, unsigned,
- tree op, vec<tree> *, tree = NULL);
-void vect_get_vec_defs (vec_info *, stmt_vec_info, slp_tree, unsigned,
+void vect_get_vec_defs (vec_info *, slp_tree,
tree, vec<tree> *,
tree = NULL, vec<tree> * = NULL,
tree = NULL, vec<tree> * = NULL,
tree = NULL, vec<tree> * = NULL);
-void vect_get_vec_defs (vec_info *, stmt_vec_info, slp_tree, unsigned,
- tree, tree, vec<tree> *,
- tree = NULL, tree = NULL, vec<tree> * = NULL,
- tree = NULL, tree = NULL, vec<tree> * = NULL,
- tree = NULL, tree = NULL, vec<tree> * = NULL);
extern tree vect_init_vector (vec_info *, stmt_vec_info, tree, tree,
gimple_stmt_iterator *);
extern tree vect_get_slp_vect_def (slp_tree, unsigned);
@@ -2534,7 +2521,8 @@ extern bool ref_within_array_bound (gimple *, tree);
/* In tree-vect-data-refs.cc. */
extern bool vect_can_force_dr_alignment_p (const_tree, poly_uint64);
extern enum dr_alignment_support vect_supportable_dr_alignment
- (vec_info *, dr_vec_info *, tree, int);
+ (vec_info *, dr_vec_info *, tree, int,
+ gather_scatter_info * = nullptr);
extern tree vect_get_smallest_scalar_type (stmt_vec_info, tree);
extern opt_result vect_analyze_data_ref_dependences (loop_vec_info, unsigned int *);
extern bool vect_slp_analyze_instance_dependence (vec_info *, slp_instance);
@@ -2552,7 +2540,7 @@ extern bool vect_check_gather_scatter (stmt_vec_info, loop_vec_info,
extern opt_result vect_find_stmt_data_reference (loop_p, gimple *,
vec<data_reference_p> *,
vec<int> *, int);
-extern opt_result vect_analyze_data_refs (vec_info *, poly_uint64 *, bool *);
+extern opt_result vect_analyze_data_refs (vec_info *, bool *);
extern void vect_record_base_alignments (vec_info *);
extern tree vect_create_data_ref_ptr (vec_info *,
stmt_vec_info, tree, class loop *, tree,
@@ -2568,17 +2556,10 @@ extern internal_fn vect_store_lanes_supported (tree, unsigned HOST_WIDE_INT, boo
extern bool vect_grouped_load_supported (tree, bool, unsigned HOST_WIDE_INT);
extern internal_fn vect_load_lanes_supported (tree, unsigned HOST_WIDE_INT,
bool, vec<int> * = nullptr);
-extern void vect_permute_store_chain (vec_info *, vec<tree> &,
- unsigned int, stmt_vec_info,
- gimple_stmt_iterator *, vec<tree> *);
extern tree vect_setup_realignment (vec_info *,
stmt_vec_info, gimple_stmt_iterator *,
tree *, enum dr_alignment_support, tree,
class loop **);
-extern void vect_transform_grouped_load (vec_info *, stmt_vec_info, vec<tree>,
- int, gimple_stmt_iterator *);
-extern void vect_record_grouped_load_vectors (vec_info *,
- stmt_vec_info, vec<tree>);
extern tree vect_get_new_vect_var (tree, enum vect_var_kind, const char *);
extern tree vect_get_new_ssa_name (tree, enum vect_var_kind,
const char * = NULL);
@@ -2647,8 +2628,7 @@ extern bool vectorizable_reduction (loop_vec_info, stmt_vec_info,
slp_tree, slp_instance,
stmt_vector_for_cost *);
extern bool vectorizable_induction (loop_vec_info, stmt_vec_info,
- gimple **, slp_tree,
- stmt_vector_for_cost *);
+ slp_tree, stmt_vector_for_cost *);
extern bool vect_transform_reduction (loop_vec_info, stmt_vec_info,
gimple_stmt_iterator *,
slp_tree);
@@ -2656,12 +2636,12 @@ extern bool vect_transform_cycle_phi (loop_vec_info, stmt_vec_info,
slp_tree, slp_instance);
extern bool vectorizable_lc_phi (loop_vec_info, stmt_vec_info, slp_tree);
extern bool vect_transform_lc_phi (loop_vec_info, stmt_vec_info, slp_tree);
-extern bool vectorizable_phi (vec_info *, stmt_vec_info, gimple **, slp_tree,
+extern bool vectorizable_phi (vec_info *, stmt_vec_info, slp_tree,
stmt_vector_for_cost *);
extern bool vectorizable_recurr (loop_vec_info, stmt_vec_info,
- gimple **, slp_tree, stmt_vector_for_cost *);
+ slp_tree, stmt_vector_for_cost *);
extern bool vectorizable_early_exit (vec_info *, stmt_vec_info,
- gimple_stmt_iterator *, gimple **,
+ gimple_stmt_iterator *,
slp_tree, stmt_vector_for_cost *);
extern bool vect_emulated_vector_p (tree);
extern bool vect_can_vectorize_without_simd_p (tree_code);
diff --git a/gcc/varasm.cc b/gcc/varasm.cc
index 10c1d2e..8266282 100644
--- a/gcc/varasm.cc
+++ b/gcc/varasm.cc
@@ -1734,7 +1734,8 @@ assemble_asm (tree asm_str)
constraints[i]
= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
if (!parse_output_constraint (&constraints[i], i, ninputs, noutputs,
- &allows_mem, &allows_reg, &is_inout))
+ &allows_mem, &allows_reg, &is_inout,
+ nullptr))
goto done;
if (is_inout)
{
@@ -1776,7 +1777,7 @@ assemble_asm (tree asm_str)
= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
if (!parse_input_constraint (&constraints[i + noutputs], i,
ninputs, noutputs, 0, constraints,
- &allows_mem, &allows_reg))
+ &allows_mem, &allows_reg, nullptr))
goto done;
if (strchr (constraints[i], '%'))
{
@@ -2907,7 +2908,7 @@ assemble_name_resolve (const char *name)
ultimate_transparent_alias_target (&id);
if (id != id_orig)
name = IDENTIFIER_POINTER (id);
- gcc_assert (! TREE_CHAIN (id));
+ gcc_assert (!IDENTIFIER_TRANSPARENT_ALIAS (id));
}
return name;
diff --git a/gcc/warning-control.cc b/gcc/warning-control.cc
index 48446a7..e04ef69 100644
--- a/gcc/warning-control.cc
+++ b/gcc/warning-control.cc
@@ -28,7 +28,7 @@
#include "gimple.h"
#include "cgraph.h"
#include "hash-map.h"
-#include "diagnostic-spec.h"
+#include "gcc-diagnostic-spec.h"
/* Return the no-warning bit for EXPR. */
diff --git a/libcc1/ChangeLog b/libcc1/ChangeLog
index 0eb8fc6..bd1394a 100644
--- a/libcc1/ChangeLog
+++ b/libcc1/ChangeLog
@@ -1,3 +1,13 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * context.cc: Update usage of "diagnostic_info" to explicitly
+ refer to "diagnostics::diagnostic_info".
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * context.cc: Update for move of diagnostics output formats into
+ namespace "diagnostics" as "sinks".
+
2024-12-23 Simon Martin <simon@nasilyan.com>
* Makefile.am: Remove reference to deleted marshall-c.h.
diff --git a/libcc1/context.cc b/libcc1/context.cc
index af5884b..38343a7 100644
--- a/libcc1/context.cc
+++ b/libcc1/context.cc
@@ -39,7 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "langhooks.h"
#include "langhooks-def.h"
-#include "diagnostic-format-text.h"
+#include "diagnostics/text-sink.h"
#include "gcc-interface.h"
@@ -63,9 +63,9 @@ cc1_plugin::plugin_context *cc1_plugin::current_context;
// This is put into the lang hooks when the plugin starts.
static void
-plugin_print_error_function (diagnostic_text_output_format &text_output,
+plugin_print_error_function (diagnostics::text_sink &text_output,
const char *file,
- const diagnostic_info *diagnostic)
+ const diagnostics::diagnostic_info *diagnostic)
{
if (current_function_decl != NULL_TREE
&& DECL_NAME (current_function_decl) != NULL_TREE
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 3c5bae1..aeb4e14 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,23 @@
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * charset.cc: Update comment for file rename.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * internal.h: Update comment for diagnostic_t becoming
+ enum class diagnostics::kind.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * include/cpplib.h: Update for moves to "source-printing".
+ * include/rich-location.h (class label_effects): Move to...
+ (class diagnostics::label_effects): ...here.
+
+2025-07-25 David Malcolm <dmalcolm@redhat.com>
+
+ * include/rich-location.h: Replace diagnostic_path with
+ diagnostics::paths::path.
+
2025-06-17 Jason Merrill <jason@redhat.com>
* line-map.cc (linemap_location_from_module_p): Add.
diff --git a/libcpp/charset.cc b/libcpp/charset.cc
index e3accf8..95ba376 100644
--- a/libcpp/charset.cc
+++ b/libcpp/charset.cc
@@ -2420,7 +2420,7 @@ convert_escape (cpp_reader *pfile, const uchar *from, const uchar *limit,
{
encoding_rich_location rich_loc (pfile);
- /* diagnostic.cc does not support "%03o". When it does, this
+ /* pretty-print.cc does not support "%03o". When it does, this
code can use %03o directly in the diagnostic again. */
char buf[32];
sprintf(buf, "%03o", (int) c);
diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
index 7c147ae..75efdcd 100644
--- a/libcpp/include/cpplib.h
+++ b/libcpp/include/cpplib.h
@@ -1610,7 +1610,8 @@ struct cpp_decoded_char
This is a tabstop value, along with a callback for getting the
widths of characters. Normally this callback is cpp_wcwidth, but we
support other schemes for escaping non-ASCII unicode as a series of
- ASCII chars when printing the user's source code in diagnostic-show-locus.cc
+ ASCII chars when printing the user's source code in
+ gcc/diagnostics/source-printing.cc
For example, consider:
- the Unicode character U+03C0 "GREEK SMALL LETTER PI" (UTF-8: 0xCF 0x80)
diff --git a/libcpp/include/rich-location.h b/libcpp/include/rich-location.h
index fe9868d..c74e80e 100644
--- a/libcpp/include/rich-location.h
+++ b/libcpp/include/rich-location.h
@@ -25,7 +25,7 @@ along with this program; see the file COPYING3. If not see
#include "label-text.h"
class range_label;
-class label_effects;
+namespace diagnostics { class label_effects; }
/* A hint to diagnostic_show_locus on how to print a source range within a
rich_location.
@@ -213,7 +213,7 @@ semi_embedded_vec<T, NUM_EMBEDDED>::truncate (int len)
}
class fixit_hint;
-class diagnostic_path;
+namespace diagnostics { namespace paths { class path; }}
/* A "rich" source code location, for use when printing diagnostics.
A rich_location has one or more carets&ranges, where the carets
@@ -520,8 +520,8 @@ class rich_location
}
/* An optional path through the code. */
- const diagnostic_path *get_path () const { return m_path; }
- void set_path (const diagnostic_path *path) { m_path = path; }
+ const diagnostics::paths::path *get_path () const { return m_path; }
+ void set_path (const diagnostics::paths::path *path) { m_path = path; }
/* A flag for hinting that the diagnostic involves character encoding
issues, and thus that it will be helpful to the user if we show some
@@ -567,7 +567,7 @@ protected:
static const int MAX_STATIC_FIXIT_HINTS = 2;
semi_embedded_vec <fixit_hint *, MAX_STATIC_FIXIT_HINTS> m_fixit_hints;
- const diagnostic_path *m_path;
+ const diagnostics::paths::path *m_path;
};
/* Abstract base class for labelling a range within a rich_location
@@ -596,7 +596,8 @@ class range_label
virtual label_text get_text (unsigned range_idx) const = 0;
/* Get any special effects for the label (e.g. links to other labels). */
- virtual const label_effects *get_effects (unsigned /*range_idx*/) const
+ virtual const diagnostics::label_effects *
+ get_effects (unsigned /*range_idx*/) const
{
return nullptr;
}
diff --git a/libcpp/internal.h b/libcpp/internal.h
index 9973836..8ca4c75 100644
--- a/libcpp/internal.h
+++ b/libcpp/internal.h
@@ -622,8 +622,8 @@ struct cpp_reader
zero of said file. */
location_t main_loc;
- /* If non-zero, override diagnostic locations (other than DK_NOTE
- diagnostics) to this one. */
+ /* If non-zero, override diagnostic locations (other than
+ diagnostics::kind::note diagnostics) to this one. */
location_t diagnostic_override_loc;
/* Returns true iff we should warn about UTF-8 bidirectional control
diff --git a/libgm2/ChangeLog b/libgm2/ChangeLog
index 7ca3c03..c068292 100644
--- a/libgm2/ChangeLog
+++ b/libgm2/ChangeLog
@@ -1,3 +1,15 @@
+2025-07-23 Gaius Mulley <gaiusmod2@gmail.com>
+
+ PR modula2/121164
+ * libm2iso/Makefile.am (libm2iso_la_M2FLAGS): Add -Wall.
+ * libm2iso/Makefile.in: Regenerate.
+ * libm2log/Makefile.am (libm2log_la_M2FLAGS): Add -Wall.
+ * libm2log/Makefile.in: Regenerate.
+ * libm2min/Makefile.am (libm2min_la_M2FLAGS): Add -Wall.
+ * libm2min/Makefile.in: Regenerate.
+ * libm2pim/Makefile.am (libm2pim_la_M2FLAGS): Add -Wall.
+ * libm2pim/Makefile.in: Regenerate.
+
2025-06-29 Gaius Mulley <gaiusmod2@gmail.com>
PR modula2/117203
diff --git a/libgm2/libm2iso/Makefile.am b/libgm2/libm2iso/Makefile.am
index bd8af62..1af1d6a 100644
--- a/libgm2/libm2iso/Makefile.am
+++ b/libgm2/libm2iso/Makefile.am
@@ -206,6 +206,7 @@ libm2iso_la_M2FLAGS = \
-fm2-pathname=m2iso -I. -Ilibm2iso -I$(GM2_SRC)/gm2-libs-iso \
-fm2-pathname=m2pim -I$(GM2_SRC)/gm2-libs \
-fiso -fextended-opaque -fm2-g -g -Wcase-enum \
+ -Wall \
-Wreturn-type -fcase -fm2-prefix=m2iso
if TARGET_DARWIN
diff --git a/libgm2/libm2iso/Makefile.in b/libgm2/libm2iso/Makefile.in
index 1e48ad0..308c023 100644
--- a/libgm2/libm2iso/Makefile.in
+++ b/libgm2/libm2iso/Makefile.in
@@ -594,6 +594,7 @@ FLAGS_TO_PASS = $(AM_MAKEFLAGS)
@BUILD_ISOLIB_TRUE@ -fm2-pathname=m2iso -I. -Ilibm2iso -I$(GM2_SRC)/gm2-libs-iso \
@BUILD_ISOLIB_TRUE@ -fm2-pathname=m2pim -I$(GM2_SRC)/gm2-libs \
@BUILD_ISOLIB_TRUE@ -fiso -fextended-opaque -fm2-g -g -Wcase-enum \
+@BUILD_ISOLIB_TRUE@ -Wall \
@BUILD_ISOLIB_TRUE@ -Wreturn-type -fcase -fm2-prefix=m2iso
@BUILD_ISOLIB_TRUE@@TARGET_DARWIN_FALSE@libm2iso_la_link_flags = \
diff --git a/libgm2/libm2log/Makefile.am b/libgm2/libm2log/Makefile.am
index 8da0d14..8078be8 100644
--- a/libgm2/libm2log/Makefile.am
+++ b/libgm2/libm2log/Makefile.am
@@ -136,6 +136,7 @@ libm2log_la_M2FLAGS = \
-fm2-pathname=m2log -I$(GM2_SRC)/gm2-libs-log \
-fm2-pathname=m2pim -I$(GM2_SRC)/gm2-libs \
-fm2-pathname=m2iso -I$(GM2_SRC)/gm2-libs-iso \
+ -Wall \
-Wcase-enum -Wreturn-type \
-fcase -fm2-prefix=m2log
diff --git a/libgm2/libm2log/Makefile.in b/libgm2/libm2log/Makefile.in
index 6df3f16..dcd5941 100644
--- a/libgm2/libm2log/Makefile.in
+++ b/libgm2/libm2log/Makefile.in
@@ -485,6 +485,7 @@ FLAGS_TO_PASS = $(AM_MAKEFLAGS)
@BUILD_LOGLIB_TRUE@ -fm2-pathname=m2log -I$(GM2_SRC)/gm2-libs-log \
@BUILD_LOGLIB_TRUE@ -fm2-pathname=m2pim -I$(GM2_SRC)/gm2-libs \
@BUILD_LOGLIB_TRUE@ -fm2-pathname=m2iso -I$(GM2_SRC)/gm2-libs-iso \
+@BUILD_LOGLIB_TRUE@ -Wall \
@BUILD_LOGLIB_TRUE@ -Wcase-enum -Wreturn-type \
@BUILD_LOGLIB_TRUE@ -fcase -fm2-prefix=m2log
diff --git a/libgm2/libm2min/Makefile.am b/libgm2/libm2min/Makefile.am
index b95b5dd..8cee85f 100644
--- a/libgm2/libm2min/Makefile.am
+++ b/libgm2/libm2min/Makefile.am
@@ -107,6 +107,7 @@ libm2min_la_CFLAGS = -I. -I$(GM2_SRC)/gm2-libs-min -I$(GM2_SRC)/gm2-libs
libm2min_la_M2FLAGS = \
-fm2-pathname=m2min -I. -I$(GM2_SRC)/gm2-libs-min \
-fm2-pathname=m2pim -I$(GM2_SRC)/gm2-libs -fno-exceptions \
+ -Wall \
-fno-m2-plugin -fno-scaffold-dynamic -fno-scaffold-main -fm2-prefix=m2min
if TARGET_DARWIN
diff --git a/libgm2/libm2min/Makefile.in b/libgm2/libm2min/Makefile.in
index ce0efff..93bf8a4 100644
--- a/libgm2/libm2min/Makefile.in
+++ b/libgm2/libm2min/Makefile.in
@@ -449,6 +449,7 @@ libm2min_la_CFLAGS = -I. -I$(GM2_SRC)/gm2-libs-min -I$(GM2_SRC)/gm2-libs
libm2min_la_M2FLAGS = \
-fm2-pathname=m2min -I. -I$(GM2_SRC)/gm2-libs-min \
-fm2-pathname=m2pim -I$(GM2_SRC)/gm2-libs -fno-exceptions \
+ -Wall \
-fno-m2-plugin -fno-scaffold-dynamic -fno-scaffold-main -fm2-prefix=m2min
@TARGET_DARWIN_FALSE@libm2min_la_link_flags = $(am__append_1)
diff --git a/libgm2/libm2pim/Makefile.am b/libgm2/libm2pim/Makefile.am
index f8e9aae..56bbb3e 100644
--- a/libgm2/libm2pim/Makefile.am
+++ b/libgm2/libm2pim/Makefile.am
@@ -185,6 +185,7 @@ libm2pim_la_M2FLAGS = \
-fm2-pathname=m2pim -I. -I$(GM2_SRC)/gm2-libs \
-fm2-pathname=m2iso -I$(GM2_SRC)/gm2-libs-iso \
-fm2-g -g -Wcase-enum -Wreturn-type \
+ -Wall \
-fcase -fm2-prefix=m2pim
if TARGET_DARWIN
diff --git a/libgm2/libm2pim/Makefile.in b/libgm2/libm2pim/Makefile.in
index 8d101c4..63f8fc9 100644
--- a/libgm2/libm2pim/Makefile.in
+++ b/libgm2/libm2pim/Makefile.in
@@ -564,6 +564,7 @@ FLAGS_TO_PASS = $(AM_MAKEFLAGS)
@BUILD_PIMLIB_TRUE@ -fm2-pathname=m2pim -I. -I$(GM2_SRC)/gm2-libs \
@BUILD_PIMLIB_TRUE@ -fm2-pathname=m2iso -I$(GM2_SRC)/gm2-libs-iso \
@BUILD_PIMLIB_TRUE@ -fm2-g -g -Wcase-enum -Wreturn-type \
+@BUILD_PIMLIB_TRUE@ -Wall \
@BUILD_PIMLIB_TRUE@ -fcase -fm2-prefix=m2pim
@BUILD_PIMLIB_TRUE@@TARGET_DARWIN_FALSE@libm2pim_la_link_flags = \
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index 4f52a19..2689f3e 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,18 @@
+2025-07-21 Thomas Schwinge <tschwinge@baylibre.com>
+
+ PR target/119853
+ PR target/119854
+ * testsuite/libgomp.c++/target-cdtor-1.C: Adjust for
+ 'targetm.cxx.use_aeabi_atexit'.
+ * testsuite/libgomp.c++/target-cdtor-2.C: Likewise.
+
+2025-07-18 Andrew Stubbs <ams@baylibre.com>
+
+ PR target/121156
+ * config/gcn/bar.c (gomp_team_barrier_wait_end): Remove unused
+ "generation" variable.
+ (gomp_team_barrier_wait_cancel_end): Likewise.
+
2025-07-17 Thomas Schwinge <tschwinge@baylibre.com>
PR target/119692
diff --git a/libgomp/config/gcn/bar.c b/libgomp/config/gcn/bar.c
index 52b344c..57ac648 100644
--- a/libgomp/config/gcn/bar.c
+++ b/libgomp/config/gcn/bar.c
@@ -79,7 +79,7 @@ gomp_team_barrier_wake (gomp_barrier_t *bar, int count)
void
gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
{
- unsigned int generation, gen;
+ unsigned int gen;
if (__builtin_expect (state & BAR_WAS_LAST, 0))
{
@@ -105,7 +105,6 @@ gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
}
}
- generation = state;
state &= ~BAR_CANCELLED;
int retry = 100;
do
@@ -128,7 +127,6 @@ gomp_team_barrier_wait_end (gomp_barrier_t *bar, gomp_barrier_state_t state)
gomp_barrier_handle_tasks (state);
gen = __atomic_load_n (&bar->generation, MEMMODEL_ACQUIRE);
}
- generation |= gen & BAR_WAITING_FOR_TASK;
}
while (gen != state + BAR_INCR);
}
@@ -152,7 +150,7 @@ bool
gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar,
gomp_barrier_state_t state)
{
- unsigned int generation, gen;
+ unsigned int gen;
if (__builtin_expect (state & BAR_WAS_LAST, 0))
{
@@ -184,7 +182,6 @@ gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar,
if (__builtin_expect (state & BAR_CANCELLED, 0))
return true;
- generation = state;
int retry = 100;
do
{
@@ -209,7 +206,6 @@ gomp_team_barrier_wait_cancel_end (gomp_barrier_t *bar,
gomp_barrier_handle_tasks (state);
gen = __atomic_load_n (&bar->generation, MEMMODEL_RELAXED);
}
- generation |= gen & BAR_WAITING_FOR_TASK;
}
while (gen != state + BAR_INCR);
diff --git a/libgomp/testsuite/libgomp.c++/target-cdtor-1.C b/libgomp/testsuite/libgomp.c++/target-cdtor-1.C
index ecb029e..7e8cc58 100644
--- a/libgomp/testsuite/libgomp.c++/target-cdtor-1.C
+++ b/libgomp/testsuite/libgomp.c++/target-cdtor-1.C
@@ -63,14 +63,19 @@ int main()
return 0;
}
-/* Verify '__cxa_atexit' calls.
+/* Verify '__cxa_atexit' calls (or '__aeabi_atexit', per 'targetm.cxx.use_aeabi_atexit').
For the host, there are four expected calls:
- { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, } 4 optimized { target cxa_atexit } } }
- { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sH1, \&__dso_handle>} 1 optimized { target cxa_atexit } } }
- { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sHD1, \&__dso_handle>} 1 optimized { target cxa_atexit } } }
- { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZNSt6vectorI1SSaIS0_EED1Ev, \&svHD1, \&__dso_handle>} 1 optimized { target cxa_atexit } } }
- { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sH2, \&__dso_handle>} 1 optimized { target cxa_atexit } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, } 4 optimized { target { cxa_atexit && { ! arm_eabi } } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__aeabi_atexit, } 4 optimized { target { cxa_atexit && arm_eabi } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sH1, \&__dso_handle>} 1 optimized { target { cxa_atexit && { ! arm_eabi } } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__aeabi_atexit, NULL, \&sH1, _ZN1SD1Ev, \&__dso_handle>} 1 optimized { target { cxa_atexit && arm_eabi } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sHD1, \&__dso_handle>} 1 optimized { target { cxa_atexit && { ! arm_eabi } } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__aeabi_atexit, NULL, \&sHD1, _ZN1SD1Ev, \&__dso_handle>} 1 optimized { target { cxa_atexit && arm_eabi } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZNSt6vectorI1SSaIS0_EED1Ev, \&svHD1, \&__dso_handle>} 1 optimized { target { cxa_atexit && { ! arm_eabi } } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__aeabi_atexit, NULL, \&svHD1, _ZNSt6vectorI1SSaIS0_EED1Ev, \&__dso_handle>} 1 optimized { target { cxa_atexit && arm_eabi } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sH2, \&__dso_handle>} 1 optimized { target { cxa_atexit && { ! arm_eabi } } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__aeabi_atexit, NULL, \&sH2, _ZN1SD1Ev, \&__dso_handle>} 1 optimized { target { cxa_atexit && arm_eabi } } } }
For the device, there are two expected calls:
{ dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_atexit, } 2 optimized { target cxa_atexit } } }
diff --git a/libgomp/testsuite/libgomp.c++/target-cdtor-2.C b/libgomp/testsuite/libgomp.c++/target-cdtor-2.C
index 75e48ca..9c85122 100644
--- a/libgomp/testsuite/libgomp.c++/target-cdtor-2.C
+++ b/libgomp/testsuite/libgomp.c++/target-cdtor-2.C
@@ -93,14 +93,19 @@ int main()
return 0;
}
-/* Verify '__cxa_atexit' calls.
+/* Verify '__cxa_atexit' calls (or '__aeabi_atexit', per 'targetm.cxx.use_aeabi_atexit').
For the host, there are four expected calls:
- { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, } 4 optimized { target cxa_atexit } } }
- { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sH1, \&__dso_handle>} 1 optimized { target cxa_atexit } } }
- { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sHD1, \&__dso_handle>} 1 optimized { target cxa_atexit } } }
- { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZNSt6vectorI1SSaIS0_EED1Ev, \&svHD1, \&__dso_handle>} 1 optimized { target cxa_atexit } } }
- { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sH2, \&__dso_handle>} 1 optimized { target cxa_atexit } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, } 4 optimized { target { cxa_atexit && { ! arm_eabi } } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__aeabi_atexit, } 4 optimized { target { cxa_atexit && arm_eabi } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sH1, \&__dso_handle>} 1 optimized { target { cxa_atexit && { ! arm_eabi } } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__aeabi_atexit, NULL, \&sH1, _ZN1SD1Ev, \&__dso_handle>} 1 optimized { target { cxa_atexit && arm_eabi } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sHD1, \&__dso_handle>} 1 optimized { target { cxa_atexit && { ! arm_eabi } } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__aeabi_atexit, NULL, \&sHD1, _ZN1SD1Ev, \&__dso_handle>} 1 optimized { target { cxa_atexit && arm_eabi } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZNSt6vectorI1SSaIS0_EED1Ev, \&svHD1, \&__dso_handle>} 1 optimized { target { cxa_atexit && { ! arm_eabi } } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__aeabi_atexit, NULL, \&svHD1, _ZNSt6vectorI1SSaIS0_EED1Ev, \&__dso_handle>} 1 optimized { target { cxa_atexit && arm_eabi } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__cxa_atexit, NULL, _ZN1SD1Ev, \&sH2, \&__dso_handle>} 1 optimized { target { cxa_atexit && { ! arm_eabi } } } } }
+ { dg-final { scan-tree-dump-times {gimple_call <__aeabi_atexit, NULL, \&sH2, _ZN1SD1Ev, \&__dso_handle>} 1 optimized { target { cxa_atexit && arm_eabi } } } }
For the device, there are two expected calls:
{ dg-final { scan-offload-tree-dump-times {gimple_call <__cxa_atexit, } 2 optimized { target cxa_atexit } } }
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 013b16a..9b6504b 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,242 @@
+2025-07-25 Tuur Martens <tuurmartens4@gmail.com>
+
+ * include/bits/unordered_map.h: Rectify referencing of
+ non-existent type.
+
+2025-07-24 Nathaniel Shead <nathanieloshead@gmail.com>
+
+ PR c++/117294
+ PR c++/113854
+ * testsuite/20_util/any/misc/any_cast_neg.cc: Adjust
+ diagnostics.
+ * testsuite/20_util/expected/illformed_neg.cc: Likewise.
+ * testsuite/20_util/optional/monadic/or_else_neg.cc: Likewise.
+ * testsuite/23_containers/array/creation/3_neg.cc: Likewise.
+ * testsuite/24_iterators/range_generators/lwg3900.cc: Likewise.
+ * testsuite/29_atomics/atomic/requirements/types_neg.cc:
+ Likewise.
+ * testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc:
+ Likewise.
+ * testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc:
+ Likewise.
+ * testsuite/std/format/arguments/args_neg.cc: Likewise.
+ * testsuite/std/format/string_neg.cc: Likewise.
+
+2025-07-24 Tomasz Kamiński <tkaminsk@redhat.com>
+
+ PR libstdc++/104874
+ * testsuite/24_iterators/random_access/string_vector_iterators.cc:
+ Reworked.
+
+2025-07-24 Tomasz Kamiński <tkaminsk@redhat.com>
+
+ * testsuite/21_strings/basic_string/cons/from_range.cc: Replace
+ test_constexpr with test_ranges inside static_assert.
+ * testsuite/21_strings/basic_string/modifiers/append/append_range.cc:
+ Likewise.
+ * testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc:
+ Likewise.
+ * testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc:
+ Likewise.
+ * testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc:
+ Likewise.
+ * testsuite/23_containers/vector/bool/cons/from_range.cc: Likewise.
+ * testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc:
+ Likewise.
+ * testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc:
+ Likewise.
+ * testsuite/23_containers/vector/cons/from_range.cc: Likewise.
+ * testsuite/23_containers/vector/modifiers/assign/assign_range.cc:
+ Likewise.
+ * testsuite/23_containers/vector/modifiers/insert/insert_range.cc:
+ Likewise.
+ * testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc:
+ Run full test_ranges instead of span-only in test_constexpr.
+ * testsuite/23_containers/vector/modifiers/append_range.cc:
+ Replace test_constexpr with calls to test_ranges and test_overlapping.
+ * testsuite/util/testsuite_allocator.h (__gnu_test::SimpleAllocator):
+ Declared member functions as constexpr.
+
+2025-07-23 Luc Grosheintz <luc.grosheintz@gmail.com>
+
+ * testsuite/23_containers/mdspan/accessors/default.cc: Delete.
+ * testsuite/23_containers/mdspan/accessors/generic.cc: Slightly
+ generalize the test code previously in default.cc.
+
+2025-07-23 Luc Grosheintz <luc.grosheintz@gmail.com>
+
+ * testsuite/23_containers/mdspan/extents/ctor_ints.cc: Remove
+ superfluous parens.
+ * testsuite/23_containers/mdspan/extents/ctor_shape.cc: Ditto.
+ * testsuite/23_containers/mdspan/mdspan.cc: Ditto.
+
+2025-07-23 Tomasz Kamiński <tkaminsk@redhat.com>
+
+ PR libstdc++/119137
+ * testsuite/23_containers/inplace_vector/access/elem.cc: Cover
+ front and back methods and const calls.
+ * testsuite/23_containers/inplace_vector/access/elem_neg.cc:
+ Likewise.
+ * testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc:
+ New test.
+ * testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc:
+ New test.
+
+2025-07-22 Tomasz Kamiński <tkaminsk@redhat.com>
+
+ PR libstdc++/119137
+ * testsuite/23_containers/inplace_vector/cons/from_range.cc: Run
+ iterators and range test at compile-time.
+ * testsuite/23_containers/inplace_vector/modifiers/assign.cc:
+ Likewise.
+ * testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc:
+ Likewise.
+ * testsuite/util/testsuite_iterators.h (__gnu_test::BoundsContainer)
+ (__gnu_test::OutputContainer, __gnu_test::WritableObject)
+ (__gnu_test::output_iterator_wrapper, __gnu_test::input_iterator_wrapper)
+ (__gnu_test::forward_iterator_wrapper)
+ (__gnu_test::bidirectional_iterator_wrapper)
+ (__gnu_test::random_access_iterator_wrapper)
+ (__gnu_test::test_container): Add appropriate _GLIBCXXNN_CONSTEXPR
+ macros to member functions.
+ (__gnu_test::contiguous_iterator_wrapper)
+ (__gnu_test::input_iterator_wrapper_rval)
+ (__gnu_test::test_range, __gnu_test::test_range_nocopy)
+ (__gnu_test::test_sized_range_sized_sent)
+ (__gnu_test::test_sized_range): Add constexpr specifier to member
+ functions.
+
+2025-07-22 Tomasz Kamiński <tkaminsk@redhat.com>
+
+ PR libstdc++/119137
+ * include/std/inplace_vector (inplace_vector::assign_range):
+ Replace _Nm with _M_size in the assigment loop.
+
+2025-07-21 Luc Grosheintz <luc.grosheintz@gmail.com>
+
+ * include/std/mdspan (mdspan::mdspan): Make default ctor
+ conditionally noexcept.
+ * testsuite/23_containers/mdspan/mdspan.cc: Add tests.
+
+2025-07-21 Luc Grosheintz <luc.grosheintz@gmail.com>
+
+ * include/std/mdspan (mdspan::is_always_unique): Make
+ conditionally noexcept.
+ (mdspan::is_always_exhaustive): Ditto.
+ (mdspan::is_always_strided): Ditto.
+ (mdspan::is_unique): Ditto.
+ (mdspan::is_exhaustive): Ditto.
+ (mdspan::is_strided): Ditto.
+ * testsuite/23_containers/mdspan/layout_like.h: Make noexcept
+ configurable. Add ThrowingLayout.
+ * testsuite/23_containers/mdspan/mdspan.cc: Add tests for
+ noexcept.
+
+2025-07-20 Jakub Jelinek <jakub@redhat.com>
+
+ PR libstdc++/121174
+ * src/c++23/std.cc.in (std::dextents): Export. Add to FIXME comments
+ other not yet implemented nor exported <mdspan> entities.
+
+2025-07-18 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/bits/stl_iterator_base_types.h (__any_input_iterator):
+ Only define when __cpp_lib_concepts is defined.
+
+2025-07-18 Jonathan Wakely <jwakely@redhat.com>
+
+ * doc/xml/manual/appendix_contributing.xml: Remove Paolo from
+ list of maintainers to contact about contributing.
+ * doc/html/manual/appendix_contributing.html: Regenerate.
+
+2025-07-18 Jonathan Wakely <jwakely@redhat.com>
+
+ * doc/xml/manual/build_hacking.xml: Document that
+ windows_zones-map.h is a generated file.
+ * doc/html/manual/appendix_porting.html: Regenerate.
+
+2025-07-18 Tomasz Kamiński <tkaminsk@redhat.com>
+
+ PR libstdc++/119137
+ * include/std/inplace_vector (inplace_vector::operator=):
+ Qualify call to std::addressof.
+
+2025-07-18 Tomasz Kamiński <tkaminsk@redhat.com>
+
+ PR libstdc++/121154
+ * include/bits/chrono_io.h (_ChronoSpec::_M_time_point): Remove.
+ (_ChronoSpec::_M_needs_ok_check): Define
+ (__formatter_chrono::_M_parse): Set _M_needs_ok_check.
+ (__formatter_chrono::_M_check_ok): Check values also for debug mode,
+ and return __string_view.
+ (__formatter_chrono::_M_format_to): Handle results of _M_check_ok.
+ (__formatter_chrono::_M_wi, __formatter_chrono::_M_a_A)
+ (__formatter_chrono::_M_b_B, __formatter_chrono::_M_C_y_Y)
+ (__formatter_chrono::_M_d_e, __formatter_chrono::_M_F):
+ Removed handling of _M_debug.
+ (__formatter_chrono::__M_m): Print zero unpadded in _M_debug mode.
+ (__formatter_duration::_S_spec_for): Remove _M_time_point refernce.
+ (__formatter_duration::_M_parse): Override _M_needs_ok_check.
+ * testsuite/std/time/month/io.cc: Test for localized !ok() values.
+ * testsuite/std/time/weekday/io.cc: Test for localized !ok() values.
+
+2025-07-18 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/121150
+ * testsuite/20_util/hash/int128.cc: Cast expected values to
+ size_t.
+
+2025-07-18 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/bits/unicode.h (_Utf_iterator::operator--): Reorder
+ conditions and update position after reading a code unit.
+ (_Utf_iterator::_M_read_reverse): Define.
+ (_Utf_iterator::_M_read_utf8): Return extracted code point.
+ (_Utf_iterator::_M_read_reverse_utf8): Define.
+ (_Utf_iterator::_M_read_reverse_utf16): Define.
+ (_Utf_iterator::_M_read_reverse_utf32): Define.
+ * testsuite/ext/unicode/view.cc: Add checks for reversed views
+ and reverse iteration.
+
+2025-07-18 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/bits/unicode.h (_Utf_iterator): Reorder data members
+ to be more compact.
+
+2025-07-18 Jonathan Wakely <jwakely@redhat.com>
+ Tomasz Kamiński <tkaminsk@redhat.com>
+
+ PR libstdc++/119137
+ * doc/doxygen/user.cfg.in (INPUT): Add new header.
+ * include/Makefile.am: Add new header.
+ * include/Makefile.in: Regenerate.
+ * include/bits/stl_iterator_base_types.h (__any_input_iterator):
+ Define.
+ * include/bits/version.def (inplace_vector): Define.
+ * include/bits/version.h: Regenerate.
+ * include/precompiled/stdc++.h: Include new header.
+ * src/c++23/std.cc.in: Export contents if new header.
+ * include/std/inplace_vector: New file.
+ * testsuite/23_containers/inplace_vector/access/capacity.cc: New file.
+ * testsuite/23_containers/inplace_vector/access/elem.cc: New file.
+ * testsuite/23_containers/inplace_vector/access/elem_neg.cc: New file.
+ * testsuite/23_containers/inplace_vector/cons/1.cc: New file.
+ * testsuite/23_containers/inplace_vector/cons/from_range.cc: New file.
+ * testsuite/23_containers/inplace_vector/cons/throws.cc: New file.
+ * testsuite/23_containers/inplace_vector/copy.cc: New file.
+ * testsuite/23_containers/inplace_vector/erasure.cc: New file.
+ * testsuite/23_containers/inplace_vector/modifiers/assign.cc: New file.
+ * testsuite/23_containers/inplace_vector/modifiers/erase.cc: New file.
+ * testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc:
+ New file.
+ * testsuite/23_containers/inplace_vector/modifiers/single_insert.cc:
+ New file.
+ * testsuite/23_containers/inplace_vector/move.cc: New file.
+ * testsuite/23_containers/inplace_vector/relops.cc: New file.
+ * testsuite/23_containers/inplace_vector/version.cc: New file.
+ * testsuite/util/testsuite_iterators.h (input_iterator_wrapper::base):
+ Define.
+
2025-07-17 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/96710
diff --git a/libstdc++-v3/doc/doxygen/user.cfg.in b/libstdc++-v3/doc/doxygen/user.cfg.in
index 536e035..8969bb8 100644
--- a/libstdc++-v3/doc/doxygen/user.cfg.in
+++ b/libstdc++-v3/doc/doxygen/user.cfg.in
@@ -869,6 +869,7 @@ INPUT = @srcdir@/doc/doxygen/doxygroups.cc \
include/functional \
include/future \
include/generator \
+ include/inplace_vector \
include/iomanip \
include/ios \
include/iosfwd \
diff --git a/libstdc++-v3/doc/html/manual/appendix_contributing.html b/libstdc++-v3/doc/html/manual/appendix_contributing.html
index 24d5a04..baac20a 100644
--- a/libstdc++-v3/doc/html/manual/appendix_contributing.html
+++ b/libstdc++-v3/doc/html/manual/appendix_contributing.html
@@ -60,13 +60,11 @@
this question would be appreciated.
</p><p>
Please contact
- Paolo Carlini at <code class="email">&lt;<a class="email" href="mailto:paolo.carlini@oracle.com">paolo.carlini@oracle.com</a>&gt;</code>
- or
Jonathan Wakely at <code class="email">&lt;<a class="email" href="mailto:jwakely+assign@redhat.com">jwakely+assign@redhat.com</a>&gt;</code>
if you are confused about the assignment or have general licensing
questions. When requesting an assignment form from
<code class="email">&lt;<a class="email" href="mailto:assign@gnu.org">assign@gnu.org</a>&gt;</code>, please CC the libstdc++
- maintainers above so that progress can be monitored.
+ maintainer above so that progress can be monitored.
</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a id="list.getting"></a>Getting Sources</h3></div></div></div><p>
<a class="link" href="https://gcc.gnu.org/gitwrite.html" target="_top">Getting write access
(look for "Write after approval")</a>
diff --git a/libstdc++-v3/doc/html/manual/appendix_porting.html b/libstdc++-v3/doc/html/manual/appendix_porting.html
index e0f52db..887fa50 100644
--- a/libstdc++-v3/doc/html/manual/appendix_porting.html
+++ b/libstdc++-v3/doc/html/manual/appendix_porting.html
@@ -497,4 +497,11 @@ baseline file.
See <a class="xref" href="configure.html" title="Configure">Configuring</a> for the
<code class="code">--with-libstdcxx-zoneinfo</code> option that determines whether
this file is used.
+ </p></li><li class="listitem"><p>
+ The header file
+ <code class="filename">src/c++20/windows_zones-map.h</code>
+ is generated by the Python script
+ <code class="filename">scripts/gen_windows_zones_map.py</code>
+ using the XML file <a class="link" href="https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml" target="_top">https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml</a>
+ from the Unicode CLDR Project.
</p></li></ul></div></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="source_design_notes.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="appendix.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="documentation_hacking.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Design Notes </td><td width="20%" align="center"><a accesskey="h" href="../index.html">Home</a></td><td width="40%" align="right" valign="top"> Writing and Generating Documentation</td></tr></table></div></body></html> \ No newline at end of file
diff --git a/libstdc++-v3/doc/xml/manual/appendix_contributing.xml b/libstdc++-v3/doc/xml/manual/appendix_contributing.xml
index b924545..b2bc1d7 100644
--- a/libstdc++-v3/doc/xml/manual/appendix_contributing.xml
+++ b/libstdc++-v3/doc/xml/manual/appendix_contributing.xml
@@ -113,13 +113,11 @@
<para>
Please contact
- Paolo Carlini at <email>paolo.carlini@oracle.com</email>
- or
Jonathan Wakely at <email>jwakely+assign@redhat.com</email>
if you are confused about the assignment or have general licensing
questions. When requesting an assignment form from
<email>assign@gnu.org</email>, please CC the libstdc++
- maintainers above so that progress can be monitored.
+ maintainer above so that progress can be monitored.
</para>
</section>
diff --git a/libstdc++-v3/doc/xml/manual/build_hacking.xml b/libstdc++-v3/doc/xml/manual/build_hacking.xml
index 077c063..20de49f 100644
--- a/libstdc++-v3/doc/xml/manual/build_hacking.xml
+++ b/libstdc++-v3/doc/xml/manual/build_hacking.xml
@@ -742,6 +742,17 @@ baseline file.
this file is used.
</para>
</listitem>
+ <listitem>
+ <para>
+ The header file
+ <filename class="headerfile">src/c++20/windows_zones-map.h</filename>
+ is generated by the Python script
+ <filename>scripts/gen_windows_zones_map.py</filename>
+ using the XML file <link xmlns:xlink="http://www.w3.org/1999/xlink"
+ xlink:href="https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml"/>
+ from the Unicode CLDR Project.
+ </para>
+ </listitem>
</itemizedlist>
</section> <!-- Generated files -->
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index cc402f06..6f248fe 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -77,6 +77,7 @@ std_headers = \
${std_srcdir}/forward_list \
${std_srcdir}/fstream \
${std_srcdir}/future \
+ ${std_srcdir}/inplace_vector \
${std_srcdir}/iomanip \
${std_srcdir}/ios \
${std_srcdir}/iosfwd \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 0ef8564..014466f 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -433,6 +433,7 @@ std_freestanding = \
@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/forward_list \
@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/fstream \
@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/future \
+@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/inplace_vector \
@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/iomanip \
@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/ios \
@GLIBCXX_HOSTED_TRUE@ ${std_srcdir}/iosfwd \
diff --git a/libstdc++-v3/include/bits/chrono_io.h b/libstdc++-v3/include/bits/chrono_io.h
index fe3c912..809d795 100644
--- a/libstdc++-v3/include/bits/chrono_io.h
+++ b/libstdc++-v3/include/bits/chrono_io.h
@@ -280,8 +280,9 @@ namespace __format
// in the format-spec, e.g. "{:L%a}" is localized and locale-specific,
// but "{:L}" is only localized and "{:%a}" is only locale-specific.
unsigned _M_locale_specific : 1;
- // Indicates that we are handling time_point.
- unsigned _M_time_point : 1;
+ // Indicates if parts that are checked for ok come directly from the
+ // input, instead of being computed.
+ unsigned _M_needs_ok_check : 1;
// Indicates that duration should be treated as floating point.
unsigned _M_floating_point_rep : 1;
// Indicate that duration uses user-defined representation.
@@ -570,7 +571,15 @@ namespace __format
_ChronoSpec<_CharT> __spec = __def;
- auto __finalize = [this, &__spec] {
+ auto __finalize = [this, &__spec, &__def] {
+ using enum _ChronoParts;
+ _ChronoParts __checked
+ = __spec._M_debug ? _YearMonthDay|_IndexedWeekday
+ : _Month|_Weekday;
+ // n.b. for calendar types __def._M_needed contains only parts
+ // copied from the input, remaining ones are computed, and thus ok
+ __spec._M_needs_ok_check
+ = __spec._M_needs(__def._M_needed & __checked);
_M_spec = __spec;
};
@@ -821,10 +830,10 @@ namespace __format
__throw_format_error("chrono format error: unescaped '%' in "
"chrono-specs");
- _M_spec = __spec;
- _M_spec._M_chrono_specs
- = __string_view(__chrono_specs, __first - __chrono_specs);
+ __spec._M_chrono_specs
+ = __string_view(__chrono_specs, __first - __chrono_specs);
+ __finalize();
return __first;
}
@@ -972,30 +981,71 @@ namespace __format
return __out;
}
- void
- _M_check_ok(const _ChronoData<_CharT>& __t, _CharT __conv) const
+ __string_view
+ _M_check_ok(const _ChronoData<_CharT>& __t, _CharT& __conv) const
{
- // n.b. for time point all date parts are computed, so
- // they are always ok.
- if (_M_spec._M_time_point || _M_spec._M_debug)
- return;
+ if (!_M_spec._M_debug)
+ {
+ switch (__conv)
+ {
+ case 'a':
+ case 'A':
+ if (!__t._M_weekday.ok()) [[unlikely]]
+ __throw_format_error("format error: invalid weekday");
+ break;
+ case 'b':
+ case 'h':
+ case 'B':
+ if (!__t._M_month.ok()) [[unlikely]]
+ __throw_format_error("format error: invalid month");
+ break;
+ default:
+ break;
+ }
+ return __string_view();
+ }
switch (__conv)
{
+ // %\0 is extension for handling weekday index
+ case '\0':
+ if (__t._M_weekday_index < 1 || __t._M_weekday_index > 5) [[unlikely]]
+ return _GLIBCXX_WIDEN("index");
+ break;
case 'a':
case 'A':
if (!__t._M_weekday.ok()) [[unlikely]]
- __throw_format_error("format error: invalid weekday");
- return;
+ {
+ __conv = 'w'; // print as decimal number
+ return _GLIBCXX_WIDEN("weekday");
+ }
+ break;
case 'b':
case 'h':
case 'B':
if (!__t._M_month.ok()) [[unlikely]]
- __throw_format_error("format error: invalid month");
- return;
+ {
+ __conv = 'm'; // print as decimal number
+ return _GLIBCXX_WIDEN("month");
+ }
+ break;
+ case 'd':
+ case 'e':
+ if (!__t._M_day.ok()) [[unlikely]]
+ return _GLIBCXX_WIDEN("day");
+ break;
+ case 'F':
+ if (!(__t._M_year/__t._M_month/__t._M_day).ok()) [[unlikely]]
+ return _GLIBCXX_WIDEN("date");
+ break;
+ case 'Y':
+ if (!__t._M_year.ok()) [[unlikely]]
+ return _GLIBCXX_WIDEN("year");
+ break;
default:
- return;
+ break;
}
+ return __string_view();
}
template<typename _OutIter, typename _FormatContext>
@@ -1054,9 +1104,12 @@ namespace __format
do
{
_CharT __c = *__first++;
- _M_check_ok(__t, __c);
+ __string_view __invalid;
+ if (_M_spec._M_needs_ok_check)
+ __invalid = _M_check_ok(__t, __c);
- if (__use_locale_fmt && _S_localized_spec(__c, __mod)) [[unlikely]]
+ if (__invalid.empty() &&__use_locale_fmt
+ && _S_localized_spec(__c, __mod)) [[unlikely]]
__out = _M_locale_fmt(std::move(__out), __fc.locale(),
__tm, __c, __mod);
else switch (__c)
@@ -1164,6 +1217,14 @@ namespace __format
__first = __last;
break;
}
+
+ if (!__invalid.empty())
+ {
+ constexpr __string_view __pref = _GLIBCXX_WIDEN(" is not a valid ");
+ __out = __format::__write(std::move(__out), __pref);
+ __out = __format::__write(std::move(__out), __invalid);
+ }
+
__mod = _CharT();
// Scan for next '%' and write out everything before it.
__string_view __str(__first, __last - __first);
@@ -1193,9 +1254,6 @@ namespace __format
// %\0 Extension to format weekday index, used only by empty format spec
_CharT __buf[3];
__out = __format::__write(std::move(__out), _S_str_d1(__buf, __wi));
- if (_M_spec._M_debug && (__wi < 1 || __wi > 5))
- __out = __format::__write(std::move(__out),
- __string_view(_GLIBCXX_WIDEN(" is not a valid index")));
return std::move(__out);
}
@@ -1205,15 +1263,6 @@ namespace __format
{
// %a Locale's abbreviated weekday name.
// %A Locale's full weekday name.
- if (_M_spec._M_debug && !__wd.ok())
- {
- _CharT __buf[3];
- __out = __format::__write(std::move(__out),
- _S_str_d1(__buf, __wd.c_encoding()));
- return __format::__write(std::move(__out),
- __string_view(_GLIBCXX_WIDEN(" is not a valid weekday")));
- }
-
__string_view __str = _S_weekdays[__wd.c_encoding()];
if (!__full)
__str = __str.substr(0, 3);
@@ -1226,15 +1275,6 @@ namespace __format
{
// %b Locale's abbreviated month name.
// %B Locale's full month name.
- if (_M_spec._M_debug && !__m.ok())
- {
- _CharT __buf[3];
- __out = __format::__write(std::move(__out),
- _S_str_d1(__buf, (unsigned)__m));
- return __format::__write(std::move(__out),
- __string_view(_GLIBCXX_WIDEN(" is not a valid month")));
- }
-
__string_view __str = _S_months[(unsigned)__m - 1];
if (!__full)
__str = __str.substr(0, 3);
@@ -1303,10 +1343,6 @@ namespace __format
}
__out = __format::__write(std::move(__out), __sv);
}
-
- if (_M_spec._M_debug && __conv == 'Y' && !__y.ok()) [[unlikely]]
- __out = __format::__write(std::move(__out),
- __string_view(_GLIBCXX_WIDEN(" is not a valid year")));
return __out;
}
@@ -1365,9 +1401,6 @@ namespace __format
}
__out = __format::__write(std::move(__out), __sv);
- if (_M_spec._M_debug && !__d.ok()) [[unlikely]]
- __out = __format::__write(std::move(__out),
- __string_view(_GLIBCXX_WIDEN(" is not a valid day")));
return std::move(__out);
}
@@ -1404,9 +1437,6 @@ namespace __format
__out = __format::__write(std::move(__out), __sv);
}
- if (_M_spec._M_debug && !(__t._M_year/__t._M_month/__t._M_day).ok())
- __out = __format::__write(std::move(__out),
- __string_view(_GLIBCXX_WIDEN(" is not a valid date")));
return std::move(__out);
}
@@ -1474,8 +1504,10 @@ namespace __format
{
// %m month as a decimal number.
// %Om Locale's alternative representation.
-
auto __i = (unsigned)__m;
+ if (__i == 0 && _M_spec._M_debug) [[unlikely]]
+ // 0 should not be padded to two digits
+ return __format::__write(std::move(__out), _S_digit(0));
_CharT __buf[3];
return __format::__write(std::move(__out), _S_str_d2(__buf, __i));
@@ -1852,7 +1884,6 @@ namespace __format
using enum _ChronoParts;
_ChronoSpec<_CharT> __res{};
- __res._M_time_point = (__parts & _DateTime) == _DateTime;
__res._M_floating_point_rep = chrono::treat_as_floating_point_v<_Rep>;
__res._M_custom_rep = !is_arithmetic_v<_Rep>;
__res._M_prec = chrono::hh_mm_ss<_Duration>::fractional_width;
@@ -1901,6 +1932,10 @@ namespace __format
auto __res
= __formatter_chrono<_CharT>::_M_parse(__pc, __parts, __def);
+ // n.b. durations do not contain date parts, and for time point all
+ // date parts are computed, and they are always ok.
+ _M_spec._M_needs_ok_check = false;
+
// check for custom floating point durations, if digits of output
// will contain subseconds, then formatters must support specifying
// precision.
diff --git a/libstdc++-v3/include/bits/stl_iterator_base_types.h b/libstdc++-v3/include/bits/stl_iterator_base_types.h
index a67d7bd..0c34ad7 100644
--- a/libstdc++-v3/include/bits/stl_iterator_base_types.h
+++ b/libstdc++-v3/include/bits/stl_iterator_base_types.h
@@ -257,6 +257,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _InIter>
concept __has_input_iter_cat
= is_convertible_v<__iter_category_t<_InIter>, input_iterator_tag>;
+
+#ifdef __cpp_lib_concepts
+ // Is a Cpp17InputIterator or satisfies std::input_iterator.
+ template<typename _InIterator>
+ concept __any_input_iterator
+ = input_iterator<_InIterator> || __has_input_iter_cat<_InIterator>;
+#endif
#endif
template<typename _It,
diff --git a/libstdc++-v3/include/bits/unicode.h b/libstdc++-v3/include/bits/unicode.h
index 83a9b0a..88e97d4 100644
--- a/libstdc++-v3/include/bits/unicode.h
+++ b/libstdc++-v3/include/bits/unicode.h
@@ -209,10 +209,15 @@ namespace __unicode
constexpr _Utf_iterator&
operator--() requires bidirectional_iterator<_Iter>
{
- if (!_M_buf_index && _M_curr() != _M_first())
- _M_read_reverse();
- else if (_M_buf_index)
+ if (_M_buf_index > 0)
--_M_buf_index;
+ else if (_M_curr() != _M_first())
+ {
+ _M_read_reverse();
+ _M_buf_index = _M_buf_last - 1;
+ ranges::advance(_M_curr(), -_M_to_increment);
+ }
+ // else erroneous, but ignored for now.
return *this;
}
@@ -269,7 +274,18 @@ namespace __unicode
}
constexpr void
- _M_read_reverse(); // TODO
+ _M_read_reverse() requires bidirectional_iterator<_Iter>
+ {
+ if constexpr (sizeof(_FromFmt) == sizeof(uint8_t))
+ _M_read_reverse_utf8();
+ else if constexpr (sizeof(_FromFmt) == sizeof(uint16_t))
+ _M_read_reverse_utf16();
+ else
+ {
+ static_assert(sizeof(_FromFmt) == sizeof(uint32_t));
+ _M_read_reverse_utf32();
+ }
+ }
template<typename>
struct _Guard
@@ -285,7 +301,7 @@ namespace __unicode
_It _M_orig;
};
- constexpr void
+ constexpr char32_t
_M_read_utf8()
{
_Guard<_Iter> __g{this, _M_curr()};
@@ -383,6 +399,8 @@ namespace __unicode
__c = _S_error();
_M_update(__c, __to_incr);
+
+ return __c;
}
constexpr void
@@ -425,6 +443,116 @@ namespace __unicode
_M_update(__c, 1);
}
+ constexpr void
+ _M_read_reverse_utf8() requires bidirectional_iterator<_Iter>
+ {
+ const auto __first = _M_first();
+ auto __curr = _M_curr();
+ // The code point we decode:
+ char32_t __c{};
+ // The last code unit read:
+ uint8_t __u = *--__curr;
+ // Count of bytes read:
+ uint8_t __to_incr = 1;
+
+ if (__u <= 0x7F) [[likely]]
+ {
+ _M_update(__u, 1);
+ return;
+ }
+
+ // Continuation bytes match 10xxxxxx
+ auto __is_continuation = [](uint8_t __b) {
+ return (__b & 0xC0) == 0x80;
+ };
+ // 0xC0 and 0xC1 would produce overlong encodings of ASCII characters.
+ // 0xF5-0xFF would produce code points above U+10FFFF
+ auto __is_invalid = [](uint8_t __b) {
+ return (__b & 0xFE) == 0xC0 || __b >= 0xF5;
+ };
+
+ // No valid or invalid multibyte sequence is longer than 4 bytes,
+ // so skip back over at most four bytes.
+ while (__is_continuation(__u) && __to_incr < 4 && __curr != __first)
+ {
+ ++__to_incr;
+ __u = *--__curr;
+ }
+
+ // If the last byte read was a continuation byte then either we read
+ // four continuation bytes, or stopped at the start of the sequence.
+ // Either way, the maximal subparts are the individual continuation
+ // bytes so each one should be replaced with U+FFFD.
+ if (__is_continuation(__u) || __is_invalid(__u)) [[unlikely]]
+ {
+ // Either found four continuation bytes (maximum allowed is three)
+ // or first non-continuation byte is an invalid UTF-8 code unit.
+ _M_update(_S_error(), 1);
+ return;
+ }
+ // __u is a valid start byte so use countl_one to get the expected
+ // length of the multibyte sequence that starts with this byte.
+ int __seq_length = std::countl_one((unsigned char)__u);
+ if (__seq_length < __to_incr) [[unlikely]]
+ {
+ // If the expected number of continuation bytes is less than
+ // the number we found, then the last continuation byte is a
+ // maximal subpart and the decremented iterator points to it.
+ _M_update(_S_error(), 1);
+ return;
+ }
+
+ auto __orig = std::__exchange(_M_curr(), std::move(__curr));
+ if (_M_read_utf8() == _S_error()) [[unlikely]]
+ {
+ if (_M_to_increment < __to_incr) // Read truncated sequence, set
+ _M_to_increment = 1; // curr to last continuation byte.
+ }
+
+ _M_curr() = std::move(__orig);
+ // operator--() will move back by _M_to_increment
+ }
+
+ constexpr void
+ _M_read_reverse_utf16() requires bidirectional_iterator<_Iter>
+ {
+ _Guard<_Iter> __g{this, _M_curr()};
+ char32_t __c{};
+ uint16_t __u = *--_M_curr();
+ uint8_t __to_incr = 1;
+
+ if (__u < 0xD800 || __u > 0xDFFF) [[likely]]
+ __c = __u;
+ else if (__u >= 0xDC00 && _M_curr() != _M_first()) [[likely]]
+ {
+ // read a low surrogate, expect a high surrogate before it.
+ uint16_t __u2 = *--_M_curr();
+ if (__u2 < 0xD800 || __u2 > 0xDC00) [[unlikely]]
+ __c = _S_error(); // unpaired low surrogate
+ else
+ {
+ __to_incr = 2;
+ uint32_t __x = (__u2 & 0x3F) << 10 | (__u & 0x3FF);
+ uint32_t __w = (__u2 >> 6) & 0x1F;
+ __c = (__w + 1) << 16 | __x;
+ }
+ }
+ else
+ __c = _S_error(); // unpaired surrogate
+
+ _M_update(__c, __to_incr);
+ }
+
+ constexpr void
+ _M_read_reverse_utf32() requires bidirectional_iterator<_Iter>
+ {
+ _Guard<_Iter> __g{this, _M_curr()};
+ char32_t __c = *--_M_curr();
+ if (!__is_scalar_value(__c)) [[unlikely]]
+ __c = _S_error();
+ _M_update(__c, 1);
+ }
+
// Encode the code point __c as one or more code units in _M_buf.
constexpr void
_M_update(char32_t __c, uint8_t __to_incr)
@@ -509,9 +637,6 @@ namespace __unicode
constexpr _Iter
_M_curr() const { return _M_first_and_curr._M_curr; }
- // Buffer holding the individual code units of the current code point.
- array<value_type, 4 / sizeof(_ToFmt)> _M_buf;
-
// _M_first is not needed for non-bidirectional ranges.
template<typename _It>
struct _First_and_curr
@@ -553,13 +678,16 @@ namespace __unicode
// start (or end, for non-forward iterators) of the current code point.
_First_and_curr<_Iter> _M_first_and_curr;
+ // The end of the underlying input range.
+ [[no_unique_address]] _Sent _M_last;
+
+ // Buffer holding the individual code units of the current code point.
+ array<value_type, 4 / sizeof(_ToFmt)> _M_buf;
+
uint8_t _M_buf_index = 0; // Index of current code unit in the buffer.
uint8_t _M_buf_last = 0; // Number of code units in the buffer.
uint8_t _M_to_increment = 0; // How far to advance _M_curr on increment.
- // The end of the underlying input range.
- [[no_unique_address]] _Sent _M_last;
-
template<typename _FromFmt2, typename _ToFmt2,
input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
typename _ErrHandler>
diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h
index fc07ffc..cc9e2c4 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -91,9 +91,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
*
* @tparam _Key Type of key objects.
* @tparam _Tp Type of mapped objects.
- * @tparam _Hash Hashing function object type, defaults to hash<_Value>.
+ * @tparam _Hash Hashing function object type, defaults to hash<_Key>.
* @tparam _Pred Predicate function object type, defaults
- * to equal_to<_Value>.
+ * to equal_to<_Key>.
* @tparam _Alloc Allocator type, defaults to
* std::allocator<std::pair<const _Key, _Tp>>.
*
@@ -1360,9 +1360,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
*
* @tparam _Key Type of key objects.
* @tparam _Tp Type of mapped objects.
- * @tparam _Hash Hashing function object type, defaults to hash<_Value>.
+ * @tparam _Hash Hashing function object type, defaults to hash<_Key>.
* @tparam _Pred Predicate function object type, defaults
- * to equal_to<_Value>.
+ * to equal_to<_Key>.
* @tparam _Alloc Allocator type, defaults to
* std::allocator<std::pair<const _Key, _Tp>>.
*
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 2f70a52..dbe2cb8 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1989,6 +1989,14 @@ ftms = {
};
ftms = {
+ name = inplace_vector;
+ values = {
+ v = 202406;
+ cxxmin = 26;
+ };
+};
+
+ftms = {
name = indirect;
values = {
v = 202502;
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index 8e0ae68..7bb6016 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2229,6 +2229,16 @@
#endif /* !defined(__cpp_lib_modules) && defined(__glibcxx_want_modules) */
#undef __glibcxx_want_modules
+#if !defined(__cpp_lib_inplace_vector)
+# if (__cplusplus > 202302L)
+# define __glibcxx_inplace_vector 202406L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_inplace_vector)
+# define __cpp_lib_inplace_vector 202406L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_inplace_vector) && defined(__glibcxx_want_inplace_vector) */
+#undef __glibcxx_want_inplace_vector
+
#if !defined(__cpp_lib_indirect)
# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
# define __glibcxx_indirect 202502L
diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h
index e7d89c9..733a5e5 100644
--- a/libstdc++-v3/include/precompiled/stdc++.h
+++ b/libstdc++-v3/include/precompiled/stdc++.h
@@ -237,6 +237,7 @@
#endif
#if __cplusplus > 202302L
+#include <inplace_vector>
#include <text_encoding>
#include <stdbit.h>
#include <stdckdint.h>
diff --git a/libstdc++-v3/include/std/inplace_vector b/libstdc++-v3/include/std/inplace_vector
new file mode 100644
index 0000000..290cf6e
--- /dev/null
+++ b/libstdc++-v3/include/std/inplace_vector
@@ -0,0 +1,1379 @@
+// Sequence container with fixed capacity -*- C++ -*-
+
+// Copyright The GNU Toolchain Authors.
+//
+// This file is part of the GNU ISO C++ Library. This library 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.
+
+// This library 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/inplace_vector
+ * This is a Standard C++ Library header.
+ * @ingroup sequences
+ */
+
+#ifndef _GLIBCXX_INPLACE_VECTOR
+#define _GLIBCXX_INPLACE_VECTOR 1
+
+#pragma GCC system_header
+
+#define __glibcxx_want_inplace_vector
+#include <bits/version.h>
+
+#ifdef __glibcxx_inplace_vector // C++ >= 26
+#include <compare>
+#include <initializer_list>
+#include <bits/range_access.h>
+#include <bits/ranges_base.h> // borrowed_iterator_t, __detail::__container_compatible_range
+#include <bits/ranges_util.h> // subrange
+#include <bits/ranges_uninitialized.h>
+#include <bits/refwrap.h>
+#include <bits/stl_construct.h>
+#include <bits/stl_uninitialized.h>
+#include <bits/stl_algo.h> // rotate
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ // [indirect], class template indirect
+ template<typename _Tp, size_t _Nm>
+ class inplace_vector
+ {
+ public:
+
+ // types:
+ using value_type = _Tp;
+ using pointer = _Tp*;
+ using const_pointer = const _Tp*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using iterator
+ = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>;
+ using const_iterator
+ = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ // [containers.sequences.inplace.vector.cons], construct/copy/destroy
+ constexpr
+ inplace_vector() noexcept
+ { _M_init(); }
+
+ constexpr explicit
+ inplace_vector(size_type __n)
+ {
+ _M_init();
+ _S_reserve(__n);
+ std::uninitialized_value_construct_n(data(), __n);
+ _M_size = __n;
+ }
+
+ constexpr
+ inplace_vector(size_type __n, const _Tp& __value)
+ {
+ _M_init();
+ _S_reserve(__n);
+ std::uninitialized_fill_n(data(), __n, __value);
+ _M_size = __n;
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr
+ inplace_vector(_InputIterator __first, _InputIterator __last)
+ : inplace_vector()
+ {
+ if (const auto __n = _S_distance(__first, __last))
+ {
+ _S_reserve(__n);
+ std::uninitialized_copy(__first, __last, data());
+ _M_size = __n;
+ }
+ else
+ {
+ while (__first != __last)
+ emplace_back(*__first++);
+ }
+ }
+
+ template <__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr
+ inplace_vector(from_range_t, _Rg&& __rg)
+ : inplace_vector()
+ { append_range(__rg); }
+
+ constexpr
+ inplace_vector(initializer_list<_Tp> __il)
+ {
+ _M_init();
+ _S_reserve(__il.size());
+ std::uninitialized_copy(__il.begin(), __il.end(), data());
+ _M_size = __il.size();
+ }
+
+ inplace_vector(const inplace_vector&)
+ requires is_trivially_copy_constructible_v<_Tp>
+ = default;
+
+ constexpr
+ inplace_vector(const inplace_vector& __other)
+ noexcept(is_nothrow_copy_constructible_v<_Tp>)
+ {
+ _M_init();
+ std::uninitialized_copy(__other.begin(), __other.end(), data());
+ _M_size = __other.size();
+ }
+
+ inplace_vector(inplace_vector&&)
+ requires is_trivially_move_constructible_v<_Tp>
+ = default;
+
+ constexpr
+ inplace_vector(inplace_vector&& __other)
+ noexcept(is_nothrow_move_constructible_v<_Tp>)
+ {
+ _M_init();
+ std::uninitialized_move(__other.begin(), __other.end(), data());
+ _M_size = __other.size();
+ }
+
+ ~inplace_vector()
+ requires is_trivially_destructible_v<_Tp>
+ = default;
+
+ constexpr
+ ~inplace_vector()
+ { clear(); }
+
+ inplace_vector&
+ operator=(const inplace_vector&)
+ requires is_trivially_copy_assignable_v<_Tp>
+ && is_trivially_copy_constructible_v<_Tp>
+ && is_trivially_destructible_v<_Tp>
+ = default;
+
+ constexpr inplace_vector&
+ operator=(const inplace_vector& __other)
+ noexcept(is_nothrow_copy_assignable_v<_Tp>
+ && is_nothrow_copy_constructible_v<_Tp>)
+ {
+ if (std::addressof(__other) != this) [[likely]]
+ assign(__other.begin(), __other.end());
+ return *this;
+ }
+
+ inplace_vector&
+ operator=(inplace_vector&&)
+ requires is_trivially_move_assignable_v<_Tp>
+ && is_trivially_move_constructible_v<_Tp>
+ && is_trivially_destructible_v<_Tp>
+ = default;
+
+ constexpr inplace_vector&
+ operator=(inplace_vector&& __other)
+ noexcept(is_nothrow_move_assignable_v<_Tp>
+ && is_nothrow_move_constructible_v<_Tp>)
+ {
+ if (std::addressof(__other) != this) [[likely]]
+ assign(std::make_move_iterator(__other.begin()),
+ std::make_move_iterator(__other.end()));
+ return *this;
+ }
+
+ constexpr inplace_vector&
+ operator=(initializer_list<_Tp> __il)
+ {
+ assign(__il.begin(), __il.end());
+ return *this;
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr void
+ assign(_InputIterator __first, _InputIterator __last)
+ {
+ if (const auto __n = _S_distance(__first, __last))
+ {
+ _S_reserve(__n);
+ if (_M_size <= __n)
+ {
+ for (size_t __i = 0; __i < _M_size; ++__i, (void)++__first)
+ _M_elems[__i] = *__first;
+ std::uninitialized_copy(__first, __last, end());
+ }
+ else
+ std::destroy(std::copy(__first, __last, begin()), end());
+ _M_size = __n;
+ }
+ else
+ {
+ size_t __i = 0;
+ for (;__first != __last && __i < _M_size; ++__first)
+ _M_elems[__i++] = *__first;
+ if (__first == __last)
+ {
+ std::_Destroy_n(data() + __i, _M_size - __i);
+ _M_size = __i;
+ }
+ else
+ {
+ while (__first != __last)
+ emplace_back(*__first++);
+ }
+ }
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ assign_range(_Rg&& __rg)
+ {
+ if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
+ {
+ const auto __sz = ranges::distance(__rg);
+ if (__sz > _Nm)
+ __throw_bad_alloc();
+ if (__sz <= size())
+ {
+ ranges::copy_n(ranges::begin(__rg), __sz, data());
+ std::destroy(data() + __sz, data() + _M_size);
+ }
+ else
+ {
+ auto [__in, __out] = ranges::copy_n(
+ ranges::begin(__rg), _M_size,
+ data());
+ ranges::uninitialized_copy(
+ std::move(__in), ranges::end(__rg),
+ __out, unreachable_sentinel);
+ }
+ _M_size = __sz;
+ }
+ else
+ {
+ auto __in = ranges::begin(__rg);
+ auto __end = ranges::end(__rg);
+ size_type __n = 0;
+ for (; __n < _M_size && __in != __end; ++__in)
+ _M_elems[__n++] = *__in;
+
+ if (__in == __end)
+ {
+ std::destroy(data() + __n, data() + _M_size);
+ _M_size = __n;
+ return;
+ }
+ else if (__n < _Nm)
+ {
+ auto __res = ranges::uninitialized_copy(
+ std::move(__in), __end,
+ data() + __n, data() + _Nm);
+ _M_size = __res.out - data();
+ if (__res.in == ranges::end(__rg))
+ return;
+ }
+ __throw_bad_alloc();
+ }
+ }
+
+ constexpr void
+ assign(size_type __n, const _Tp& __u)
+ {
+ _S_reserve(__n);
+ if (_M_size <= __n)
+ std::uninitialized_fill_n(std::fill_n(data(), _M_size, __u),
+ __n - _M_size, __u);
+ else
+ std::destroy_n(std::fill_n(data(), __n, __u), _M_size - __n);
+ _M_size = __n;
+ }
+
+ constexpr void
+ assign(initializer_list<_Tp> __il)
+ { assign(__il.begin(), __il.end()); }
+
+ // iterators
+ [[nodiscard]]
+ constexpr iterator
+ begin() noexcept { return iterator(data()); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ begin() const noexcept { return const_iterator(data()); }
+
+ [[nodiscard]]
+ constexpr iterator
+ end() noexcept
+ { return iterator(data() + _M_size); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ end() const noexcept
+ { return const_iterator(data() + _M_size); }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rbegin() noexcept
+ { return reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rbegin() const noexcept
+ { return const_reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rend() noexcept { return reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rend() const noexcept { return const_reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cbegin() const noexcept { return begin(); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cend() const noexcept { return end(); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crbegin() const noexcept { return rbegin(); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crend() const noexcept { return rend(); }
+
+ // [containers.sequences.inplace.vector.members] size/capacity
+ [[nodiscard]]
+ constexpr bool
+ empty() const noexcept { return _M_size == 0; }
+
+ [[nodiscard]]
+ constexpr size_type
+ size() const noexcept
+ {
+ if (_M_size > _Nm)
+ __builtin_unreachable();
+ return _M_size;
+ }
+
+ [[nodiscard]]
+ static constexpr size_type
+ max_size() noexcept { return _Nm; }
+
+ [[nodiscard]]
+ static constexpr size_type
+ capacity() noexcept { return _Nm; }
+
+ constexpr void
+ resize(size_type __n)
+ {
+ _S_reserve(__n);
+ if (__n > _M_size)
+ std::uninitialized_value_construct_n(data() + _M_size, __n - _M_size);
+ else if (__n < _M_size)
+ std::destroy_n(data() + __n, _M_size - __n);
+ _M_size = __n;
+ }
+
+ constexpr void
+ resize(size_type __n, const _Tp& __c)
+ {
+ _S_reserve(__n);
+ if (__n > _M_size)
+ std::uninitialized_fill_n(data() + _M_size, __n - _M_size, __c);
+ else if (__n < _M_size)
+ std::destroy_n(data() + __n, _M_size - __n);
+ _M_size = __n;
+ }
+
+ static constexpr void
+ reserve(size_type __n)
+ { _S_reserve(__n); }
+
+ static constexpr void
+ shrink_to_fit() { }
+
+ // element access
+ [[nodiscard]]
+ constexpr reference
+ operator[](size_type __n)
+ {
+ __glibcxx_requires_subscript(__n);
+ return _M_elems[__n];
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ operator[](size_type __n) const
+ {
+ __glibcxx_requires_subscript(__n);
+ return _M_elems[__n];
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ at(size_type __n) const
+ {
+ if (__n >= _M_size)
+ std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
+ "(which is %zu) "
+ ">= size() (which is %zu)"),
+ __n, _M_size);
+ return _M_elems[__n];
+ }
+
+ [[nodiscard]]
+ constexpr reference
+ at(size_type __n)
+ {
+ if (__n >= _M_size)
+ std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
+ "(which is %zu) "
+ ">= size() (which is %zu)"),
+ __n, _M_size);
+ return _M_elems[__n];
+ }
+
+ [[nodiscard]]
+ constexpr reference
+ front()
+ {
+ __glibcxx_requires_nonempty();
+ return _M_elems[0];
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ front() const
+ {
+ __glibcxx_requires_nonempty();
+ return _M_elems[0];
+ }
+
+ [[nodiscard]]
+ constexpr reference
+ back()
+ {
+ __glibcxx_requires_nonempty();
+ return _M_elems[_M_size - 1];
+ }
+
+ [[nodiscard]]
+ constexpr const_reference
+ back() const
+ {
+ __glibcxx_requires_nonempty();
+ return _M_elems[_M_size - 1];
+ }
+
+ // [containers.sequences.inplace.vector.data], data access
+
+ [[nodiscard]]
+ constexpr _Tp*
+ data() noexcept
+ { return static_cast<pointer>(_M_elems); }
+
+ [[nodiscard]]
+ constexpr const _Tp*
+ data() const noexcept
+ { return static_cast<const_pointer>(_M_elems); }
+
+ // [containers.sequences.inplace.vector.modifiers], modifiers
+ template<typename... _Args>
+ constexpr _Tp&
+ emplace_back(_Args&&... __args)
+ {
+ if (_M_size >= _Nm)
+ __throw_bad_alloc();
+ return unchecked_emplace_back(std::forward<_Args>(__args)...);
+ }
+
+ constexpr _Tp&
+ push_back(const _Tp& __x)
+ { return emplace_back(__x); }
+
+ constexpr _Tp&
+ push_back(_Tp&& __x)
+ { return emplace_back(std::move(__x)); }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ append_range(_Rg&& __rg)
+ {
+ if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
+ {
+ const auto __sz = ranges::distance(__rg);
+ if (__sz > (_Nm - size()))
+ __throw_bad_alloc();
+ // Bounded on output range due PR121143
+ ranges::uninitialized_copy(
+ ranges::begin(__rg), unreachable_sentinel,
+ data() + _M_size, data() + _M_size + __sz);
+ _M_size += size_type(__sz);
+ }
+ else
+ {
+ ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm);
+ auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail);
+ _M_size = __out - data();
+ if (__in != ranges::end(__rg))
+ __throw_bad_alloc();
+ }
+ }
+
+ constexpr void
+ pop_back()
+ {
+ __glibcxx_requires_nonempty();
+ --_M_size;
+ _M_elems[_M_size].~_Tp();
+ }
+
+ template<typename... _Args>
+ constexpr _Tp*
+ try_emplace_back(_Args&&... __args)
+ {
+ if (_M_size >= _Nm) [[unlikely]]
+ return nullptr;
+ auto& __r = unchecked_emplace_back(std::forward<_Args>(__args)...);
+ return __builtin_addressof(__r);
+ }
+
+ constexpr _Tp*
+ try_push_back(const _Tp& __x)
+ {
+ if (_M_size >= _Nm) [[unlikely]]
+ return nullptr;
+ return __builtin_addressof(unchecked_emplace_back(__x));
+ }
+
+ constexpr _Tp*
+ try_push_back(_Tp&& __x)
+ {
+ if (_M_size >= _Nm) [[unlikely]]
+ return nullptr;
+ return __builtin_addressof(unchecked_emplace_back(std::move(__x)));
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr ranges::borrowed_iterator_t<_Rg>
+ try_append_range(_Rg&& __rg)
+ {
+ if constexpr (ranges::sized_range<_Rg>)
+ {
+ auto __n = ranges::distance(__rg);
+ if (__n == 0) [[unlikely]]
+ return ranges::begin(__rg);
+
+ const auto __end = data() + _M_size;
+ const size_t __avail = _Nm - size();
+ if (__n <= __avail)
+ _M_size += size_type(__n);
+ else
+ {
+ __n = __avail;
+ _M_size = _Nm;
+ }
+ return ranges::uninitialized_copy_n(
+ ranges::begin(__rg), __n,
+ __end, unreachable_sentinel).in;
+ }
+ else
+ {
+ ranges::subrange<pointer> __tail(data() + _M_size, data() + _Nm);
+ auto [__in, __out] = ranges::uninitialized_copy(__rg, __tail);
+ _M_size = __out - data();
+ return std::move(__in);
+ }
+ }
+
+ template<typename... _Args>
+ constexpr _Tp&
+ unchecked_emplace_back(_Args&&... __args)
+ {
+ __glibcxx_assert(_M_size < _Nm);
+ auto __p = std::construct_at(data() + _M_size,
+ std::forward<_Args>(__args)...);
+ ++_M_size;
+ return *__p;
+ }
+
+ constexpr _Tp&
+ unchecked_push_back(const _Tp& __x)
+ { return unchecked_emplace_back(__x); }
+
+ constexpr _Tp&
+ unchecked_push_back(_Tp&& __x)
+ { return unchecked_emplace_back(std::move(__x)); }
+
+ template<typename... _Args>
+ constexpr iterator
+ emplace(const_iterator __position, _Args&&... __args)
+ {
+ size_t __b = __position - cbegin(); // elements before position
+ __glibcxx_assert(__b <= _M_size);
+ if (_M_size >= _Nm)
+ __throw_bad_alloc();
+ iterator __pos = begin() + __b;
+ std::construct_at(data() + _M_size, std::forward<_Args>(__args)...);
+ if (_M_size++)
+ std::rotate(__pos, end() - 1, end());
+ return __pos;
+ }
+
+ constexpr iterator
+ insert(const_iterator __position, const _Tp& __x)
+ { return emplace(__position, __x); }
+
+ constexpr iterator
+ insert(const_iterator __position, _Tp&& __x)
+ { return emplace(__position, std::move(__x)); }
+
+ constexpr iterator
+ insert(const_iterator __position, size_type __n, const _Tp& __x)
+ {
+ size_t __b = __position - cbegin(); // elements before position
+ __glibcxx_assert(__b <= _M_size);
+ if ((_Nm - _M_size) < __n)
+ __throw_bad_alloc();
+ iterator __pos = begin() + __b;
+ std::uninitialized_fill_n(data() + _M_size, __n, __x);
+ if (std::__exchange(_M_size, _M_size + __n))
+ std::rotate(__pos, end() - __n, end());
+ return __pos;
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr iterator
+ insert(const_iterator __position, _InputIterator __first,
+ _InputIterator __last)
+ {
+ size_t __b = __position - cbegin(); // elements before position
+ __glibcxx_assert(__b <= _M_size);
+ iterator __pos = begin() + __b;
+ const size_t __s = _M_size;
+ if (const auto __n = _S_distance(__first, __last))
+ {
+ if ((_Nm - _M_size) < __n)
+ __throw_bad_alloc();
+ std::uninitialized_copy(__first, __last, data() + _M_size);
+ _M_size += __n;
+ }
+ else
+ {
+ while (__first != __last)
+ emplace_back(*__first++);
+ }
+ if (__s)
+ std::rotate(__pos, begin() + __s, end());
+ return __pos;
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr iterator
+ insert_range(const_iterator __position, _Rg&& __rg)
+ {
+ iterator __pos = begin() + (__position - cbegin());
+ const auto __end = end();
+ if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)
+ {
+ const auto __len = ranges::distance(__rg);
+ if (__len > (_Nm - size()))
+ __throw_bad_alloc();
+ if (!__len) [[unlikely]]
+ return __pos;
+
+ const size_type __n = size_type(__len);
+ const size_type __num_after = __end - __pos;
+ if (__num_after >= __n)
+ {
+ ranges::uninitialized_move(__end - __n, __end,
+ __end, unreachable_sentinel);
+ _M_size += __n;
+ ranges::move_backward(__pos, __end - __n, __end);
+ ranges::copy(__rg, __pos);
+ }
+ else if constexpr (ranges::forward_range<_Rg>)
+ {
+ auto __mid = ranges::next(ranges::begin(__rg), __num_after);
+ ranges::uninitialized_copy(__mid, ranges::end(__rg),
+ __end, unreachable_sentinel);
+ _M_size += __n - __num_after;
+ ranges::uninitialized_move(__pos, __end,
+ __pos + __n, unreachable_sentinel);
+ _M_size += __num_after;
+ ranges::copy(ranges::begin(__rg), __mid, __pos);
+ }
+ else
+ {
+ ranges::uninitialized_copy(
+ ranges::begin(__rg), ranges::end(__rg),
+ __end, unreachable_sentinel);
+ _M_size += __n;
+ std::rotate(__pos, __end, end());
+ }
+ }
+ else
+ {
+ append_range(__rg);
+ std::rotate(__pos, __end, end());
+ }
+ return __pos;
+ }
+
+ constexpr iterator
+ insert(const_iterator __position, initializer_list<_Tp> __il)
+ { return insert(__position, __il.begin(), __il.end()); }
+
+ constexpr iterator
+ erase(const_iterator __position)
+ {
+ size_t __n = __position - cbegin();
+ __glibcxx_assert(__n < _M_size);
+ iterator __pos = begin() + __n;
+ std::move(__pos + 1, end(), __pos);
+ pop_back();
+ return __pos;
+ }
+
+ constexpr iterator
+ erase(const_iterator __first, const_iterator __last)
+ {
+ size_t __n = __first - cbegin();
+ size_t __x = __last - __first;
+ __glibcxx_assert(__n <= _M_size);
+ __glibcxx_assert(__x <= _M_size);
+ iterator __pos = begin() + __n;
+ iterator __end = std::move(__pos + __x, end(), __pos);
+ std::destroy_n(__end, __x);
+ _M_size -= __x;
+ return __pos;
+ }
+
+ constexpr void
+ swap(inplace_vector& __x)
+ noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>)
+ {
+ inplace_vector* __vs[2]{ this, std::addressof(__x) };
+ const auto __smaller = __vs[__x.size() < size()];
+ const auto __bigger = __vs[__x.size() >= size()];
+ size_type __n = __smaller->size();
+ size_type __n2 = __bigger->size();
+
+ if constexpr (is_nothrow_move_constructible_v<_Tp>)
+ {
+ for (size_type __i = __n; __i < __n2; ++__i)
+ {
+ std::construct_at(__smaller->data() + __i,
+ std::move(*(__bigger->data() + __i)));
+ std::destroy_at(__bigger->data() + __i);
+ }
+ }
+ else
+ {
+ std::uninitialized_copy(__bigger->data() + __n,
+ __bigger->data() + __n2,
+ __smaller->data() + __n);
+ std::destroy(__bigger->data() + __n, __bigger->data() + __n2);
+ }
+ __smaller->_M_size = __n2;
+ __bigger->_M_size = __n;
+
+ using std::swap;
+ for (size_type __i = 0; __i < __n; __i++)
+ swap(_M_elems[__i], __x._M_elems[__i]);
+ }
+
+ constexpr void
+ clear() noexcept
+ {
+ std::destroy_n(data(), size_t(_M_size));
+ _M_size = 0;
+ }
+
+ constexpr friend bool
+ operator==(const inplace_vector& __x, const inplace_vector& __y)
+ { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); }
+
+ constexpr friend auto
+ operator<=>(const inplace_vector& __x, const inplace_vector& __y)
+ requires requires (const _Tp __t) {
+ { __t < __t } -> __detail::__boolean_testable;
+ }
+ {
+ return std::lexicographical_compare_three_way(__x.begin(), __x.end(),
+ __y.begin(), __y.end(),
+ __detail::__synth3way);
+ }
+
+ constexpr friend void
+ swap(inplace_vector& __x, inplace_vector& __y)
+ noexcept(is_nothrow_swappable_v<_Tp> && is_nothrow_move_constructible_v<_Tp>)
+ { __x.swap(__y); }
+
+ private:
+ union {
+ _Tp _M_elems[_Nm];
+ };
+
+ // Check whether integer type _UInt is wide enough to store _Nm,
+ // so that we use a smaller type for _M_size when that saves space.
+ template<typename _UInt, bool = (alignof(_Tp) <= sizeof(_UInt))>
+ static constexpr bool __fits
+ = _Nm <= __gnu_cxx::__int_traits<_UInt>::__max;
+
+ // Don't bother using a smaller type if alignment of the array elements
+ // means that it doesn't actually save space.
+ template<typename _UInt>
+ static constexpr bool __fits<_UInt, false> = false;
+
+ static consteval auto __select_size_type()
+ {
+ if constexpr (__fits<unsigned char>)
+ return (unsigned char)0;
+#if __SHRT_WIDTH__ < __SIZE_WIDTH__
+ else if constexpr (__fits<unsigned short>)
+ return (unsigned short)0;
+#endif
+#if __INT_WIDTH__ < __SIZE_WIDTH__ && __INT_WIDTH__ > __SHRT_WIDTH__
+ else if constexpr (__fits<unsigned int>)
+ return 0u;
+#endif
+#if __LONG_WIDTH__ < __SIZE_WIDTH__ && __LONG_WIDTH__ > __INT_WIDTH__
+ else if constexpr (__fits<unsigned long>)
+ return 0ul;
+#endif
+ else // Just use size_t.
+ return 0uz;
+ }
+ decltype(__select_size_type()) _M_size = 0;
+
+ constexpr void
+ _M_init()
+ {
+ if !consteval
+ {
+#if __glibcxx_start_lifetime_as
+ std::start_lifetime_as_array<_Tp>(data(), _Nm);
+#endif
+ }
+ else
+ {
+ // TODO: use new(_M_elems) _Tp[_Nm]() once PR121068 is fixed
+ if constexpr (is_trivial_v<_Tp>)
+ for (size_t __i = 0; __i < _Nm; ++__i)
+ _M_elems[__i] = _Tp();
+ else
+ __builtin_unreachable(); // only trivial types are supported at compile time
+ }
+ }
+
+ static constexpr void
+ _S_reserve(size_t __n)
+ {
+ if (__n > _Nm)
+ __throw_bad_alloc();
+ }
+
+ template<typename _InputIterator>
+ constexpr static auto
+ _S_distance(_InputIterator __first, _InputIterator __last)
+ {
+ if constexpr (sized_sentinel_for<_InputIterator, _InputIterator>
+ || forward_iterator<_InputIterator>)
+ return (size_type)ranges::distance(__first, __last);
+ else if constexpr (derived_from<__iter_category_t<_InputIterator>,
+ forward_iterator_tag>)
+ return (size_type)std::distance(__first, __last);
+ else
+ return false_type{};
+ }
+ };
+
+ // [inplace.vector.special], specialized algorithms
+ template<typename _Tp, size_t _Nm>
+ constexpr void
+ swap(inplace_vector<_Tp, _Nm>& __x, inplace_vector<_Tp, _Nm>& __y)
+ noexcept(noexcept(__x.swap(__y)))
+ { __x.swap(__y); }
+
+ // specialization for zero capacity, that is required to be trivally copyable
+ // and empty regardless of _Tp.
+ template<typename _Tp>
+ class inplace_vector<_Tp, 0>
+ {
+ public:
+ // types:
+ using value_type = _Tp;
+ using pointer = _Tp*;
+ using const_pointer = const _Tp*;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using iterator
+ = __gnu_cxx::__normal_iterator<_Tp*, inplace_vector>;
+ using const_iterator
+ = __gnu_cxx::__normal_iterator<const _Tp*, inplace_vector>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ // [containers.sequences.inplace.vector.cons], construct/copy/destroy
+ inplace_vector() = default;
+
+ constexpr explicit
+ inplace_vector(size_type __n)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ constexpr
+ inplace_vector(size_type __n, const _Tp& __value)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr
+ inplace_vector(_InputIterator __first, _InputIterator __last)
+ {
+ if (__first != __last)
+ __throw_bad_alloc();
+ }
+
+ template <__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr
+ inplace_vector(from_range_t, _Rg&& __rg)
+ {
+ if (ranges::begin(__rg) != ranges::end(__rg))
+ __throw_bad_alloc();
+ }
+
+ constexpr
+ inplace_vector(initializer_list<_Tp> __il)
+ {
+ if (__il.size() != 0)
+ __throw_bad_alloc();
+ }
+
+ inplace_vector(const inplace_vector&) = default;
+ inplace_vector(inplace_vector&&) = default;
+
+ constexpr
+ ~inplace_vector() = default;
+
+ inplace_vector&
+ operator=(const inplace_vector&) = default;
+
+ inplace_vector&
+ operator=(inplace_vector&&) = default;
+
+ constexpr inplace_vector&
+ operator=(initializer_list<_Tp> __il)
+ {
+ if (__il.size() != 0)
+ __throw_bad_alloc();
+ }
+
+ template<__any_input_iterator _InputIterator>
+ constexpr void
+ assign(_InputIterator __first, _InputIterator __last)
+ {
+ if (__first != __last)
+ __throw_bad_alloc();
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ assign_range(_Rg&& __rg)
+ {
+ if (ranges::begin(__rg) != ranges::end(__rg))
+ __throw_bad_alloc();
+ }
+
+ constexpr void
+ assign(size_type __n, const _Tp& __u)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ constexpr void
+ assign(initializer_list<_Tp> __il)
+ {
+ if (__il.size() != 0)
+ __throw_bad_alloc();
+ }
+
+ // iterators
+ [[nodiscard]]
+ constexpr iterator
+ begin() noexcept { return iterator(nullptr); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ begin() const noexcept { return const_iterator(nullptr); }
+
+ [[nodiscard]]
+ constexpr iterator
+ end() noexcept { return iterator(nullptr); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ end() const noexcept { return const_iterator(nullptr); }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rbegin() noexcept
+ { return reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rbegin() const noexcept
+ { return const_reverse_iterator(end()); }
+
+ [[nodiscard]]
+ constexpr reverse_iterator
+ rend() noexcept { return reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ rend() const noexcept { return const_reverse_iterator(begin()); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cbegin() const noexcept { return begin(); }
+
+ [[nodiscard]]
+ constexpr const_iterator
+ cend() const noexcept { return end(); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crbegin() const noexcept { return rbegin(); }
+
+ [[nodiscard]]
+ constexpr const_reverse_iterator
+ crend() const noexcept { return rend(); }
+
+ // [containers.sequences.inplace.vector.members] size/capacity
+ [[nodiscard]]
+ constexpr bool
+ empty() const noexcept { return true; }
+
+ [[nodiscard]]
+ constexpr size_type
+ size() const noexcept { return 0; }
+
+ [[nodiscard]]
+ static constexpr size_type
+ max_size() noexcept { return 0; }
+
+ [[nodiscard]]
+ static constexpr size_type
+ capacity() noexcept { return 0; }
+
+ constexpr void
+ resize(size_type __n)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ constexpr void
+ resize(size_type __n, const _Tp&)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ static constexpr void
+ reserve(size_type __n)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ }
+
+ static constexpr void
+ shrink_to_fit() { }
+
+ // element access
+ [[nodiscard,noreturn]]
+ constexpr reference
+ operator[](size_type)
+ { __builtin_trap(); }
+
+ [[nodiscard,noreturn]]
+ constexpr const_reference
+ operator[](size_type) const
+ { __builtin_trap(); }
+
+ [[nodiscard,noreturn]]
+ constexpr const_reference
+ at(size_type __n) const
+ {
+ std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
+ "(which is %zu) "
+ ">= size() (which is 0)"),
+ __n);
+ }
+
+ [[nodiscard,noreturn]]
+ constexpr reference
+ at(size_type __n)
+ {
+ std::__throw_out_of_range_fmt(__N("inplace_vector::at: __n "
+ "(which is %zu) "
+ ">= size() (which is 0)"),
+ __n);
+ }
+
+ [[nodiscard,noreturn]]
+ constexpr reference
+ front()
+ { __builtin_trap(); }
+
+ [[nodiscard,noreturn]]
+ constexpr const_reference
+ front() const
+ { __builtin_trap(); }
+
+ [[nodiscard,noreturn]]
+ constexpr reference
+ back()
+ { __builtin_trap(); }
+
+ [[nodiscard,noreturn]]
+ constexpr const_reference
+ back() const
+ { __builtin_trap(); }
+
+ // [containers.sequences.inplace.vector.data], data access
+
+ [[nodiscard]]
+ constexpr _Tp*
+ data() noexcept
+ { return nullptr; }
+
+ [[nodiscard]]
+ constexpr const _Tp*
+ data() const noexcept
+ { return nullptr; }
+
+ // [containers.sequences.inplace.vector.modifiers], modifiers
+ template<typename... _Args>
+ [[noreturn]]
+ constexpr _Tp&
+ emplace_back(_Args&&...)
+ { __throw_bad_alloc(); }
+
+ [[noreturn]]
+ constexpr _Tp&
+ push_back(const _Tp&)
+ { __throw_bad_alloc(); }
+
+ [[noreturn]]
+ constexpr _Tp&
+ push_back(_Tp&&)
+ { __throw_bad_alloc(); }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr void
+ append_range(_Rg&& __rg)
+ {
+ if (ranges::begin(__rg) != ranges::end(__rg))
+ __throw_bad_alloc();
+ }
+
+ [[noreturn]]
+ constexpr void
+ pop_back()
+ { __builtin_trap(); }
+
+ template<typename... _Args>
+ constexpr _Tp*
+ try_emplace_back(_Args&&...)
+ { return nullptr; }
+
+ constexpr _Tp*
+ try_push_back(const _Tp&)
+ { return nullptr; }
+
+ constexpr _Tp*
+ try_push_back(_Tp&&)
+ { return nullptr; }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr ranges::borrowed_iterator_t<_Rg>
+ try_append_range(_Rg&& __rg)
+ { return ranges::begin(__rg); }
+
+ template<typename... _Args>
+ [[noreturn]]
+ constexpr _Tp&
+ unchecked_emplace_back(_Args&&...)
+ { __builtin_trap(); }
+
+ [[noreturn]]
+ constexpr _Tp&
+ unchecked_push_back(const _Tp&)
+ { __builtin_trap(); }
+
+ [[noreturn]]
+ constexpr _Tp&
+ unchecked_push_back(_Tp&&)
+ { __builtin_trap(); }
+
+ template<typename... _Args>
+ [[noreturn]]
+ constexpr iterator
+ emplace(const_iterator, _Args&&...)
+ { __throw_bad_alloc(); }
+
+ [[noreturn]]
+ constexpr iterator
+ insert(const_iterator, const _Tp&)
+ { __throw_bad_alloc(); }
+
+ [[noreturn]]
+ constexpr iterator
+ insert(const_iterator, _Tp&&)
+ { __throw_bad_alloc(); }
+
+ constexpr iterator
+ insert(const_iterator, size_type __n, const _Tp&)
+ {
+ if (__n != 0)
+ __throw_bad_alloc();
+ return begin();
+ }
+
+ template<typename _InputIterator>
+ constexpr iterator
+ insert(const_iterator, _InputIterator __first, _InputIterator __last)
+ {
+ if (__first != __last)
+ __throw_bad_alloc();
+ return begin();
+ }
+
+ template<__detail::__container_compatible_range<_Tp> _Rg>
+ constexpr iterator
+ insert_range(const_iterator, _Rg&& __rg)
+ {
+ if (ranges::begin(__rg) != ranges::end(__rg))
+ __throw_bad_alloc();
+ return begin();
+ }
+
+ constexpr iterator
+ insert(const_iterator, initializer_list<_Tp> __il)
+ {
+ if (__il.size() != 0)
+ __throw_bad_alloc();
+ return begin();
+ }
+
+ [[noreturn]]
+ constexpr iterator
+ erase(const_iterator)
+ { __builtin_trap(); }
+
+ constexpr iterator
+ erase(const_iterator __first, const_iterator __last)
+ {
+ __glibcxx_assert(__first == __last);
+ return begin();
+ }
+
+ constexpr void
+ swap(inplace_vector& __x)
+ noexcept
+ { }
+
+ constexpr void
+ clear() noexcept
+ { }
+
+ constexpr friend bool
+ operator==(const inplace_vector&, const inplace_vector&)
+ { return true; }
+
+ constexpr friend auto
+ operator<=>(const inplace_vector&, const inplace_vector&)
+ requires requires (const _Tp __t) {
+ { __t < __t } -> __detail::__boolean_testable;
+ }
+ { return std::strong_ordering::equal; }
+
+ // n.b. there is not explicit wording requiring that swap for inplace_vector,
+ // with zero size, works even if element type is not swappable. However given
+ // that move operations are required to be present and trivial, it makes sense
+ // to support them.
+ constexpr friend void
+ swap(inplace_vector&, inplace_vector&) noexcept
+ { }
+ };
+
+ template<typename _Tp, size_t _Nm, typename _Predicate>
+ constexpr size_t
+ erase_if(inplace_vector<_Tp, _Nm>& __cont, _Predicate __pred)
+ {
+ using namespace __gnu_cxx;
+ const auto __osz = __cont.size();
+ const auto __end = __cont.end();
+ auto __removed = std::__remove_if(__cont.begin(), __end,
+ __ops::__pred_iter(std::ref(__pred)));
+ if (__removed != __end)
+ {
+ __cont.erase(__niter_wrap(__cont.begin(), __removed),
+ __cont.end());
+ return __osz - __cont.size();
+ }
+ return 0;
+ }
+
+
+ template<typename _Tp, size_t _Nm, typename _Up>
+ constexpr size_t
+ erase(inplace_vector<_Tp, _Nm>& __cont, const _Up& __value)
+ {
+ using namespace __gnu_cxx;
+ const auto __osz = __cont.size();
+ const auto __end = __cont.end();
+ auto __removed = std::__remove_if(__cont.begin(), __end,
+ __ops::__iter_equals_val(__value));
+ if (__removed != __end)
+ {
+ __cont.erase(__niter_wrap(__cont.begin(), __removed),
+ __cont.end());
+ return __osz - __cont.size();
+ }
+ return 0;
+ }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace
+
+#endif // __glibcxx_inplace_vector
+#endif // _GLIBCXX_INPLACE_VECTOR
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index 271fdb5..055778d 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -1114,11 +1114,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr
mdspan()
requires (rank_dynamic() > 0)
- && is_default_constructible_v<data_handle_type>
+ && is_default_constructible_v<data_handle_type>
&& is_default_constructible_v<mapping_type>
- && is_default_constructible_v<accessor_type>
- : _M_accessor(), _M_mapping(), _M_handle()
- { }
+ && is_default_constructible_v<accessor_type> = default;
constexpr
mdspan(const mdspan& __other) = default;
@@ -1275,31 +1273,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr const accessor_type&
accessor() const noexcept { return _M_accessor; }
+ // Strengthened noexcept for all `is_*` methods.
+
static constexpr bool
- is_always_unique() { return mapping_type::is_always_unique(); }
+ is_always_unique() noexcept(noexcept(mapping_type::is_always_unique()))
+ { return mapping_type::is_always_unique(); }
static constexpr bool
- is_always_exhaustive() { return mapping_type::is_always_exhaustive(); }
+ is_always_exhaustive()
+ noexcept(noexcept(mapping_type::is_always_exhaustive()))
+ { return mapping_type::is_always_exhaustive(); }
static constexpr bool
- is_always_strided() { return mapping_type::is_always_strided(); }
+ is_always_strided()
+ noexcept(noexcept(mapping_type::is_always_strided()))
+ { return mapping_type::is_always_strided(); }
constexpr bool
- is_unique() const { return _M_mapping.is_unique(); }
+ is_unique() const noexcept(noexcept(_M_mapping.is_unique()))
+ { return _M_mapping.is_unique(); }
constexpr bool
- is_exhaustive() const { return _M_mapping.is_exhaustive(); }
+ is_exhaustive() const noexcept(noexcept(_M_mapping.is_exhaustive()))
+ { return _M_mapping.is_exhaustive(); }
constexpr bool
- is_strided() const { return _M_mapping. is_strided(); }
+ is_strided() const noexcept(noexcept(_M_mapping.is_strided()))
+ { return _M_mapping. is_strided(); }
constexpr index_type
stride(rank_type __r) const { return _M_mapping.stride(__r); }
private:
- [[no_unique_address]] accessor_type _M_accessor;
- [[no_unique_address]] mapping_type _M_mapping;
- [[no_unique_address]] data_handle_type _M_handle;
+ [[no_unique_address]] accessor_type _M_accessor = accessor_type();
+ [[no_unique_address]] mapping_type _M_mapping = mapping_type();
+ [[no_unique_address]] data_handle_type _M_handle = data_handle_type();
};
template<typename _CArray>
diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in
index dd05a83..9301ed9 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -1513,7 +1513,15 @@ export namespace std
using std::initializer_list;
}
-// <inplace_vector> FIXME
+// <inplace_vector>
+#if __cpp_lib_inplace_vector
+export namespace std
+{
+ using std::inplace_vector;
+ using std::erase;
+ using std::erase_if;
+}
+#endif
// <iomanip>
export namespace std
@@ -1842,12 +1850,15 @@ export namespace std
export namespace std
{
using std::extents;
+ using std::dextents;
using std::layout_left;
using std::layout_right;
using std::layout_stride;
using std::default_accessor;
using std::mdspan;
- // FIXME layout_left_padded, layout_right_padded, aligned_accessor, mdsubspan
+ // FIXME layout_left_padded, layout_right_padded, aligned_accessor,
+ // strided_slice, submdspan_mapping_result, full_extent_t, full_extent,
+ // submdspan_extents, mdsubspan
}
#endif
diff --git a/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc b/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
index 9740e09..9e5c64c 100644
--- a/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/any/misc/any_cast_neg.cc
@@ -27,6 +27,7 @@ void test01()
const any y(1);
any_cast<int&>(y); // { dg-error "here" }
// { dg-error "Template argument must be constructible from a const value" "" { target { *-*-* } } 0 }
+ // { dg-error "binding reference of type 'int&' to 'const int' discards qualifiers" "" { target { *-*-* } } 0 }
}
void test02()
@@ -34,6 +35,7 @@ void test02()
any y(1);
any_cast<int&&>(y); // { dg-error "here" }
// { dg-error "Template argument must be constructible from an lvalue" "" { target { *-*-* } } 0 }
+ // { dg-error "cannot bind rvalue reference of type 'int&&' to lvalue of type 'int'" "" { target { *-*-* } } 0 }
}
void test03()
@@ -41,6 +43,7 @@ void test03()
any y(1);
any_cast<int&>(std::move(y)); // { dg-error "here" }
// { dg-error "Template argument must be constructible from an rvalue" "" { target { *-*-* } } 0 }
+ // { dg-error "cannot bind non-const lvalue reference of type 'int&' to an rvalue of type 'int'" "" { target { *-*-* } } 0 }
}
// { dg-prune-output "invalid 'static_cast'" }
diff --git a/libstdc++-v3/testsuite/20_util/expected/illformed_neg.cc b/libstdc++-v3/testsuite/20_util/expected/illformed_neg.cc
index 69c13b4..69aa4a1 100644
--- a/libstdc++-v3/testsuite/20_util/expected/illformed_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/expected/illformed_neg.cc
@@ -13,6 +13,7 @@ test_unexpected()
std::unexpected<void()> func(test_unexpected); // { dg-error "here" }
// { dg-error "no matching function for call to" "" { target *-*-* } 0 }
// { dg-error "invalidly declared function type" "" { target *-*-* } 0 }
+ // { dg-error "could not convert" "" { target *-*-* } 0 }
// an array type,
std::unexpected<int[2]> array(i); // { dg-error "here" }
diff --git a/libstdc++-v3/testsuite/20_util/hash/int128.cc b/libstdc++-v3/testsuite/20_util/hash/int128.cc
index 7c3a1ba..a26d2e2 100644
--- a/libstdc++-v3/testsuite/20_util/hash/int128.cc
+++ b/libstdc++-v3/testsuite/20_util/hash/int128.cc
@@ -9,12 +9,12 @@ int main()
#ifdef __SIZEOF_INT128__
std::hash<__int128> h;
__int128 i = (__int128)0x123456789;
- VERIFY( h(i) == i );
+ VERIFY( h(i) == (std::size_t)i );
VERIFY( h(-i) == (std::size_t)-i );
VERIFY( h(~i) == (std::size_t)~i );
std::hash<unsigned __int128> hu;
unsigned __int128 u = i;
- VERIFY( hu(u) == u );
+ VERIFY( hu(u) == (std::size_t)u );
VERIFY( hu(~u) == (std::size_t)~u );
#endif
}
diff --git a/libstdc++-v3/testsuite/20_util/optional/monadic/or_else_neg.cc b/libstdc++-v3/testsuite/20_util/optional/monadic/or_else_neg.cc
index f5028c1..12a67bb 100644
--- a/libstdc++-v3/testsuite/20_util/optional/monadic/or_else_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/monadic/or_else_neg.cc
@@ -26,4 +26,5 @@ test02()
std::optional<move_only> mo;
mo.or_else([]{ return std::optional<move_only>{}; }); // { dg-error "no matching function" }
+ // { dg-error "use of deleted function" "" { target *-*-* } 0 }
}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc
index 6331050..df9e4c3 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/from_range.cc
@@ -73,16 +73,19 @@ do_test(Alloc alloc)
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range>(std::allocator<char>());
- do_test<Range>(__gnu_test::uneq_allocator<char>(42));
do_test<Range>(std::allocator<wchar_t>());
- do_test<Range>(__gnu_test::uneq_allocator<wchar_t>(42));
+
+ if not consteval {
+ do_test<Range>(__gnu_test::uneq_allocator<char>(42));
+ do_test<Range>(__gnu_test::uneq_allocator<wchar_t>(42));
+ }
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -101,9 +104,9 @@ test_ranges()
// Not lvalue-convertible to char
struct C {
- C(char v) : val(v) { }
- operator char() && { return val; }
- bool operator==(char b) const { return b == val; }
+ constexpr C(char v) : val(v) { }
+ constexpr operator char() && { return val; }
+ constexpr bool operator==(char b) const { return b == val; }
char val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -112,18 +115,10 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
-{
-#if _GLIBCXX_USE_CXX11_ABI
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::string_view>(std::allocator<char>());
-#endif // _GLIBCXX_USE_CXX11_ABI
- return true;
-}
-
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+#if _GLIBCXX_USE_CXX11_ABI
+ static_assert( test_ranges() );
+#endif // _GLIBCXX_USE_CXX11_ABI
}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc
index 6c0bc0c..984db36 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/append/append_range.cc
@@ -49,7 +49,7 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<char>>();
@@ -58,7 +58,7 @@ do_test_a()
do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -77,9 +77,9 @@ test_ranges()
// Not lvalue-convertible to char
struct C {
- C(char v) : val(v) { }
- operator char() && { return val; }
- bool operator==(char b) const { return b == val; }
+ constexpr C(char v) : val(v) { }
+ constexpr operator char() && { return val; }
+ constexpr bool operator==(char b) const { return b == val; }
char val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -107,19 +107,11 @@ test_overlapping()
VERIFY( c == "1234abcd1234" );
}
-constexpr bool
-test_constexpr()
-{
-#if _GLIBCXX_USE_CXX11_ABI
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::string_view, std::allocator<char>>();
-#endif // _GLIBCXX_USE_CXX11_ABI
- return true;
-}
-
int main()
{
test_ranges();
test_overlapping();
- static_assert( test_constexpr() );
+#if _GLIBCXX_USE_CXX11_ABI
+ static_assert( test_ranges() );
+#endif // _GLIBCXX_USE_CXX11_ABI
}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc
index 310c8bc..aa1b329 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/assign/assign_range.cc
@@ -41,7 +41,7 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<char>>();
@@ -50,7 +50,7 @@ do_test_a()
do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -69,9 +69,9 @@ test_ranges()
// Not lvalue-convertible to char
struct C {
- C(char v) : val(v) { }
- operator char() && { return val; }
- bool operator==(char b) const { return b == val; }
+ constexpr C(char v) : val(v) { }
+ constexpr operator char() && { return val; }
+ constexpr bool operator==(char b) const { return b == val; }
char val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -98,19 +98,11 @@ test_overlapping()
VERIFY( c == "1234" );
}
-constexpr bool
-test_constexpr()
-{
-#if _GLIBCXX_USE_CXX11_ABI
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::string_view, std::allocator<char>>();
-#endif // _GLIBCXX_USE_CXX11_ABI
- return true;
-}
-
int main()
{
test_ranges();
test_overlapping();
- static_assert( test_constexpr() );
+#if _GLIBCXX_USE_CXX11_ABI
+ static_assert( test_ranges() );
+#endif // _GLIBCXX_USE_CXX11_ABI
}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc
index 4fead32..c026fd4 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/insert/insert_range.cc
@@ -54,7 +54,7 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<char>>();
@@ -63,7 +63,7 @@ do_test_a()
do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -82,9 +82,9 @@ test_ranges()
// Not lvalue-convertible to char
struct C {
- C(char v) : val(v) { }
- operator char() && { return val; }
- bool operator==(char b) const { return b == val; }
+ constexpr C(char v) : val(v) { }
+ constexpr operator char() && { return val; }
+ constexpr bool operator==(char b) const { return b == val; }
char val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -112,19 +112,11 @@ test_overlapping()
VERIFY( c == "12123434abcd" );
}
-constexpr bool
-test_constexpr()
-{
-#if _GLIBCXX_USE_CXX11_ABI
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::string_view, std::allocator<char>>();
-#endif // _GLIBCXX_USE_CXX11_ABI
- return true;
-}
-
int main()
{
test_ranges();
test_overlapping();
- static_assert( test_constexpr() );
+#if _GLIBCXX_USE_CXX11_ABI
+ static_assert( test_ranges() );
+#endif // _GLIBCXX_USE_CXX11_ABI
}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc
index 9acf11a..4c6bba5 100644
--- a/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/modifiers/replace/replace_with_range.cc
@@ -54,7 +54,7 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<char>>();
@@ -63,7 +63,7 @@ do_test_a()
do_test<Range, __gnu_test::SimpleAllocator<wchar_t>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -82,9 +82,9 @@ test_ranges()
// Not lvalue-convertible to char
struct C {
- C(char v) : val(v) { }
- operator char() && { return val; }
- bool operator==(char b) const { return b == val; }
+ constexpr C(char v) : val(v) { }
+ constexpr operator char() && { return val; }
+ constexpr bool operator==(char b) const { return b == val; }
char val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -115,19 +115,11 @@ test_overlapping()
VERIFY( c == "12123434abcd" );
}
-constexpr bool
-test_constexpr()
-{
-#if _GLIBCXX_USE_CXX11_ABI
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::string_view, std::allocator<char>>();
-#endif // _GLIBCXX_USE_CXX11_ABI
- return true;
-}
-
int main()
{
test_ranges();
test_overlapping();
- static_assert( test_constexpr() );
+#if _GLIBCXX_USE_CXX11_ABI
+ static_assert( test_ranges() );
+#endif // _GLIBCXX_USE_CXX11_ABI
}
diff --git a/libstdc++-v3/testsuite/23_containers/array/creation/3_neg.cc b/libstdc++-v3/testsuite/23_containers/array/creation/3_neg.cc
index ae06302..1335228 100644
--- a/libstdc++-v3/testsuite/23_containers/array/creation/3_neg.cc
+++ b/libstdc++-v3/testsuite/23_containers/array/creation/3_neg.cc
@@ -54,3 +54,5 @@ test03()
}
// { dg-prune-output "static assertion failed" }
+// { dg-prune-output "use of deleted function" }
+// { dg-prune-output "could not convert" }
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc
new file mode 100644
index 0000000..2797e20
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/capacity.cc
@@ -0,0 +1,51 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+
+template<size_t N, typename T>
+constexpr void
+test_reserve()
+{
+ std::inplace_vector<T, N> v;
+
+ static_assert(v.max_size() == N);
+ static_assert(v.capacity() == N);
+
+ // static methods
+ v.shrink_to_fit();
+ v.reserve(0);
+ v.reserve(N);
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ v.reserve(N + 2);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+#endif
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_reserve<0, int>();
+ test_reserve<4, int>();
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc
new file mode 100644
index 0000000..bc06aa0
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem.cc
@@ -0,0 +1,115 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <stdexcept>
+#include <testsuite_hooks.h>
+#include <utility>
+
+template<size_t N, typename T>
+constexpr void
+test_out_of_capacity()
+{
+ std::inplace_vector<T, N> v;
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ (void)v.at(N + 2);
+ VERIFY(false);
+ }
+ catch (std::out_of_range const&)
+ {
+ }
+
+ try
+ {
+ (void)as_const(v).at(N + 2);
+ VERIFY(false);
+ }
+ catch (std::out_of_range const&)
+ {
+ }
+#endif
+}
+
+
+template<bool Const, typename T, size_t N>
+using InplaceVector = std::conditional_t<Const,
+ const std::inplace_vector<T, N>,
+ std::inplace_vector<T, N>>;
+
+template<bool Const, typename T>
+constexpr void
+test_access()
+{
+ InplaceVector<Const, T, 10> v{1, 2, 3, 4, 5};
+
+ auto& e0a = v[0];
+ auto& e0b = v.at(0);
+ auto& e0c = v.front();
+ VERIFY( &e0a == &e0b );
+ VERIFY( &e0a == &e0c );
+ VERIFY( &e0a == &v.begin()[0] );
+ VERIFY( &e0a == &v.cbegin()[0] );
+ VERIFY( &e0a == v.data() );
+ VERIFY( e0a == T(1) );
+
+ auto& e3a = v[2];
+ auto& e3b = v.at(2);
+ VERIFY( &e3a == &e3b );
+ VERIFY( &e3a == &v.begin()[2] );
+ VERIFY( &e3a == &v.cbegin()[2] );
+ VERIFY( &e3a == v.data() + 2 );
+ VERIFY( e3a == T(3) );
+
+ auto& e4a = v[4];
+ auto& e4b = v.at(4);
+ auto& e4c = v.back();
+ VERIFY( &e4a == &e4b );
+ VERIFY( &e4a == &e4c );
+ VERIFY( &e4a == &v.begin()[4] );
+ VERIFY( &e4a == &v.cbegin()[4] );
+ VERIFY( &e4a == v.data() + 4 );
+ VERIFY( e4a == T(5) );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ (void)v.at(7);
+ VERIFY(false);
+ }
+ catch (std::out_of_range const&)
+ {
+ }
+#endif
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_out_of_capacity<0, int>();
+ test_out_of_capacity<4, int>();
+ test_access<true, int>();
+ test_access<false, int>();
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc
new file mode 100644
index 0000000..b2bff0d
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/access/elem_neg.cc
@@ -0,0 +1,65 @@
+// { dg-do compile { target c++26 } }
+
+#include <inplace_vector>
+
+template<bool Const, typename T, size_t N>
+using InplaceVector
+ = std::conditional_t<Const,
+ const std::inplace_vector<T, N>,
+ std::inplace_vector<T, N>>;
+
+template<bool Const, size_t N, typename T>
+constexpr bool
+test_front_on_empty()
+{
+ InplaceVector<Const, T, N> v;
+ (void)v.front(); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<bool Const, size_t N, typename T>
+constexpr bool
+test_back_on_empty()
+{
+ InplaceVector<Const, T, N> v;
+ (void)v.back(); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<bool Const, size_t N, typename T>
+constexpr bool
+test_out_of_capacity()
+{
+ InplaceVector<Const, T, N> v;
+ (void)v[N+2]; // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<bool Const, typename T>
+constexpr bool
+test_out_of_size()
+{
+ InplaceVector<Const, T, 10> v{1, 2, 3, 4, 5};
+ (void)v[7]; // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+static_assert(test_front_on_empty<false, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_front_on_empty<false, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_back_on_empty<false, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_back_on_empty<false, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_capacity<false, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_capacity<false, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_size<false, int>()); // { dg-error "in 'constexpr' expansion of" }
+
+static_assert(test_front_on_empty<true, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_front_on_empty<true, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_back_on_empty<true, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_back_on_empty<true, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_capacity<true, 0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_capacity<true, 4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_out_of_size<true, int>()); // { dg-error "in 'constexpr' expansion of" }
+
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "is not a constant expression" }
+// { dg-prune-output "call to non-'constexpr' function" }
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
new file mode 100644
index 0000000..e9c2cdc
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/1.cc
@@ -0,0 +1,385 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ constexpr X() { } // not trivially default constructible
+};
+
+struct N
+{
+ constexpr N() noexcept { } // not trivially default constructible
+};
+
+struct D
+{
+ ~D() {} // not trivially destructible
+};
+
+struct U
+{
+ U() noexcept(false) = default; // lies about noexcept
+};
+
+// n5008 inplace.vector.overview says for inplace_vector<T, 0>
+// provides trivial copy/move/default cosntructpr regardless of T
+struct Z
+{
+ constexpr Z(int) {}
+ Z() = delete;
+};
+
+static_assert(std::is_default_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_default_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_default_constructible_v<std::inplace_vector<N, 2>>);
+static_assert(std::is_default_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_default_constructible_v<std::inplace_vector<U, 2>>);
+// The operators are not constrained, as for any other container
+static_assert(std::is_default_constructible_v<std::inplace_vector<Z, 2>>);
+
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<N, 2>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<U, 2>>);
+
+// Needs to set size to zero, not trivial
+static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<N, 2>>);
+static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_trivially_default_constructible_v<std::inplace_vector<U, 2>>);
+
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<N, 2>>);
+static_assert(!std::is_trivially_destructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<U, 2>>);
+
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<N, 0>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_default_constructible_v<std::inplace_vector<U, 0>>);
+
+// Size is always zero, so trivial
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<N, 0>>);
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_trivially_default_constructible_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<N, 0>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_destructible_v<std::inplace_vector<U, 0>>);
+
+static_assert(std::is_empty_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_empty_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_empty_v<std::inplace_vector<N, 0>>);
+static_assert(std::is_empty_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_empty_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_empty_v<std::inplace_vector<Z, 0>>);
+
+constexpr void
+test_default()
+{
+ std::inplace_vector<int, 5> c;
+ VERIFY( c.size() == 0 );
+ VERIFY( c.capacity() == 5 );
+ VERIFY( c.empty() );
+ VERIFY( c.begin() == c.end() );
+
+ std::inplace_vector<int, 0> c0;
+ VERIFY( c0.size() == 0 );
+ VERIFY( c0.capacity() == 0 );
+ VERIFY( c0.empty() );
+ VERIFY( c0.begin() == c0.end() );
+
+ std::inplace_vector<Z, 0> z0;
+ VERIFY( z0.size() == 0 );
+ VERIFY( z0.capacity() == 0 );
+ VERIFY( z0.empty() );
+ VERIFY( z0.begin() == z0.end() );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> cx;
+ VERIFY( cx.size() == 0 );
+ VERIFY( cx.capacity() == 5 );
+ VERIFY( cx.empty() );
+ VERIFY( cx.begin() == cx.end() );
+
+ std::inplace_vector<X, 0> cx0;
+ VERIFY( cx0.size() == 0 );
+ VERIFY( cx0.capacity() == 0 );
+ VERIFY( cx0.empty() );
+ VERIFY( cx0.begin() == cx0.end() );
+}
+
+constexpr void
+test_n()
+{
+ std::inplace_vector<int, 5> c(2);
+ VERIFY( c.size() == 2 );
+ VERIFY( c.capacity() == 5 );
+ VERIFY( not c.empty() );
+ VERIFY( c.begin() + 2 == c.end() );
+ VERIFY( c[0] == 0 );
+ VERIFY( c[1] == 0 );
+
+ std::inplace_vector<int, 2> c2(2);
+ VERIFY( c2.size() == 2 );
+ VERIFY( c2.capacity() == 2 );
+ VERIFY( not c2.empty() );
+ VERIFY( c2.begin() + 2 == c2.end() );
+ VERIFY( c2[0] == 0 );
+ VERIFY( c2[1] == 0 );
+
+ std::inplace_vector<int, 0> c0(0);
+ VERIFY( c0.size() == 0 );
+ VERIFY( c0.capacity() == 0 );
+ VERIFY( c0.empty() );
+ VERIFY( c0.begin() == c0.end() );
+
+ std::inplace_vector<int, 2> c20(0);
+ VERIFY( c20.size() == 0 );
+ VERIFY( c20.capacity() == 2 );
+ VERIFY( c20.empty() );
+ VERIFY( c20.begin() == c20.end() );
+
+ std::inplace_vector<Z, 0> z0(0);
+ VERIFY( z0.size() == 0 );
+ VERIFY( z0.capacity() == 0 );
+ VERIFY( z0.empty() );
+ VERIFY( z0.begin() == z0.end() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if not consteval {
+ try
+ {
+ std::inplace_vector<int, 2> ct(3);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ try
+ {
+ std::inplace_vector<int, 0> ct(1);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ }
+#endif
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> cx(3);
+ VERIFY( cx.size() == 3 );
+ VERIFY( cx.capacity() == 5 );
+ VERIFY( not cx.empty() );
+ VERIFY( cx.begin() + 3 == cx.end() );
+ (void) cx[2];
+}
+
+constexpr void
+test_n_val()
+{
+ std::inplace_vector<int, 5> c(2, 99);
+ VERIFY( c.size() == 2 );
+ VERIFY( c.capacity() == 5 );
+ VERIFY( not c.empty() );
+ VERIFY( c.begin() + 2 == c.end() );
+ VERIFY( c[0] == 99 );
+ VERIFY( c[1] == 99 );
+
+ std::inplace_vector<int, 1> c1(1, 44);
+ VERIFY( c1.size() == 1 );
+ VERIFY( c1.capacity() == 1 );
+ VERIFY( not c1.empty() );
+ VERIFY( c1.begin() + 1 == c1.end() );
+ VERIFY( c1[0] == 44 );
+
+ std::inplace_vector<int, 0> c0(0, 33);
+ VERIFY( c0.size() == 0 );
+ VERIFY( c0.capacity() == 0 );
+ VERIFY( c0.empty() );
+ VERIFY( c0.begin() == c0.end() );
+
+ std::inplace_vector<int, 2> c20(0, 22);
+ VERIFY( c20.size() == 0 );
+ VERIFY( c20.capacity() == 2 );
+ VERIFY( c20.empty() );
+ VERIFY( c20.begin() == c20.end() );
+
+ std::inplace_vector<Z, 0> z0(0, 33);
+ VERIFY( z0.size() == 0 );
+ VERIFY( z0.capacity() == 0 );
+ VERIFY( z0.empty() );
+ VERIFY( z0.begin() == z0.end() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if not consteval {
+ try
+ {
+ std::inplace_vector<int, 2> ct(3, 11);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ try
+ {
+ std::inplace_vector<int, 0> ct(2, 11);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ }
+#endif
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> cx(4);
+ VERIFY( cx.size() == 4 );
+ VERIFY( cx.capacity() == 5 );
+ VERIFY( not cx.empty() );
+ VERIFY( cx.begin() + 4 == cx.end() );
+ (void) cx[3];
+}
+
+constexpr void
+test_initializer_list()
+{
+ std::inplace_vector<int, 5> c{22, 33};
+ VERIFY( c.size() == 2 );
+ VERIFY( c.capacity() == 5 );
+ VERIFY( not c.empty() );
+ VERIFY( c.begin() + 2 == c.end() );
+ VERIFY( c[0] == 22 );
+ VERIFY( c[1] == 33 );
+
+ std::inplace_vector<int, 1> c1{44};
+ VERIFY( c1.size() == 1 );
+ VERIFY( c1.capacity() == 1 );
+ VERIFY( not c1.empty() );
+ VERIFY( c1.begin() + 1 == c1.end() );
+ VERIFY( c1[0] == 44 );
+
+ std::inplace_vector<int, 0> c0({});
+ VERIFY( c0.size() == 0 );
+ VERIFY( c0.capacity() == 0 );
+ VERIFY( c0.empty() );
+ VERIFY( c0.begin() == c0.end() );
+
+ std::inplace_vector<int, 2> c20({});
+ VERIFY( c20.size() == 0 );
+ VERIFY( c20.capacity() == 2 );
+ VERIFY( c20.empty() );
+ VERIFY( c20.begin() == c20.end() );
+
+ std::inplace_vector<Z, 0> z0({});
+ VERIFY( z0.size() == 0 );
+ VERIFY( z0.capacity() == 0 );
+ VERIFY( z0.empty() );
+ VERIFY( z0.begin() == z0.end() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if not consteval {
+ try
+ {
+ std::inplace_vector<int, 2> ct{11, 22, 33};
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ try
+ {
+ std::inplace_vector<int, 0> ct{11, 22};
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ }
+#endif
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> cx{X(), X(), X(), X()};
+ VERIFY( cx.size() == 4 );
+ VERIFY( cx.capacity() == 5 );
+ VERIFY( not cx.empty() );
+ VERIFY( cx.begin() + 4 == cx.end() );
+ (void) cx[3];
+}
+
+constexpr std::inplace_vector<int, 0> e0;
+constexpr std::inplace_vector<X, 0> e1;
+constexpr std::inplace_vector<Z, 0> e2;
+
+constexpr std::inplace_vector<int, 5> g1;
+constexpr std::inplace_vector<int, 5> g2(2, 100);
+constexpr std::inplace_vector<int, 5> g3 = g2;
+constexpr std::inplace_vector<int, 5> g4{1, 2, 3};
+constexpr std::inplace_vector<int, 5> g5 = [] {
+ std::inplace_vector<int, 5> res;
+ res = g3;
+ return res;
+}();
+
+int main()
+{
+ auto tests = [] {
+ test_default();
+ test_n();
+ test_n_val();
+ test_initializer_list();
+ return true;
+ };
+
+ tests();
+ constexpr bool _ = tests();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc
new file mode 100644
index 0000000..4a2f193
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/from_range.cc
@@ -0,0 +1,177 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::span<const T> r) {
+ if (l.size() != r.size())
+ return false;
+ for (auto i = 0u; i < l.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+};
+
+template<typename T, template<class TT> class ItType>
+constexpr void
+do_test_it()
+{
+ // The vector's value_type.
+ using V = int;
+
+ T a[]{1,2,3,4,5,6,7,8,9};
+ using It = ItType<T>;
+
+ auto bounds = typename It::ContainerType(a, a+9);
+ std::inplace_vector<V, 0> e0(It(a, &bounds), It(a, &bounds));
+ VERIFY( e0.empty() );
+
+ bounds = typename It::ContainerType(a, a+9);
+ std::inplace_vector<V, 10> v0(It(a, &bounds), It(a, &bounds));
+ VERIFY( v0.empty() );
+
+ bounds = typename It::ContainerType(a, a+9);
+ std::inplace_vector<V, 10> v4(It(a, &bounds), It(a+4, &bounds));
+ VERIFY( eq<T>(v4, {a, 4}) );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ bounds = typename It::ContainerType(a, a+9);
+ try
+ {
+ std::inplace_vector<int, 5> v9(It(a, &bounds), It(a+9, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ bounds = typename It::ContainerType(a, a+9);
+ try
+ {
+ std::inplace_vector<int, 0> v2(It(a, &bounds), It(a+2, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+#endif
+}
+
+constexpr bool
+test_iterators()
+{
+ using namespace __gnu_test;
+
+ do_test_it<int, input_iterator_wrapper>();
+ do_test_it<int, forward_iterator_wrapper>();
+ do_test_it<int, random_access_iterator_wrapper>();
+
+ do_test_it<short, forward_iterator_wrapper>();
+ return true;
+}
+
+template<typename Range>
+constexpr void
+do_test_r()
+{
+ // The vector's value_type.
+ using V = int;
+
+ // The range's value_type.
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9};
+
+ std::inplace_vector<V, 0> e0(std::from_range, Range(a, a+0));
+ VERIFY( e0.empty() );
+
+ std::inplace_vector<V, 10> v0(std::from_range, Range(a, a+0));
+ VERIFY( v0.empty() );
+
+ std::inplace_vector<V, 10> v4(std::from_range, Range(a, a+4));
+ VERIFY( eq<T>(v4, {a, 4}) );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ std::inplace_vector<V, 5> v9(std::from_range, Range(a, a+9));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+
+ try
+ {
+ std::inplace_vector<V, 0> v3(std::from_range, Range(a, a+3));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+#endif
+}
+
+constexpr bool
+test_ranges()
+{
+ using namespace __gnu_test;
+
+ do_test_r<test_forward_range<int>>();
+ do_test_r<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_r<test_input_range<int>>();
+ do_test_r<test_input_sized_range<int>>();
+ do_test_r<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_r<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_r<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_r<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ do_test_r<test_forward_range<short>>();
+ do_test_r<test_input_range<short>>();
+
+ // Not lvalue-convertible to int
+ struct C {
+ constexpr C(int v) : val(v) { }
+ constexpr operator int() && { return val; }
+ constexpr bool operator==(int b) const { return b == val; }
+ int val;
+ };
+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
+ do_test_r<rvalue_input_range>();
+
+ return true;
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_iterators();
+ test_ranges();
+ return true;
+ };
+
+ test_all();
+ static_assert( test_all() );
+}
+
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc
new file mode 100644
index 0000000..4ce39d1
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/cons/throws.cc
@@ -0,0 +1,129 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <testsuite_allocator.h>
+
+struct CopyFailed {};
+
+struct Thrower
+{
+ static inline size_t throw_after = 0;
+ static inline size_t incontainer = 0;
+
+ Thrower() {}
+ Thrower(int x) {}
+ Thrower(const Thrower&)
+ {
+ if (incontainer >= throw_after)
+ throw CopyFailed();
+ ++incontainer;
+ }
+
+ ~Thrower()
+ { --incontainer; }
+};
+
+template<template<class TT> class ItType>
+void
+do_test_it()
+{
+ // The vector's value_type.
+ using V = Thrower;
+
+ V a[]{1,2,3,4,5,6,7,8,9};
+ using It = ItType<V>;
+
+ auto bounds = typename It::ContainerType(a, a+9);
+ Thrower::throw_after = 100;
+ Thrower::incontainer = 0;
+ try
+ {
+ std::inplace_vector<V, 5> v9(It(a, &bounds), It(a+9, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( Thrower::incontainer == 0 );
+
+ bounds = typename It::ContainerType(a, a+9);
+ Thrower::throw_after = 2;
+ Thrower::incontainer = 0;
+ try
+ {
+ std::inplace_vector<V, 5> v2(It(a, &bounds), It(a+3, &bounds));
+ VERIFY(false);
+ }
+ catch (CopyFailed const&)
+ {
+ }
+ VERIFY( Thrower::incontainer == 0 );
+}
+
+bool
+test_iterators()
+{
+ using namespace __gnu_test;
+ do_test_it<input_iterator_wrapper>();
+ do_test_it<forward_iterator_wrapper>();
+ do_test_it<random_access_iterator_wrapper>();
+ return true;
+}
+
+template<typename Range>
+void
+do_test_r()
+{
+ // The vector's value_type.
+ using V = Thrower;
+
+ V a[]{1,2,3,4,5,6,7,8,9};
+
+ Thrower::throw_after = 100;
+ Thrower::incontainer = 0;
+ try
+ {
+ std::inplace_vector<V, 5> v9(std::from_range, Range(a, a+9));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( Thrower::incontainer == 0 );
+
+ Thrower::throw_after = 2;
+ Thrower::incontainer = 0;
+ try
+ {
+ std::inplace_vector<V, 5> v9(std::from_range, Range(a, a+3));
+ VERIFY(false);
+ }
+ catch (CopyFailed const&)
+ {
+ }
+ VERIFY( Thrower::incontainer == 0 );
+}
+
+bool
+test_ranges()
+{
+ using namespace __gnu_test;
+ do_test_r<test_forward_range<Thrower>>();
+ do_test_r<test_sized_range_sized_sent<Thrower, forward_iterator_wrapper>>();
+
+ do_test_r<test_input_range<Thrower>>();
+ do_test_r<test_input_sized_range<Thrower>>();
+ do_test_r<test_sized_range_sized_sent<Thrower, input_iterator_wrapper>>();
+ return true;
+}
+
+int main()
+{
+ test_iterators();
+ test_ranges();
+}
+
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
new file mode 100644
index 0000000..d149e63
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/copy.cc
@@ -0,0 +1,247 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+#include <ranges>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<bool CNoex, bool ANoex>
+struct N
+{
+ N() = default;
+ constexpr N(const N&) noexcept(CNoex) { } // not trivial
+ constexpr N& operator=(const N& o) noexcept(ANoex) // not trivial
+ { return *this; }
+};
+
+struct D
+{
+ D() = default;
+ D(const D&) = default;
+ D& operator=(const D&) = default;
+ ~D() {} // not trivially destructible
+};
+
+struct U
+{
+ U() = default;
+ U(const U&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
+ U& operator=(const U&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
+};
+
+// n5008 inplace.vector.overview p5 says for inplace_vector<T, 0>
+// provides trivial copy/move/default cosntructpr regardless of T
+struct Z
+{
+ Z(Z&&) = delete;
+ Z& operator=(Z&&) = delete;
+};
+
+template<size_t N, typename T>
+ constexpr std::inplace_vector<T, N> const&
+ materialize(std::inplace_vector<T, N> const& r)
+ { return r; }
+
+static_assert(std::is_copy_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_copy_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_copy_constructible_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_copy_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_copy_constructible_v<std::inplace_vector<U, 2>>);
+// The operators are not constrained, as for any other container
+static_assert(std::is_copy_constructible_v<std::inplace_vector<Z, 2>>);
+
+// conditional noexcept here is libstdc++ extension,
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<N<true, true>, 2>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<N<true, false>, 2>>);
+static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<N<false, true>, 2>>);
+static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_nothrow_copy_constructible_v<std::inplace_vector<U, 2>>);
+
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<N<true, true>, 2>>);
+// is_trivially_copy_constructible_v checks destructor
+static_assert(!std::is_trivially_copy_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<U, 2>>);
+
+static_assert(std::is_copy_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_copy_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_copy_assignable_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_copy_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_copy_assignable_v<std::inplace_vector<U, 2>>);
+// The operators are not constrained, as for any other container
+static_assert(std::is_copy_assignable_v<std::inplace_vector<Z, 2>>);
+
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<N<true, true>, 2>>);
+static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<N<true, false>, 2>>);
+static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<N<false, true>, 2>>);
+static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_nothrow_copy_assignable_v<std::inplace_vector<U, 2>>);
+
+// conditional noexcept here is libstdc++ extension,
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<N<true, true>, 2>>);
+// destructor is not trivial
+static_assert(!std::is_trivially_copy_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<U, 2>>);
+
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_nothrow_copy_constructible_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_trivially_copy_constructible_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_nothrow_copy_assignable_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_trivially_copy_assignable_v<std::inplace_vector<Z, 0>>);
+
+
+template<typename T, size_t N>
+constexpr bool
+eq(const std::inplace_vector<T, N>& s, std::span<const T> o)
+{ return std::ranges::equal(s, o); }
+
+constexpr void
+test_ctor()
+{
+ auto e0 = materialize<0, int>({});
+ VERIFY( e0.empty() );
+ auto e1 = materialize<0, X>({});
+ VERIFY( e1.empty() );
+ auto e2 = materialize<0, Z>({});
+ VERIFY( e2.empty() );
+
+ auto c0 = materialize<5, int>({});
+ VERIFY( c0.empty() );
+
+ auto c3 = materialize<5, int>({1, 2, 3});
+ VERIFY( eq(c3, {1, 2, 3}) );
+
+ auto c5 = materialize<5, int>({1, 2, 3, 4, 5});
+ VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ auto x0 = materialize<3, X>({});
+ VERIFY( x0.empty() );
+
+ auto x2 = materialize<3, X>({1, 2});
+ VERIFY( eq(x2, {1, 2}) );
+
+ auto x3 = materialize<3, X>({1, 2, 3});
+ VERIFY( eq(x3, {1, 2, 3}) );
+}
+
+constexpr void
+test_assign()
+{
+ std::inplace_vector<int, 0> e0;
+ e0 = materialize<0, int>({});
+ VERIFY( e0.empty() );
+ std::inplace_vector<X, 0> e1;
+ e1 = materialize<0, X>({});
+ VERIFY( e1.empty() );
+ std::inplace_vector<Z, 0> e2;
+ e2 = materialize<0, Z>({});
+ VERIFY( e2.empty() );
+
+ std::inplace_vector<int, 5> c;
+ c = materialize<5, int>({});
+ VERIFY( c.empty() );
+
+ c = materialize<5, int>({1, 2, 3});
+ VERIFY( eq(c, {1, 2, 3}) );
+
+ c = materialize<5, int>({1, 2, 3, 4, 5});
+ VERIFY( eq(c, {1, 2, 3, 4, 5}) );
+
+ c = materialize<5, int>({4, 5});
+ VERIFY( eq(c, {4, 5}) );
+
+ c = materialize<5, int>({});
+ VERIFY( c.empty() );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> x;
+ x = materialize<5, X>({});
+ VERIFY( x.empty() );
+
+ x = materialize<5, X>({1, 2, 3});
+ VERIFY( eq(x, {1, 2, 3}) );
+
+ x = materialize<5, X>({1, 2, 3, 4, 5});
+ VERIFY( eq(x, {1, 2, 3, 4, 5}) );
+
+ x = materialize<5, X>({4, 5});
+ VERIFY( eq(x, {4, 5}) );
+
+ x = materialize<5, X>({});
+ VERIFY( x.empty() );
+}
+
+constexpr auto e0 = materialize<0, int>({});
+constexpr auto e1 = materialize<0, X>({});
+constexpr auto e2 = materialize<0, Z>({});
+
+constexpr auto t1 = materialize<3, int>({});
+constexpr auto t2 = materialize<3, int>({1, 2});
+constexpr auto t3 = materialize<3, int>({11, 22, 33});
+
+int main()
+{
+ auto tests = [] {
+ test_ctor();
+ test_assign();
+ return true;
+ };
+
+ tests();
+ constexpr bool _ = tests();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc
new file mode 100644
index 0000000..c7fda09
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/erasure.cc
@@ -0,0 +1,49 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+#include <testsuite_hooks.h>
+
+constexpr void
+test_erase()
+{
+ std::inplace_vector<int, 15> c{1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 4, 4, 9};
+ std::erase(c, 4);
+ VERIFY( c.size() == 10 );
+ std::erase(c, 1);
+ VERIFY( c.size() == 8 );
+ std::erase(c, 9);
+ VERIFY( c.size() == 7 );
+ VERIFY( (c == std::inplace_vector<int, 15>{2, 3, 5, 6, 5, 3, 2}) );
+
+ std::inplace_vector<int, 0> e;
+ std::erase(e, 10);
+ VERIFY( e.empty() );
+}
+
+constexpr void
+test_erase_if()
+{
+ std::inplace_vector<int, 15> c{1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 4, 4, 9};
+ std::erase_if(c, [](int i) { return i > 5; });
+ VERIFY( c.size() == 12 );
+ std::erase_if(c, [](int i) { return i == 4; });
+ VERIFY( c.size() == 8 );
+ std::erase_if(c, [](int i) { return i & 1; });
+ VERIFY( (c == std::inplace_vector<int, 15>{2, 2}) );
+
+ std::inplace_vector<int, 0> e;
+ std::erase_if(e, [](int i) { return i > 5; });
+ VERIFY( e.empty() );
+}
+
+int main()
+{
+ test_erase();
+ test_erase_if();
+
+ constexpr bool _ = [] {
+ test_erase();
+ test_erase_if();
+ return true;
+ }();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc
new file mode 100644
index 0000000..65b505e
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/assign.cc
@@ -0,0 +1,379 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::span<const T> r) {
+ if (l.size() != r.size())
+ return false;
+ for (auto i = 0u; i < l.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+};
+
+template<size_t N, typename T, template<class TT> class ItType>
+constexpr void
+test_assign_empty_it()
+{
+ using namespace __gnu_test;
+
+ T a[]{1,2,3,4,5,6,7,8,9,10};
+ using It = ItType<T>;
+ using Range = test_range<T, ItType>;
+ using SizedRange = test_sized_range<T, ItType>;
+
+ const std::inplace_vector<T, N> src(std::from_range, std::span(a, N));
+ std::inplace_vector<T, N> v;
+
+ v = src;
+ v.assign_range(Range(a, a));
+ VERIFY( v.empty() );
+ v.assign_range(Range(a, a));
+ VERIFY( v.empty() );
+
+ v = src;
+ v.assign_range(SizedRange(a, a));
+ VERIFY( v.empty() );
+
+ v = src;
+ auto bounds = typename It::ContainerType(a, a+9);
+ v.assign(It(a, &bounds), It(a, &bounds));
+ VERIFY( v.empty() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ static_assert(N < 9);
+
+ v = src;
+ try
+ {
+ v.assign_range(Range(a, a+9));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ if constexpr (std::ranges::sized_range<Range> || std::ranges::forward_range<Range>)
+ VERIFY( eq<T>(v, {a, N}) );
+
+ v = src;
+ try
+ {
+ v.assign_range(SizedRange(a, a+9));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ v = src;
+ bounds = typename It::ContainerType(a, a+9);
+ try
+ {
+ v.assign(It(a, &bounds), It(a+9, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ if constexpr(std::forward_iterator<It>)
+ VERIFY( eq<T>(v, {a, N}) );
+#endif
+}
+
+template<size_t N, typename T>
+constexpr void
+test_assign_empty_other()
+{
+ T a[]{1,2,3,4,5,6,7,8,9,10};
+ const std::inplace_vector<T, N> src(std::from_range, std::span(a, N));
+ std::inplace_vector<T, N> v;
+
+ v = src;
+ v.assign(0, T(4));
+ VERIFY( v.empty() );
+
+ v = src;
+ v.assign({});
+ VERIFY( v.empty() );
+
+ v = src;
+ v = {};
+ VERIFY( v.empty() );
+
+ v = src;
+ v.resize(0, T(3));
+ VERIFY( v.empty() );
+
+ v = src;
+ v.resize(0);
+ VERIFY( v.empty() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ static_assert(N < 9);
+
+ v = src;
+ try
+ {
+ v.assign(9, T(4));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ std::initializer_list<T> il =
+ {T(0), T(1), T(2), T(3), T(4), T(5), T(6), T(7), T(8), T(9), T(10)};
+ try
+ {
+ v.assign(il);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v = il;
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.resize(9, T(3));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.resize(9);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+#endif
+}
+
+template<size_t N, typename T>
+constexpr void
+test_assign_empty()
+{
+ using namespace __gnu_test;
+ test_assign_empty_it<N, T, input_iterator_wrapper>();
+ test_assign_empty_it<N, T, forward_iterator_wrapper>();
+ test_assign_empty_it<N, T, random_access_iterator_wrapper>();
+
+ test_assign_empty_other<N, T>;
+}
+
+template<typename Range>
+constexpr void
+test_assign_range()
+{
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+ std::inplace_vector<T, 10> v;
+ v.assign_range(Range(a,a+5));
+ VERIFY( eq<T>(v, {a, 5}) );
+
+ v.assign_range(Range(a,a+7));
+ VERIFY( eq<T>(v, {a, 7}) );
+
+ v.assign_range(Range(a,a+3));
+ VERIFY( eq<T>(v, {a, 3}) );
+
+ v.assign_range(Range(a,a+10));
+ VERIFY( eq<T>(v, {a, 10}) );
+}
+
+template<typename T, template<class TT> class ItType>
+constexpr void
+test_assign_iterators()
+{
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+ using It = ItType<T>;
+
+ std::inplace_vector<T, 10> v;
+
+ auto bounds = typename It::ContainerType(a, a+15);
+ v.assign(It(a, &bounds), It(a+5, &bounds));
+ VERIFY( eq<T>(v, {a, 5}) );
+
+ bounds = typename It::ContainerType(a, a+15);
+ v.assign(It(a, &bounds), It(a+7, &bounds));
+ VERIFY( eq<T>(v, {a, 7}) );
+
+ bounds = typename It::ContainerType(a, a+15);
+ v.assign(It(a, &bounds), It(a+3, &bounds));
+ VERIFY( eq<T>(v, {a, 3}) );
+
+ bounds = typename It::ContainerType(a, a+15);
+ v.assign(It(a, &bounds), It(a+10, &bounds));
+ VERIFY( eq<T>(v, {a, 10}) );
+}
+
+template<typename T>
+constexpr void
+test_assign_initializer_list()
+{
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+ std::inplace_vector<T, 10> v;
+
+ v.assign({T(1), T(2), T(3), T(4), T(5)});
+ VERIFY( eq<T>(v, {a, 5}) );
+
+ v = {T(1), T(2), T(3), T(4), T(5), T(6), T(7)};
+ VERIFY( eq<T>(v, {a, 7}) );
+
+ v.assign({T(1), T(2), T(3)});
+ VERIFY( eq<T>(v, {a, 3}) );
+
+ v = {T(1), T(2), T(3), T(4), T(5), T(6), T(7), T(8), T(9), T(10)};
+ VERIFY( eq<T>(v, {a, 10}) );
+}
+
+template<typename T>
+constexpr void
+test_assign_repeated()
+{
+ auto rep = [](const std::inplace_vector<T, 10>& v, size_t c, const T& t)
+ {
+ if (v.size() != c)
+ return false;
+ for (const T& o : v)
+ if (o != t)
+ return false;
+ return true;
+ };
+
+ std::inplace_vector<T, 10> v;
+
+ v.assign(5, T(1));
+ VERIFY( rep(v, 5, T(1)) );
+
+ v.assign(7, T(2));
+ VERIFY( rep(v, 7, T(2)) );
+
+ v.assign(3, T(4));
+ VERIFY( rep(v, 3, T(4)) );
+
+ v.assign(10, T(8));
+ VERIFY( rep(v, 10, T(8)) );
+}
+
+template<typename T>
+constexpr void
+test_resize()
+{
+ T a[]{1,1,1,1,2,2,2,0,0,0};
+
+ std::inplace_vector<T, 10> v;
+
+ v.resize(4, T(1));
+ VERIFY( eq<T>(v, {a, 4}) );
+
+ v.resize(7, T(2));
+ VERIFY( eq<T>(v, {a, 7}) );
+
+ v.resize(10);
+ VERIFY( eq<T>(v, {a, 10}) );
+
+ v.resize(6, T(1));
+ VERIFY( eq<T>(v, {a, 6}) );
+}
+
+template<typename T>
+constexpr void
+test_assigns()
+{
+ using namespace __gnu_test;
+ test_assign_range<test_forward_range<int>>();
+ test_assign_range<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ test_assign_range<test_input_range<int>>();
+ test_assign_range<test_input_sized_range<int>>();
+ test_assign_range<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ test_assign_range<test_range<int, input_iterator_wrapper_nocopy>>();
+ test_assign_range<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ test_assign_range<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ test_assign_iterators<T, input_iterator_wrapper>();
+ test_assign_iterators<T, forward_iterator_wrapper>();
+ test_assign_iterators<T, random_access_iterator_wrapper>();
+
+ test_assign_initializer_list<T>();
+ test_assign_repeated<T>();
+ test_resize<T>();
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_assign_empty<0, int>();
+ test_assign_empty<0, X>();
+ test_assign_empty<2, int>();
+
+ test_assigns<int>();
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error uncomemnt test_inserts<X>()
+#endif
+ if !consteval {
+ test_assign_empty<2, X>();
+ test_assigns<X>();
+ }
+ return true;
+ };
+
+
+ test_all();
+ static_assert(test_all());
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc
new file mode 100644
index 0000000..8b82ab4
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase.cc
@@ -0,0 +1,117 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::span<const T> r) {
+ if (l.size() != r.size())
+ return false;
+ for (auto i = 0u; i < l.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::initializer_list<T> r)
+{ return eq<T>(l, std::span<const T>(r)); }
+
+template<size_t N, typename T>
+constexpr void
+test_erase_all_or_none()
+{
+ using namespace __gnu_test;
+
+ T a[]{1,2,3,4,5,6,7,8,9};
+ const T c(10);
+
+ std::inplace_vector<T, N> src(std::from_range, std::span(a, a+N));
+ std::inplace_vector<T, N> v;
+
+ v = src;
+ auto it = v.erase(v.begin(), v.begin());
+ VERIFY( it == v.begin() );
+ VERIFY( eq<T>(v, {a, N}) );
+
+ it = v.erase(v.end(), v.end());
+ VERIFY( it == v.end() );
+ VERIFY( eq<T>(v, {a, N}) );
+
+ it = v.erase(v.begin(), v.end());
+ VERIFY( it == v.begin() );
+ VERIFY( v.empty() );
+
+ v = src;
+ v.clear();
+ VERIFY( v.empty() );
+}
+
+template<typename T>
+constexpr void
+test_erase()
+{
+ std::inplace_vector<T, 10> v{T(1), T(2), T(3), T(4), T(5), T(6), T(7)};
+
+ auto it = v.erase(v.begin());
+ VERIFY( eq<T>(v, {T(2), T(3), T(4), T(5), T(6), T(7)}) );
+ VERIFY( it == v.begin() );
+
+ it = v.erase(v.end()-1);
+ VERIFY( eq<T>(v, {T(2), T(3), T(4), T(5), T(6)}) );
+ VERIFY( it == v.end() );
+
+ it = v.erase(v.begin()+2, v.begin()+4);
+ VERIFY( eq<T>(v, {T(2), T(3), T(6)}) );
+ VERIFY( it == v.begin()+2 );
+
+ it = v.erase(v.end()-1, v.end());
+ VERIFY( eq<T>(v, {T(2), T(3)}) );
+ VERIFY( it == v.end() );
+
+ it = v.erase(v.begin(), v.begin()+1);
+ VERIFY( eq<T>(v, {T(3)}) );
+ VERIFY( it == v.begin() );
+
+ v.pop_back();
+ VERIFY( v.empty() );
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_erase_all_or_none<0, int>();
+ test_erase_all_or_none<0, X>();
+
+ test_erase_all_or_none<4, int>();
+
+ test_erase<int>();
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error uncomemnt test_inserts<X>()
+#endif
+ if ! consteval {
+ test_erase_all_or_none<4, X>();
+ }
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc
new file mode 100644
index 0000000..a1f43b3
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/erase_neg.cc
@@ -0,0 +1,43 @@
+// { dg-do compile { target c++26 } }
+
+#include <inplace_vector>
+
+template<size_t N, typename T>
+constexpr bool
+test_pop_back_on_empty()
+{
+ std::inplace_vector<T, N> v;
+ v.pop_back(); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<size_t N, typename T>
+constexpr bool
+test_erase_begin_on_empty()
+{
+ std::inplace_vector<T, N> v;
+ v.erase(v.begin()); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<size_t N, typename T>
+constexpr bool
+test_erase_end(size_t size = 0)
+{
+ std::inplace_vector<T, N> v(size, T());
+ v.erase(v.end()); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+static_assert(test_pop_back_on_empty<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_pop_back_on_empty<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_begin_on_empty<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_begin_on_empty<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_end<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_end<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_end<4, int>(2)); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_erase_end<4, int>(4)); // { dg-error "in 'constexpr' expansion of" }
+
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "is not a constant expression" }
+// { dg-prune-output "call to non-'constexpr' function" }
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc
new file mode 100644
index 0000000..6a5b62f
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/multi_insert.cc
@@ -0,0 +1,606 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::span<const T> r) {
+ if (l.size() != r.size())
+ return false;
+ for (auto i = 0u; i < l.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+prefix(const std::inplace_vector<V, N>& l, std::span<const T> r) {
+ if (l.size() < r.size())
+ return false;
+ for (auto i = 0u; i < r.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+};
+
+template<size_t N, typename T, template<class TT> class ItType>
+constexpr void
+test_add_to_full_it()
+{
+ using namespace __gnu_test;
+
+ T a[]{1,2,3,4,5,6,7,8,9};
+ using It = ItType<T>;
+ using Range = test_range<T, ItType>;
+ using SizedRange = test_sized_range<T, ItType>;
+
+ std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N));
+
+ Range r1(a, a);
+ auto rit1 = v.try_append_range(r1);
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( rit1.base() == a );
+
+ SizedRange r2(a, a);
+ auto rit2 = v.try_append_range(r2);
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( rit2.base() == a );
+
+ v.append_range(Range(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+ v.append_range(SizedRange(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+
+ auto it = v.insert_range(v.end(), Range(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.end() );
+ it = v.insert_range(v.end(), SizedRange(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.end() );
+
+ auto bounds = typename It::ContainerType(a, a+9);
+ it = v.insert(v.end(), It(a, &bounds), It(a, &bounds));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.end() );
+
+ it = v.insert_range(v.begin(), SizedRange(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.begin() );
+ it = v.insert_range(v.begin(), Range(a, a));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.begin() );
+
+ bounds = typename It::ContainerType(a, a+9);
+ it = v.insert(v.begin(), It(a, &bounds), It(a, &bounds));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.begin() );
+
+ // Inserting non-empty range
+ Range r3(a+3, a+5);
+ auto rit3 = v.try_append_range(r3);
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( rit3.base() == a+3 );
+
+ SizedRange r4(a+2, a+5);
+ auto rit4 = v.try_append_range(r4);
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( rit4.base() == a+2 );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ v.append_range(Range(a, a + 5));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.append_range(SizedRange(a, a + 5));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.insert_range(v.begin(), SizedRange(a, a+5));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.insert_range(v.begin(), Range(a, a+5));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ auto gn = std::ranges::sized_range<Range> || std::ranges::forward_range<Range> ? N : 0;
+ VERIFY( prefix<T>(v, {a, gn}) );
+
+ v = std::inplace_vector<T, N>(std::from_range, std::span(a, a+N));
+ try
+ {
+ v.insert_range(v.begin(), Range(a, a+5));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ gn = std::forward_iterator<It> ? N : 0;
+ VERIFY( prefix<T>(v, {a, gn}) );
+#endif
+}
+
+template<size_t N, typename T>
+constexpr void
+test_add_to_full_other()
+{
+ using namespace __gnu_test;
+
+ T a[]{1,2,3,4,5,6,7,8,9};
+ std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N));
+
+ auto it = v.insert(v.end(), {});
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.end() );
+ it = v.insert(v.end(), 0u, T(2));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.end() );
+
+ it = v.insert(v.begin(), {});
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.begin() );
+ it = v.insert(v.begin(), 0u, T(2));
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( it == v.begin() );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ v = std::inplace_vector<T, N>(std::from_range, std::span(a, a+N));
+ try
+ {
+ v.insert(v.begin(), {T(1), T(2), T(3)});
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.insert(v.begin(), 4u, T(3));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+#endif
+}
+
+
+template<size_t N, typename T>
+constexpr void
+test_add_to_full()
+{
+ using namespace __gnu_test;
+ test_add_to_full_it<N, T, input_iterator_wrapper>();
+ test_add_to_full_it<N, T, forward_iterator_wrapper>();
+ test_add_to_full_it<N, T, random_access_iterator_wrapper>();
+
+ test_add_to_full_other<N, T>();
+}
+
+template<typename Range>
+constexpr void
+test_append_range()
+{
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+ std::inplace_vector<T, 20> v;
+ v.append_range(Range(a,a+10));
+ VERIFY( eq<T>(v, {a, 10}) );
+
+ v.append_range(Range(a+10, a+15));
+ VERIFY( eq<T>(v, {a, 15}) );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ v.append_range(Range(a, a+10));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(v, {a, 15}) );
+#endif
+}
+
+template<typename Range>
+constexpr void
+test_try_append_range()
+{
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25};
+
+ std::inplace_vector<T, 20> v;
+ Range r1 = Range(a, a+10);
+ auto it1 = v.try_append_range(r1);
+ VERIFY( eq<T>(v, {a, 10}) );
+ VERIFY( it1.base() == a+10 );
+
+ Range r2 = Range(a+10, a+15);
+ auto it2 = v.try_append_range(r2);
+ VERIFY( eq<T>(v, {a, 15}) );
+ VERIFY( it2.base() == a+15 );
+
+ Range r3 = Range(a+15, a+25);
+ auto it3 = v.try_append_range(r3);
+ VERIFY( eq<T>(v, {a, 20}) );
+ VERIFY( it3.base() == a+20 );
+}
+
+template<typename Range>
+constexpr void
+test_insert_range()
+{
+ using T = std::ranges::range_value_t<Range>;
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+ std::inplace_vector<T, 20> v;
+ auto it = v.insert_range(v.begin(), Range(a+10,a+15));
+ VERIFY( eq<T>(v, {a+10, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert_range(v.begin(), Range(a, a+5));
+ VERIFY( prefix<T>(v, {a, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert_range(v.begin() + 5, Range(a+5, a+10));
+ VERIFY( eq<T>(v, {a, 15}) );
+ VERIFY( it == v.begin() + 5 );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ const bool seg = std::ranges::sized_range<Range> || std::ranges::forward_range<Range>;
+ auto vc = v;
+ try
+ {
+ vc.insert_range(vc.begin(), Range(a, a+10));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, seg ? 15 : 0}) );
+
+ vc = v;
+ try
+ {
+ vc.insert_range(vc.begin()+5, Range(a, a+10));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, seg ? 15 : 5}) );
+
+ vc = v;
+ try
+ {
+ vc.insert_range(vc.end(), Range(a, a+10));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, 15}) );
+#endif
+}
+
+template<typename Range>
+constexpr void
+do_test_ranges()
+{
+ test_append_range<Range>();
+ test_try_append_range<Range>();
+ test_insert_range<Range>();
+}
+
+template<typename T, template<class TT> class ItType>
+constexpr void
+test_insert_iterators()
+{
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+ using It = ItType<T>;
+
+ std::inplace_vector<T, 20> v;
+
+ auto bounds = typename It::ContainerType(a, a+15);
+ auto it = v.insert(v.begin(), It(a+10, &bounds), It(a+15, &bounds));
+ VERIFY( eq<T>(v, {a+10, 5}) );
+ VERIFY( it == v.begin() );
+
+ bounds = typename It::ContainerType(a, a+15);
+ it = v.insert(v.begin(), It(a, &bounds), It(a+5, &bounds));
+ VERIFY( prefix<T>(v, {a, 5}) );
+ VERIFY( it == v.begin() );
+
+ bounds = typename It::ContainerType(a, a+15);
+ it = v.insert(v.begin() + 5, It(a+5, &bounds), It(a+10, &bounds));
+ VERIFY( eq<T>(v, {a, 15}) );
+ VERIFY( it == v.begin() + 5 );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ const bool seg = std::forward_iterator<It>;
+ auto vc = v;
+ bounds = typename It::ContainerType(a, a+15);
+ try
+ {
+ vc.insert(vc.begin(), It(a, &bounds), It(a+10, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, seg ? 15 : 0}) );
+
+ vc = v;
+ bounds = typename It::ContainerType(a, a+15);
+ try
+ {
+ vc.insert(vc.begin()+5, It(a, &bounds), It(a+10, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, seg ? 15 : 5}) );
+
+ vc = v;
+ bounds = typename It::ContainerType(a, a+15);
+ try
+ {
+ vc.insert(vc.end(), It(a, &bounds), It(a+10, &bounds));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( prefix<T>(vc, {a, 15}) );
+#endif
+}
+
+template<typename T>
+constexpr void
+test_insert_initializer_list()
+{
+ T a[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+
+ std::inplace_vector<T, 20> v;
+
+ auto it = v.insert(v.begin(), {T(11), T(12), T(13), T(14), T(15)});
+ VERIFY( eq<T>(v, {a+10, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert(v.begin(), {T(1), T(2), T(3), T(4), T(5)});
+ VERIFY( prefix<T>(v, {a, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert(v.begin() + 5, {T(6), T(7), T(8), T(9), T(10)});
+ VERIFY( eq<T>(v, {a, 15}) );
+ VERIFY( it == v.begin() + 5 );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::initializer_list<T> il
+ = {T(0), T(1), T(2), T(3), T(4), T(5), T(6), T(7), T(8), T(9)};
+
+ try
+ {
+ v.insert(v.begin(), il);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+
+ try
+ {
+ v.insert(v.begin()+5, il);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+
+ try
+ {
+ v.insert(v.end(), il);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+#endif
+}
+
+template<typename T>
+constexpr void
+test_insert_repeated()
+{
+ T a[]{5,5,5,5,5,6,6,6,6,6,7,7,7,7,7};
+
+ std::inplace_vector<T, 20> v;
+
+ auto it = v.insert(v.begin(), 5, T(7));
+ VERIFY( eq<T>(v, {a+10, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert(v.begin(), 5, T(5));
+ VERIFY( prefix<T>(v, {a, 5}) );
+ VERIFY( it == v.begin() );
+
+ it = v.insert(v.begin() + 5, 5, T(6));
+ VERIFY( eq<T>(v, {a, 15}) );
+ VERIFY( it == v.begin() + 5 );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ v.insert(v.begin(), 10u, T(6));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+
+ try
+ {
+ v.insert(v.begin()+5, 10u, T(6));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+
+ try
+ {
+ v.insert(v.end(), 10u, T(6));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, 15}) );
+#endif
+}
+
+template<typename T>
+constexpr void
+test_inserts()
+{
+ using namespace __gnu_test;
+ do_test_ranges<test_forward_range<int>>();
+ do_test_ranges<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();
+
+ do_test_ranges<test_input_range<int>>();
+ do_test_ranges<test_input_sized_range<int>>();
+ do_test_ranges<test_sized_range_sized_sent<int, input_iterator_wrapper>>();
+
+ do_test_ranges<test_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_ranges<test_sized_range<int, input_iterator_wrapper_nocopy>>();
+ do_test_ranges<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();
+
+ test_insert_iterators<T, input_iterator_wrapper>();
+ test_insert_iterators<T, forward_iterator_wrapper>();
+ test_insert_iterators<T, random_access_iterator_wrapper>();
+
+test_insert_initializer_list<T>();
+test_insert_repeated<T>();
+}
+
+int main()
+{
+auto test_all = []{
+ test_add_to_full<0, int>();
+ test_add_to_full<0, X>();
+ test_add_to_full<4, int>();
+
+ test_inserts<int>();
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error uncomemnt test_inserts<X>()
+#endif
+ if !consteval {
+ test_add_to_full<4, X>();
+ test_inserts<X>();
+ }
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc
new file mode 100644
index 0000000..d5e893c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert.cc
@@ -0,0 +1,215 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<typename T, typename V, size_t N>
+constexpr bool
+eq(const std::inplace_vector<V, N>& l, std::span<const T> r) {
+ if (l.size() != r.size())
+ return false;
+ for (auto i = 0u; i < l.size(); ++i)
+ if (l[i] != r[i])
+ return false;
+ return true;
+};
+
+template<size_t N, typename T>
+constexpr void
+test_add_to_full()
+{
+ using namespace __gnu_test;
+
+ T a[]{1,2,3,4,5,6,7,8,9};
+ const T c(10);
+
+ std::inplace_vector<T, N> v(std::from_range, std::span(a, a+N));
+
+ VERIFY( v.try_emplace_back(1) == nullptr );
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( v.try_push_back(T(1)) == nullptr );
+ VERIFY( eq<T>(v, {a, N}) );
+ VERIFY( v.try_push_back(c) == nullptr );
+ VERIFY( eq<T>(v, {a, N}) );
+
+#ifdef __cpp_exceptions
+#ifdef __cpp_lib_constexpr_exceptions
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ try
+ {
+ v.emplace_back(1);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.push_back(T(1));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.push_back(c);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.insert(v.end(), T(1));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.insert(v.begin(), c);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.emplace(v.end(), c);
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+
+ try
+ {
+ v.emplace(v.begin(), T(2));
+ VERIFY(false);
+ }
+ catch (std::bad_alloc const&)
+ {
+ }
+ VERIFY( eq<T>(v, {a, N}) );
+#endif
+}
+
+template<typename T>
+constexpr void
+test_inserts()
+{
+ T a[]{3,14,13,1,2,3,4,5,3,7,8,3,10,11,3};
+ const T c(3);
+
+ std::inplace_vector<T, 20> v;
+
+ v.emplace_back(1);
+ VERIFY( eq<T>(v, {a+3, 1}) );
+ v.push_back(T(2));
+ VERIFY( eq<T>(v, {a+3, 2}) );
+ v.push_back(c);
+ VERIFY( eq<T>(v, {a+3, 3}) );
+
+ v.unchecked_emplace_back(4);
+ VERIFY( eq<T>(v, {a+3, 4}) );
+ v.unchecked_push_back(T(5));
+ VERIFY( eq<T>(v, {a+3, 5}) );
+ v.unchecked_push_back(c);
+ VERIFY( eq<T>(v, {a+3, 6}) );
+
+ T* ptr = v.try_emplace_back(7);
+ VERIFY( eq<T>(v, {a+3, 7}) );
+ VERIFY( ptr = &v.back() );
+ ptr = v.try_push_back(T(8));
+ VERIFY( eq<T>(v, {a+3, 8}) );
+ VERIFY( ptr = &v.back() );
+ ptr = v.try_push_back(c);
+ VERIFY( eq<T>(v, {a+3, 9}) );
+ VERIFY( ptr = &v.back() );
+
+ auto it = v.emplace(v.end(), 10);
+ VERIFY( eq<T>(v, {a+3, 10}) );
+ VERIFY( it == v.end()-1 );
+ it = v.insert(v.end(), T(11));
+ VERIFY( eq<T>(v, {a+3, 11}) );
+ VERIFY( it == v.end()-1 );
+ it = v.insert(v.end(), c);
+ VERIFY( eq<T>(v, {a+3, 12}) );
+ VERIFY( it == v.end()-1 );
+
+ it = v.emplace(v.begin(), 13);
+ VERIFY( eq<T>(v, {a+2, 13}) );
+ VERIFY( it == v.begin() );
+ it = v.insert(v.begin(), T(14));
+ VERIFY( eq<T>(v, {a+1, 14}) );
+ VERIFY( it == v.begin() );
+ it = v.insert(v.begin(), c);
+ VERIFY( eq<T>(v, {a+0, 15}) );
+ VERIFY( it == v.begin() );
+
+ it = v.emplace(v.begin()+2, 22);
+ VERIFY( *it == 22 );
+ VERIFY( it == v.begin()+2 );
+ it = v.insert(v.begin()+6, T(24));
+ VERIFY( *it == 24 );
+ VERIFY( it == v.begin()+6 );
+ it = v.insert(v.begin()+13, c);
+ VERIFY( *it == 3 );
+ VERIFY( it == v.begin()+13 );
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_add_to_full<0, int>();
+ test_add_to_full<0, X>();
+
+ test_add_to_full<4, int>();
+
+ test_inserts<int>();
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error uncomemnt test_inserts<X>()
+#endif
+ if ! consteval {
+ test_add_to_full<4, X>();
+ test_inserts<X>();
+ }
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc
new file mode 100644
index 0000000..0552b8c
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/modifiers/single_insert_neg.cc
@@ -0,0 +1,42 @@
+// { dg-do compile { target c++26 } }
+
+#include <inplace_vector>
+
+template<size_t N, typename T>
+constexpr bool
+test_unchecked_emplace_back()
+{
+ std::inplace_vector<T, N> v(N, T(1));
+ v.unchecked_emplace_back(); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<size_t N, typename T>
+constexpr bool
+test_push_back_lvalue()
+{
+ auto val = T();;
+ std::inplace_vector<T, N> v(N, T(1));
+ v.unchecked_push_back(val); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+template<size_t N, typename T>
+constexpr bool
+test_push_back_rvalue()
+{
+ std::inplace_vector<T, N> v(N, T(1));
+ v.unchecked_push_back(T()); // { dg-error "in 'constexpr' expansion of" }
+ return true;
+}
+
+static_assert(test_unchecked_emplace_back<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_unchecked_emplace_back<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_push_back_lvalue<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_push_back_lvalue<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_push_back_rvalue<0, int>()); // { dg-error "in 'constexpr' expansion of" }
+static_assert(test_push_back_rvalue<4, int>()); // { dg-error "in 'constexpr' expansion of" }
+
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "is not a constant expression" }
+// { dg-prune-output "call to non-'constexpr' function" }
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
new file mode 100644
index 0000000..5abcc87
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/move.cc
@@ -0,0 +1,358 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+#include <ranges>
+#include <testsuite_hooks.h>
+
+struct X
+{
+ X() = default;
+ constexpr X(int p) : v(p) {}
+ constexpr X(const X& o) : v(o.v) { } // not trivial
+ constexpr X(X&& o) : v(o.v) { } // not trivial
+
+ constexpr X& operator=(const X& o) // not trivial
+ { v = o.v; return *this; }
+ constexpr X& operator=(X&& o) // not trivial
+ { v = o.v; return *this; }
+
+ int v;
+
+ friend auto operator<=>(const X&, const X&) = default;
+};
+
+template<bool CNoex, bool ANoex>
+struct N
+{
+ N() = default;
+ constexpr N(N&&) noexcept(CNoex) { } // not trivial
+ constexpr N& operator=(N&& o) noexcept(ANoex) // not trivial
+ { return *this; }
+};
+
+struct D
+{
+ D() = default;
+ D(D&&) = default;
+ D& operator=(D&&) = default;
+ ~D() {} // not trivially destructible
+};
+
+struct U
+{
+ U() = default;
+ U(U&&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
+ U& operator=(U&&) noexcept(false) = default; // lies about noexcept, is trivial but throwing
+};
+
+template<bool SNoex, bool CNoex, bool ANoex>
+struct S {
+ S() = default;
+ constexpr S(S&&) noexcept(CNoex) { } // not trivial
+ constexpr S& operator=(S&& o) noexcept(ANoex) // not trivial
+ { return *this; }
+
+ friend constexpr
+ void swap(S&, S&) noexcept(SNoex) {}
+};
+
+// n5008 inplace.vector.overview says for inplace_vector<T, 0>
+// provides trivial copy/move/default cosntructpr regardless of T
+struct Z
+{
+ Z(const Z&) = delete;
+ Z& operator=(const Z&) = delete;
+};
+
+template<size_t N, typename T>
+ constexpr std::inplace_vector<T, N>
+ materialize(std::initializer_list<int> il)
+ {
+ std::inplace_vector<T, N> res;
+ for (int x : il)
+ res.emplace_back(x);
+ return res;
+ }
+
+static_assert(std::is_move_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_move_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_move_constructible_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_move_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_move_constructible_v<std::inplace_vector<U, 2>>);
+// The operators are not constrained, as for any other container
+static_assert(std::is_move_constructible_v<std::inplace_vector<Z, 2>>);
+
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<N<true, true>, 2>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<N<true, false>, 2>>);
+static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<N<false, true>, 2>>);
+static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_nothrow_move_constructible_v<std::inplace_vector<U, 2>>);
+
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<X, 2>>);
+static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<N<true, true>, 2>>);
+// is_trivially_move_constructible_v checks destructor
+static_assert(!std::is_trivially_move_constructible_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<U, 2>>);
+
+static_assert(std::is_move_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(std::is_move_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_move_assignable_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_move_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_move_assignable_v<std::inplace_vector<U, 2>>);
+// The operators are not constrained, as for any other container
+static_assert(std::is_move_assignable_v<std::inplace_vector<Z, 2>>);
+
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<N<true, true>, 2>>);
+static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<N<true, false>, 2>>);
+static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<N<false, true>, 2>>);
+static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_nothrow_move_assignable_v<std::inplace_vector<U, 2>>);
+
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<X, 2>>);
+static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<N<true, true>, 2>>);
+// destructor is not trivial
+static_assert(!std::is_trivially_move_assignable_v<std::inplace_vector<D, 2>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<U, 2>>);
+
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<int, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<X, 2>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<N<true, true>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<N<true, false>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<N<false, true>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<N<false, false>, 2>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<S<true, true, true>, 2>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<S<true, true, false>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<true, false, true>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<true, false, false>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<false, true, false>, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<S<false, false, false>, 2>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<D, 2>>);
+static_assert(!std::is_nothrow_swappable_v<std::inplace_vector<U, 2>>);
+
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_nothrow_move_constructible_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_trivially_move_constructible_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_nothrow_move_assignable_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_trivially_move_assignable_v<std::inplace_vector<Z, 0>>);
+
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<int, 0>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<X, 0>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<N<false, false>, 0>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<D, 0>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<U, 0>>);
+static_assert(std::is_nothrow_swappable_v<std::inplace_vector<Z, 0>>);
+
+template<typename T, size_t N>
+constexpr bool
+eq(const std::inplace_vector<T, N>& s, std::span<const T> o)
+{ return std::ranges::equal(s, o); }
+
+constexpr void
+test_ctor()
+{
+ auto e0 = materialize<0, int>({});
+ VERIFY( e0.empty() );
+ auto e1 = materialize<0, X>({});
+ VERIFY( e1.empty() );
+ auto e2 = materialize<0, Z>({});
+ VERIFY( e2.empty() );
+
+ auto c0 = materialize<5, int>({});
+ VERIFY( c0.empty() );
+
+ auto c3 = materialize<5, int>({1, 2, 3});
+ VERIFY( eq(c3, {1, 2, 3}) );
+
+ auto c5 = materialize<5, int>({1, 2, 3, 4, 5});
+ VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ auto x0 = materialize<3, X>({});
+ VERIFY( x0.empty() );
+
+ auto x2 = materialize<3, X>({1, 2});
+ VERIFY( eq(x2, {1, 2}) );
+
+ auto x3 = materialize<3, X>({1, 2, 3});
+ VERIFY( eq(x3, {1, 2, 3}) );
+}
+
+constexpr void
+test_assign()
+{
+ std::inplace_vector<int, 0> e0;
+ e0 = materialize<0, int>({});
+ VERIFY( e0.empty() );
+ std::inplace_vector<X, 0> e1;
+ e1 = materialize<0, X>({});
+ VERIFY( e1.empty() );
+ std::inplace_vector<Z, 0> e2;
+ e2 = materialize<0, Z>({});
+ VERIFY( e2.empty() );
+
+ std::inplace_vector<int, 5> c;
+ c = materialize<5, int>({});
+ VERIFY( c.empty() );
+
+ c = materialize<5, int>({1, 2, 3});
+ VERIFY( eq(c, {1, 2, 3}) );
+
+ c = materialize<5, int>({1, 2, 3, 4, 5});
+ VERIFY( eq(c, {1, 2, 3, 4, 5}) );
+
+ c = materialize<5, int>({4, 5});
+ VERIFY( eq(c, {4, 5}) );
+
+ c = materialize<5, int>({});
+ VERIFY( c.empty() );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> x;
+ x = materialize<5, X>({});
+ VERIFY( x.empty() );
+
+ x = materialize<5, X>({1, 2, 3});
+ VERIFY( eq(x, {1, 2, 3}) );
+
+ x = materialize<5, X>({1, 2, 3, 4, 5});
+ VERIFY( eq(x, {1, 2, 3, 4, 5}) );
+
+ x = materialize<5, X>({4, 5});
+ VERIFY( eq(x, {4, 5}) );
+
+ x = materialize<5, X>({});
+ VERIFY( x.empty() );
+}
+
+constexpr void
+test_swap()
+{
+ std::inplace_vector<int, 0> e0a, e0b;
+ swap(e0a, e0b);
+ VERIFY( e0a.empty() );
+ VERIFY( e0b.empty() );
+ e0a.swap(e0b);
+ VERIFY( e0a.empty() );
+ VERIFY( e0b.empty() );
+
+ std::inplace_vector<X, 0> e1a, e1b;
+ swap(e1a, e1b);
+ VERIFY( e1a.empty() );
+ VERIFY( e1b.empty() );
+ e1a.swap(e1b);
+ VERIFY( e1a.empty() );
+ VERIFY( e1b.empty() );
+
+ std::inplace_vector<Z, 0> e2a, e2b;
+ swap(e2a, e2b);
+ VERIFY( e2a.empty() );
+ VERIFY( e2b.empty() );
+ e2a.swap(e2b);
+ VERIFY( e2a.empty() );
+ VERIFY( e2b.empty() );
+
+ std::inplace_vector<int, 5> c0;
+ std::inplace_vector<int, 5> c3{1, 2, 3};
+ std::inplace_vector<int, 5> c5{1, 2, 3, 4, 5};
+
+ swap(c0, c3);
+ VERIFY( c3.empty() );
+ VERIFY( eq(c0, {1, 2, 3}) );
+ c0.swap(c3);
+ VERIFY( c0.empty() );
+ VERIFY( eq(c3, {1, 2, 3}) );
+
+ swap(c3, c5);
+ VERIFY( eq(c5, {1, 2, 3}) );
+ VERIFY( eq(c3, {1, 2, 3, 4, 5}) );
+ c5.swap(c3);
+ VERIFY( eq(c3, {1, 2, 3}) );
+ VERIFY( eq(c5, {1, 2, 3, 4, 5}) );
+
+#ifdef __cpp_lib_constexpr_inplace_vector
+#error remove the consteval check
+#endif
+ if consteval {
+ return;
+ }
+
+ std::inplace_vector<X, 5> x0;
+ std::inplace_vector<X, 5> x3 = {1, 2, 3};
+ std::inplace_vector<X, 5> x5 = {1, 2, 3, 4, 5};
+
+ swap(x0, x3);
+ VERIFY( x3.empty() );
+ VERIFY( eq(x0, {1, 2, 3}) );
+ x0.swap(x3);
+ VERIFY( x0.empty() );
+ VERIFY( eq(x3, {1, 2, 3}) );
+
+ swap(x3, x5);
+ VERIFY( eq(x5, {1, 2, 3}) );
+ VERIFY( eq(x3, {1, 2, 3, 4, 5}) );
+ x5.swap(x3);
+ VERIFY( eq(x3, {1, 2, 3}) );
+ VERIFY( eq(x5, {1, 2, 3, 4, 5}) );
+}
+
+constexpr auto e0 = materialize<0, int>({});
+constexpr auto e1 = materialize<0, X>({});
+constexpr auto e2 = materialize<0, Z>({});
+
+constexpr auto t1 = materialize<3, int>({});
+constexpr auto t2 = materialize<3, int>({1, 2});
+constexpr auto t3 = materialize<3, int>({11, 22, 33});
+
+int main()
+{
+ auto tests = [] {
+ test_ctor();
+ test_assign();
+ test_swap();
+ return true;
+ };
+
+ tests();
+ constexpr bool _ = tests();
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc
new file mode 100644
index 0000000..f9c5ce9
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/relops.cc
@@ -0,0 +1,60 @@
+// { dg-do run { target c++26 } }
+
+#include <inplace_vector>
+
+#include <span>
+#include <testsuite_hooks.h>
+
+template<size_t N, typename T>
+constexpr void
+test_equal(size_t c)
+{
+ T a[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
+ std::inplace_vector<T, N> v(a, a+c);
+ VERIFY( v == v );
+ VERIFY( !(v != v) );
+ VERIFY( !(v < v) );
+ VERIFY( !(v > v) );
+ VERIFY( v <= v );
+ VERIFY( v >= v );
+ VERIFY( (v <=> v) == 0 );
+}
+
+template<typename T>
+constexpr void
+test_not_equal()
+{
+ std::inplace_vector<T, 10> v3l{T{1}, T{2}, T{3}};
+ std::inplace_vector<T, 10> v3g{T{1}, T{3}, T{3}};
+ VERIFY( !(v3l == v3g) );
+ VERIFY( v3l != v3g );
+ VERIFY( v3l < v3g );
+ VERIFY( !(v3l > v3g) );
+ VERIFY( v3l <= v3g );
+ VERIFY( !(v3l >= v3g) );
+ VERIFY( (v3l <=> v3g) < 0 );
+
+ std::inplace_vector<T, 10> v2{T{1}, T{2}};
+ VERIFY( !(v2 == v3l) );
+ VERIFY( v2 != v3l );
+ VERIFY( v2 < v3l );
+ VERIFY( !(v2 > v3l) );
+ VERIFY( v2 <= v3l );
+ VERIFY( !(v2 >= v3l) );
+ VERIFY( (v2 <=> v3l) < 0 );
+}
+
+int main()
+{
+ auto test_all = [] {
+ test_equal<0, int>(0);
+ test_equal<4, int>(0);
+ test_equal<4, int>(2);
+ test_equal<4, int>(4);
+ test_not_equal<int>();
+ return true;
+ };
+
+ test_all();
+ static_assert(test_all());;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
new file mode 100644
index 0000000..a5bbdb8
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/inplace_vector/version.cc
@@ -0,0 +1,20 @@
+// { dg-do preprocess { target c++26 } }
+// { dg-add-options no_pch }
+
+#include <inplace_vector>
+
+#ifndef __cpp_lib_inplace_vector
+# error "Feature-test macro for inplace_vector missing in <inplace_vector>"
+#elif __cpp_lib_inplace_vector != 202406L
+# error "Feature-test macro for inplace_vector has wrong value in <inplace_vector>"
+#endif
+
+#undef __cpp_lib_inplace_vector
+
+#include <version>
+
+#ifndef __cpp_lib_inplace_vector
+# error "Feature-test macro for inplace_vector missing in <version>"
+#elif __cpp_lib_inplace_vector != 202406L
+# error "Feature-test macro for inplace_vector has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc
deleted file mode 100644
index c036f8a..0000000
--- a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/default.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// { dg-do run { target c++23 } }
-#include <mdspan>
-
-#include <testsuite_hooks.h>
-
-constexpr size_t dyn = std::dynamic_extent;
-
-template<typename Accessor>
- constexpr void
- test_accessor_policy()
- {
- static_assert(std::copyable<Accessor>);
- static_assert(std::is_nothrow_move_constructible_v<Accessor>);
- static_assert(std::is_nothrow_move_assignable_v<Accessor>);
- static_assert(std::is_nothrow_swappable_v<Accessor>);
- }
-
-constexpr bool
-test_access()
-{
- std::default_accessor<double> accessor;
- std::array<double, 5> a{10, 11, 12, 13, 14};
- VERIFY(accessor.access(a.data(), 0) == 10);
- VERIFY(accessor.access(a.data(), 4) == 14);
- return true;
-}
-
-constexpr bool
-test_offset()
-{
- std::default_accessor<double> accessor;
- std::array<double, 5> a{10, 11, 12, 13, 14};
- VERIFY(accessor.offset(a.data(), 0) == a.data());
- VERIFY(accessor.offset(a.data(), 4) == a.data() + 4);
- return true;
-}
-
-class Base
-{ };
-
-class Derived : public Base
-{ };
-
-constexpr void
-test_ctor()
-{
- // T -> T
- static_assert(std::is_nothrow_constructible_v<std::default_accessor<double>,
- std::default_accessor<double>>);
- static_assert(std::is_convertible_v<std::default_accessor<double>,
- std::default_accessor<double>>);
-
- // T -> const T
- static_assert(std::is_convertible_v<std::default_accessor<double>,
- std::default_accessor<const double>>);
- static_assert(std::is_convertible_v<std::default_accessor<Derived>,
- std::default_accessor<const Derived>>);
-
- // const T -> T
- static_assert(!std::is_constructible_v<std::default_accessor<double>,
- std::default_accessor<const double>>);
- static_assert(!std::is_constructible_v<std::default_accessor<Derived>,
- std::default_accessor<const Derived>>);
-
- // T <-> volatile T
- static_assert(std::is_convertible_v<std::default_accessor<int>,
- std::default_accessor<volatile int>>);
- static_assert(!std::is_constructible_v<std::default_accessor<int>,
- std::default_accessor<volatile int>>);
-
- // size difference
- static_assert(!std::is_constructible_v<std::default_accessor<char>,
- std::default_accessor<int>>);
-
- // signedness
- static_assert(!std::is_constructible_v<std::default_accessor<int>,
- std::default_accessor<unsigned int>>);
- static_assert(!std::is_constructible_v<std::default_accessor<unsigned int>,
- std::default_accessor<int>>);
-
- // Derived <-> Base
- static_assert(!std::is_constructible_v<std::default_accessor<Base>,
- std::default_accessor<Derived>>);
- static_assert(!std::is_constructible_v<std::default_accessor<Derived>,
- std::default_accessor<Base>>);
-
-}
-
-int
-main()
-{
- test_accessor_policy<std::default_accessor<double>>();
- test_access();
- static_assert(test_access());
- test_offset();
- static_assert(test_offset());
- test_ctor();
- return 0;
-}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc
new file mode 100644
index 0000000..c335035
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/accessors/generic.cc
@@ -0,0 +1,125 @@
+// { dg-do run { target c++23 } }
+#include <mdspan>
+
+#include <testsuite_hooks.h>
+
+template<typename Accessor>
+ constexpr bool
+ test_class_properties()
+ {
+ static_assert(std::is_trivially_copyable_v<Accessor>);
+ static_assert(std::semiregular<Accessor>);
+ return true;
+ }
+
+template<typename Accessor>
+ constexpr bool
+ test_accessor_policy()
+ {
+ static_assert(std::copyable<Accessor>);
+ static_assert(std::is_nothrow_move_constructible_v<Accessor>);
+ static_assert(std::is_nothrow_move_assignable_v<Accessor>);
+ static_assert(std::is_nothrow_swappable_v<Accessor>);
+ return true;
+ }
+
+class Base
+{ };
+
+class Derived : public Base
+{ };
+
+template<template<typename T> typename Accessor>
+ constexpr bool
+ test_ctor()
+ {
+ // T -> T
+ static_assert(std::is_nothrow_constructible_v<Accessor<double>,
+ Accessor<double>>);
+ static_assert(std::is_convertible_v<Accessor<double>, Accessor<double>>);
+
+ // T -> const T
+ static_assert(std::is_convertible_v<Accessor<double>,
+ Accessor<const double>>);
+ static_assert(std::is_convertible_v<Accessor<Derived>,
+ Accessor<const Derived>>);
+
+ // const T -> T
+ static_assert(!std::is_constructible_v<Accessor<double>,
+ Accessor<const double>>);
+ static_assert(!std::is_constructible_v<Accessor<Derived>,
+ Accessor<const Derived>>);
+
+ // T <-> volatile T
+ static_assert(std::is_convertible_v<Accessor<int>, Accessor<volatile int>>);
+ static_assert(!std::is_constructible_v<Accessor<int>,
+ Accessor<volatile int>>);
+
+ // size difference
+ static_assert(!std::is_constructible_v<Accessor<char>, Accessor<int>>);
+
+ // signedness
+ static_assert(!std::is_constructible_v<Accessor<int>,
+ Accessor<unsigned int>>);
+ static_assert(!std::is_constructible_v<Accessor<unsigned int>,
+ Accessor<int>>);
+
+ // Derived <-> Base
+ static_assert(!std::is_constructible_v<Accessor<Base>, Accessor<Derived>>);
+ static_assert(!std::is_constructible_v<Accessor<Derived>, Accessor<Base>>);
+ return true;
+ }
+
+template<template<typename T> typename Accessor>
+ constexpr bool
+ test_properties()
+ {
+ test_class_properties<Accessor<double>>();
+ test_accessor_policy<Accessor<double>>();
+ test_ctor<Accessor>();
+ return true;
+ }
+
+static_assert(test_properties<std::default_accessor>());
+
+template<typename A>
+ constexpr size_t
+ accessor_alignment = alignof(typename A::element_type);
+
+template<typename Accessor>
+ constexpr void
+ test_access(Accessor accessor)
+ {
+ constexpr size_t N = accessor_alignment<Accessor>;
+ alignas(N) std::array<double, 5> a{10, 11, 12, 13, 14};
+ for (size_t i = 0; i < a.size(); ++i)
+ VERIFY(accessor.access(a.data(), i) == 10 + i);
+ }
+
+template<typename Accessor>
+ constexpr void
+ test_offset(Accessor accessor)
+ {
+ constexpr size_t N = accessor_alignment<Accessor>;
+ alignas(N) std::array<double, 5> a{10, 11, 12, 13, 14};
+ for (size_t i = 0; i < a.size(); ++i)
+ VERIFY(accessor.offset(a.data(), i) == a.data() + i);
+ }
+
+template<typename Accessor>
+ constexpr bool
+ test_all()
+ {
+ auto accessor = Accessor{};
+ test_offset(accessor);
+ test_access(accessor);
+ return true;
+ }
+
+int
+main()
+{
+ test_all<std::default_accessor<double>>();
+ static_assert(test_all<std::default_accessor<double>>());
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
index 3a70efd..d5f07c1 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_ints.cc
@@ -35,20 +35,20 @@ test_all()
auto expected = std::extents<int, 1, 2, 3>(1, 2, 3);
// From all extents.
- VERIFY((std::extents<int, 1, 2, 3>(1, 2, 3)) == expected);
- VERIFY((std::extents<int, dyn, 2, 3>(1, 2, 3)) == expected);
- VERIFY((std::extents<int, dyn, 2, dyn>(1, 2, 3)) == expected);
+ VERIFY(std::extents<int, 1, 2, 3>(1, 2, 3) == expected);
+ VERIFY(std::extents<int, dyn, 2, 3>(1, 2, 3) == expected);
+ VERIFY(std::extents<int, dyn, 2, dyn>(1, 2, 3) == expected);
- VERIFY((std::extents<int, 1, 2, 3>{1, 2, 3}) == expected);
- VERIFY((std::extents<int, dyn, 2, 3>{1, 2, 3}) == expected);
- VERIFY((std::extents<int, dyn, 2, dyn>{1, 2, 3}) == expected);
+ VERIFY(std::extents<int, 1, 2, 3>{1, 2, 3} == expected);
+ VERIFY(std::extents<int, dyn, 2, 3>{1, 2, 3} == expected);
+ VERIFY(std::extents<int, dyn, 2, dyn>{1, 2, 3} == expected);
// From only dynamic extents.
- VERIFY((std::extents<int, dyn, 2, 3>(1)) == expected);
- VERIFY((std::extents<int, dyn, 2, dyn>(1, 3)) == expected);
+ VERIFY(std::extents<int, dyn, 2, 3>(1) == expected);
+ VERIFY(std::extents<int, dyn, 2, dyn>(1, 3) == expected);
- VERIFY((std::extents<int, dyn, 2, 3>{1}) == expected);
- VERIFY((std::extents<int, dyn, 2, dyn>{1, 3}) == expected);
+ VERIFY(std::extents<int, dyn, 2, 3>{1} == expected);
+ VERIFY(std::extents<int, dyn, 2, dyn>{1, 3} == expected);
return true;
}
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc
index 01624f2..1682cc5 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/extents/ctor_shape.cc
@@ -66,9 +66,9 @@ namespace all_extents
test_ctor(Shape shape)
{
auto expected = std::extents<int, 1, 2, 3>();
- VERIFY((std::extents<int, 1, dyn, 3>(shape)) == expected);
- VERIFY((std::extents<int, dyn, dyn, dyn>(shape)) == expected);
- VERIFY((std::extents<int, 1, 2, 3>(shape)) == expected);
+ VERIFY(std::extents<int, 1, dyn, 3>(shape) == expected);
+ VERIFY(std::extents<int, dyn, dyn, dyn>(shape) == expected);
+ VERIFY(std::extents<int, 1, 2, 3>(shape) == expected);
}
constexpr void
@@ -90,8 +90,8 @@ namespace all_extents
auto span = std::span<int, 0>(shape);
auto expected = std::extents<int>();
- VERIFY((std::extents<int>(shape)) == expected);
- VERIFY((std::extents<int>(span)) == expected);
+ VERIFY(std::extents<int>(shape) == expected);
+ VERIFY(std::extents<int>(span) == expected);
}
constexpr bool
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h b/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h
index 6a0f8ca..ded6e9d 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layout_like.h
@@ -1,83 +1,87 @@
#ifndef TEST_MDSPAN_LAYOUT_LIKE_H
#define TEST_MDSPAN_LAYOUT_LIKE_H 1
-struct LayoutLike
-{
- template<typename Extents>
- class mapping
- {
- public:
- using extents_type = Extents;
- using index_type = typename extents_type::index_type;
- using size_type = typename extents_type::size_type;
- using rank_type = typename extents_type::rank_type;
- using layout_type = LayoutLike;
-
- constexpr
- mapping() noexcept = default;
-
- constexpr
- mapping(Extents exts)
- : m_exts(exts)
- { }
-
- constexpr const extents_type&
- extents() const noexcept { return m_exts; }
-
- constexpr index_type
- required_span_size() const noexcept
+template<bool Noexcept>
+ struct CustomLayout
+ {
+ template<typename Extents>
+ class mapping
{
- for (size_t i = 0; i < extents_type::rank(); ++i)
- if (m_exts.extent(i) == 0)
- return 0;
- return 1;
- }
-
- template<typename... Indices>
- requires (sizeof...(Indices) == extents_type::rank())
+ public:
+ using extents_type = Extents;
+ using index_type = typename extents_type::index_type;
+ using size_type = typename extents_type::size_type;
+ using rank_type = typename extents_type::rank_type;
+ using layout_type = CustomLayout;
+
+ constexpr
+ mapping() noexcept = default;
+
+ constexpr
+ mapping(Extents exts)
+ : m_exts(exts)
+ { }
+
+ constexpr const extents_type&
+ extents() const noexcept(Noexcept) { return m_exts; }
+
constexpr index_type
- operator()(Indices...) const noexcept
+ required_span_size() const noexcept(Noexcept)
+ {
+ for (size_t i = 0; i < extents_type::rank(); ++i)
+ if (m_exts.extent(i) == 0)
+ return 0;
+ return 1;
+ }
+
+ template<typename... Indices>
+ requires (sizeof...(Indices) == extents_type::rank())
+ constexpr index_type
+ operator()(Indices...) const noexcept(Noexcept)
+ { return 0; }
+
+ static constexpr index_type
+ stride(rank_type) noexcept(Noexcept)
{ return 0; }
- static constexpr index_type
- stride(rank_type) noexcept
- { return 0; }
+ static constexpr bool
+ is_always_unique() noexcept(Noexcept)
+ { return false; }
- static constexpr bool
- is_always_unique() noexcept
- { return false; }
+ static constexpr bool
+ is_always_exhaustive() noexcept(Noexcept)
+ { return true; }
- static constexpr bool
- is_always_exhaustive() noexcept
- { return true; }
+ static constexpr bool
+ is_always_strided() noexcept(Noexcept)
+ { return true; }
- static constexpr bool
- is_always_strided() noexcept
- { return true; }
+ constexpr bool
+ is_unique() const noexcept(Noexcept)
+ {
+ if (required_span_size() == 0)
+ return true;
- constexpr bool
- is_unique() noexcept
- {
- if (required_span_size() == 0)
+ for (size_t i = 0; i < extents_type::rank(); ++i)
+ if (m_exts.extent(i) > 1)
+ return false;
return true;
+ }
- for (size_t i = 0; i < extents_type::rank(); ++i)
- if (m_exts.extent(i) > 1)
- return false;
- return true;
- }
+ static constexpr bool
+ is_exhaustive() noexcept(Noexcept)
+ { return true; }
- static constexpr bool
- is_exhaustive() noexcept
- { return true; }
+ static constexpr bool
+ is_strided() noexcept(Noexcept)
+ { return true; }
- static constexpr bool
- is_strided() noexcept
- { return true; }
+ private:
+ Extents m_exts;
+ };
+ };
- private:
- Extents m_exts;
- };
-};
+using LayoutLike = CustomLayout<true>;
+using ThrowingLayout = CustomLayout<false>;
#endif
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
index be4a1b1..bdfc6eb 100644
--- a/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/mdspan.cc
@@ -4,6 +4,7 @@
#include <testsuite_hooks.h>
#include "int_like.h"
#include "layout_like.h"
+#include <stdexcept>
constexpr auto dyn = std::dynamic_extent;
@@ -114,6 +115,27 @@ test_class_properties_all()
return true;
}
+template<typename T>
+ class ThrowingDefaultAccessor
+ {
+ public:
+ using element_type = T;
+ using reference = element_type&;
+ using data_handle_type = element_type*;
+ using offset_policy = ThrowingDefaultAccessor;
+
+ ThrowingDefaultAccessor() noexcept(false)
+ { }
+
+ reference
+ access(data_handle_type p, size_t i) const
+ { return p[i]; }
+
+ typename offset_policy::data_handle_type
+ offset(data_handle_type p, size_t i) const
+ { return p + i; }
+ };
+
constexpr bool
test_default_ctor()
{
@@ -130,6 +152,18 @@ test_default_ctor()
return true;
}
+template<template<typename T> typename Accessor, bool Expected>
+ constexpr void
+ test_nothrow_default_ctor()
+ {
+ using Extents = std::extents<int, dyn>;
+ using Layout = std::layout_left;
+ using MDSpan = std::mdspan<double, Extents, Layout, Accessor<double>>;
+
+ static_assert(std::is_default_constructible_v<MDSpan>);
+ static_assert(std::is_nothrow_default_constructible_v<MDSpan> == Expected);
+ }
+
constexpr bool
test_from_other()
{
@@ -206,9 +240,9 @@ test_from_pointer_and_shape()
assert_deduced_typedefs<double, std::dextents<size_t, 2>>(md);
VERIFY(md.rank() == 2);
VERIFY(md.rank_dynamic() == 2);
- VERIFY((md[0, 0]) == data[0]);
- VERIFY((md[0, 1]) == data[1]);
- VERIFY((md[1, 0]) == data[3]);
+ VERIFY(md[0, 0] == data[0]);
+ VERIFY(md[0, 1] == data[1]);
+ VERIFY(md[1, 0] == data[3]);
};
verify(std::mdspan(data.data(), shape[0], shape[1]));
@@ -428,10 +462,10 @@ test_from_opaque_accessor()
using MDSpan = decltype(md);
static_assert(std::same_as<MDSpan::accessor_type, decltype(a)>);
- VERIFY((md[0, 0, 0]) == 0.0);
+ VERIFY(md[0, 0, 0] == 0.0);
VERIFY(md.accessor().access_count == 1);
- VERIFY((md[2, 4, 6]) == 0.0);
+ VERIFY(md[2, 4, 6] == 0.0);
VERIFY(md.accessor().access_count == 2);
}
@@ -480,8 +514,8 @@ test_from_base_class_accessor()
using MDSpan = decltype(md);
static_assert(std::same_as<MDSpan::accessor_type, decltype(a)>);
static_assert(std::same_as<decltype(md[0, 0, 0]), Base&>);
- VERIFY((md[0, 0, 0].value) == 1.0);
- VERIFY((md[2, 4, 6].value) == 1.0);
+ VERIFY(md[0, 0, 0].value == 1.0);
+ VERIFY(md[2, 4, 6].value == 1.0);
}
constexpr bool
@@ -490,8 +524,8 @@ test_from_mapping_like()
double data = 1.1;
auto m = LayoutLike::mapping<std::extents<int, 1, 2, 3>>{};
auto md = std::mdspan(&data, m);
- VERIFY((md[0, 0, 0]) == data);
- VERIFY((md[0, 1, 2]) == data);
+ VERIFY(md[0, 0, 0] == data);
+ VERIFY(md[0, 1, 2] == data);
return true;
}
@@ -535,13 +569,13 @@ template<typename Int, bool ValidForPacks, bool ValidForArrays>
{
storage[mapping(i, j, k)] = 1.0;
if constexpr (ValidForPacks)
- VERIFY((md[Int(i), Int(j), Int(k)]) == 1.0);
+ VERIFY(md[Int(i), Int(j), Int(k)] == 1.0);
if constexpr (ValidForArrays)
{
std::array<Int, 3> ijk{Int(i), Int(j), Int(k)};
- VERIFY((md[ijk]) == 1.0);
- VERIFY((md[std::span(ijk)]) == 1.0);
+ VERIFY(md[ijk] == 1.0);
+ VERIFY(md[std::span(ijk)] == 1.0);
}
storage[mapping(i, j, k)] = 0.0;
}
@@ -650,6 +684,21 @@ test_nothrow_movable_all()
test_nothrow_movable<false, false>();
}
+template<typename Layout, bool Expected>
+ constexpr void
+ test_nothrow_is_methods()
+ {
+ using Extents = std::extents<int, dyn>;
+ using MDSpan = std::mdspan<double, Extents, Layout>;
+ static_assert(noexcept(MDSpan::is_always_unique()) == Expected);
+ static_assert(noexcept(MDSpan::is_always_exhaustive()) == Expected);
+ static_assert(noexcept(MDSpan::is_always_strided()) == Expected);
+
+ static_assert(noexcept(std::declval<MDSpan>().is_unique()) == Expected);
+ static_assert(noexcept(std::declval<MDSpan>().is_exhaustive()) == Expected);
+ static_assert(noexcept(std::declval<MDSpan>().is_strided()) == Expected);
+ }
+
int
main()
{
@@ -668,6 +717,9 @@ main()
test_default_ctor();
static_assert(test_default_ctor());
+ test_nothrow_default_ctor<std::default_accessor, true>();
+ test_nothrow_default_ctor<ThrowingDefaultAccessor, false>();
+
test_from_other();
static_assert(test_from_other());
@@ -713,5 +765,7 @@ main()
test_swap_adl();
test_nothrow_movable_all();
+ test_nothrow_is_methods<std::layout_right, true>();
+ test_nothrow_is_methods<ThrowingLayout, false>();
return 0;
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc
index 339c06bd..516d888 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc
@@ -42,14 +42,16 @@ do_test(Alloc alloc)
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range>(std::allocator<bool>());
- do_test<Range>(__gnu_test::uneq_allocator<bool>(42));
+ if not consteval {
+ do_test<Range>(__gnu_test::uneq_allocator<bool>(42));
+ }
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -71,9 +73,9 @@ test_ranges()
// Not lvalue-convertible to bool
struct C {
- C(bool v) : val(v) { }
- operator bool() && { return val; }
- bool operator==(bool b) const { return b == val; }
+ constexpr C(bool v) : val(v) { }
+ constexpr operator bool() && { return val; }
+ constexpr bool operator==(bool b) const { return b == val; }
bool val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -82,16 +84,8 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
-{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<bool>>(std::allocator<bool>());
- return true;
-}
-
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+ static_assert( test_ranges() );
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc
index 7e58700..ced7efe 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc
@@ -59,14 +59,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<bool>>();
do_test<Range, __gnu_test::SimpleAllocator<bool>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -88,9 +88,9 @@ test_ranges()
// Not lvalue-convertible to bool
struct C {
- C(bool v) : val(v) { }
- operator bool() && { return val; }
- bool operator==(bool b) const { return b == val; }
+ constexpr C(bool v) : val(v) { }
+ constexpr operator bool() && { return val; }
+ constexpr bool operator==(bool b) const { return b == val; }
bool val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -99,16 +99,8 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
-{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>, std::allocator<bool>>();
- return true;
-}
-
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+ static_assert( test_ranges() );
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc
index 43a698f..c2e2186 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc
@@ -38,14 +38,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<bool>>();
do_test<Range, __gnu_test::SimpleAllocator<bool>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -67,9 +67,9 @@ test_ranges()
// Not lvalue-convertible to bool
struct C {
- C(bool v) : val(v) { }
- operator bool() && { return val; }
- bool operator==(bool b) const { return b == val; }
+ constexpr C(bool v) : val(v) { }
+ constexpr operator bool() && { return val; }
+ constexpr bool operator==(bool b) const { return b == val; }
bool val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -81,8 +81,7 @@ test_ranges()
constexpr bool
test_constexpr()
{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>, std::allocator<bool>>();
+ test_ranges();
// Some basic tests for overlapping ranges in constant expressions.
using I = std::vector<bool>::iterator;
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc
index 5c65610..2ec91b0 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc
@@ -55,14 +55,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<bool>>();
do_test<Range, __gnu_test::SimpleAllocator<bool>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -84,9 +84,9 @@ test_ranges()
// Not lvalue-convertible to bool
struct C {
- C(bool v) : val(v) { }
- operator bool() && { return val; }
- bool operator==(bool b) const { return b == val; }
+ constexpr C(bool v) : val(v) { }
+ constexpr operator bool() && { return val; }
+ constexpr bool operator==(bool b) const { return b == val; }
bool val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -95,16 +95,8 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
-{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<bool>, std::allocator<bool>>();
- return true;
-}
-
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+ static_assert( test_ranges() );
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc
index 3784b9c..be3e699 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc
@@ -58,14 +58,16 @@ do_test(Alloc alloc)
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range>(std::allocator<int>());
- do_test<Range>(__gnu_test::uneq_allocator<int>(42));
+ if not consteval {
+ do_test<Range>(__gnu_test::uneq_allocator<int>(42));
+ }
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -87,9 +89,9 @@ test_ranges()
// Not lvalue-convertible to int
struct C {
- C(int v) : val(v) { }
- operator int() && { return val; }
- bool operator==(int b) const { return b == val; }
+ constexpr C(int v) : val(v) { }
+ constexpr operator int() && { return val; }
+ constexpr bool operator==(int b) const { return b == val; }
int val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -98,14 +100,6 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
-{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>>(std::allocator<int>());
- return true;
-}
-
void
test_pr120367()
{
@@ -130,6 +124,6 @@ test_pr120367()
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+ static_assert( test_ranges() );
test_pr120367();
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc
index be097e2..f5b21df 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc
@@ -42,14 +42,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<int>>();
do_test<Range, __gnu_test::SimpleAllocator<int>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -71,9 +71,9 @@ test_ranges()
// Not lvalue-convertible to int
struct C {
- C(int v) : val(v) { }
- operator int() && { return val; }
- bool operator==(int b) const { return b == val; }
+ constexpr C(int v) : val(v) { }
+ constexpr operator int() && { return val; }
+ constexpr bool operator==(int b) const { return b == val; }
int val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -82,7 +82,7 @@ test_ranges()
return true;
}
-void
+constexpr void
test_overlapping()
{
using __gnu_test::test_input_range;
@@ -199,64 +199,14 @@ test_overlapping()
}
}
-constexpr bool
-test_constexpr()
+int main()
{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>, std::allocator<int>>();
-
- // Some basic tests for overlapping ranges in constant expressions.
- struct InputRange
- {
- struct Sent { const void* end; };
-
- struct Iter
- {
- using value_type = int;
- using difference_type = int;
- constexpr explicit Iter(int* p) : ptr(p) { }
- constexpr Iter& operator++() { ++ptr; return *this; }
- constexpr Iter operator++(int) { auto i = *this; ++ptr; return i; }
- constexpr int operator*() const { return *ptr; }
- constexpr bool operator==(const Iter&) const = default;
- constexpr bool operator==(const Sent& s) const { return ptr == s.end; }
- int* ptr;
- };
-
- Iter iter;
- Sent sent;
-
- constexpr InputRange(int* f, int* l) : iter{f}, sent{l} { }
- constexpr Iter begin() const { return iter; }
- constexpr Sent end() const { return sent; }
+ auto test_all = [] {
+ test_ranges();
+ test_overlapping();
+ return true;
};
- static_assert( std::ranges::input_range<InputRange> );
- static_assert( ! std::ranges::forward_range<InputRange> );
-
- std::vector<int> vec(5);
-
- // Test overlapping input ranges
- vec.resize(vec.capacity());
- vec.append_range(InputRange(vec.data(), vec.data() + 3)); // no capacity
- vec.reserve(vec.capacity() + 2);
- vec.append_range(InputRange(vec.data(), vec.data() + 4)); // some capacity
- vec.reserve(vec.capacity() + 6);
- vec.append_range(InputRange(vec.data(), vec.data() + 5)); // enough capacity
-
- // Test overlapping forward ranges
- vec.resize(vec.capacity());
- vec.append_range(std::span<int>(vec)); // no capacity
- vec.reserve(vec.size() + 2);
- vec.append_range(std::span<int>(vec).subspan(1, 4)); // some capacity
- vec.reserve(vec.size() + 6);
- vec.append_range(std::span<int>(vec).subspan(1, 5)); // enough capacity
- return true;
-}
-
-int main()
-{
- test_ranges();
- test_overlapping();
- static_assert( test_constexpr() );
+ test_all();
+ static_assert( test_all() );
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc
index db3b06c..26d33bc 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc
@@ -63,14 +63,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<int>>();
do_test<Range, __gnu_test::SimpleAllocator<int>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -92,9 +92,9 @@ test_ranges()
// Not lvalue-convertible to int
struct C {
- C(int v) : val(v) { }
- operator int() && { return val; }
- bool operator==(int b) const { return b == val; }
+ constexpr C(int v) : val(v) { }
+ constexpr operator int() && { return val; }
+ constexpr bool operator==(int b) const { return b == val; }
int val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -103,16 +103,8 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
-{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>, std::allocator<int>>();
- return true;
-}
-
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+ static_assert( test_ranges() );
}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc
index 5907143..506bebb 100644
--- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc
+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc
@@ -59,14 +59,14 @@ do_test()
}
template<typename Range>
-void
+constexpr void
do_test_a()
{
do_test<Range, std::allocator<int>>();
do_test<Range, __gnu_test::SimpleAllocator<int>>();
}
-bool
+constexpr bool
test_ranges()
{
using namespace __gnu_test;
@@ -88,9 +88,9 @@ test_ranges()
// Not lvalue-convertible to int
struct C {
- C(int v) : val(v) { }
- operator int() && { return val; }
- bool operator==(int b) const { return b == val; }
+ constexpr C(int v) : val(v) { }
+ constexpr operator int() && { return val; }
+ constexpr bool operator==(int b) const { return b == val; }
int val;
};
using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;
@@ -99,16 +99,8 @@ test_ranges()
return true;
}
-constexpr bool
-test_constexpr()
-{
- // XXX: this doesn't test the non-forward_range code paths are constexpr.
- do_test<std::span<short>, std::allocator<int>>();
- return true;
-}
-
int main()
{
test_ranges();
- static_assert( test_constexpr() );
+ static_assert( test_ranges() );
}
diff --git a/libstdc++-v3/testsuite/24_iterators/random_access/string_vector_iterators.cc b/libstdc++-v3/testsuite/24_iterators/random_access/string_vector_iterators.cc
index a8dbe51..22803e7 100644
--- a/libstdc++-v3/testsuite/24_iterators/random_access/string_vector_iterators.cc
+++ b/libstdc++-v3/testsuite/24_iterators/random_access/string_vector_iterators.cc
@@ -17,238 +17,162 @@
// along with this program; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-
#include <string>
#include <vector>
#include <testsuite_hooks.h>
-int
+void
string_stuff()
{
- int failures(0);
-
std::string s("abcde");
std::string::iterator i1(s.begin());
- if (*i1 != 'a')
- ++failures;
+ VERIFY( *i1 == 'a' );
++i1;
- if (*i1 != 'b')
- ++failures;
+ VERIFY( *i1 == 'b' );
- if (*i1++ != 'b')
- ++failures;
- if (*i1 != 'c')
- ++failures;
+ VERIFY( *i1++ == 'b' );
+ VERIFY( *i1 == 'c' );
++ ++i1;
- if (*i1 != 'e')
- ++failures;
+ VERIFY( *i1 == 'e' );
--i1;
- if (*i1 != 'd')
- ++failures;
+ VERIFY( *i1 == 'd' );
- if (*i1-- != 'd')
- ++failures;
- if (*i1 != 'c')
- ++failures;
+ VERIFY( *i1-- == 'd' );
+ VERIFY( *i1 == 'c' );
-- --i1;
- if (*i1 != 'a')
- ++failures;
+ VERIFY( *i1 == 'a' );
std::string::iterator i2;
i2 = s.end();
std::iterator_traits<std::string::iterator>::difference_type d1;
d1 = i2 - i1;
- if (d1 != 5)
- ++failures;
+ VERIFY( d1 == 5 );
std::iterator_traits<std::string::iterator>::value_type v1;
v1 = i1[0];
- if (v1 != 'a')
- ++failures;
+ VERIFY( v1 == 'a' );
std::iterator_traits<std::string::iterator>::reference r1(i1[0]);
- if (r1 != 'a')
- ++failures;
+ VERIFY( r1 == 'a' );
r1 = 'x';
- if (r1 != 'x')
- ++failures;
+ VERIFY( r1 == 'x' );
r1 = 'a';
- if ((i1 != i2) != true)
- ++failures;
- if ((i1 == i2) != false)
- ++failures;
- if ((i1 < i2) != true)
- ++failures;
- if ((i1 > i2) != false)
- ++failures;
- if ((i1 <= i2) != true)
- ++failures;
- if ((i1 >= i2) != false)
- ++failures;
+ VERIFY( (i1 != i2) == true );
+ VERIFY( (i1 == i2) == false );
+ VERIFY( (i1 < i2) == true );
+ VERIFY( (i1 > i2) == false );
+ VERIFY( (i1 <= i2) == true );
+ VERIFY( (i1 >= i2) == false );
std::string::iterator i3;
i3 = i1;
- if ((i3 == i1) != true)
- ++failures;
+ VERIFY( (i3 == i1) == true );
i3 += 5;
- if ((i3 == i2) != true)
- ++failures;
+ VERIFY( (i3 == i2) == true );
i3 -= 5;
- if ((i3 == i1) != true)
- ++failures;
-
- if (i3 + 5 != i2)
- ++failures;
-
- if (5 + i3 != i2)
- ++failures;
+ VERIFY( (i3 == i1) == true );
- if (i2 - 5 != i3)
- ++failures;
+ VERIFY( i3 + 5 == i2 );
+ VERIFY( 5 + i3 == i2 );
+ VERIFY( i2 - 5 == i3 );
- if (i1[0] != 'a')
- ++failures;
+ VERIFY( i1[0] == 'a' );
i1[4] = 'x';
- if (i2[-1] != 'x')
- ++failures;
+ VERIFY( i2[-1] == 'x' );
i1[4] = 'e';
i1[2] = 'x';
- if (i2[-3] != 'x')
- ++failures;
+ VERIFY( i2[-3] == 'x' );
i1[2] = 'c';
std::string::const_iterator ci1(s.begin());
- if (*ci1 != 'a')
- ++failures;
+ VERIFY( *ci1 == 'a' );
++ci1;
- if (*ci1 != 'b')
- ++failures;
+ VERIFY( *ci1 == 'b' );
- if (*ci1++ != 'b')
- ++failures;
- if (*ci1 != 'c')
- ++failures;
+ VERIFY( *ci1++ == 'b' );
+ VERIFY( *ci1 == 'c' );
++ ++ci1;
- if (*ci1 != 'e')
- ++failures;
+ VERIFY( *ci1 == 'e' );
--ci1;
- if (*ci1 != 'd')
- ++failures;
+ VERIFY( *ci1 == 'd' );
- if (*ci1-- != 'd')
- ++failures;
- if (*ci1 != 'c')
- ++failures;
+ VERIFY( *ci1-- == 'd' );
+ VERIFY( *ci1 == 'c' );
-- --ci1;
- if (*ci1 != 'a')
- ++failures;
+ VERIFY( *ci1 == 'a' );
std::string::const_iterator ci2;
ci2 = s.end();
std::iterator_traits<std::string::const_iterator>::difference_type d2;
d2 = ci2 - ci1;
- if (d2 != 5)
- ++failures;
+ VERIFY( d2 == 5 );
std::iterator_traits<std::string::const_iterator>::value_type v2;
v2 = ci1[0];
- if (v2 != 'a')
- ++failures;
+ VERIFY( v2 == 'a' );
std::iterator_traits<std::string::const_iterator>::reference r2(ci1[0]);
- if (r2 != 'a')
- ++failures;
-
- if ((ci1 != ci2) != true)
- ++failures;
- if ((ci1 == ci2) != false)
- ++failures;
- if ((ci1 < ci2) != true)
- ++failures;
- if ((ci1 > ci2) != false)
- ++failures;
- if ((ci1 <= ci2) != true)
- ++failures;
- if ((ci1 >= ci2) != false)
- ++failures;
+ VERIFY( r2 == 'a' );
+
+ VERIFY( (ci1 != ci2) == true );
+ VERIFY( (ci1 == ci2) == false );
+ VERIFY( (ci1 < ci2) == true );
+ VERIFY( (ci1 > ci2) == false );
+ VERIFY( (ci1 <= ci2) == true );
+ VERIFY( (ci1 >= ci2) == false );
std::string::const_iterator ci3;
ci3 = ci1;
- if ((ci3 == ci1) != true)
- ++failures;
+ VERIFY( ci3 == ci1 );
ci3 += 5;
- if ((ci3 == ci2) != true)
- ++failures;
+ VERIFY( ci3 == ci2 );
ci3 -= 5;
- if ((ci3 == ci1) != true)
- ++failures;
-
- if (ci3 + 5 != ci2)
- ++failures;
-
- if (5 + ci3 != ci2)
- ++failures;
-
- if (ci2 - 5 != ci3)
- ++failures;
+ VERIFY( ci3 == ci1 );
- if (ci1[2] != 'c')
- ++failures;
+ VERIFY( ci3 + 5 == ci2 );
+ VERIFY( 5 + ci3 == ci2 );
+ VERIFY( ci2 - 5 == ci3 );
- if (ci2[-1] != 'e')
- ++failures;
+ VERIFY( ci1[2] == 'c' );
+ VERIFY( ci2[-1] == 'e' );
// iterator and const_iterator
std::string::const_iterator ci4(i1);
- if ((ci4 == i1) != true)
- ++failures;
- if ((ci4 != i1) != false)
- ++failures;
- if ((ci4 < i1) != false)
- ++failures;
- if ((ci4 > i1) != false)
- ++failures;
- if ((ci4 <= i1) != true)
- ++failures;
- if ((ci4 >= i1) != true)
- ++failures;
+ VERIFY( (ci4 == i1) == true );
+ VERIFY( (ci4 != i1) == false );
+ VERIFY( (ci4 < i1) == false );
+ VERIFY( (ci4 > i1) == false );
+ VERIFY( (ci4 <= i1) == true );
+ VERIFY( (ci4 >= i1) == true );
ci4 = i2;
- if ((i2 == ci4) != true)
- ++failures;
- if ((i2 < ci4) != false)
- ++failures;
- if ((i2 > ci4) != false)
- ++failures;
- if ((i2 <= ci4) != true)
- ++failures;
- if ((i2 >= ci4) != true)
- ++failures;
+ VERIFY( (i2 == ci4) == true );
+ VERIFY( (i2 < ci4) == false );
+ VERIFY( (i2 > ci4) == false );
+ VERIFY( (i2 <= ci4) == true );
+ VERIFY( (i2 >= ci4) == true );
const std::string cs("ABCDE");
std::string::const_iterator ci5(cs.begin());
- if (ci5[0] != 'A')
- ++failures;
-
- return failures;
+ VERIFY( ci5[0] == 'A' );
}
-int
+void
vector_stuff()
{
int failures(0);
@@ -261,347 +185,190 @@ vector_stuff()
v.push_back(int(5));
std::vector<int>::iterator i1(v.begin());
- if (*i1 != 1)
- ++failures;
+ VERIFY( *i1 == 1 );
++i1;
- if (*i1 != 2)
- ++failures;
+ VERIFY( *i1 == 2 );
- if (*i1++ != 2)
- ++failures;
- if (*i1 != 3)
- ++failures;
+ VERIFY( *i1++ == 2 );
+ VERIFY( *i1 == 3 );
++ ++i1;
- if (*i1 != 5)
- ++failures;
+ VERIFY( *i1 == 5 );
--i1;
- if (*i1 != 4)
- ++failures;
+ VERIFY( *i1 == 4 );
- if (*i1-- != 4)
- ++failures;
- if (*i1 != 3)
- ++failures;
+ VERIFY( *i1-- == 4 );
+ VERIFY( *i1 == 3 );
-- --i1;
- if (*i1 != 1)
- ++failures;
+ VERIFY( *i1 == 1 );
std::vector<int>::iterator i2;
i2 = v.end();
std::iterator_traits<std::vector<int>::iterator>::difference_type d1;
d1 = i2 - i1;
- if (d1 != 5)
- ++failures;
+ VERIFY( d1 == 5 );
std::iterator_traits<std::vector<int>::iterator>::value_type v1;
v1 = i1[0];
- if (v1 != 1)
- ++failures;
+ VERIFY( v1 == 1 );
std::iterator_traits<std::vector<int>::iterator>::reference r1(i1[0]);
- if (r1 != 1)
- ++failures;
+ VERIFY( r1 == 1 );
r1 = 9;
- if (r1 != 9)
- ++failures;
+ VERIFY( r1 == 9 );
r1 = 1;
- if ((i1 != i2) != true)
- ++failures;
- if ((i1 == i2) != false)
- ++failures;
- if ((i1 < i2) != true)
- ++failures;
- if ((i1 > i2) != false)
- ++failures;
- if ((i1 <= i2) != true)
- ++failures;
- if ((i1 >= i2) != false)
- ++failures;
+ VERIFY( (i1 != i2) == true );
+ VERIFY( (i1 == i2) == false );
+ VERIFY( (i1 < i2) == true );
+ VERIFY( (i1 > i2) == false );
+ VERIFY( (i1 <= i2) == true );
+ VERIFY( (i1 >= i2) == false );
std::vector<int>::iterator i3;
i3 = i1;
- if ((i3 == i1) != true)
- ++failures;
+ VERIFY( (i3 == i1) == true );
i3 += 5;
- if ((i3 == i2) != true)
- ++failures;
+ VERIFY( (i3 == i2) == true );
i3 -= 5;
- if ((i3 == i1) != true)
- ++failures;
-
- if (i3 + 5 != i2)
- ++failures;
-
- if (5 + i3 != i2)
- ++failures;
+ VERIFY( (i3 == i1) == true );
- if (i2 - 5 != i3)
- ++failures;
+ VERIFY( i3 + 5 == i2 );
+ VERIFY( 5 + i3 == i2 );
+ VERIFY( i2 - 5 == i3 );
- if (i1[0] != 1)
- ++failures;
+ VERIFY( i1[0] == 1 );
i1[4] = 9;
- if (i2[-1] != 9)
- ++failures;
+ VERIFY( i2[-1] == 9 );
i1[4] = 5;
i1[2] = 9;
- if (i2[-3] != 9)
- ++failures;
+ VERIFY( i2[-3] == 9 );
i1[2] = 3;
std::vector<int>::const_iterator ci1(v.begin());
- if (*ci1 != 1)
- ++failures;
+ VERIFY( *ci1 == 1 );
++ci1;
- if (*ci1 != 2)
- ++failures;
+ VERIFY( *ci1 == 2 );
- if (*ci1++ != 2)
- ++failures;
- if (*ci1 != 3)
- ++failures;
+ VERIFY( *ci1++ == 2 );
+ VERIFY( *ci1 == 3 );
++ ++ci1;
- if (*ci1 != 5)
- ++failures;
+ VERIFY( *ci1 == 5 );
--ci1;
- if (*ci1 != 4)
- ++failures;
+ VERIFY( *ci1 == 4 );
- if (*ci1-- != 4)
- ++failures;
- if (*ci1 != 3)
- ++failures;
+ VERIFY( *ci1-- == 4 );
+ VERIFY( *ci1 == 3 );
-- --ci1;
- if (*ci1 != 1)
- ++failures;
+ VERIFY( *ci1 == 1 );
std::vector<int>::const_iterator ci2;
ci2 = v.end();
std::iterator_traits<std::vector<int>::const_iterator>::difference_type d2;
d2 = ci2 - ci1;
- if (d2 != 5)
- ++failures;
+ VERIFY( d2 == 5 );
std::iterator_traits<std::vector<int>::const_iterator>::value_type v2;
v2 = ci1[0];
- if (v2 != 1)
- ++failures;
+ VERIFY( v2 == 1 );
std::iterator_traits<std::vector<int>::const_iterator>::reference
r2(ci1[0]);
- if (r2 != 1)
- ++failures;
-
- if ((ci1 != ci2) != true)
- ++failures;
- if ((ci1 == ci2) != false)
- ++failures;
- if ((ci1 < ci2) != true)
- ++failures;
- if ((ci1 > ci2) != false)
- ++failures;
- if ((ci1 <= ci2) != true)
- ++failures;
- if ((ci1 >= ci2) != false)
- ++failures;
+ VERIFY( r2 == 1 );
+
+ VERIFY( (ci1 != ci2) == true );
+ VERIFY( (ci1 == ci2) == false );
+ VERIFY( (ci1 < ci2) == true );
+ VERIFY( (ci1 > ci2) == false );
+ VERIFY( (ci1 <= ci2) == true );
+ VERIFY( (ci1 >= ci2) == false );
std::vector<int>::const_iterator ci3;
ci3 = ci1;
- if ((ci3 == ci1) != true)
- ++failures;
+ VERIFY( (ci3 == ci1) == true );
ci3 += 5;
- if ((ci3 == ci2) != true)
- ++failures;
+ VERIFY( (ci3 == ci2) == true );
ci3 -= 5;
- if ((ci3 == ci1) != true)
- ++failures;
-
- if (ci3 + 5 != ci2)
- ++failures;
+ VERIFY( (ci3 == ci1) == true );
- if (5 + ci3 != ci2)
- ++failures;
+ VERIFY( ci3 + 5 == ci2 );
+ VERIFY( 5 + ci3 == ci2 );
+ VERIFY( ci2 - 5 == ci3 );
- if (ci2 - 5 != ci3)
- ++failures;
+ VERIFY( ci1[2] == 3 );
- if (ci1[2] != 3)
- ++failures;
-
- if (ci2[-1] != 5)
- ++failures;
+ VERIFY( ci2[-1] == 5 );
// iterator to const_iterator
std::vector<int>::const_iterator ci4(i1);
- if ((ci4 == i1) != true)
- ++failures;
- if ((ci4 != i1) != false)
- ++failures;
- if ((ci4 < i1) != false)
- ++failures;
- if ((ci4 > i1) != false)
- ++failures;
- if ((ci4 <= i1) != true)
- ++failures;
- if ((ci4 >= i1) != true)
- ++failures;
+ VERIFY( (ci4 == i1) == true );
+ VERIFY( (ci4 != i1) == false );
+ VERIFY( (ci4 < i1) == false );
+ VERIFY( (ci4 > i1) == false );
+ VERIFY( (ci4 <= i1) == true );
+ VERIFY( (ci4 >= i1) == true );
ci4 = i2;
- if ((i2 == ci4) != true)
- ++failures;
- if ((i2 < ci4) != false)
- ++failures;
- if ((i2 > ci4) != false)
- ++failures;
- if ((i2 <= ci4) != true)
- ++failures;
- if ((i2 >= ci4) != true)
- ++failures;
+ VERIFY( (i2 == ci4) == true );
+ VERIFY( (i2 < ci4) == false );
+ VERIFY( (i2 > ci4) == false );
+ VERIFY( (i2 <= ci4) == true );
+ VERIFY( (i2 >= ci4) == true );
const std::vector<int> cv(v);
std::vector<int>::const_iterator ci5(cv.begin());
- if (ci5[0] != 1)
- ++failures;
+ VERIFY( ci5[0] == 1 );
std::vector<std::string> vs;
vs.push_back(std::string("abc"));
std::vector<std::string>::iterator ivs(vs.begin());
- if (ivs->c_str()[1] != 'b')
- ++failures;
-
- return failures;
+ VERIFY( ivs->c_str()[1] == 'b' );
}
-int
+void
reverse_stuff()
{
- int failures(0);
-
std::string s("abcde");
std::string::reverse_iterator ri(s.rbegin());
- if (*ri != 'e')
- ++failures;
+ VERIFY( *ri == 'e' );
std::iterator_traits<std::string::reverse_iterator>::difference_type d;
d = s.rend() - ri;
- if (d != 5)
- ++failures;
+ VERIFY( d == 5 );
const std::string cs("abcde");
std::string::const_reverse_iterator cri(cs.rend());
- if (cri - 5 != cs.rbegin())
- ++failures;
-
- return failures;
-}
-
-// the following should be compiler errors
-// flag runtime errors in case they slip through the compiler
-int
-wrong_stuff()
-{
- int failures(0);
-
-#ifdef ITER24_F1
- extern void f(std::vector<std::string*>::iterator);
- std::vector<std::string*> vs[2];
- f(vs); // address of array is not an iterator
- failures++;
-#endif
-
-#ifdef ITER24_F2
- std::string s;
- char *i = s.begin(); // begin() doesn't return a pointer
- failures++;
-#endif
-
-#ifdef ITER24_F3
- std::string::const_iterator ci;
- std::string::iterator i;
- if (i - ci) // remove const_ is a warning
- i++;
- // failures++; only a warning
-#endif
-
-#ifdef ITER24_F4
- std::vector<char>::iterator iv;
- std::string::iterator is(iv);// vector<char> is not string
- failures++;
-#endif
-
-#ifdef ITER24_F5
- std::vector<char>::iterator iv;
- std::string::iterator is;
- if (iv == is) // vector<char> is not string
- ++iv;
- failures++;
-#endif
-
-#ifdef ITER24_F6
- std::vector<char>::const_iterator ci;
- std::vector<char>::iterator i = ci; // remove const_ is a warning
- ++i;
- // failures++; only a warning
-#endif
-
-#ifdef ITER24_F7
- std::vector<int> v(1);
- std::vector<int>::const_iterator ci(v.begin());
- *ci = 1; // cannot assign through const_iterator
- failures++;
-#endif
-
-#ifdef ITER24_F8
- std::vector<const int> v(1);
- std::vector<const int>::reference r(v.begin()[0]);
- r = 1; // cannot assign through reference to const
- failures++;
-#endif
-
- return failures;
+ VERIFY( cri - 5 == cs.rbegin() );
}
// libstdc++/6642
-int
+void
test6642()
{
std::string s;
std::string::iterator it = s.begin();
std::string::const_iterator cit = s.begin();
-
- return it - cit;
+ VERIFY( (it - cit) == 0 );
}
int
main()
{
- int failures(0);
-
- failures += string_stuff();
-
- failures += vector_stuff();
-
- failures += reverse_stuff();
-
- failures += wrong_stuff();
-
- failures += test6642();
-
- VERIFY(failures == 0);
+ string_stuff();
+ vector_stuff();
+ reverse_stuff();
return 0;
}
diff --git a/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3900.cc b/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3900.cc
index 957879e..08fd5c2 100644
--- a/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3900.cc
+++ b/libstdc++-v3/testsuite/24_iterators/range_generators/lwg3900.cc
@@ -13,4 +13,5 @@ bar(std::allocator_arg_t, std::pmr::memory_resource& mr) // { dg-error "here" }
}
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
-// { dg-error "no matching function .*memory_resource&" "" { target *-*-* } 0 }
+// { dg-error "could not convert 'const std::pmr::memory_resource'" "" { target *-*-* } 0 }
+// { dg-error "no matching function \[^\n\r\]*memory_resource&" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/29_atomics/atomic/requirements/types_neg.cc b/libstdc++-v3/testsuite/29_atomics/atomic/requirements/types_neg.cc
index 5aa3243..cfe44d2 100644
--- a/libstdc++-v3/testsuite/29_atomics/atomic/requirements/types_neg.cc
+++ b/libstdc++-v3/testsuite/29_atomics/atomic/requirements/types_neg.cc
@@ -20,6 +20,7 @@
#include <atomic>
std::atomic<const int> a; // { dg-error "here" }
+// { dg-error "assignment to read-only type" "" { target *-*-* } 0 }
struct MoveOnly
{
@@ -40,3 +41,4 @@ struct NoMove
std::atomic<NoMove> c; // { dg-error "here" }
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "use of deleted function" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc b/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc
index 2c5125b..cdbb2f4 100644
--- a/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc
+++ b/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/destructible_neg.cc
@@ -54,3 +54,4 @@ test02(std::stop_token& tok, G& g)
}
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "private within this context" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc b/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc
index 93b3186..2b2fce4 100644
--- a/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc
+++ b/libstdc++-v3/testsuite/30_threads/stop_token/stop_callback/invocable_neg.cc
@@ -32,3 +32,4 @@ test01(std::stop_token& tok, F& f)
}
// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-error "no match for call" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/ext/unicode/view.cc b/libstdc++-v3/testsuite/ext/unicode/view.cc
index 6f3c099..4ccf646 100644
--- a/libstdc++-v3/testsuite/ext/unicode/view.cc
+++ b/libstdc++-v3/testsuite/ext/unicode/view.cc
@@ -7,13 +7,24 @@
namespace uc = std::__unicode;
using namespace std::string_view_literals;
+template<std::ranges::range View>
+constexpr void
+compare(View v, std::basic_string_view<std::ranges::range_value_t<View>> s)
+{
+ long size = s.size();
+ VERIFY( std::ranges::distance(v) == size );
+ VERIFY( std::ranges::equal(v, s) );
+ auto rev = std::views::reverse(v);
+ VERIFY( std::ranges::distance(rev) == size );
+ VERIFY( std::ranges::equal(rev, s | std::views::reverse) );
+}
+
constexpr void
test_utf8_to_utf8()
{
const auto s8 = u8"£🇬🇧 €🇪🇺 æбçδé ♠♥♦♣ 🤡"sv;
uc::_Utf8_view v(s8);
- VERIFY( std::ranges::distance(v) == s8.size() );
- VERIFY( std::ranges::equal(v, s8) );
+ compare(v, s8);
}
constexpr void
@@ -22,8 +33,7 @@ test_utf8_to_utf16()
const auto s8 = u8"£🇬🇧 €🇪🇺 æбçδé ♠♥♦♣ 🤡"sv;
const std::u16string_view s16 = u"£🇬🇧 €🇪🇺 æбçδé ♠♥♦♣ 🤡";
uc::_Utf16_view v(s8);
- VERIFY( std::ranges::distance(v) == s16.size() );
- VERIFY( std::ranges::equal(v, s16) );
+ compare(v, s16);
}
constexpr void
@@ -32,36 +42,41 @@ test_utf8_to_utf32()
const auto s8 = u8"£🇬🇧 €🇪🇺 æбçδé ♠♥♦♣ 🤡"sv;
const auto s32 = U"£🇬🇧 €🇪🇺 æбçδé ♠♥♦♣ 🤡"sv;
uc::_Utf32_view v(s8);
- VERIFY( std::ranges::distance(v) == s32.size() );
- VERIFY( std::ranges::equal(v, s32) );
+ compare(v, s32);
}
constexpr void
test_illformed_utf8()
{
uc::_Utf32_view v("\xa3 10.99 \xee \xdd"sv);
- VERIFY( std::ranges::equal(v, U"\uFFFD 10.99 \uFFFD \uFFFD"sv) );
+ compare(v, U"\uFFFD 10.99 \uFFFD \uFFFD"sv);
uc::_Utf16_view v2(" \xf8\x80\x80\x80 "sv);
- VERIFY( std::ranges::distance(v2) == 6 );
- VERIFY( std::ranges::equal(v2, U" \uFFFD\uFFFD\uFFFD\uFFFD "sv) );
+ compare(v2, u" \uFFFD\uFFFD\uFFFD\uFFFD "sv);
// Examples of U+FFFD substitution from Unicode standard.
uc::_Utf8_view v3("\xc0\xaf\xe0\x80\xbf\xf0\x81\x82\x41"sv); // Table 3-8
- VERIFY( std::ranges::equal(v3, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv) );
+ compare(v3, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv);
uc::_Utf8_view v4("\xed\xa0\x80\xed\xbf\xbf\xed\xaf\x41"sv); // Table 3-9
- VERIFY( std::ranges::equal(v4, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv) );
+ compare(v4, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv);
uc::_Utf8_view v5("\xf4\x91\x92\x93\xff\x41\x80\xbf\x42"sv); // Table 3-10
- VERIFY( std::ranges::equal(v5, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41\uFFFD\uFFFD\x42"sv) );
+ compare(v5, u8"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\x41\uFFFD\uFFFD\x42"sv);
uc::_Utf8_view v6("\xe1\x80\xe2\xf0\x91\x92\xf1\xbf\x41"sv); // Table 3-11
- VERIFY( std::ranges::equal(v6, u8"\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv) );
+ compare(v6, u8"\uFFFD\uFFFD\uFFFD\uFFFD\x41"sv);
uc::_Utf32_view v7("\xe1\x80"sv);
- VERIFY( std::ranges::equal(v7, U"\uFFFD"sv) );
+ compare(v7, U"\uFFFD"sv);
uc::_Utf32_view v8("\xf1\x80"sv);
- VERIFY( std::ranges::equal(v8, U"\uFFFD"sv) );
+ compare(v8, U"\uFFFD"sv);
uc::_Utf32_view v9("\xf1\x80\x80"sv);
- VERIFY( std::ranges::equal(v9, U"\uFFFD"sv) );
+ compare(v9, U"\uFFFD"sv);
+
+ uc::_Utf32_view v10("\xcf\x80\x80\x81\x82\x83 \x84\x85\x86\x87\x88 "sv);
+ compare(v10, U"\u03C0\uFFFD\uFFFD\uFFFD\uFFFD \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD "sv);
+ uc::_Utf16_view v11("\xcf\x80\x80\x81\x82\x83 \x84\x85\x86\x87\x88 "sv);
+ compare(v11, u"\u03C0\uFFFD\uFFFD\uFFFD\uFFFD \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD "sv);
+ uc::_Utf8_view v12("\xcf\x80\x80\x81\x82\x83 \x84\x85\x86\x87\x88 "sv);
+ compare(v12, u8"\u03C0\uFFFD\uFFFD\uFFFD\uFFFD \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD "sv);
}
constexpr void
@@ -69,27 +84,27 @@ test_illformed_utf16()
{
std::u16string_view s = u"\N{CLOWN FACE}";
std::u16string_view r = u"\uFFFD";
- VERIFY( std::ranges::equal(uc::_Utf16_view(s.substr(0, 1)), r) );
- VERIFY( std::ranges::equal(uc::_Utf16_view(s.substr(1, 1)), r) );
+ compare(uc::_Utf16_view(s.substr(0, 1)), r);
+ compare(uc::_Utf16_view(s.substr(1, 1)), r);
std::array s2{ s[0], s[0] };
- VERIFY( std::ranges::equal(uc::_Utf16_view(s2), u"\uFFFD\uFFFD"sv) );
+ compare(uc::_Utf16_view(s2), u"\uFFFD\uFFFD"sv);
std::array s3{ s[0], s[0], s[1] };
- VERIFY( std::ranges::equal(uc::_Utf16_view(s3), u"\uFFFD\N{CLOWN FACE}"sv) );
+ compare(uc::_Utf16_view(s3), u"\uFFFD\N{CLOWN FACE}"sv);
std::array s4{ s[1], s[0] };
- VERIFY( std::ranges::equal(uc::_Utf16_view(s4), u"\uFFFD\uFFFD"sv) );
+ compare(uc::_Utf16_view(s4), u"\uFFFD\uFFFD"sv);
std::array s5{ s[1], s[0], s[1] };
- VERIFY( std::ranges::equal(uc::_Utf16_view(s5), u"\uFFFD\N{CLOWN FACE}"sv) );
+ compare(uc::_Utf16_view(s5), u"\uFFFD\N{CLOWN FACE}"sv);
}
constexpr void
test_illformed_utf32()
{
std::u32string_view s = U"\x110000";
- VERIFY( std::ranges::equal(uc::_Utf32_view(s), U"\uFFFD"sv) );
+ compare(uc::_Utf32_view(s), U"\uFFFD"sv);
s = U"\xFFFFFF";
- VERIFY( std::ranges::equal(uc::_Utf32_view(s), U"\uFFFD"sv) );
+ compare(uc::_Utf32_view(s), U"\uFFFD"sv);
s = U"\xFFFFFFF0";
- VERIFY( std::ranges::equal(uc::_Utf32_view(s), U"\uFFFD"sv) );
+ compare(uc::_Utf32_view(s), U"\uFFFD"sv);
}
constexpr void
@@ -110,6 +125,13 @@ test_past_the_end()
iter++;
VERIFY( iter == v.end() );
VERIFY( *iter == U'4' );
+ std::ranges::advance(iter, -4);
+ VERIFY( *iter == U'1' );
+ // Incrementing before begin has well-defined behaviour.
+ iter--;
+ VERIFY( *iter == U'1' );
+ iter--;
+ VERIFY( *iter == U'1' );
std::string_view empty;
uc::_Utf32_view v2(empty);
@@ -119,6 +141,9 @@ test_past_the_end()
iter++;
VERIFY( iter2 == v2.end() );
VERIFY( *iter2 == U'\0' );
+ iter--;
+ VERIFY( iter2 == v2.end() );
+ VERIFY( *iter2 == U'\0' );
}
int main()
diff --git a/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc b/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
index ded56fe..83c7b22 100644
--- a/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
+++ b/libstdc++-v3/testsuite/std/format/arguments/args_neg.cc
@@ -42,3 +42,4 @@ void test_const_arg()
}
// { dg-prune-output "no matching function for call to .*::basic_format_arg<" }
+// { dg-prune-output "use of deleted function" }
diff --git a/libstdc++-v3/testsuite/std/format/string_neg.cc b/libstdc++-v3/testsuite/std/format/string_neg.cc
index 09cc9a2..acae88e 100644
--- a/libstdc++-v3/testsuite/std/format/string_neg.cc
+++ b/libstdc++-v3/testsuite/std/format/string_neg.cc
@@ -8,3 +8,5 @@ auto s = std::format(" {9} "); // { dg-error "call to consteval function" }
struct X { };
std::format_string<X> str(""); // { dg-error "here" }
// { dg-error "std::formatter must be specialized" "" { target *-*-* } 0 }
+
+// { dg-prune-output "use of deleted function" }
diff --git a/libstdc++-v3/testsuite/std/time/month/io.cc b/libstdc++-v3/testsuite/std/time/month/io.cc
index 99ec073..edfa196 100644
--- a/libstdc++-v3/testsuite/std/time/month/io.cc
+++ b/libstdc++-v3/testsuite/std/time/month/io.cc
@@ -24,6 +24,9 @@ test_ostream()
ss.imbue(std::locale(ISO_8859(15,fr_FR)));
ss << month(1);
VERIFY( ss.str() == "janv." );
+ ss.str("");
+ ss << month(0) << '|' << month(13);
+ VERIFY( ss.str() == "0 is not a valid month|13 is not a valid month" );
}
void
@@ -66,6 +69,10 @@ test_format()
VERIFY( s == "Jan" );
s = std::format(loc_fr, "{:L%b}", month(1));
VERIFY( s == "janv." );
+ s = std::format(loc_fr, "{:L}", month(0));
+ VERIFY( s == "0 is not a valid month" );
+ s = std::format(loc_fr, "{:L}", month(13));
+ VERIFY( s == "13 is not a valid month" );
std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
std::string_view my_specs = "bBhm";
diff --git a/libstdc++-v3/testsuite/std/time/weekday/io.cc b/libstdc++-v3/testsuite/std/time/weekday/io.cc
index a56cdae..90a9bcb 100644
--- a/libstdc++-v3/testsuite/std/time/weekday/io.cc
+++ b/libstdc++-v3/testsuite/std/time/weekday/io.cc
@@ -69,6 +69,8 @@ test_format()
VERIFY( s == "Mon" );
s = std::format(loc_fr, "{:L%a}", weekday(1));
VERIFY( s == "lun." );
+ s = std::format(loc_fr, "{:L}", weekday(25));
+ VERIFY( s == "25 is not a valid weekday" );
std::string_view specs = "aAbBcCdDeFgGhHIjmMpqQrRSTuUVwWxXyYzZ";
std::string_view my_specs = "aAuw";
diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h b/libstdc++-v3/testsuite/util/testsuite_allocator.h
index e5ffad2..ee95752 100644
--- a/libstdc++-v3/testsuite/util/testsuite_allocator.h
+++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h
@@ -517,19 +517,24 @@ namespace __gnu_test
constexpr SimpleAllocator() noexcept { }
template <class T>
+ constexpr
SimpleAllocator(const SimpleAllocator<T>&) { }
+ _GLIBCXX20_CONSTEXPR
Tp *allocate(std::size_t n)
{ return std::allocator<Tp>().allocate(n); }
+ _GLIBCXX20_CONSTEXPR
void deallocate(Tp *p, std::size_t n)
{ std::allocator<Tp>().deallocate(p, n); }
};
template <class T, class U>
+ constexpr
bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&)
{ return true; }
template <class T, class U>
+ constexpr
bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&)
{ return false; }
diff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h
index 74a8739..acd412a 100644
--- a/libstdc++-v3/testsuite/util/testsuite_iterators.h
+++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h
@@ -61,10 +61,12 @@ namespace __gnu_test
T* first;
T* last;
+ _GLIBCXX_CONSTEXPR
BoundsContainer(T* _first, T* _last) : first(_first), last(_last)
{ }
- std::size_t size() const { return last - first; }
+ _GLIBCXX_CONSTEXPR std::size_t
+ size() const { return last - first; }
};
// Simple container for holding state of a set of output iterators.
@@ -74,11 +76,13 @@ namespace __gnu_test
T* incrementedto;
bool* writtento;
+ _GLIBCXX20_CONSTEXPR
OutputContainer(T* _first, T* _last)
: BoundsContainer<T>(_first, _last), incrementedto(_first),
writtento(new bool[this->size()]())
{ }
+ _GLIBCXX20_CONSTEXPR
~OutputContainer()
{ delete[] writtento; }
};
@@ -92,12 +96,14 @@ namespace __gnu_test
public:
OutputContainer<T>* SharedInfo;
+ _GLIBCXX_CONSTEXPR
WritableObject(T* ptr_in, OutputContainer<T>* SharedInfo_in):
ptr(ptr_in), SharedInfo(SharedInfo_in)
{ }
#if __cplusplus >= 201103L
template<class U>
+ _GLIBCXX14_CONSTEXPR
typename std::enable_if<std::is_assignable<T&, U>::value>::type
operator=(U&& new_val) const
{
@@ -107,6 +113,7 @@ namespace __gnu_test
}
#else
template<class U>
+ _GLIBCXX14_CONSTEXPR
void
operator=(const U& new_val)
{
@@ -128,6 +135,7 @@ namespace __gnu_test
struct output_iterator_wrapper
{
protected:
+ _GLIBCXX_CONSTEXPR
output_iterator_wrapper() : ptr(0), SharedInfo(0)
{ }
@@ -142,6 +150,7 @@ namespace __gnu_test
T* ptr;
ContainerType* SharedInfo;
+ _GLIBCXX14_CONSTEXPR
output_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in)
: ptr(_ptr), SharedInfo(SharedInfo_in)
{
@@ -155,6 +164,7 @@ namespace __gnu_test
operator=(const output_iterator_wrapper&) = default;
#endif
+ _GLIBCXX14_CONSTEXPR
WritableObject<T>
operator*() const
{
@@ -163,6 +173,7 @@ namespace __gnu_test
return WritableObject<T>(ptr, SharedInfo);
}
+ _GLIBCXX14_CONSTEXPR
output_iterator_wrapper&
operator++()
{
@@ -173,6 +184,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
output_iterator_wrapper
operator++(int)
{
@@ -224,13 +236,19 @@ namespace __gnu_test
struct deref_proxy
{
T* ptr;
- operator const T&() const { return *ptr; }
+
+ _GLIBCXX_CONSTEXPR
+ operator const T&() const
+ { return *ptr; }
} p;
- deref_proxy operator*() const { return p; }
+ _GLIBCXX_CONSTEXPR
+ deref_proxy operator*() const
+ { return p; }
};
protected:
+ _GLIBCXX_CONSTEXPR
input_iterator_wrapper() : ptr(0), SharedInfo(0)
{ }
@@ -245,6 +263,7 @@ namespace __gnu_test
T* ptr;
ContainerType* SharedInfo;
+ _GLIBCXX14_CONSTEXPR
input_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in)
: ptr(_ptr), SharedInfo(SharedInfo_in)
{ ITERATOR_VERIFY(ptr >= SharedInfo->first && ptr <= SharedInfo->last); }
@@ -256,6 +275,7 @@ namespace __gnu_test
operator=(const input_iterator_wrapper&) = default;
#endif
+ _GLIBCXX14_CONSTEXPR
bool
operator==(const input_iterator_wrapper& in) const
{
@@ -264,26 +284,34 @@ namespace __gnu_test
return ptr == in.ptr;
}
+ _GLIBCXX14_CONSTEXPR
bool
operator!=(const input_iterator_wrapper& in) const
{
return !(*this == in);
}
- T&
- operator*() const
+ _GLIBCXX_CONSTEXPR
+ T* base() const
+ {
+ return ptr;
+ }
+
+ _GLIBCXX14_CONSTEXPR
+ T& operator*() const
{
ITERATOR_VERIFY(SharedInfo && ptr < SharedInfo->last);
ITERATOR_VERIFY(ptr >= SharedInfo->first);
return *ptr;
}
- T*
- operator->() const
+ _GLIBCXX14_CONSTEXPR
+ T* operator->() const
{
return &**this;
}
+ _GLIBCXX14_CONSTEXPR
input_iterator_wrapper&
operator++()
{
@@ -294,6 +322,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
post_inc_proxy
operator++(int)
{
@@ -334,10 +363,12 @@ namespace __gnu_test
typedef BoundsContainer<T> ContainerType;
typedef std::forward_iterator_tag iterator_category;
+ _GLIBCXX14_CONSTEXPR
forward_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in)
: input_iterator_wrapper<T>(_ptr, SharedInfo_in)
{ }
+ _GLIBCXX14_CONSTEXPR
forward_iterator_wrapper()
{ }
@@ -348,17 +379,18 @@ namespace __gnu_test
operator=(const forward_iterator_wrapper&) = default;
#endif
- T&
- operator*() const
+ _GLIBCXX14_CONSTEXPR
+ T& operator*() const
{
ITERATOR_VERIFY(this->SharedInfo && this->ptr < this->SharedInfo->last);
return *(this->ptr);
}
- T*
- operator->() const
+ _GLIBCXX14_CONSTEXPR
+ T* operator->() const
{ return &**this; }
+ _GLIBCXX14_CONSTEXPR
forward_iterator_wrapper&
operator++()
{
@@ -367,6 +399,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
forward_iterator_wrapper
operator++(int)
{
@@ -376,8 +409,8 @@ namespace __gnu_test
}
#if __cplusplus >= 201402L
- bool
- operator==(const forward_iterator_wrapper& it) const noexcept
+ constexpr
+ bool operator==(const forward_iterator_wrapper& it) const noexcept
{
// Since C++14 value-initialized forward iterators are comparable.
if (this->SharedInfo == nullptr || it.SharedInfo == nullptr)
@@ -388,8 +421,8 @@ namespace __gnu_test
return base_this == base_that;
}
- bool
- operator!=(const forward_iterator_wrapper& it) const noexcept
+ constexpr
+ bool operator!=(const forward_iterator_wrapper& it) const noexcept
{
return !(*this == it);
}
@@ -409,10 +442,12 @@ namespace __gnu_test
typedef BoundsContainer<T> ContainerType;
typedef std::bidirectional_iterator_tag iterator_category;
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in)
: forward_iterator_wrapper<T>(_ptr, SharedInfo_in)
{ }
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper()
: forward_iterator_wrapper<T>()
{ }
@@ -425,6 +460,7 @@ namespace __gnu_test
operator=(const bidirectional_iterator_wrapper&) = default;
#endif
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper&
operator++()
{
@@ -433,6 +469,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper
operator++(int)
{
@@ -441,6 +478,7 @@ namespace __gnu_test
return tmp;
}
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper&
operator--()
{
@@ -449,6 +487,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
bidirectional_iterator_wrapper
operator--(int)
{
@@ -472,10 +511,12 @@ namespace __gnu_test
typedef BoundsContainer<T> ContainerType;
typedef std::random_access_iterator_tag iterator_category;
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper(T* _ptr, ContainerType* SharedInfo_in)
: bidirectional_iterator_wrapper<T>(_ptr, SharedInfo_in)
{ }
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper()
: bidirectional_iterator_wrapper<T>()
{ }
@@ -488,6 +529,7 @@ namespace __gnu_test
operator=(const random_access_iterator_wrapper&) = default;
#endif
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper&
operator++()
{
@@ -496,6 +538,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper
operator++(int)
{
@@ -504,6 +547,7 @@ namespace __gnu_test
return tmp;
}
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper&
operator--()
{
@@ -512,6 +556,7 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper
operator--(int)
{
@@ -520,6 +565,7 @@ namespace __gnu_test
return tmp;
}
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper&
operator+=(std::ptrdiff_t n)
{
@@ -536,10 +582,12 @@ namespace __gnu_test
return *this;
}
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper&
operator-=(std::ptrdiff_t n)
{ return *this += -n; }
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper
operator-(std::ptrdiff_t n) const
{
@@ -547,6 +595,7 @@ namespace __gnu_test
return tmp -= n;
}
+ _GLIBCXX14_CONSTEXPR
std::ptrdiff_t
operator-(const random_access_iterator_wrapper<T>& in) const
{
@@ -554,42 +603,44 @@ namespace __gnu_test
return this->ptr - in.ptr;
}
- T&
- operator[](std::ptrdiff_t n) const
+ _GLIBCXX14_CONSTEXPR
+ T& operator[](std::ptrdiff_t n) const
{ return *(*this + n); }
- bool
- operator<(const random_access_iterator_wrapper<T>& in) const
+ _GLIBCXX14_CONSTEXPR
+ bool operator<(const random_access_iterator_wrapper<T>& in) const
{
ITERATOR_VERIFY(this->SharedInfo == in.SharedInfo);
return this->ptr < in.ptr;
}
- bool
- operator>(const random_access_iterator_wrapper<T>& in) const
+ _GLIBCXX14_CONSTEXPR
+ bool operator>(const random_access_iterator_wrapper<T>& in) const
{
return in < *this;
}
- bool
- operator>=(const random_access_iterator_wrapper<T>& in) const
+ _GLIBCXX14_CONSTEXPR
+ bool operator>=(const random_access_iterator_wrapper<T>& in) const
{
return !(*this < in);
}
- bool
- operator<=(const random_access_iterator_wrapper<T>& in) const
+ _GLIBCXX14_CONSTEXPR
+ bool operator<=(const random_access_iterator_wrapper<T>& in) const
{
return !(*this > in);
}
};
template<typename T>
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper<T>
operator+(random_access_iterator_wrapper<T> it, std::ptrdiff_t n)
{ return it += n; }
template<typename T>
+ _GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper<T>
operator+(std::ptrdiff_t n, random_access_iterator_wrapper<T> it)
{ return it += n; }
@@ -607,14 +658,17 @@ namespace __gnu_test
{
typename ItType<T>::ContainerType bounds;
+ _GLIBCXX_CONSTEXPR
test_container(T* _first, T* _last) : bounds(_first, _last)
{ }
template<std::size_t N>
explicit
+ _GLIBCXX_CONSTEXPR
test_container(T (&arr)[N]) : bounds(arr, arr+N)
{ }
+ _GLIBCXX14_CONSTEXPR
ItType<T>
it(int pos)
{
@@ -622,6 +676,7 @@ namespace __gnu_test
return ItType<T>(bounds.first + pos, &bounds);
}
+ _GLIBCXX14_CONSTEXPR
ItType<T>
it(T* pos)
{
@@ -629,18 +684,22 @@ namespace __gnu_test
return ItType<T>(pos, &bounds);
}
+ _GLIBCXX_CONSTEXPR
const T&
val(int pos)
{ return (bounds.first)[pos]; }
+ _GLIBCXX14_CONSTEXPR
ItType<T>
begin()
{ return it(bounds.first); }
+ _GLIBCXX14_CONSTEXPR
ItType<T>
end()
{ return it(bounds.last); }
+ _GLIBCXX_CONSTEXPR
std::size_t
size() const
{ return bounds.size(); }
@@ -680,6 +739,7 @@ namespace __gnu_test
// Use an integer-class type to try and break the library code.
using difference_type = std::ranges::__detail::__max_diff_type;
+ constexpr
contiguous_iterator_wrapper&
operator++()
{
@@ -687,6 +747,7 @@ namespace __gnu_test
return *this;
}
+ constexpr
contiguous_iterator_wrapper&
operator--()
{
@@ -694,6 +755,7 @@ namespace __gnu_test
return *this;
}
+ constexpr
contiguous_iterator_wrapper
operator++(int)
{
@@ -702,6 +764,7 @@ namespace __gnu_test
return tmp;
}
+ constexpr
contiguous_iterator_wrapper
operator--(int)
{
@@ -710,6 +773,7 @@ namespace __gnu_test
return tmp;
}
+ constexpr
contiguous_iterator_wrapper&
operator+=(difference_type n)
{
@@ -718,23 +782,28 @@ namespace __gnu_test
return *this;
}
- friend contiguous_iterator_wrapper
+ friend constexpr
+ contiguous_iterator_wrapper
operator+(contiguous_iterator_wrapper iter, difference_type n)
{ return iter += n; }
- friend contiguous_iterator_wrapper
+ friend constexpr
+ contiguous_iterator_wrapper
operator+(difference_type n, contiguous_iterator_wrapper iter)
{ return iter += n; }
+ constexpr
contiguous_iterator_wrapper&
operator-=(difference_type n)
{ return *this += -n; }
- friend contiguous_iterator_wrapper
+ friend constexpr
+ contiguous_iterator_wrapper
operator-(contiguous_iterator_wrapper iter, difference_type n)
{ return iter -= n; }
- friend difference_type
+ friend constexpr
+ difference_type
operator-(contiguous_iterator_wrapper l, contiguous_iterator_wrapper r)
{
const random_access_iterator_wrapper<T>& lbase = l;
@@ -742,6 +811,7 @@ namespace __gnu_test
return static_cast<difference_type>(lbase - rbase);
}
+ constexpr
decltype(auto) operator[](difference_type n) const
{
auto d = static_cast<std::ptrdiff_t>(n);
@@ -759,6 +829,7 @@ namespace __gnu_test
{
using input_iterator_wrapper<T>::input_iterator_wrapper;
+ constexpr
input_iterator_wrapper_nocopy()
: input_iterator_wrapper<T>(nullptr, nullptr)
{ }
@@ -773,6 +844,7 @@ namespace __gnu_test
using input_iterator_wrapper<T>::operator++;
+ constexpr
input_iterator_wrapper_nocopy&
operator++()
{
@@ -789,6 +861,7 @@ namespace __gnu_test
using input_iterator_wrapper<T>::operator++;
+ constexpr
input_iterator_wrapper_rval&
operator++()
{
@@ -796,8 +869,8 @@ namespace __gnu_test
return *this;
}
- T&&
- operator*() const
+ constexpr
+ T&& operator*() const
{ return std::move(input_iterator_wrapper<T>::operator*()); }
};
@@ -815,7 +888,9 @@ namespace __gnu_test
using Iter<T>::operator++;
- iterator& operator++() { Iter<T>::operator++(); return *this; }
+ constexpr
+ iterator& operator++()
+ { Iter<T>::operator++(); return *this; }
};
template<typename I>
@@ -823,21 +898,24 @@ namespace __gnu_test
{
T* end;
- friend bool operator==(const sentinel& s, const I& i) noexcept
+ friend constexpr bool
+ operator==(const sentinel& s, const I& i) noexcept
{ return s.end == i.ptr; }
- friend auto operator-(const sentinel& s, const I& i) noexcept
+ friend constexpr
+ auto operator-(const sentinel& s, const I& i) noexcept
requires std::random_access_iterator<I>
{ return std::iter_difference_t<I>(s.end - i.ptr); }
- friend auto operator-(const I& i, const sentinel& s) noexcept
+ friend constexpr auto
+ operator-(const I& i, const sentinel& s) noexcept
requires std::random_access_iterator<I>
{ return std::iter_difference_t<I>(i.ptr - s.end); }
};
protected:
- auto
- get_iterator(T* p)
+ constexpr
+ auto get_iterator(T* p)
{
if constexpr (std::default_initializable<Iter<T>>)
return Iter<T>(p, &bounds);
@@ -846,17 +924,19 @@ namespace __gnu_test
}
public:
+ constexpr
test_range(T* first, T* last) : bounds(first, last)
{ }
template<std::size_t N>
- explicit
+ explicit constexpr
test_range(T (&arr)[N]) : test_range(arr, arr+N)
{ }
- auto begin() & { return get_iterator(bounds.first); }
+ constexpr auto begin() &
+ { return get_iterator(bounds.first); }
- auto end() &
+ constexpr auto end() &
{
using I = decltype(get_iterator(bounds.last));
return sentinel<I>{bounds.last};
@@ -869,7 +949,9 @@ namespace __gnu_test
template<typename T, template<typename> class Iter>
struct test_range_nocopy : test_range<T, Iter>
{
- test_range_nocopy(T* first, T* last) : test_range<T, Iter>(first, last)
+ constexpr
+ test_range_nocopy(T* first, T* last)
+ : test_range<T, Iter>(first, last)
{}
test_range_nocopy(test_range_nocopy&&) = default;
@@ -904,6 +986,7 @@ namespace __gnu_test
{
using test_range<T, Iter>::test_range;
+ constexpr
std::size_t size() const noexcept
{ return this->bounds.size(); }
};
@@ -939,18 +1022,22 @@ namespace __gnu_test
{
T* end;
- friend bool operator==(const sentinel& s, const I& i) noexcept
+ friend constexpr
+ bool operator==(const sentinel& s, const I& i) noexcept
{ return s.end == i.ptr; }
- friend std::iter_difference_t<I>
+ friend constexpr
+ std::iter_difference_t<I>
operator-(const sentinel& s, const I& i) noexcept
{ return std::iter_difference_t<I>(s.end - i.ptr); }
- friend std::iter_difference_t<I>
+ friend constexpr
+ std::iter_difference_t<I>
operator-(const I& i, const sentinel& s) noexcept
{ return std::iter_difference_t<I>(i.ptr - s.end); }
};
+ constexpr
auto end() &
{
using I = decltype(this->get_iterator(this->bounds.last));