aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--c++tools/ChangeLog5
-rwxr-xr-xc++tools/configure11
-rw-r--r--c++tools/configure.ac6
-rw-r--r--gcc/ChangeLog117
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/c-family/c.opt2
-rw-r--r--gcc/c/ChangeLog11
-rw-r--r--gcc/c/c-decl.cc1
-rw-r--r--gcc/c/c-objc-common.cc5
-rw-r--r--gcc/c/c-parser.cc19
-rw-r--r--gcc/c/c-typeck.cc17
-rw-r--r--gcc/cobol/ChangeLog13
-rw-r--r--gcc/cobol/genapi.cc4
-rw-r--r--gcc/cobol/gengen.cc16
-rw-r--r--gcc/cobol/genutil.cc23
-rw-r--r--gcc/cobol/genutil.h3
-rw-r--r--gcc/config/or1k/or1k.opt4
-rw-r--r--gcc/config/or1k/predicates.md3
-rw-r--r--gcc/config/riscv/autovec-opt.md52
-rw-r--r--gcc/config/riscv/autovec.md54
-rw-r--r--gcc/config/riscv/riscv-c.cc18
-rw-r--r--gcc/config/riscv/riscv-ext.def13
-rw-r--r--gcc/config/riscv/riscv-ext.opt2
-rw-r--r--gcc/config/riscv/riscv-opts.h1
-rw-r--r--gcc/config/riscv/riscv-protos.h1
-rw-r--r--gcc/config/riscv/riscv-subset.h62
-rw-r--r--gcc/config/riscv/riscv-v.cc1
-rw-r--r--gcc/config/riscv/riscv-vector-costs.cc4
-rw-r--r--gcc/config/riscv/riscv.cc78
-rw-r--r--gcc/config/riscv/riscv.opt4
-rw-r--r--gcc/config/riscv/t-riscv13
-rw-r--r--gcc/config/riscv/vector-iterators.md2
-rw-r--r--gcc/config/xtensa/xtensa.cc28
-rw-r--r--gcc/config/xtensa/xtensa.md2
-rw-r--r--gcc/cp/ChangeLog51
-rw-r--r--gcc/cp/constexpr.cc6
-rw-r--r--gcc/cp/coroutines.cc58
-rw-r--r--gcc/cp/cp-tree.h1
-rw-r--r--gcc/cp/error.cc21
-rw-r--r--gcc/cp/method.cc32
-rw-r--r--gcc/cp/name-lookup.h4
-rw-r--r--gcc/cp/parser.cc21
-rw-r--r--gcc/cp/pt.cc30
-rw-r--r--gcc/cp/semantics.cc4
-rw-r--r--gcc/doc/gm2.texi3
-rw-r--r--gcc/doc/invoke.texi7
-rw-r--r--gcc/doc/riscv-ext.texi4
-rw-r--r--gcc/doc/sourcebuild.texi3
-rw-r--r--gcc/final.cc11
-rw-r--r--gcc/fortran/data.cc8
-rw-r--r--gcc/function.h1
-rw-r--r--gcc/gimple-fold.cc5
-rw-r--r--gcc/gimple-harden-conditionals.cc6
-rw-r--r--gcc/gimple-harden-control-flow.cc3
-rw-r--r--gcc/ipa-strub.cc3
-rw-r--r--gcc/lra-eliminations.cc2
-rw-r--r--gcc/lra-spills.cc2
-rw-r--r--gcc/m2/ChangeLog102
-rw-r--r--gcc/m2/gm2-compiler/M2Check.def3
-rw-r--r--gcc/m2/gm2-compiler/M2Check.mod522
-rw-r--r--gcc/m2/gm2-compiler/M2GenGCC.mod88
-rw-r--r--gcc/m2/gm2-compiler/M2MetaError.def6
-rw-r--r--gcc/m2/gm2-compiler/M2Options.def16
-rw-r--r--gcc/m2/gm2-compiler/M2Options.mod22
-rw-r--r--gcc/m2/gm2-compiler/M2Quads.mod141
-rw-r--r--gcc/m2/gm2-compiler/M2Range.def18
-rw-r--r--gcc/m2/gm2-compiler/M2Range.mod274
-rw-r--r--gcc/m2/gm2-gcc/m2options.h2
-rw-r--r--gcc/m2/gm2-lang.cc3
-rw-r--r--gcc/m2/gm2-libs-log/InOut.mod12
-rw-r--r--gcc/m2/lang.opt4
-rw-r--r--gcc/passes.cc23
-rw-r--r--gcc/rtl.h10
-rw-r--r--gcc/rtlanal.cc15
-rw-r--r--gcc/testsuite/ChangeLog103
-rw-r--r--gcc/testsuite/c-c++-common/gomp/declare-variant-2.c2
-rw-r--r--gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c13
-rw-r--r--gcc/testsuite/c-c++-common/gomp/metadirective-condition.c25
-rw-r--r--gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c9
-rw-r--r--gcc/testsuite/g++.dg/coroutines/pr118903.C40
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-lambda24.C (renamed from gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda18.C)2
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constinit21.C28
-rw-r--r--gcc/testsuite/g++.dg/ext/has_trivial_destructor-3.C21
-rw-r--r--gcc/testsuite/g++.dg/ext/is_destructible2.C24
-rw-r--r--gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C43
-rw-r--r--gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C41
-rw-r--r--gcc/testsuite/g++.dg/modules/cpp-1.C3
-rw-r--r--gcc/testsuite/g++.dg/modules/cpp-3.C1
-rw-r--r--gcc/testsuite/g++.dg/modules/cpp-4.C1
-rw-r--r--gcc/testsuite/g++.dg/tls/pr102496-1.C2
-rw-r--r--gcc/testsuite/g++.dg/tls/pr77285-1.C2
-rw-r--r--gcc/testsuite/g++.target/arm/pr120424.C34
-rw-r--r--gcc/testsuite/g++.target/i386/pr103750.C39
-rw-r--r--gcc/testsuite/gcc.dg/Wjump-misses-init-3.c10
-rw-r--r--gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c26
-rw-r--r--gcc/testsuite/gcc.dg/pr116892.c11
-rw-r--r--gcc/testsuite/gcc.dg/pr120380.c24
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c43
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/phiprop-2.c28
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_136-pr120357.c13
-rw-r--r--gcc/testsuite/gcc.target/or1k/call-1.c22
-rw-r--r--gcc/testsuite/gcc.target/or1k/got-1.c18
-rw-r--r--gcc/testsuite/gcc.target/or1k/return-2.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/arch-59.c5
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv-nofm.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c4
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv-nofm.c8
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c4
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c10
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h61
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h413
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h34
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-1-i8.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-2-i8.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-3-i8.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-4-i32.c2
-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.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-5-i32.c2
-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.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i16.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i32.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i64.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx-6-i8.c2
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_binary_data.h196
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i16.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i32.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i64.c15
-rw-r--r--gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i8.c15
-rw-r--r--gcc/testsuite/gfortran.dg/coarray_data_2.f9014
-rw-r--r--gcc/testsuite/gfortran.dg/pr119856.f9015
-rw-r--r--gcc/testsuite/gm2/pim/fail/testcharint.mod8
-rw-r--r--gcc/testsuite/gm2/pim/fail/testindrx.mod8
-rw-r--r--gcc/testsuite/gm2/pim/pass/ReturnType.mod17
-rw-r--r--gcc/testsuite/gm2/pim/pass/ReturnType2.mod19
-rw-r--r--gcc/testsuite/gm2/pim/pass/testxindr.mod17
-rw-r--r--gcc/testsuite/gm2/pim/pass/testxindr2.mod17
-rw-r--r--gcc/testsuite/gm2/pim/pass/testxindr3.mod15
-rw-r--r--gcc/testsuite/gnat.dg/controlled9.adb10
-rw-r--r--gcc/testsuite/gnat.dg/controlled9_pkg.ads5
-rw-r--r--gcc/testsuite/lib/target-supports.exp10
-rw-r--r--gcc/tree-inline.cc1
-rw-r--r--gcc/tree-pass.h6
-rw-r--r--gcc/tree-ssa-forwprop.cc8
-rw-r--r--gcc/tree-switch-conversion.cc3
-rw-r--r--gcc/tree-vect-data-refs.cc2
-rw-r--r--gcc/tree-vect-loop.cc3
-rw-r--r--gcc/tree-vrp.cc4
-rw-r--r--include/ChangeLog5
-rw-r--r--include/cuda/cuda.h3
-rw-r--r--libgcobol/ChangeLog5
-rw-r--r--libgcobol/libgcobol.cc14
-rw-r--r--libgfortran/ChangeLog8
-rw-r--r--libgfortran/io/format.c10
-rw-r--r--libgomp/ChangeLog26
-rw-r--r--libgomp/libgomp-plugin.h1
-rw-r--r--libgomp/libgomp.h3
-rw-r--r--libgomp/libgomp.map6
-rw-r--r--libgomp/libgomp.texi98
-rw-r--r--libgomp/omp.h.in4
-rw-r--r--libgomp/omp_lib.f90.in23
-rw-r--r--libgomp/omp_lib.h.in25
-rw-r--r--libgomp/plugin/cuda-lib.def1
-rw-r--r--libgomp/plugin/plugin-gcn.c80
-rw-r--r--libgomp/plugin/plugin-nvptx.c9
-rw-r--r--libgomp/target.c83
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-2.c62
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-3.c80
-rw-r--r--libgomp/testsuite/libgomp.c-c++-common/omp_target_memset.c62
-rw-r--r--libgomp/testsuite/libgomp.fortran/omp_target_memset-2.f9067
-rw-r--r--libgomp/testsuite/libgomp.fortran/omp_target_memset.f9039
-rw-r--r--libstdc++-v3/ChangeLog62
-rw-r--r--libstdc++-v3/include/bits/atomic_timed_wait.h7
-rw-r--r--libstdc++-v3/include/bits/basic_string.h4
-rw-r--r--libstdc++-v3/include/bits/cpyfunc_impl.h4
-rw-r--r--libstdc++-v3/include/bits/funcref_impl.h4
-rw-r--r--libstdc++-v3/include/bits/funcwrap.h20
-rw-r--r--libstdc++-v3/include/bits/indirect.h376
-rw-r--r--libstdc++-v3/include/bits/mofunc_impl.h4
-rw-r--r--libstdc++-v3/include/bits/ranges_algo.h7
-rw-r--r--libstdc++-v3/include/bits/stl_algo.h89
-rw-r--r--libstdc++-v3/include/bits/stl_deque.h2
-rw-r--r--libstdc++-v3/include/bits/stl_vector.h10
-rw-r--r--libstdc++-v3/include/bits/vector.tcc6
-rw-r--r--libstdc++-v3/include/bits/version.def9
-rw-r--r--libstdc++-v3/include/bits/version.h10
-rw-r--r--libstdc++-v3/include/std/bit4
-rw-r--r--libstdc++-v3/include/std/memory1
-rw-r--r--libstdc++-v3/include/std/stop_token7
-rw-r--r--libstdc++-v3/include/std/type_traits42
-rw-r--r--libstdc++-v3/src/c++20/atomic.cc24
-rw-r--r--libstdc++-v3/src/c++23/std.cc.in8
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/call.cc7
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/conv.cc35
-rw-r--r--libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/call.cc10
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/conv.cc34
-rw-r--r--libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc18
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/call.cc7
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/conv.cc35
-rw-r--r--libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc18
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc127
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc157
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc270
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc190
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc220
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc13
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc28
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/move.cc177
-rw-r--r--libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc339
240 files changed, 6492 insertions, 634 deletions
diff --git a/c++tools/ChangeLog b/c++tools/ChangeLog
index ff35cac..d5a345b 100644
--- a/c++tools/ChangeLog
+++ b/c++tools/ChangeLog
@@ -1,3 +1,8 @@
+2025-06-02 Kito Cheng <kito.cheng@sifive.com>
+
+ * configure.ac: Don't check `--enable-default-pie`.
+ * configure: Regen.
+
2024-05-07 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* configure.ac (ax_lib_socket_nsl.m4): Don't sinclude.
diff --git a/c++tools/configure b/c++tools/configure
index 1353479..6df4a2f 100755
--- a/c++tools/configure
+++ b/c++tools/configure
@@ -700,7 +700,6 @@ enable_option_checking
enable_c___tools
enable_maintainer_mode
enable_checking
-enable_default_pie
enable_host_pie
enable_host_bind_now
with_gcc_major_version_only
@@ -1335,7 +1334,6 @@ Optional Features:
enable expensive run-time checks. With LIST, enable
only specific categories of checks. Categories are:
yes,no,all,none,release.
- --enable-default-pie enable Position Independent Executable as default
--enable-host-pie build host code as PIE
--enable-host-bind-now link host code as BIND_NOW
@@ -2946,15 +2944,6 @@ $as_echo "#define ENABLE_ASSERT_CHECKING 1" >>confdefs.h
fi
-# Check whether --enable-default-pie was given.
-# Check whether --enable-default-pie was given.
-if test "${enable_default_pie+set}" = set; then :
- enableval=$enable_default_pie; PICFLAG=-fPIE
-else
- PICFLAG=
-fi
-
-
# Enable --enable-host-pie
# Check whether --enable-host-pie was given.
if test "${enable_host_pie+set}" = set; then :
diff --git a/c++tools/configure.ac b/c++tools/configure.ac
index db34ee6..8c4b72a 100644
--- a/c++tools/configure.ac
+++ b/c++tools/configure.ac
@@ -97,12 +97,6 @@ if test x$ac_assert_checking != x ; then
[Define if you want assertions enabled. This is a cheap check.])
fi
-# Check whether --enable-default-pie was given.
-AC_ARG_ENABLE(default-pie,
-[AS_HELP_STRING([--enable-default-pie],
- [enable Position Independent Executable as default])],
-[PICFLAG=-fPIE], [PICFLAG=])
-
# Enable --enable-host-pie
AC_ARG_ENABLE(host-pie,
[AS_HELP_STRING([--enable-host-pie],
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 3c37d27..74490c4 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,120 @@
+2025-06-02 Alexandre Oliva <oliva@adacore.com>
+
+ PR rtl-optimization/120424
+ PR middle-end/118939
+ * lra-spills.cc (spill_pseudos): Update insn regno info.
+ * lra-eliminations.cc (update_reg_eliminate): Recognize
+ disabling of active elimination regardless of
+ prev_can_eliminate.
+
+2025-06-02 Dongyan Chen <chendongyan@isrc.iscas.ac.cn>
+
+ * config/riscv/riscv-ext.def: New extension defs.
+ * config/riscv/riscv-ext.opt: Ditto.
+ * doc/riscv-ext.texi: Ditto.
+
+2025-06-02 Stafford Horne <shorne@gmail.com>
+
+ * config/or1k/predicates.md (call_insn_operand): Add condition
+ to not allow symbol_ref operands with TARGET_CMODEL_LARGE.
+ * config/or1k/or1k.opt: Document new -mcmodel=large
+ implications.
+ * doc/invoke.texi: Likewise.
+
+2025-06-02 Christophe Lyon <christophe.lyon@linaro.org>
+
+ * doc/sourcebuild.texi (tls_link): Add documentation.
+
+2025-06-02 Kito Cheng <kito.cheng@sifive.com>
+
+ * config/riscv/t-riscv: Adjust build rule for gen-riscv-ext-opt
+ and gen-riscv-ext-texi.
+
+2025-06-02 Kito Cheng <kito.cheng@sifive.com>
+
+ * config/riscv/riscv-c.cc (riscv_cpu_cpp_builtins): Use
+ range-based-for-loop.
+ * config/riscv/riscv-subset.h (riscv_subset_list::iterator):
+ New.
+ (riscv_subset_list::const_iterator): New.
+
+2025-06-01 H.J. Lu <hjl.tools@gmail.com>
+
+ PR other/120493
+ * final.cc (call_from_call_insn): Change the argument type to
+ const rtx_call_insn *.
+ (get_call_rtx_from): New.
+ * rtl.h (is_a_helper <const rtx_call_insn *>::test): New.
+ (get_call_rtx_from): Moved to the final.cc section.
+ * rtlanal.cc (get_call_rtx_from): Removed.
+
+2025-06-01 Andrew Pinski <quic_apinski@quicinc.com>
+
+ * tree-ssa-forwprop.cc (optimize_vector_load): Set the vuse manually
+ on the new load statements. Also remove forward declaration since
+ the definition is before the first use.
+ (pass_forwprop::execute): Likewise for complex loads.
+ (pass_data_forwprop): Remove TODO_update_ssa.
+
+2025-06-01 Pan Li <pan2.li@intel.com>
+
+ * config/riscv/autovec.md: Fix line too long for sorts
+ of pattern.
+
+2025-06-01 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp>
+
+ * config/xtensa/xtensa.cc: Remove include of reload.h.
+
+2025-06-01 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp>
+
+ * config/xtensa/xtensa.md (movsf_internal):
+ Remove destination side constraint modifier '^' in the third
+ alternative.
+
+2025-06-01 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp>
+
+ * config/xtensa/xtensa.cc
+ (xtensa_ira_change_pseudo_allocno_class):
+ New prototype and function.
+ (TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS): Define macro.
+ (xtensa_register_move_cost):
+ Change between integer and FP register move cost to a value
+ based on actual behavior, i.e. 2, the default and the same as
+ the move cost between integer registers.
+
+2025-05-31 Andrew Pinski <quic_apinski@quicinc.com>
+
+ * function.h (struct function): Remove last_verified.
+ * gimple-harden-conditionals.cc (pass_data_harden_compares): Remove
+ TODO_verify_il.
+ (pass_data_harden_conditional_branches): Likewise.
+ * gimple-harden-control-flow.cc (pass_harden_control_flow_redundancy::execute):
+ Don't return TODO_verify_il.
+ * ipa-strub.cc (pass_data_ipa_strub): Remove TODO_verify_il.
+ * passes.cc (TODO_verify_il): Define.
+ (execute_function_todo): Don't use or set last_verified.
+ (clear_last_verified): Remove.
+ (execute_one_ipa_transform_pass): Update comment before execute_todo.
+ Assert that none of the todos have TODO_verify_il set on it.
+ (execute_one_pass): Don't call clear_last_verified on all functions.
+ Assert that none of the todos have TODO_verify_il set on it.
+ * tree-inline.cc (initialize_cfun): Don't copy last_verified.
+ * tree-pass.h (TODO_verify_all): Remove.
+ * tree-vrp.cc (pass_data_early_vrp): Remove TODO_verify_all.
+ (pass_data_fast_vrp): Likewise.
+
+2025-05-31 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/120357
+ * tree-vect-loop.cc (vect_create_epilog_for_reduction): Create
+ the conditional reduction induction IV increment before the
+ main IV exit.
+
+2025-05-31 Gaius Mulley <gaiusmod2@gmail.com>
+
+ PR modula2/120389
+ * doc/gm2.texi (-fm2-strict-type-reason): Document new flag.
+
2025-05-30 David Malcolm <dmalcolm@redhat.com>
PR other/116792
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index e844ed6..42c5479 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20250531
+20250603
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 75b6531..50ba856 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -938,7 +938,7 @@ C ObjC C++ ObjC++ CPP(cpp_warn_invalid_utf8) CppReason(CPP_W_INVALID_UTF8) Var(w
Warn about invalid UTF-8 characters.
Wjump-misses-init
-C ObjC Var(warn_jump_misses_init) Warning LangEnabledby(C ObjC,Wc++-compat)
+C ObjC Var(warn_jump_misses_init) Warning LangEnabledBy(C ObjC,Wc++-compat)
Warn when a jump misses a variable initialization.
Enum
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index f36431b..53ad780 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,14 @@
+2025-06-02 Sandra Loosemore <sloosemore@baylibre.com>
+
+ * c-parser.cc (c_parser_omp_context_selector): Call
+ convert_lvalue_to_rvalue and c_objc_common_truthvalue_conversion
+ on the expression for OMP_TRAIT_PROPERTY_BOOL_EXPR.
+
+2025-06-01 Martin Uecker <uecker@tugraz.at>
+
+ PR c/120380
+ * c-objc-common.cc (get_aka_type): Ignore attributes for tagged types.
+
2025-05-30 Qing Zhao <qing.zhao@oracle.com>
PR c/120354
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 1008bca..2b0bd66 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -10293,6 +10293,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype);
TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype);
ENUM_UNDERLYING_TYPE (tem) = ENUM_UNDERLYING_TYPE (enumtype);
+ TYPE_PACKED (tem) = TYPE_PACKED (enumtype);
}
/* Finish debugging output for this type. */
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index 2016eae..d574bc7 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -216,6 +216,11 @@ get_aka_type (tree type)
return canonical ? canonical : type;
}
}
+ /* For tagged types ignore attributes because they will otherwise
+ be ignored later causing a warning inside diagnostics which leads
+ to an ICE. */
+ if (RECORD_OR_UNION_TYPE_P (type) || TREE_CODE (type) == ENUMERAL_TYPE)
+ return build_qualified_type (result, TYPE_QUALS (type));
return build_type_attribute_qual_variant (result, TYPE_ATTRIBUTES (type),
TYPE_QUALS (type));
}
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index cc0ab12..85580c5 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -26966,17 +26966,30 @@ c_parser_omp_context_selector (c_parser *parser, enum omp_tss_code set,
break;
case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR:
case OMP_TRAIT_PROPERTY_BOOL_EXPR:
- t = c_parser_expr_no_commas (parser, NULL).value;
+ {
+ c_expr texpr = c_parser_expr_no_commas (parser, NULL);
+ texpr = convert_lvalue_to_rvalue (token->location, texpr,
+ true, true);
+ t = texpr.value;
+ }
if (t == error_mark_node)
return error_mark_node;
mark_exp_read (t);
- t = c_fully_fold (t, false, NULL);
- if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR)
+ {
+ t = c_objc_common_truthvalue_conversion (token->location,
+ t,
+ boolean_type_node);
+ if (t == error_mark_node)
+ return error_mark_node;
+ }
+ else if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
{
error_at (token->location,
"property must be integer expression");
return error_mark_node;
}
+ t = c_fully_fold (t, false, NULL);
properties = make_trait_property (NULL_TREE, t, properties);
break;
case OMP_TRAIT_PROPERTY_CLAUSE_LIST:
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 2f243ca..b59b5c8a 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -846,12 +846,7 @@ composite_type_internal (tree t1, tree t2, struct composite_cache* cache)
n = finish_struct (input_location, n, fields, attributes, NULL,
&expr);
- n = qualify_type (n, t1);
-
- gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t1));
- gcc_checking_assert (!TYPE_NAME (n) || comptypes (n, t2));
-
- return n;
+ return qualify_type (n, t1);
}
/* FALLTHRU */
case ENUMERAL_TYPE:
@@ -1004,7 +999,15 @@ tree
composite_type (tree t1, tree t2)
{
struct composite_cache cache = { };
- return composite_type_internal (t1, t2, &cache);
+ tree n = composite_type_internal (t1, t2, &cache);
+ /* For function and arrays there are some cases where qualifiers do
+ not match. See PR120510. */
+ if (FUNCTION_TYPE != TREE_CODE (n) && ARRAY_TYPE != TREE_CODE (n))
+ {
+ gcc_checking_assert (comptypes (n, t1));
+ gcc_checking_assert (comptypes (n, t2));
+ }
+ return n;
}
/* Return the type of a conditional expression between pointers to
diff --git a/gcc/cobol/ChangeLog b/gcc/cobol/ChangeLog
index 44bf89f..03243e9 100644
--- a/gcc/cobol/ChangeLog
+++ b/gcc/cobol/ChangeLog
@@ -1,3 +1,16 @@
+2025-06-02 Robert Dubner <rdubner@symas.com>
+
+ PR cobol/119975
+ * genapi.cc (parser_intrinsic_call_0): Use get_time_64() function.
+ * genutil.cc (get_time_64): Definition created.
+ * genutil.h (get_time_64): Declaration created.
+
+2025-06-01 Robert Dubner <rdubner@symas.com>
+
+ PR cobol/119524
+ * gengen.cc (gg_printf): Use the new __gg__fprintf_stderr() function
+ instead of generating a call to fprintf().
+
2025-05-20 Robert Dubner <rdubner@symas.com>
James K. Lowden <jklowden@cobolworx.com>
diff --git a/gcc/cobol/genapi.cc b/gcc/cobol/genapi.cc
index 2ce9cad..5e983ab 100644
--- a/gcc/cobol/genapi.cc
+++ b/gcc/cobol/genapi.cc
@@ -10491,7 +10491,9 @@ parser_intrinsic_call_0(cbl_field_t *tgt,
{
// Pass __gg__when_compiled() the time from right now.
struct timespec tp;
- clock_gettime(CLOCK_REALTIME, &tp); // time_t tv_sec; long tv_nsec
+ uint64_t now = get_time_64();
+ tp.tv_sec = now / 1000000000;
+ tp.tv_nsec = now % 1000000000;
store_location_stuff(function_name);
gg_call(VOID,
diff --git a/gcc/cobol/gengen.cc b/gcc/cobol/gengen.cc
index 91f67d5..a5f143c 100644
--- a/gcc/cobol/gengen.cc
+++ b/gcc/cobol/gengen.cc
@@ -2152,18 +2152,6 @@ gg_printf(const char *format_string, ...)
int nargs = 0;
tree args[ARG_LIMIT];
- // Because this routine is intended for debugging, we are sending the
- // text to STDERR
-
- // Because we don't actually use stderr ourselves, we just pick it up as a
- // VOID_P and pass it along to fprintf()
- tree t_stderr = gg_declare_variable(VOID_P, "stderr",
- NULL_TREE,
- vs_external_reference);
-
- gg_push_context();
-
- args[nargs++] = t_stderr;
args[nargs++] = build_string_literal(strlen(format_string)+1, format_string);
va_list ap;
@@ -2197,7 +2185,7 @@ gg_printf(const char *format_string, ...)
static tree function = NULL_TREE;
if( !function )
{
- function = gg_get_function_address(INT, "fprintf");
+ function = gg_get_function_address(INT, "__gg__fprintf_stderr");
}
tree stmt = build_call_array_loc (location_from_lineno(),
@@ -2206,8 +2194,6 @@ gg_printf(const char *format_string, ...)
nargs,
args);
gg_append_statement(stmt);
-
- gg_pop_context();
}
tree
diff --git a/gcc/cobol/genutil.cc b/gcc/cobol/genutil.cc
index d0aaf2b3..e971043 100644
--- a/gcc/cobol/genutil.cc
+++ b/gcc/cobol/genutil.cc
@@ -2119,3 +2119,26 @@ qualified_data_location(cbl_refer_t &refer)
return gg_add(member(refer.field->var_decl_node, "data"),
refer_offset(refer));
}
+
+uint64_t
+get_time_64()
+{
+ // This code was unabashedly stolen from gcc/timevar.cc.
+ // It returns the Unix epoch with nine decimal places.
+
+ uint64_t retval = 0;
+
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec ts;
+ clock_gettime (CLOCK_REALTIME, &ts);
+ retval = ts.tv_sec * 1000000000 + ts.tv_nsec;
+ return retval;
+#endif
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ retval = tv.tv_sec * 1000000000 + tv.tv_usec * 1000;
+ return retval;
+#endif
+ return retval;
+} \ No newline at end of file
diff --git a/gcc/cobol/genutil.h b/gcc/cobol/genutil.h
index 2f4bc36..43102d7 100644
--- a/gcc/cobol/genutil.h
+++ b/gcc/cobol/genutil.h
@@ -155,4 +155,7 @@ void build_array_of_fourplets( int ngroup,
size_t N,
cbl_refer_t *refers);
void get_depending_on_value_from_odo(tree retval, cbl_field_t *odo);
+uint64_t get_time_64();
+
+
#endif
diff --git a/gcc/config/or1k/or1k.opt b/gcc/config/or1k/or1k.opt
index 00c5560..d252de0 100644
--- a/gcc/config/or1k/or1k.opt
+++ b/gcc/config/or1k/or1k.opt
@@ -69,8 +69,8 @@ are used to perform unordered floating point compare and set flag operations.
mcmodel=
Target RejectNegative Joined Enum(or1k_cmodel_type) Var(or1k_code_model) Init(CMODEL_SMALL)
Specify the code model used for accessing memory addresses. Specifying large
-enables generating binaries with large global offset tables. By default the
-value is small.
+enables generating binaries with large global offset tables and calling
+functions anywhere in an executable. By default the value is small.
Enum
Name(or1k_cmodel_type) Type(enum or1k_cmodel_type)
diff --git a/gcc/config/or1k/predicates.md b/gcc/config/or1k/predicates.md
index 11bb518..144f4d7 100644
--- a/gcc/config/or1k/predicates.md
+++ b/gcc/config/or1k/predicates.md
@@ -61,7 +61,8 @@
(match_test "TARGET_ROR"))))
(define_predicate "call_insn_operand"
- (ior (match_code "symbol_ref")
+ (ior (and (match_code "symbol_ref")
+ (match_test "!TARGET_CMODEL_LARGE"))
(match_operand 0 "register_operand")))
(define_predicate "high_operand"
diff --git a/gcc/config/riscv/autovec-opt.md b/gcc/config/riscv/autovec-opt.md
index a972eda..19eb16c 100644
--- a/gcc/config/riscv/autovec-opt.md
+++ b/gcc/config/riscv/autovec-opt.md
@@ -1713,3 +1713,55 @@
<MODE>mode);
}
[(set_attr "type" "vialu")])
+
+;; =============================================================================
+;; Combine vec_duplicate + op.vv to op.vf
+;; Include
+;; - vfmadd.vf
+;; - vfmsub.vf
+;; =============================================================================
+
+
+(define_insn_and_split "*<optab>_vf_<mode>"
+ [(set (match_operand:V_VLSF 0 "register_operand" "=vd")
+ (plus_minus:V_VLSF
+ (mult:V_VLSF
+ (vec_duplicate:V_VLSF
+ (match_operand:<VEL> 1 "register_operand" " f"))
+ (match_operand:V_VLSF 2 "register_operand" " 0"))
+ (match_operand:V_VLSF 3 "register_operand" " vr")))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3],
+ operands[2]};
+ riscv_vector::emit_vlmax_insn (code_for_pred_mul_scalar (<CODE>, <MODE>mode),
+ riscv_vector::TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfmuladd")]
+)
+
+(define_insn_and_split "*<optab>_vf_<mode>"
+ [(set (match_operand:V_VLSF 0 "register_operand" "=vd")
+ (plus_minus:V_VLSF
+ (match_operand:V_VLSF 3 "register_operand" " vr")
+ (mult:V_VLSF
+ (vec_duplicate:V_VLSF
+ (match_operand:<VEL> 1 "register_operand" " f"))
+ (match_operand:V_VLSF 2 "register_operand" " 0"))))]
+ "TARGET_VECTOR && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(const_int 0)]
+ {
+ rtx ops[] = {operands[0], operands[1], operands[2], operands[3],
+ operands[2]};
+ riscv_vector::emit_vlmax_insn (code_for_pred_mul_scalar (<CODE>, <MODE>mode),
+ riscv_vector::TERNARY_OP_FRM_DYN, ops);
+ DONE;
+ }
+ [(set_attr "type" "vfmuladd")]
+)
diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index 60c881b..c678eef 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -2493,7 +2493,8 @@
"TARGET_VECTOR"
{
insn_code icode = code_for_pred (UNSPEC_VAADD, <V_DOUBLE_TRUNC>mode);
- riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RDN, operands);
+ riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RDN,
+ operands);
DONE;
}
)
@@ -2527,7 +2528,8 @@
"TARGET_VECTOR"
{
insn_code icode = code_for_pred (UNSPEC_VAADDU, <MODE>mode);
- riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RDN, operands);
+ riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RDN,
+ operands);
DONE;
})
@@ -2540,7 +2542,8 @@
"TARGET_VECTOR"
{
insn_code icode = code_for_pred (UNSPEC_VAADDU, <MODE>mode);
- riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RNU, operands);
+ riscv_vector::emit_vlmax_insn (icode, riscv_vector::BINARY_OP_VXRM_RNU,
+ operands);
DONE;
})
@@ -2565,7 +2568,8 @@
(match_operand:V_VLSF 1 "register_operand")]
"TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math"
{
- riscv_vector::expand_vec_ceil (operands[0], operands[1], <MODE>mode, <VCONVERT>mode);
+ riscv_vector::expand_vec_ceil (operands[0], operands[1], <MODE>mode,
+ <VCONVERT>mode);
DONE;
}
)
@@ -2575,7 +2579,8 @@
(match_operand:V_VLSF 1 "register_operand")]
"TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math"
{
- riscv_vector::expand_vec_floor (operands[0], operands[1], <MODE>mode, <VCONVERT>mode);
+ riscv_vector::expand_vec_floor (operands[0], operands[1], <MODE>mode,
+ <VCONVERT>mode);
DONE;
}
)
@@ -2585,7 +2590,8 @@
(match_operand:V_VLSF 1 "register_operand")]
"TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math"
{
- riscv_vector::expand_vec_nearbyint (operands[0], operands[1], <MODE>mode, <VCONVERT>mode);
+ riscv_vector::expand_vec_nearbyint (operands[0], operands[1], <MODE>mode,
+ <VCONVERT>mode);
DONE;
}
)
@@ -2595,7 +2601,8 @@
(match_operand:V_VLSF 1 "register_operand")]
"TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math"
{
- riscv_vector::expand_vec_rint (operands[0], operands[1], <MODE>mode, <VCONVERT>mode);
+ riscv_vector::expand_vec_rint (operands[0], operands[1], <MODE>mode,
+ <VCONVERT>mode);
DONE;
}
)
@@ -2605,7 +2612,8 @@
(match_operand:V_VLSF 1 "register_operand")]
"TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math"
{
- riscv_vector::expand_vec_round (operands[0], operands[1], <MODE>mode, <VCONVERT>mode);
+ riscv_vector::expand_vec_round (operands[0], operands[1], <MODE>mode,
+ <VCONVERT>mode);
DONE;
}
)
@@ -2615,7 +2623,8 @@
(match_operand:V_VLSF 1 "register_operand")]
"TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math"
{
- riscv_vector::expand_vec_trunc (operands[0], operands[1], <MODE>mode, <VCONVERT>mode);
+ riscv_vector::expand_vec_trunc (operands[0], operands[1], <MODE>mode,
+ <VCONVERT>mode);
DONE;
}
)
@@ -2625,7 +2634,8 @@
(match_operand:V_VLSF 1 "register_operand")]
"TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math"
{
- riscv_vector::expand_vec_roundeven (operands[0], operands[1], <MODE>mode, <VCONVERT>mode);
+ riscv_vector::expand_vec_roundeven (operands[0], operands[1], <MODE>mode,
+ <VCONVERT>mode);
DONE;
}
)
@@ -2682,7 +2692,8 @@
(match_operand:V_VLS_F_CONVERT_SI 1 "register_operand")]
"TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math"
{
- riscv_vector::expand_vec_lceil (operands[0], operands[1], <MODE>mode, <V_F2SI_CONVERT>mode);
+ riscv_vector::expand_vec_lceil (operands[0], operands[1], <MODE>mode,
+ <V_F2SI_CONVERT>mode);
DONE;
}
)
@@ -2692,7 +2703,8 @@
(match_operand:V_VLS_F_CONVERT_DI 1 "register_operand")]
"TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math"
{
- riscv_vector::expand_vec_lceil (operands[0], operands[1], <MODE>mode, <V_F2DI_CONVERT>mode);
+ riscv_vector::expand_vec_lceil (operands[0], operands[1], <MODE>mode,
+ <V_F2DI_CONVERT>mode);
DONE;
}
)
@@ -2702,7 +2714,8 @@
(match_operand:V_VLS_F_CONVERT_SI 1 "register_operand")]
"TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math"
{
- riscv_vector::expand_vec_lfloor (operands[0], operands[1], <MODE>mode, <V_F2SI_CONVERT>mode);
+ riscv_vector::expand_vec_lfloor (operands[0], operands[1], <MODE>mode,
+ <V_F2SI_CONVERT>mode);
DONE;
}
)
@@ -2712,7 +2725,8 @@
(match_operand:V_VLS_F_CONVERT_DI 1 "register_operand")]
"TARGET_VECTOR && !flag_trapping_math && !flag_rounding_math"
{
- riscv_vector::expand_vec_lfloor (operands[0], operands[1], <MODE>mode, <V_F2DI_CONVERT>mode);
+ riscv_vector::expand_vec_lfloor (operands[0], operands[1], <MODE>mode,
+ <V_F2DI_CONVERT>mode);
DONE;
}
)
@@ -2744,7 +2758,8 @@
(match_operand:V_VLSI 2 "register_operand")]
"TARGET_VECTOR"
{
- riscv_vector::expand_vec_usadd (operands[0], operands[1], operands[2], <MODE>mode);
+ riscv_vector::expand_vec_usadd (operands[0], operands[1], operands[2],
+ <MODE>mode);
DONE;
}
)
@@ -2755,7 +2770,8 @@
(match_operand:V_VLSI 2 "register_operand")]
"TARGET_VECTOR"
{
- riscv_vector::expand_vec_ssadd (operands[0], operands[1], operands[2], <MODE>mode);
+ riscv_vector::expand_vec_ssadd (operands[0], operands[1], operands[2],
+ <MODE>mode);
DONE;
}
)
@@ -2766,7 +2782,8 @@
(match_operand:V_VLSI 2 "register_operand")]
"TARGET_VECTOR"
{
- riscv_vector::expand_vec_ussub (operands[0], operands[1], operands[2], <MODE>mode);
+ riscv_vector::expand_vec_ussub (operands[0], operands[1], operands[2],
+ <MODE>mode);
DONE;
}
)
@@ -2777,7 +2794,8 @@
(match_operand:V_VLSI 2 "register_operand")]
"TARGET_VECTOR"
{
- riscv_vector::expand_vec_sssub (operands[0], operands[1], operands[2], <MODE>mode);
+ riscv_vector::expand_vec_sssub (operands[0], operands[1], operands[2],
+ <MODE>mode);
DONE;
}
)
diff --git a/gcc/config/riscv/riscv-c.cc b/gcc/config/riscv/riscv-c.cc
index 1ff1968..d2c0af3 100644
--- a/gcc/config/riscv/riscv-c.cc
+++ b/gcc/config/riscv/riscv-c.cc
@@ -239,26 +239,22 @@ riscv_cpu_cpp_builtins (cpp_reader *pfile)
size_t max_ext_len = 0;
/* Figure out the max length of extension name for reserving buffer. */
- for (const riscv_subset_t *subset = subset_list->begin ();
- subset != subset_list->end ();
- subset = subset->next)
- max_ext_len = MAX (max_ext_len, subset->name.length ());
+ for (auto &subset : *subset_list)
+ max_ext_len = MAX (max_ext_len, subset.name.length ());
char *buf = (char *)alloca (max_ext_len + 10 /* For __riscv_ and '\0'. */);
- for (const riscv_subset_t *subset = subset_list->begin ();
- subset != subset_list->end ();
- subset = subset->next)
+ for (auto &subset : *subset_list)
{
- int version_value = riscv_ext_version_value (subset->major_version,
- subset->minor_version);
+ int version_value = riscv_ext_version_value (subset.major_version,
+ subset.minor_version);
/* Special rule for zicsr and zifencei, it's used for ISA spec 2.2 or
earlier. */
- if ((subset->name == "zicsr" || subset->name == "zifencei")
+ if ((subset.name == "zicsr" || subset.name == "zifencei")
&& version_value == 0)
version_value = riscv_ext_version_value (2, 0);
- sprintf (buf, "__riscv_%s", subset->name.c_str ());
+ sprintf (buf, "__riscv_%s", subset.name.c_str ());
builtin_define_with_int_value (buf, version_value);
}
}
diff --git a/gcc/config/riscv/riscv-ext.def b/gcc/config/riscv/riscv-ext.def
index dbda8de..d0adc2b 100644
--- a/gcc/config/riscv/riscv-ext.def
+++ b/gcc/config/riscv/riscv-ext.def
@@ -1676,6 +1676,19 @@ DEFINE_RISCV_EXT(
/* EXTRA_EXTENSION_FLAGS */ 0)
DEFINE_RISCV_EXT(
+ /* NAME */ smcntrpmf,
+ /* UPPERCAE_NAME */ SMCNTRPMF,
+ /* FULL_NAME */ "Cycle and instret privilege mode filtering",
+ /* DESC */ "",
+ /* URL */ ,
+ /* DEP_EXTS */ ({"zicsr"}),
+ /* SUPPORTED_VERSIONS */ ({{1, 0}}),
+ /* FLAG_GROUP */ sm,
+ /* BITMASK_GROUP_ID */ BITMASK_NOT_YET_ALLOCATED,
+ /* BITMASK_BIT_POSITION*/ BITMASK_NOT_YET_ALLOCATED,
+ /* EXTRA_EXTENSION_FLAGS */ 0)
+
+DEFINE_RISCV_EXT(
/* NAME */ smepmp,
/* UPPERCAE_NAME */ SMEPMP,
/* FULL_NAME */ "PMP Enhancements for memory access and execution prevention on Machine mode",
diff --git a/gcc/config/riscv/riscv-ext.opt b/gcc/config/riscv/riscv-ext.opt
index 5e9c5f5..c0dcde6 100644
--- a/gcc/config/riscv/riscv-ext.opt
+++ b/gcc/config/riscv/riscv-ext.opt
@@ -335,6 +335,8 @@ Mask(SHVSATPA) Var(riscv_sh_subext)
Mask(SMAIA) Var(riscv_sm_subext)
+Mask(SMCNTRPMF) Var(riscv_sm_subext)
+
Mask(SMEPMP) Var(riscv_sm_subext)
Mask(SMMPM) Var(riscv_sm_subext)
diff --git a/gcc/config/riscv/riscv-opts.h b/gcc/config/riscv/riscv-opts.h
index c02c599..e1a820b 100644
--- a/gcc/config/riscv/riscv-opts.h
+++ b/gcc/config/riscv/riscv-opts.h
@@ -164,6 +164,7 @@ enum riscv_tls_type {
(TARGET_VECTOR && riscv_mautovec_segment)
#define GPR2VR_COST_UNPROVIDED -1
+#define FPR2VR_COST_UNPROVIDED -1
/* Extra extension flags, used for carry extra info for a RISC-V extension. */
enum
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index d8c8f6b..a033120 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -841,6 +841,7 @@ const struct riscv_tune_info *
riscv_parse_tune (const char *, bool);
const cpu_vector_cost *get_vector_costs ();
int get_gr2vr_cost ();
+int get_fr2vr_cost ();
enum
{
diff --git a/gcc/config/riscv/riscv-subset.h b/gcc/config/riscv/riscv-subset.h
index c5d9fab..a35537d 100644
--- a/gcc/config/riscv/riscv-subset.h
+++ b/gcc/config/riscv/riscv-subset.h
@@ -109,9 +109,6 @@ public:
static riscv_subset_list *parse (const char *, location_t);
const char *parse_single_ext (const char *, bool exact_single_p = true);
- const riscv_subset_t *begin () const {return m_head;};
- const riscv_subset_t *end () const {return NULL;};
-
int match_score (riscv_subset_list *) const;
void set_loc (location_t);
@@ -119,6 +116,65 @@ public:
void set_allow_adding_dup (bool v) { m_allow_adding_dup = v; }
void finalize ();
+
+ class iterator
+ {
+ public:
+ explicit iterator(riscv_subset_t *node) : m_node(node) {}
+
+ riscv_subset_t &operator*() const { return *m_node; }
+ riscv_subset_t *operator->() const { return m_node; }
+
+ iterator &operator++()
+ {
+ if (m_node)
+ m_node = m_node->next;
+ return *this;
+ }
+
+ bool operator!=(const iterator &other) const
+ {
+ return m_node != other.m_node;
+ }
+
+ bool operator==(const iterator &other) const
+ {
+ return m_node == other.m_node;
+ }
+
+ private:
+ riscv_subset_t *m_node;
+ };
+
+ iterator begin() { return iterator(m_head); }
+ iterator end() { return iterator(nullptr); }
+
+ class const_iterator
+ {
+ public:
+ explicit const_iterator(const riscv_subset_t *node) : m_node(node) {}
+
+ const riscv_subset_t &operator*() const { return *m_node; }
+ const riscv_subset_t *operator->() const { return m_node; }
+
+ const_iterator &operator++()
+ {
+ if (m_node)
+ m_node = m_node->next;
+ return *this;
+ }
+
+ bool operator!=(const const_iterator &other) const
+ {
+ return m_node != other.m_node;
+ }
+
+ private:
+ const riscv_subset_t *m_node;
+ };
+
+ const_iterator begin() const { return const_iterator(m_head); }
+ const_iterator end() const { return const_iterator(nullptr); }
};
extern const riscv_subset_list *riscv_cmdline_subset_list (void);
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index 6162797..a41317f 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -5567,6 +5567,7 @@ expand_vx_binary_vec_vec_dup (rtx op_0, rtx op_1, rtx op_2,
case IOR:
case XOR:
case MULT:
+ case DIV:
icode = code_for_pred_scalar (code, mode);
break;
default:
diff --git a/gcc/config/riscv/riscv-vector-costs.cc b/gcc/config/riscv/riscv-vector-costs.cc
index a39b611..4d8170d 100644
--- a/gcc/config/riscv/riscv-vector-costs.cc
+++ b/gcc/config/riscv/riscv-vector-costs.cc
@@ -1099,8 +1099,8 @@ costs::adjust_stmt_cost (enum vect_cost_for_stmt kind, loop_vec_info loop,
switch (kind)
{
case scalar_to_vec:
- stmt_cost += (FLOAT_TYPE_P (vectype) ? costs->regmove->FR2VR
- : get_gr2vr_cost ());
+ stmt_cost
+ += (FLOAT_TYPE_P (vectype) ? get_fr2vr_cost () : get_gr2vr_cost ());
break;
case vec_to_scalar:
stmt_cost += (FLOAT_TYPE_P (vectype) ? costs->regmove->VR2FR
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index d3cee96..b168a64 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -3891,6 +3891,25 @@ riscv_extend_cost (rtx op, bool unsigned_p)
return COSTS_N_INSNS (2);
}
+/* Return the cost of the vector binary rtx like add, minus, mult.
+ The cost of gr2vr will be appended if there one of the op comes
+ from the VEC_DUPLICATE. */
+
+static int
+get_vector_binary_rtx_cost (rtx x, int gr2vr_cost)
+{
+ gcc_assert (riscv_v_ext_mode_p (GET_MODE (x)));
+
+ rtx op_0 = XEXP (x, 0);
+ rtx op_1 = XEXP (x, 1);
+
+ if (GET_CODE (op_0) == VEC_DUPLICATE
+ || GET_CODE (op_1) == VEC_DUPLICATE)
+ return (gr2vr_cost + 1) * COSTS_N_INSNS (1);
+ else
+ return COSTS_N_INSNS (1);
+}
+
/* Implement TARGET_RTX_COSTS. */
#define SINGLE_SHIFT_COST 1
@@ -3904,6 +3923,7 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
if (riscv_v_ext_mode_p (mode))
{
int gr2vr_cost = get_gr2vr_cost ();
+ int fr2vr_cost = get_fr2vr_cost ();
switch (outer_code)
{
@@ -3914,6 +3934,21 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
case VEC_DUPLICATE:
*total = gr2vr_cost * COSTS_N_INSNS (1);
break;
+ case IF_THEN_ELSE:
+ {
+ rtx op_1 = XEXP (x, 1);
+
+ switch (GET_CODE (op_1))
+ {
+ case DIV:
+ *total = get_vector_binary_rtx_cost (op_1, gr2vr_cost);
+ break;
+ default:
+ *total = COSTS_N_INSNS (1);
+ break;
+ }
+ }
+ break;
case PLUS:
case MINUS:
case AND:
@@ -3923,14 +3958,29 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN
{
rtx op_0 = XEXP (x, 0);
rtx op_1 = XEXP (x, 1);
+ rtx op;
if (GET_CODE (op_0) == VEC_DUPLICATE
|| GET_CODE (op_1) == VEC_DUPLICATE)
- *total = (gr2vr_cost + 1) * COSTS_N_INSNS (1);
- else
- *total = COSTS_N_INSNS (1);
+ {
+ *total = (gr2vr_cost + 1) * COSTS_N_INSNS (1);
+ break;
+ }
+ else if (GET_CODE (op = op_0) == MULT
+ || GET_CODE (op = op_1) == MULT)
+ {
+ rtx mult_op0 = XEXP (op, 0);
+ if (GET_CODE (mult_op0) == VEC_DUPLICATE)
+ {
+ if (FLOAT_MODE_P (mode))
+ *total = (fr2vr_cost + 1) * COSTS_N_INSNS (1);
+ else
+ *total = (gr2vr_cost + 1) * COSTS_N_INSNS (1);
+ break;
+ }
+ }
}
- break;
+ /* Fall through. */
default:
*total = COSTS_N_INSNS (1);
break;
@@ -9781,7 +9831,7 @@ riscv_register_move_cost (machine_mode mode,
if (from_is_gpr)
return get_gr2vr_cost ();
else if (from_is_fpr)
- return get_vector_costs ()->regmove->FR2VR;
+ return get_fr2vr_cost ();
}
return riscv_secondary_memory_needed (mode, from, to) ? 8 : 2;
@@ -12647,6 +12697,21 @@ get_gr2vr_cost ()
return cost;
}
+/* Return the cost of moving data from floating-point to vector register.
+ It will take the value of --param=fpr2vr-cost if it is provided.
+ Otherwise the default regmove->FR2VR will be returned. */
+
+int
+get_fr2vr_cost ()
+{
+ int cost = get_vector_costs ()->regmove->FR2VR;
+
+ if (fpr2vr_cost != FPR2VR_COST_UNPROVIDED)
+ cost = fpr2vr_cost;
+
+ return cost;
+}
+
/* Implement targetm.vectorize.builtin_vectorization_cost. */
static int
@@ -12712,8 +12777,7 @@ riscv_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
case vec_construct:
{
/* TODO: This is too pessimistic in case we can splat. */
- int regmove_cost = fp ? costs->regmove->FR2VR
- : get_gr2vr_cost ();
+ int regmove_cost = fp ? get_fr2vr_cost () : get_gr2vr_cost ();
return (regmove_cost + common_costs->scalar_to_vec_cost)
* estimated_poly_value (TYPE_VECTOR_SUBPARTS (vectype));
}
diff --git a/gcc/config/riscv/riscv.opt b/gcc/config/riscv/riscv.opt
index b2b9d33..6543fd1 100644
--- a/gcc/config/riscv/riscv.opt
+++ b/gcc/config/riscv/riscv.opt
@@ -286,6 +286,10 @@ Max number of bytes to compare as part of inlined strcmp/strncmp routines (defau
Target RejectNegative Joined UInteger Var(gpr2vr_cost) Init(GPR2VR_COST_UNPROVIDED)
Set the cost value of the rvv instruction when operate from GPR to VR.
+-param=fpr2vr-cost=
+Target RejectNegative Joined UInteger Var(fpr2vr_cost) Init(FPR2VR_COST_UNPROVIDED)
+Set the cost value of the rvv instruction when operate from FPR to VR.
+
-param=riscv-autovec-mode=
Target Undocumented RejectNegative Joined Var(riscv_autovec_mode) Save
Set the only autovec mode to try.
diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv
index 854daa9..32092d8 100644
--- a/gcc/config/riscv/t-riscv
+++ b/gcc/config/riscv/t-riscv
@@ -198,19 +198,24 @@ RISCV_EXT_DEFS = \
$(srcdir)/config/riscv/riscv-ext.opt: $(RISCV_EXT_DEFS)
-build/gen-riscv-ext-opt$(build_exeext): $(srcdir)/config/riscv/gen-riscv-ext-opt.cc \
+build/gen-riscv-ext-opt.o: $(srcdir)/config/riscv/gen-riscv-ext-opt.cc \
$(RISCV_EXT_DEFS)
- $(CXX_FOR_BUILD) $(CXXFLAGS_FOR_BUILD) $< -o $@
+ $(CXX_FOR_BUILD) $(CXXFLAGS_FOR_BUILD) -c $< -o $@
+
+build/gen-riscv-ext-opt$(build_exeext): build/gen-riscv-ext-opt.o
+ $(LINKER_FOR_BUILD) $(BUILD_LINKERFLAGS) $(BUILD_LDFLAGS) -o $@ $<
s-riscv-ext.opt: build/gen-riscv-ext-opt$(build_exeext)
$(RUN_GEN) build/gen-riscv-ext-opt$(build_exeext) > tmp-riscv-ext.opt
$(SHELL) $(srcdir)/../move-if-change tmp-riscv-ext.opt $(srcdir)/config/riscv/riscv-ext.opt
$(STAMP) s-riscv-ext.opt
-build/gen-riscv-ext-texi$(build_exeext): $(srcdir)/config/riscv/gen-riscv-ext-texi.cc \
+build/gen-riscv-ext-texi.o: $(srcdir)/config/riscv/gen-riscv-ext-texi.cc \
$(RISCV_EXT_DEFS)
- $(CXX_FOR_BUILD) $(CXXFLAGS_FOR_BUILD) $< -o $@
+ $(CXX_FOR_BUILD) $(CXXFLAGS_FOR_BUILD) -c $< -o $@
+build/gen-riscv-ext-texi$(build_exeext): build/gen-riscv-ext-texi.o
+ $(LINKER_FOR_BUILD) $(BUILD_LINKERFLAGS) $(BUILD_LDFLAGS) -o $@ $<
$(srcdir)/doc/riscv-ext.texi: $(RISCV_EXT_DEFS)
$(srcdir)/doc/riscv-ext.texi: s-riscv-ext.texi ; @true
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 2bd99ee..62fd1c0 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -4042,7 +4042,7 @@
])
(define_code_iterator any_int_binop_no_shift_vx [
- plus minus and ior xor mult
+ plus minus and ior xor mult div
])
(define_code_iterator any_int_unop [neg not])
diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc
index e03dee3..a9d67a5 100644
--- a/gcc/config/xtensa/xtensa.cc
+++ b/gcc/config/xtensa/xtensa.cc
@@ -48,7 +48,6 @@ along with GCC; see the file COPYING3. If not see
#include "alias.h"
#include "explow.h"
#include "expr.h"
-#include "reload.h"
#include "langhooks.h"
#include "gimplify.h"
#include "builtins.h"
@@ -197,6 +196,8 @@ static void xtensa_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
tree function);
static rtx xtensa_delegitimize_address (rtx);
+static reg_class_t xtensa_ira_change_pseudo_allocno_class (int, reg_class_t,
+ reg_class_t);
@@ -366,6 +367,9 @@ static rtx xtensa_delegitimize_address (rtx);
#undef TARGET_DIFFERENT_ADDR_DISPLACEMENT_P
#define TARGET_DIFFERENT_ADDR_DISPLACEMENT_P hook_bool_void_true
+#undef TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS
+#define TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS xtensa_ira_change_pseudo_allocno_class
+
struct gcc_target targetm = TARGET_INITIALIZER;
@@ -4432,12 +4436,10 @@ xtensa_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
&& reg_class_subset_p (to, AR_REGS)))
return 2;
- /* The cost between AR_REGS and FR_REGS must be <= 8 (2x the default
- MEMORY_MOVE_COST) to avoid unwanted spills, and > 4 (2x the above
- case) to avoid excessive register-to-register moves. */
+ /* The cost between AR_REGS and FR_REGS is 2 (the default value). */
if ((reg_class_subset_p (from, AR_REGS) && to == FP_REGS)
|| (from == FP_REGS && reg_class_subset_p (to, AR_REGS)))
- return 5;
+ return 2;
if ((reg_class_subset_p (from, AR_REGS) && to == ACC_REG)
|| (from == ACC_REG && reg_class_subset_p (to, AR_REGS)))
@@ -5433,4 +5435,20 @@ xtensa_delegitimize_address (rtx op)
return op;
}
+/* Implement TARGET_IRA_CHANGE_PSEUDO_ALLOCNO_CLASS, in order to tell
+ the register allocator to avoid using ALL_REGS rclass. */
+
+static reg_class_t
+xtensa_ira_change_pseudo_allocno_class (int regno, reg_class_t allocno_class,
+ reg_class_t best_class)
+{
+ if (allocno_class != ALL_REGS)
+ return allocno_class;
+
+ if (best_class != ALL_REGS)
+ return best_class;
+
+ return FLOAT_MODE_P (PSEUDO_REGNO_MODE (regno)) ? FP_REGS : AR_REGS;
+}
+
#include "gt-xtensa.h"
diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index 88f011c..c7ac456 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -1453,7 +1453,7 @@
})
(define_insn "movsf_internal"
- [(set (match_operand:SF 0 "nonimmed_operand" "=f,f,^U,D,a,D,R,a,f,a,a,W,a,U")
+ [(set (match_operand:SF 0 "nonimmed_operand" "=f,f,U,D,a,D,R,a,f,a,a,W,a,U")
(match_operand:SF 1 "move_operand" "f,^U,f,d,T,R,d,r,r,f,Y,iF,U,r"))]
"((register_operand (operands[0], SFmode)
|| register_operand (operands[1], SFmode))
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3f05db3..a8f2b4e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,54 @@
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/107600
+ * method.cc (destructible_expr): Fix refs and arrays of unknown
+ bound.
+
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/120506
+ * constexpr.cc (cxx_eval_outermost_constant_expr): Always check
+ CONSTRUCTOR_NO_CLEARING.
+
+2025-06-02 Iain Sandoe <iain@sandoe.co.uk>
+
+ * coroutines.cc (build_actor_fn): Remove an unused
+ label, guard the frame deallocation correctly, use
+ simpler APIs to build if and return statements.
+
+2025-06-02 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/118903
+ * constexpr.cc (potential_constant_expression_1): Emit
+ an error when co_await et. al. are used in constexpr
+ contexts.
+
+2025-06-02 Iain Sandoe <iain@sandoe.co.uk>
+
+ * error.cc (dump_expr): Add co_await, co_yield and co_return.
+
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/107600
+ * method.cc (destructible_expr): Handle non-classes.
+ (constructible_expr): Check for abstract class here...
+ (is_xible_helper): ...not here.
+
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/107600
+ * semantics.cc (trait_expr_value) [CPTK_HAS_TRIVIAL_DESTRUCTOR]:
+ Add cp_unevaluated.
+
+2025-06-02 Sandra Loosemore <sloosemore@baylibre.com>
+
+ * cp-tree.h (maybe_convert_cond): Declare.
+ * parser.cc (cp_parser_omp_context_selector): Call
+ maybe_convert_cond and fold_build_cleanup_point_expr on the
+ expression for OMP_TRAIT_PROPERTY_BOOL_EXPR.
+ * pt.cc (tsubst_omp_context_selector): Likewise.
+ * semantics.cc (maybe_convert_cond): Remove static declaration.
+
2025-05-30 Jason Merrill <jason@redhat.com>
PR c++/113563
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 61481c6..b9fdc94 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -9278,8 +9278,7 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
/* After verify_constant because reduced_constant_expression_p can unset
CONSTRUCTOR_NO_CLEARING. */
- if (!non_constant_p
- && TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r))
+ if (TREE_CODE (r) == CONSTRUCTOR && CONSTRUCTOR_NO_CLEARING (r))
{
if (!allow_non_constant)
error ("%qE is not a constant expression because it refers to "
@@ -11024,6 +11023,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now,
case CO_AWAIT_EXPR:
case CO_YIELD_EXPR:
case CO_RETURN_EXPR:
+ if (flags & tf_error)
+ constexpr_error (cp_expr_loc_or_loc (t, input_location), fundef_p,
+ "%qE is not a constant expression", t);
return false;
/* Assume a TU-local entity is not constant, we'll error later when
diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc
index 5815a8c..7f5d30c 100644
--- a/gcc/cp/coroutines.cc
+++ b/gcc/cp/coroutines.cc
@@ -2543,8 +2543,8 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
/* Finish the resume dispatcher. */
finish_switch_stmt (dispatcher);
- finish_else_clause (lsb_if);
+ finish_else_clause (lsb_if);
finish_if_stmt (lsb_if);
/* If we reach here then we've hit UB. */
@@ -2583,69 +2583,53 @@ build_actor_fn (location_t loc, tree coro_frame_type, tree actor, tree fnbody,
/* Add in our function body with the co_returns rewritten to final form. */
add_stmt (fnbody);
- /* now do the tail of the function. */
+ /* Now do the tail of the function; first cleanups. */
r = build_stmt (loc, LABEL_EXPR, del_promise_label);
add_stmt (r);
- /* Destructors for the things we built explicitly. */
+ /* Destructors for the things we built explicitly.
+ promise... */
if (tree c = cxx_maybe_build_cleanup (promise_proxy, tf_warning_or_error))
- add_stmt (c);
-
- tree del_frame_label
- = create_named_label_with_ctx (loc, "coro.delete.frame", actor);
- r = build_stmt (loc, LABEL_EXPR, del_frame_label);
- add_stmt (r);
-
- /* Here deallocate the frame (if we allocated it), which we will have at
- present. */
- tree fnf2_x
- = coro_build_frame_access_expr (actor_frame, coro_frame_needs_free_id,
- false, tf_warning_or_error);
+ finish_expr_stmt (c);
- tree need_free_if = begin_if_stmt ();
- fnf2_x = build1 (CONVERT_EXPR, integer_type_node, fnf2_x);
- tree cmp = build2 (NE_EXPR, integer_type_node, fnf2_x, integer_zero_node);
- finish_if_stmt_cond (cmp, need_free_if);
+ /* Argument copies ... */
while (!param_dtor_list->is_empty ())
{
tree parm_id = param_dtor_list->pop ();
tree a = coro_build_frame_access_expr (actor_frame, parm_id, false,
tf_warning_or_error);
if (tree dtor = cxx_maybe_build_cleanup (a, tf_warning_or_error))
- add_stmt (dtor);
+ finish_expr_stmt (dtor);
}
+ /* Here deallocate the frame (if we allocated it), which we will have at
+ present. */
+ tree fnf2_x
+ = coro_build_frame_access_expr (actor_frame, coro_frame_needs_free_id,
+ false, tf_warning_or_error);
+ tree need_free_if = begin_if_stmt ();
+ finish_if_stmt_cond (fnf2_x, need_free_if);
+
/* Build the frame DTOR. */
tree del_coro_fr
= build_coroutine_frame_delete_expr (actor_fp, frame_size,
promise_type, loc);
finish_expr_stmt (del_coro_fr);
finish_then_clause (need_free_if);
- tree scope = IF_SCOPE (need_free_if);
- IF_SCOPE (need_free_if) = NULL;
- r = do_poplevel (scope);
- add_stmt (r);
+ finish_if_stmt (need_free_if);
- /* done. */
- r = build_stmt (loc, RETURN_EXPR, NULL);
- suppress_warning (r); /* We don't want a warning about this. */
- r = maybe_cleanup_point_expr_void (r);
- add_stmt (r);
+ /* Done. */
+ finish_return_stmt (NULL_TREE);
/* This is the suspend return point. */
- r = build_stmt (loc, LABEL_EXPR, ret_label);
- add_stmt (r);
+ add_stmt (build_stmt (loc, LABEL_EXPR, ret_label));
- r = build_stmt (loc, RETURN_EXPR, NULL);
- suppress_warning (r); /* We don't want a warning about this. */
- r = maybe_cleanup_point_expr_void (r);
- add_stmt (r);
+ finish_return_stmt (NULL_TREE);
/* This is the 'continuation' return point. For such a case we have a coro
handle (from the await_suspend() call) and we want handle.resume() to
execute as a tailcall allowing arbitrary chaining of coroutines. */
- r = build_stmt (loc, LABEL_EXPR, continue_label);
- add_stmt (r);
+ add_stmt (build_stmt (loc, LABEL_EXPR, continue_label));
/* Should have been set earlier by the coro_initialized code. */
gcc_assert (void_coro_handle_address);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e5e20e1..3cf4a76 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7956,6 +7956,7 @@ extern bool perform_deferred_access_checks (tsubst_flags_t);
extern bool perform_or_defer_access_check (tree, tree, tree,
tsubst_flags_t,
access_failure_info *afi = NULL);
+extern tree maybe_convert_cond (tree);
/* RAII sentinel to ensures that deferred access checks are popped before
a function returns. */
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 6364345..69da381 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -3269,6 +3269,27 @@ dump_expr (cxx_pretty_printer *pp, tree t, int flags)
break;
}
+ case CO_AWAIT_EXPR:
+ pp_cxx_ws_string (pp, "co_await");
+ pp_cxx_whitespace (pp);
+ dump_expr (pp, TREE_OPERAND (t, 0), flags);
+ break;
+
+ case CO_YIELD_EXPR:
+ pp_cxx_ws_string (pp, "co_yield");
+ pp_cxx_whitespace (pp);
+ dump_expr (pp, TREE_OPERAND (t, 0), flags);
+ break;
+
+ case CO_RETURN_EXPR:
+ pp_cxx_ws_string (pp, "co_return");
+ if (TREE_OPERAND (t, 0))
+ {
+ pp_cxx_whitespace (pp);
+ dump_expr (pp, TREE_OPERAND (t, 0), flags);
+ }
+ break;
+
/* This list is incomplete, but should suffice for now.
It is very important that `sorry' does not call
`report_error_function'. That could cause an infinite loop. */
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 3a675d9..67a80a3 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -2251,6 +2251,8 @@ constructible_expr (tree to, tree from)
const int len = TREE_VEC_LENGTH (from);
if (CLASS_TYPE_P (to))
{
+ if (ABSTRACT_CLASS_TYPE_P (to))
+ return error_mark_node;
tree ctype = to;
vec<tree, va_gc> *args = NULL;
if (!TYPE_REF_P (to))
@@ -2330,17 +2332,35 @@ constructible_expr (tree to, tree from)
return expr;
}
-/* Return declval<T>().~T() treated as an unevaluated operand. */
+/* Valid if "Either T is a reference type, or T is a complete object type for
+ which the expression declval<U&>().~U() is well-formed when treated as an
+ unevaluated operand ([expr.context]), where U is remove_all_extents_t<T>."
+
+ For a class U, return the destructor call; otherwise return void_node if
+ valid or error_mark_node if not. */
static tree
destructible_expr (tree to)
{
cp_unevaluated cp_uneval_guard;
int flags = LOOKUP_NORMAL|LOOKUP_DESTRUCTOR;
- to = build_trait_object (to);
- tree r = build_delete (input_location, TREE_TYPE (to), to,
- sfk_complete_destructor, flags, 0, tf_none);
- return r;
+ if (TYPE_REF_P (to))
+ return void_node;
+ if (!COMPLETE_TYPE_P (complete_type (to)))
+ return error_mark_node;
+ to = strip_array_types (to);
+ if (CLASS_TYPE_P (to))
+ {
+ to = build_trait_object (to);
+ return build_delete (input_location, TREE_TYPE (to), to,
+ sfk_complete_destructor, flags, 0, tf_none);
+ }
+ /* [expr.prim.id.dtor] If the id-expression names a pseudo-destructor, T
+ shall be a scalar type.... */
+ else if (scalarish_type_p (to))
+ return void_node;
+ else
+ return error_mark_node;
}
/* Returns a tree iff TO is assignable (if CODE is MODIFY_EXPR) or
@@ -2352,7 +2372,7 @@ is_xible_helper (enum tree_code code, tree to, tree from, bool trivial)
{
to = complete_type (to);
deferring_access_check_sentinel acs (dk_no_deferred);
- if (VOID_TYPE_P (to) || ABSTRACT_CLASS_TYPE_P (to)
+ if (VOID_TYPE_P (to)
|| (from && FUNC_OR_METHOD_TYPE_P (from)
&& (TYPE_READONLY (from) || FUNCTION_REF_QUALIFIED (from))))
return error_mark_node;
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 4216a51..2fa736b 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -501,6 +501,10 @@ enum WMB_Flags
WMB_Hidden = 1 << 3,
WMB_Purview = 1 << 4,
};
+inline WMB_Flags operator|(WMB_Flags x, WMB_Flags y)
+{ return WMB_Flags(+x|y); }
+inline WMB_Flags& operator|=(WMB_Flags& x, WMB_Flags y)
+{ return x = x|y; }
extern unsigned walk_module_binding (tree binding, bitmap partitions,
bool (*)(tree decl, WMB_Flags, void *data),
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 3d30339..8633763 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -49986,12 +49986,25 @@ cp_parser_omp_context_selector (cp_parser *parser, enum omp_tss_code set,
&& !value_dependent_expression_p (t))
{
t = fold_non_dependent_expr (t);
- if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR)
{
- error_at (token->location,
- "property must be integer expression");
- return error_mark_node;
+ t = maybe_convert_cond (t);
+ if (t == error_mark_node)
+ return error_mark_node;
+ }
+ else
+ {
+ t = convert_from_reference (t);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error_at (token->location,
+ "property must be integer expression");
+ return error_mark_node;
+ }
}
+ if (!processing_template_decl
+ && TREE_CODE (t) != CLEANUP_POINT_EXPR)
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
}
properties = make_trait_property (NULL_TREE, t, properties);
break;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ccb623d..c5a3abe 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -18380,7 +18380,9 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain,
}
}
- switch (omp_ts_map[OMP_TS_CODE (sel)].tp_type)
+ enum omp_tp_type property_kind
+ = omp_ts_map[OMP_TS_CODE (sel)].tp_type;
+ switch (property_kind)
{
case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR:
case OMP_TRAIT_PROPERTY_BOOL_EXPR:
@@ -18388,12 +18390,26 @@ tsubst_omp_context_selector (tree ctx, tree args, tsubst_flags_t complain,
args, complain, in_decl);
t = fold_non_dependent_expr (t);
if (!value_dependent_expression_p (t)
- && !type_dependent_expression_p (t)
- && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
- error_at (cp_expr_loc_or_input_loc (t),
- "property must be integer expression");
- else
- properties = make_trait_property (NULL_TREE, t, NULL_TREE);
+ && !type_dependent_expression_p (t))
+ {
+ if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR)
+ t = maybe_convert_cond (t);
+ else
+ {
+ t = convert_from_reference (t);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error_at (cp_expr_loc_or_input_loc (t),
+ "property must be integer expression");
+ t = error_mark_node;
+ }
+ }
+ }
+ if (t != error_mark_node
+ && !processing_template_decl
+ && TREE_CODE (t) != CLEANUP_POINT_EXPR)
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ properties = make_trait_property (NULL_TREE, t, NULL_TREE);
break;
case OMP_TRAIT_PROPERTY_CLAUSE_LIST:
if (OMP_TS_CODE (sel) == OMP_TRAIT_CONSTRUCT_SIMD)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index cafc9d0..7bc346b 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -52,7 +52,6 @@ along with GCC; see the file COPYING3. If not see
during template instantiation, which may be regarded as a
degenerate form of parsing. */
-static tree maybe_convert_cond (tree);
static tree finalize_nrv_r (tree *, int *, void *);
/* Used for OpenMP non-static data member privatization. */
@@ -1117,7 +1116,7 @@ annotate_saver::restore (tree new_inner)
statement. Convert it to a boolean value, if appropriate.
In addition, verify sequence points if -Wsequence-point is enabled. */
-static tree
+tree
maybe_convert_cond (tree cond)
{
/* Empty conditions remain empty. */
@@ -13420,6 +13419,7 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
if (CLASS_TYPE_P (type1) && type_build_dtor_call (type1))
{
deferring_access_check_sentinel dacs (dk_no_check);
+ cp_unevaluated un;
tree fn = get_dtor (type1, tf_none);
if (!fn && !seen_error ())
warning (0, "checking %qs for type %qT with a destructor that "
diff --git a/gcc/doc/gm2.texi b/gcc/doc/gm2.texi
index 8293da4..9bd0f0d 100644
--- a/gcc/doc/gm2.texi
+++ b/gcc/doc/gm2.texi
@@ -540,6 +540,9 @@ lines compiled.
@item -fm2-strict-type
experimental flag to turn on the new strict type checker.
+@item -fm2-strict-type-reason
+provides more detail why the types are incompatible.
+
@item -fm2-whole-program
compile all implementation modules and program module at once. Notice
that you need to take care if you are compiling different dialect
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 0150ad0..8de0085 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -30911,12 +30911,13 @@ to store the immediate to a register first.
@opindex mcmodel=
@opindex mcmodel=small
@item -mcmodel=small
-Generate OpenRISC code for the small model: The GOT is limited to 64k. This is
-the default model.
+Generate OpenRISC code for the small model: The GOT is limited to 64k and
+function call jumps are limited to 64M offsets. This is the default model.
@opindex mcmodel=large
@item -mcmodel=large
-Generate OpenRISC code for the large model: The GOT may grow up to 4G in size.
+Generate OpenRISC code for the large model: The GOT may grow up to 4G in size
+and function call jumps can target the full 4G address space.
@end table
diff --git a/gcc/doc/riscv-ext.texi b/gcc/doc/riscv-ext.texi
index 7a22d84..e64c0d6 100644
--- a/gcc/doc/riscv-ext.texi
+++ b/gcc/doc/riscv-ext.texi
@@ -494,6 +494,10 @@
@tab 1.0
@tab Advanced interrupt architecture extension
+@item smcntrpmf
+@tab 1.0
+@tab Cycle and instret privilege mode filtering
+
@item smepmp
@tab 1.0
@tab PMP Enhancements for memory access and execution prevention on Machine mode
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 9043002..6c5586e 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -1976,6 +1976,9 @@ at plain @option{-O2}.
@item tls
Target supports thread-local storage.
+@item tls_link
+Target supports linking TLS executables.
+
@item tls_native
Target supports native (rather than emulated) thread-local storage.
diff --git a/gcc/final.cc b/gcc/final.cc
index 12c6eb0..a4dbab7 100644
--- a/gcc/final.cc
+++ b/gcc/final.cc
@@ -2072,7 +2072,7 @@ output_alternate_entry_point (FILE *file, rtx_insn *insn)
/* Given a CALL_INSN, find and return the nested CALL. */
static rtx
-call_from_call_insn (rtx_call_insn *insn)
+call_from_call_insn (const rtx_call_insn *insn)
{
rtx x;
gcc_assert (CALL_P (insn));
@@ -2098,6 +2098,15 @@ call_from_call_insn (rtx_call_insn *insn)
return x;
}
+/* Return the CALL in X if there is one. */
+
+rtx
+get_call_rtx_from (const rtx_insn *insn)
+{
+ const rtx_call_insn *call_insn = as_a<const rtx_call_insn *> (insn);
+ return call_from_call_insn (call_insn);
+}
+
/* Print a comment into the asm showing FILENAME, LINENUM, and the
corresponding source line, if available. */
diff --git a/gcc/fortran/data.cc b/gcc/fortran/data.cc
index 5c83f69..a438c26 100644
--- a/gcc/fortran/data.cc
+++ b/gcc/fortran/data.cc
@@ -593,7 +593,13 @@ gfc_assign_data_value (gfc_expr *lvalue, gfc_expr *rvalue, mpz_t index,
{
/* Point the container at the new expression. */
if (last_con == NULL)
- symbol->value = expr;
+ {
+ symbol->value = expr;
+ /* For a new initializer use the location from the
+ constructor as fallback. */
+ if (!GFC_LOCUS_IS_SET(expr->where) && con != NULL)
+ symbol->value->where = con->where;
+ }
else
last_con->expr = expr;
}
diff --git a/gcc/function.h b/gcc/function.h
index 2260d67..370629f 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -333,7 +333,6 @@ struct GTY(()) function {
/* Properties used by the pass manager. */
unsigned int curr_properties;
- unsigned int last_verified;
/* Different from normal TODO_flags which are handled right at the
beginning or the end of one pass execution, the pending_TODOs
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 0f43761..185f9db 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -198,10 +198,7 @@ can_refer_decl_in_current_unit_p (tree decl, tree from_decl)
tree
create_tmp_reg_or_ssa_name (tree type, gimple *stmt)
{
- if (gimple_in_ssa_p (cfun))
- return make_ssa_name (type, stmt);
- else
- return create_tmp_reg (type);
+ return make_ssa_name (type, stmt);
}
/* CVAL is value taken from DECL_INITIAL of variable. Try to transform it into
diff --git a/gcc/gimple-harden-conditionals.cc b/gcc/gimple-harden-conditionals.cc
index 3ad3bb9..d4a418d 100644
--- a/gcc/gimple-harden-conditionals.cc
+++ b/gcc/gimple-harden-conditionals.cc
@@ -61,8 +61,7 @@ const pass_data pass_data_harden_compares = {
0, // properties_destroyed
0, // properties_start
TODO_update_ssa
- | TODO_cleanup_cfg
- | TODO_verify_il, // properties_finish
+ | TODO_cleanup_cfg, // properties_finish
};
class pass_harden_compares : public gimple_opt_pass
@@ -96,8 +95,7 @@ const pass_data pass_data_harden_conditional_branches = {
0, // properties_destroyed
0, // properties_start
TODO_update_ssa
- | TODO_cleanup_cfg
- | TODO_verify_il, // properties_finish
+ | TODO_cleanup_cfg, // properties_finish
};
class pass_harden_conditional_branches : public gimple_opt_pass
diff --git a/gcc/gimple-harden-control-flow.cc b/gcc/gimple-harden-control-flow.cc
index e46acaf..f129ff1 100644
--- a/gcc/gimple-harden-control-flow.cc
+++ b/gcc/gimple-harden-control-flow.cc
@@ -1549,8 +1549,7 @@ pass_harden_control_flow_redundancy::execute (function *fun)
return
TODO_update_ssa
- | TODO_cleanup_cfg
- | TODO_verify_il;
+ | TODO_cleanup_cfg;
}
/* Instantiate a hardcfr pass. */
diff --git a/gcc/ipa-strub.cc b/gcc/ipa-strub.cc
index 99cc9d9..d7c0a92 100644
--- a/gcc/ipa-strub.cc
+++ b/gcc/ipa-strub.cc
@@ -1770,8 +1770,7 @@ const pass_data pass_data_ipa_strub = {
0, // properties_start
TODO_update_ssa
| TODO_cleanup_cfg
- | TODO_rebuild_cgraph_edges
- | TODO_verify_il, // properties_finish
+ | TODO_rebuild_cgraph_edges, // properties_finish
};
class pass_ipa_strub : public simple_ipa_opt_pass
diff --git a/gcc/lra-eliminations.cc b/gcc/lra-eliminations.cc
index d84a7d1..bb708b0 100644
--- a/gcc/lra-eliminations.cc
+++ b/gcc/lra-eliminations.cc
@@ -1185,7 +1185,7 @@ update_reg_eliminate (bitmap insns_with_changed_offsets)
setup_can_eliminate (ep, false);
continue;
}
- if (ep->can_eliminate != prev && elimination_map[ep->from] == ep)
+ if (!ep->can_eliminate && elimination_map[ep->from] == ep)
{
/* We cannot use this elimination anymore -- find another
one. */
diff --git a/gcc/lra-spills.cc b/gcc/lra-spills.cc
index fc912c4..4febc69 100644
--- a/gcc/lra-spills.cc
+++ b/gcc/lra-spills.cc
@@ -556,7 +556,7 @@ spill_pseudos (void)
fprintf (lra_dump_file,
"Changing spilled pseudos to memory in insn #%u\n",
INSN_UID (insn));
- lra_push_insn (insn);
+ lra_push_insn_and_update_insn_regno_info (insn);
if (lra_reg_spill_p || targetm.different_addr_displacement_p ())
lra_set_used_insn_alternative (insn, LRA_UNKNOWN_ALT);
}
diff --git a/gcc/m2/ChangeLog b/gcc/m2/ChangeLog
index 0009211..6b19a4d 100644
--- a/gcc/m2/ChangeLog
+++ b/gcc/m2/ChangeLog
@@ -1,3 +1,105 @@
+2025-06-01 Gaius Mulley <gaiusmod2@gmail.com>
+
+ PR modula2/120474
+ * gm2-libs-log/InOut.mod (LocalWrite): Call FIO.FlushBuffer.
+
+2025-06-01 Gaius Mulley <gaiusmod2@gmail.com>
+
+ PR modula2/120497
+ * gm2-compiler/M2Range.mod (IsAssignmentCompatible): Remove from
+ import list.
+ (FoldTypeReturnFunc): Rewrite to skip the Lvalue of a var
+ variable.
+ (CodeTypeReturnFunc): Ditto.
+ (CodeTypeIndrX): Call AssignmentTypeCompatible rather than
+ IsAssignmentCompatible.
+ (FoldTypeIndrX): Ditto.
+
+2025-05-31 Gaius Mulley <gaiusmod2@gmail.com>
+
+ PR modula2/120389
+ * gm2-compiler/M2Check.def (AssignmentTypeCompatible): Add new
+ parameter enableReason.
+ * gm2-compiler/M2Check.mod (EquivalenceProcedure): New type.
+ (falseReason2): New procedure function.
+ (falseReason1): Ditto.
+ (falseReason0): Ditto.
+ (checkTypeEquivalence): Rewrite.
+ (checkUnboundedArray): Ditto.
+ (checkUnbounded): Ditto.
+ (checkArrayTypeEquivalence): Ditto.
+ (checkCharStringTypeEquivalence): Ditto.
+ (buildError4): Add false reason.
+ (buildError2): Ditto.
+ (IsTyped): Use GetDType.
+ (IsTypeEquivalence): New procedure function.
+ (checkVarTypeEquivalence): Ditto.
+ (checkVarEquivalence ): Rewrite.
+ (checkConstMeta): Ditto.
+ (checkEnumField): New procedure function.
+ (checkEnumFieldEquivalence): Ditto.
+ (checkSubrangeTypeEquivalence): Rewrite.
+ (checkSystemEquivalence): Ditto.
+ (checkTypeKindViolation): Ditto.
+ (doCheckPair): Ditto.
+ (InitEquivalenceArray): New procedure.
+ (addEquivalence): Ditto.
+ (checkProcType): Rewrite.
+ (deconstruct): Deallocate reason string.
+ (AssignmentTypeCompatible): Initialize reason and reasonEnable
+ fields.
+ (ParameterTypeCompatible): Ditto.
+ (doExpressionTypeCompatible): Ditto.
+ * gm2-compiler/M2GenGCC.mod (CodeIndrX) Rewrite.
+ (CheckBinaryExpressionTypes): Rewrite and simplify now that the
+ type checker is more robust.
+ (CheckElementSetTypes): Ditto.
+ (CodeXIndr): Add new range assignment type check.
+ * gm2-compiler/M2MetaError.def: Correct comments.
+ * gm2-compiler/M2Options.def (SetStrictTypeAssignment): New procedure.
+ (SetStrictTypeReason): Ditto.
+ * gm2-compiler/M2Options.mod: (SetStrictTypeAssignment): New procedure.
+ (SetStrictTypeReason): Ditto.
+ (StrictTypeReason): Initialize.
+ (StrictTypeAssignment): Ditto.
+ * gm2-compiler/M2Quads.mod (CheckBreak): Delete.
+ (BreakQuad): New global variable.
+ (BreakAtQuad): Delete.
+ (gdbhook): New procedure.
+ (BreakWhenQuadCreated): Ditto.
+ (CheckBreak): Ditto.
+ (Init): Call BreakWhenQuadCreated and gdbhook.
+ (doBuildAssignment): Add type assignment range check.
+ (CheckProcTypeAndProcedure): Only check if the procedure
+ types differ.
+ (doIndrX): Add type IndrX range check.
+ (CheckReturnType): Add range return type check.
+ * gm2-compiler/M2Range.def (InitTypesIndrXCheck): New procedure
+ function.
+ (InitTypesReturnTypeCheck): Ditto.
+ * gm2-compiler/M2Range.mod (InitTypesIndrXCheck): New procedure
+ function.
+ (InitTypesReturnTypeCheck): Ditto.
+ (HandlerExists): Add new clauses.
+ (FoldAssignment): Pass extra FALSE parameter to
+ AssignmentTypeCompatible.
+ (FoldTypeReturnFunc): New procedure.
+ (FoldTypeAssign): Ditto.
+ (FoldTypeIndrX): Ditto.
+ (CodeTypeAssign): Rewrite.
+ (CodeTypeIndrX): New procedure.
+ (CodeTypeReturnFunc): Ditto.
+ (FoldTypeCheck): Add new case clauses.
+ (CodeTypeCheck): Ditto.
+ (FoldRangeCheckLower): Ditto.
+ (IssueWarning): Ditto.
+ * gm2-gcc/m2options.h (M2Options_SetStrictTypeAssignment): New
+ function prototype.
+ (M2Options_SetStrictTypeReason): Ditto.
+ * gm2-lang.cc (gm2_langhook_handle_option): New case clause
+ OPT_fm2_strict_type_reason.
+ * lang.opt (-fm2-strict-type-reason): New option.
+
2025-05-22 Gaius Mulley <gaiusmod2@gmail.com>
PR modula2/120389
diff --git a/gcc/m2/gm2-compiler/M2Check.def b/gcc/m2/gm2-compiler/M2Check.def
index 0ceb173..9d9f760 100644
--- a/gcc/m2/gm2-compiler/M2Check.def
+++ b/gcc/m2/gm2-compiler/M2Check.def
@@ -50,7 +50,8 @@ PROCEDURE ParameterTypeCompatible (token: CARDINAL; format: ARRAY OF CHAR;
*)
PROCEDURE AssignmentTypeCompatible (token: CARDINAL; format: ARRAY OF CHAR;
- des, expr: CARDINAL) : BOOLEAN ;
+ des, expr: CARDINAL;
+ enableReason: BOOLEAN) : BOOLEAN ;
(*
diff --git a/gcc/m2/gm2-compiler/M2Check.mod b/gcc/m2/gm2-compiler/M2Check.mod
index d86ef8e..614526c 100644
--- a/gcc/m2/gm2-compiler/M2Check.mod
+++ b/gcc/m2/gm2-compiler/M2Check.mod
@@ -36,26 +36,33 @@ FROM M2System IMPORT IsSystemType, IsGenericSystemType, IsSameSize, IsComplexN ;
FROM M2Base IMPORT IsParameterCompatible, IsAssignmentCompatible, IsExpressionCompatible, IsComparisonCompatible, IsBaseType, IsMathType, ZType, CType, RType, IsComplexType, Char ;
FROM Indexing IMPORT Index, InitIndex, GetIndice, PutIndice, KillIndex, HighIndice, LowIndice, IncludeIndiceIntoIndex, ForeachIndiceInIndexDo ;
FROM M2Error IMPORT Error, InternalError, NewError, ErrorString, ChainError ;
-FROM M2MetaError IMPORT MetaErrorStringT2, MetaErrorStringT3, MetaErrorStringT4, MetaString2, MetaString3, MetaString4, MetaError1 ;
+
+FROM M2MetaError IMPORT MetaErrorStringT0, MetaErrorStringT2, MetaErrorStringT3,
+ MetaErrorStringT4,
+ MetaString0, MetaString1, MetaString2, MetaString3,
+ MetaString4,
+ MetaError0, MetaError1 ;
+
FROM StrLib IMPORT StrEqual ;
FROM M2Debug IMPORT Assert ;
-FROM SymbolTable IMPORT NulSym, IsRecord, IsSet, GetDType, GetSType, IsType,
+FROM SymbolTable IMPORT NulSym, IsRecord, IsSet, GetDType, GetType, IsType,
SkipType, IsProcedure, NoOfParamAny, IsVarParamAny, GetNth,
GetNthParamAny, IsProcType, IsVar, IsEnumeration, IsArray,
IsSubrange, GetArraySubscript, IsConst,
IsReallyPointer, IsPointer, IsParameter, ModeOfAddr,
- GetMode, GetType, IsUnbounded, IsComposite, IsConstructor,
+ GetMode, IsUnbounded, IsComposite, IsConstructor,
IsParameter, IsConstString, IsConstLitInternal, IsConstLit,
GetStringLength, GetProcedureProcType, IsHiddenType,
- IsHiddenReallyPointer, GetDimension ;
+ IsHiddenReallyPointer, GetDimension, IsFieldEnumeration ;
FROM M2GCCDeclare IMPORT GetTypeMin, GetTypeMax ;
FROM M2System IMPORT Address ;
FROM M2ALU IMPORT Equ, PushIntegerTree ;
+FROM M2Options IMPORT StrictTypeReason ;
FROM m2expr IMPORT AreConstantsEqual ;
-FROM SymbolConversion IMPORT Mod2Gcc ;
-FROM DynamicStrings IMPORT String, InitString, KillString ;
+FROM SymbolConversion IMPORT Mod2Gcc, GccKnowsAbout ;
+FROM DynamicStrings IMPORT String, InitString, KillString, ConCat, Mark ;
FROM M2LexBuf IMPORT GetTokenNo ;
FROM Storage IMPORT ALLOCATE ;
FROM SYSTEM IMPORT ADR ;
@@ -63,7 +70,8 @@ FROM libc IMPORT printf ;
CONST
- debugging = FALSE ;
+ debugging = FALSE ;
+ MaxEquvalence = 20 ;
TYPE
errorSig = POINTER TO RECORD
@@ -83,6 +91,8 @@ TYPE
checkType = (parameter, assignment, expression) ;
tInfo = POINTER TO RECORD
+ reasonEnable: BOOLEAN ;
+ reason,
format : String ;
kind : checkType ;
token,
@@ -105,11 +115,14 @@ TYPE
status = (true, false, unknown, visited, unused) ;
+ EquivalenceProcedure = PROCEDURE (status, tInfo, CARDINAL, CARDINAL) : status ;
VAR
- pairFreeList : pair ;
- tinfoFreeList: tInfo ;
- errors : Index ;
+ pairFreeList : pair ;
+ tinfoFreeList : tInfo ;
+ errors : Index ;
+ HighEquivalence: CARDINAL ;
+ Equivalence : ARRAY [1..MaxEquvalence] OF EquivalenceProcedure ;
(*
@@ -159,6 +172,53 @@ END dumptInfo ;
(*
+ falseReason2 - return false. It also stores the message as the
+ reason for the false value.
+*)
+
+PROCEDURE falseReason2 (message: ARRAY OF CHAR; tinfo: tInfo;
+ left, right: CARDINAL) : status ;
+BEGIN
+ IF tinfo^.reasonEnable AND (tinfo^.reason = NIL)
+ THEN
+ tinfo^.reason := MetaString2 (InitString (message), left, right)
+ END ;
+ RETURN false
+END falseReason2 ;
+
+
+(*
+ falseReason1 - return false. It also stores the message as the
+ reason for the false value.
+*)
+
+PROCEDURE falseReason1 (message: ARRAY OF CHAR; tinfo: tInfo;
+ operand: CARDINAL) : status ;
+BEGIN
+ IF tinfo^.reasonEnable AND (tinfo^.reason = NIL)
+ THEN
+ tinfo^.reason := MetaString1 (InitString (message), operand)
+ END ;
+ RETURN false
+END falseReason1 ;
+
+
+(*
+ falseReason0 - return false. It also stores the message as the
+ reason for the false value.
+*)
+
+PROCEDURE falseReason0 (message: ARRAY OF CHAR; tinfo: tInfo) : status ;
+BEGIN
+ IF tinfo^.reasonEnable AND (tinfo^.reason = NIL)
+ THEN
+ tinfo^.reason := MetaString0 (InitString (message))
+ END ;
+ RETURN false
+END falseReason0 ;
+
+
+(*
isKnown - returns BOOLEAN:TRUE if result is status:true or status:false.
*)
@@ -192,31 +252,29 @@ END isFalse ;
checkTypeEquivalence - returns TRUE if left and right can be skipped and found to be equal.
*)
-PROCEDURE checkTypeEquivalence (result: status; left, right: CARDINAL) : status ;
-VAR
- leftT, rightT: CARDINAL ;
+PROCEDURE checkTypeEquivalence (result: status;
+ tinfo: tInfo;
+ left, right: CARDINAL) : status ;
BEGIN
- (* firstly check to see if we already have resolved this as false. *)
- IF isFalse (result)
+ IF left = right
THEN
- RETURN result
- ELSE
- (* check to see if we dont care about left or right. *)
- IF (left = NulSym) OR (right = NulSym)
+ RETURN true
+ ELSIF IsType (left) AND IsType (right)
+ THEN
+ IF IsHiddenType (left) AND IsHiddenType (right)
+ THEN
+ RETURN falseReason2 ('opaque types {%1a} {%2a} differ', tinfo, left, right)
+ ELSIF (IsHiddenType (left) AND (right = Address)) OR
+ (IsHiddenType (right) AND (left = Address))
THEN
RETURN true
- ELSE
- leftT := SkipType (left) ;
- rightT := SkipType (right) ;
- IF leftT = rightT
- THEN
- RETURN true
- ELSIF IsType (leftT) AND IsType (rightT)
- THEN
- (* the fundamental types are definitely different. *)
- RETURN false
- END
END
+ ELSIF IsTypeEquivalence (left)
+ THEN
+ RETURN checkPair (result, tinfo, GetDType (left), right)
+ ELSIF IsTypeEquivalence (right)
+ THEN
+ RETURN checkPair (result, tinfo, left, GetDType (right))
END ;
RETURN result
END checkTypeEquivalence ;
@@ -246,13 +304,15 @@ BEGIN
PushIntegerTree (Mod2Gcc (rLow)) ;
IF NOT Equ (tinfo^.token)
THEN
- RETURN false
+ RETURN falseReason2 ('low values of the subrange types {%1a} {%2a} differ',
+ tinfo, left, right)
END ;
PushIntegerTree (Mod2Gcc (lHigh)) ;
PushIntegerTree (Mod2Gcc (rHigh)) ;
IF NOT Equ (tinfo^.token)
THEN
- RETURN false
+ RETURN falseReason2 ('high values of the subrange types {%1a} {%2a} differ',
+ tinfo, left, right)
END
END ;
RETURN true
@@ -266,6 +326,7 @@ END checkSubrange ;
*)
PROCEDURE checkUnboundedArray (result: status;
+ tinfo: tInfo;
unbounded, array: CARDINAL) : status ;
VAR
dim : CARDINAL ;
@@ -280,13 +341,13 @@ BEGIN
Assert (IsUnbounded (unbounded)) ;
Assert (IsArray (array)) ;
dim := GetDimension (unbounded) ;
- ubtype := GetType (unbounded) ;
+ ubtype := GetDType (unbounded) ;
type := array ;
REPEAT
- type := GetType (type) ;
+ type := GetDType (type) ;
DEC (dim) ;
(* Check type equivalences. *)
- IF checkTypeEquivalence (result, type, ubtype) = true
+ IF checkTypeEquivalence (result, tinfo, type, ubtype) = true
THEN
RETURN true
END ;
@@ -294,11 +355,13 @@ BEGIN
(* If we have run out of dimensions we conclude false. *)
IF dim = 0
THEN
- RETURN false
+ RETURN falseReason0 ('unbounded array has less dimensions than the array',
+ tinfo)
END ;
UNTIL NOT IsArray (type)
END ;
- RETURN false
+ RETURN falseReason0 ('array has less dimensions than the unbounded array',
+ tinfo)
END checkUnboundedArray ;
@@ -327,14 +390,18 @@ BEGIN
referenced. We use GetDimension for 'bar' which is 2. *)
IF GetDimension (formal) # GetDimension (tinfo^.actual)
THEN
- RETURN false
+ RETURN falseReason2 ('the formal parameter unbounded array {%1a} has a different number' +
+ ' of dimensions to the actual parameter unbounded array {%2a}',
+ tinfo, formal, actual)
END ;
- IF checkTypeEquivalence (result, GetType (formal), GetType (actual)) = true
+ IF checkTypeEquivalence (result, tinfo, GetType (formal), GetType (actual)) = true
THEN
RETURN true
END
END ;
- RETURN false
+ RETURN falseReason2 ('the formal unbounded array type {%1a}' +
+ ' and the actual unbounded array type {%2a} differ',
+ tinfo, formal, actual)
END checkUnboundedUnbounded ;
@@ -373,10 +440,14 @@ BEGIN
END
ELSIF IsArray (right)
THEN
- RETURN checkUnboundedArray (result, unbounded, right)
+ RETURN checkUnboundedArray (result, tinfo, unbounded, right)
ELSIF IsUnbounded (right)
THEN
RETURN checkUnboundedUnbounded (result, tinfo, unbounded, right)
+ ELSE
+ RETURN falseReason2 ('the formal unbounded array type {%1a}' +
+ ' and the actual unbounded array type {%2a} differ',
+ tinfo, unbounded, right)
END
END
END ;
@@ -400,7 +471,7 @@ BEGIN
THEN
lSub := GetArraySubscript (left) ;
rSub := GetArraySubscript (right) ;
- result := checkPair (result, tinfo, GetSType (left), GetSType (right)) ;
+ result := checkPair (result, tinfo, GetDType (left), GetDType (right)) ;
IF (lSub # NulSym) AND (rSub # NulSym)
THEN
result := checkSubrange (result, tinfo, getSType (lSub), getSType (rSub))
@@ -423,31 +494,58 @@ BEGIN
END
ELSIF IsArray (left) AND IsConst (right)
THEN
- result := checkPair (result, tinfo, GetType (left), GetType (right))
+ result := checkPair (result, tinfo, GetDType (left), GetDType (right))
ELSIF IsArray (right) AND IsConst (left)
THEN
- result := checkPair (result, tinfo, GetType (left), GetType (right))
+ result := checkPair (result, tinfo, GetDType (left), GetDType (right))
END ;
RETURN result
END checkArrayTypeEquivalence ;
(*
- checkGenericTypeEquivalence - check left and right for generic equivalence.
+ checkCharStringTypeEquivalence - check char and string constants for type equivalence.
*)
-PROCEDURE checkGenericTypeEquivalence (result: status; left, right: CARDINAL) : status ;
+PROCEDURE checkCharStringTypeEquivalence (result: status; tinfo: tInfo;
+ left, right: CARDINAL) : status ;
BEGIN
IF isFalse (result)
THEN
RETURN result
- ELSIF left = right
+ ELSIF left = Char
THEN
- RETURN true
- ELSE
- RETURN result
- END
-END checkGenericTypeEquivalence ;
+ IF IsConst (right)
+ THEN
+ (* We might not know the length of the string yet, in which case we return true. *)
+ IF IsConstString (right) AND
+ ((NOT GccKnowsAbout (right)) OR (GetStringLength (tinfo^.token, right) <= 1))
+ THEN
+ RETURN true
+ ELSE
+ RETURN falseReason2 ('the string {%2a} does not fit into a {%1a}',
+ tinfo, left, right)
+ END
+ ELSIF IsParameter (right)
+ THEN
+ right := GetDType (right) ;
+ IF (right = Char) OR (IsUnbounded (right) AND (SkipType (GetDType (right)) = Char))
+ THEN
+ RETURN true
+ END
+ ELSIF IsArray (right)
+ THEN
+ IF Char = SkipType (GetDType (right))
+ THEN
+ RETURN true
+ END
+ END
+ ELSIF right = Char
+ THEN
+ RETURN checkCharStringTypeEquivalence (result, tinfo, right, left)
+ END ;
+ RETURN result
+END checkCharStringTypeEquivalence ;
(*
@@ -491,7 +589,7 @@ BEGIN
THEN
IF tinfo^.error = NIL
THEN
- (* need to create top level error message first. *)
+ (* We need to create top level error message first. *)
tinfo^.error := NewError (tinfo^.token) ;
(* The parameters to MetaString4 in buildError4 must match the order
of paramters passed to ParameterTypeCompatible. *)
@@ -499,9 +597,17 @@ BEGIN
tinfo^.procedure,
tinfo^.formal, tinfo^.actual,
tinfo^.nth) ;
+ (* Append the overall reason for the failure. *)
+ IF tinfo^.reason # NIL
+ THEN
+ (* The string tinfo^.reason is given to the error handler. *)
+ s := ConCat (s, Mark (InitString (" because "))) ;
+ s := ConCat (s, tinfo^.reason) ;
+ tinfo^.reason := NIL (* Hand over deconstructing to M2MetaError. *)
+ END ;
ErrorString (tinfo^.error, s)
END ;
- (* and also generate a sub error containing detail. *)
+ (* And now also generate a sub error containing detail. *)
IF (left # tinfo^.left) OR (right # tinfo^.right)
THEN
MetaError1 ('formal parameter {%1EDad}', right) ;
@@ -512,7 +618,7 @@ END buildError4 ;
(*
- buildError2 - generate a MetaString2 error. This is called by all three kinds of errors.
+ buildError2 - generate a MetaString2 error.
*)
PROCEDURE buildError2 (tinfo: tInfo; left, right: CARDINAL) ;
@@ -543,6 +649,14 @@ BEGIN
left, right)
END ;
+ (* Lastly the overall reason for the failure. *)
+ IF tinfo^.reason # NIL
+ THEN
+ (* The string tinfo^.reason is given to the error handler. *)
+ s := ConCat (s, Mark (InitString (" because "))) ;
+ s := ConCat (s, tinfo^.reason) ;
+ tinfo^.reason := NIL (* Hand over deconstructing to M2MetaError. *)
+ END ;
ErrorString (tinfo^.error, s)
END
END
@@ -559,7 +673,7 @@ BEGIN
THEN
RETURN true
ELSE
- (* check whether errors are required. *)
+ (* Check whether errors are required. *)
IF tinfo^.format # NIL
THEN
CASE tinfo^.kind OF
@@ -700,11 +814,21 @@ PROCEDURE IsTyped (sym: CARDINAL) : BOOLEAN ;
BEGIN
RETURN IsVar (sym) OR IsParameter (sym) OR IsConstructor (sym) OR
(IsConst (sym) AND IsConstructor (sym)) OR IsParameter (sym) OR
- (IsConst (sym) AND (GetType (sym) # NulSym))
+ (IsConst (sym) AND (GetDType (sym) # NulSym))
END IsTyped ;
(*
+ IsTypeEquivalence - returns TRUE if sym is a type equivalence symbol.
+*)
+
+PROCEDURE IsTypeEquivalence (sym: CARDINAL) : BOOLEAN ;
+BEGIN
+ RETURN IsType (sym) AND (GetDType (sym) # NulSym) AND (GetDType (sym) # sym)
+END IsTypeEquivalence ;
+
+
+(*
isLValue -
*)
@@ -715,6 +839,38 @@ END isLValue ;
(*
+ checkVarTypeEquivalence -
+*)
+
+PROCEDURE checkVarTypeEquivalence (result: status; tinfo: tInfo;
+ left, right: CARDINAL) : status ;
+BEGIN
+ IF isFalse (result)
+ THEN
+ RETURN result
+ ELSIF (left = NulSym) OR (right = NulSym)
+ THEN
+ RETURN true
+ ELSE
+ IF IsVar (left) OR IsVar (right)
+ THEN
+ (* Either left or right will change, so we can call doCheckPair. *)
+ IF IsVar (left)
+ THEN
+ left := getType (left)
+ END ;
+ IF IsVar (right)
+ THEN
+ right := getType (right)
+ END ;
+ RETURN doCheckPair (result, tinfo, left, right)
+ END
+ END ;
+ RETURN result
+END checkVarTypeEquivalence ;
+
+
+(*
checkVarEquivalence - this test must be done early as it checks the symbol mode.
An LValue is treated as a pointer during assignment and the
LValue is attached to a variable. This function skips the variable
@@ -722,40 +878,44 @@ END isLValue ;
*)
PROCEDURE checkVarEquivalence (result: status; tinfo: tInfo;
- left, right: CARDINAL) : status ;
+ des, expr: CARDINAL) : status ;
BEGIN
IF isFalse (result)
THEN
RETURN result
- ELSIF IsTyped (left) OR IsTyped (right)
+ ELSIF IsTyped (des) OR IsTyped (expr)
THEN
IF tinfo^.kind = assignment
THEN
+ IF GetDType (des) = GetDType (expr)
+ THEN
+ RETURN true
(* LValues are only relevant during assignment. *)
- IF isLValue (left) AND (NOT isLValue (right))
+ ELSIF isLValue (des) AND (NOT isLValue (expr))
THEN
- IF SkipType (getType (right)) = Address
+ IF SkipType (getType (expr)) = Address
THEN
RETURN true
- ELSIF IsPointer (SkipType (getType (right)))
+ ELSIF IsPointer (SkipType (getType (expr)))
THEN
- right := GetDType (SkipType (getType (right)))
+ expr := GetDType (SkipType (getType (expr))) ;
+ RETURN doCheckPair (result, tinfo, getType (des), expr)
END
- ELSIF isLValue (right) AND (NOT isLValue (left))
+ ELSIF isLValue (expr) AND (NOT isLValue (des))
THEN
- IF SkipType (getType (left)) = Address
+ IF SkipType (getType (des)) = Address
THEN
RETURN true
- ELSIF IsPointer (SkipType (getType (left)))
+ ELSIF IsPointer (SkipType (getType (des)))
THEN
- left := GetDType (SkipType (getType (left)))
+ des := GetDType (SkipType (getType (des))) ;
+ RETURN doCheckPair (result, tinfo, des, getType (expr))
END
END
END ;
- RETURN doCheckPair (result, tinfo, getType (left), getType (right))
- ELSE
- RETURN result
- END
+ RETURN doCheckPair (result, tinfo, getType (des), getType (expr))
+ END ;
+ RETURN result
END checkVarEquivalence ;
@@ -790,10 +950,15 @@ BEGIN
IsProcedure (typeRight) OR IsRecord (typeRight) OR
IsReallyPointer (typeRight)
THEN
- RETURN false
+ RETURN falseReason1 ('constant string is incompatible with {%1ad}',
+ tinfo, typeRight)
ELSIF IsArray (typeRight)
THEN
- RETURN doCheckPair (result, tinfo, Char, GetType (typeRight))
+ RETURN doCheckPair (result, tinfo, Char, GetDType (typeRight))
+ ELSIF NOT GccKnowsAbout (left)
+ THEN
+ (* We do not know the length of this string, so assume true. *)
+ RETURN true
ELSIF GetStringLength (tinfo^.token, left) = 1
THEN
RETURN doCheckPair (result, tinfo, Char, typeRight)
@@ -805,7 +970,9 @@ BEGIN
typeLeft := GetDType (left) ;
IF IsZRCType (typeLeft) AND IsUnbounded (typeRight)
THEN
- RETURN false
+ RETURN falseReason2 ('the constant {%1a} is incompatible' +
+ ' with an unbounded array of {%2a}',
+ tinfo, typeLeft, typeRight)
ELSE
RETURN doCheckPair (result, tinfo, typeLeft, typeRight)
END
@@ -815,6 +982,58 @@ END checkConstMeta ;
(*
+ checkEnumField -
+*)
+
+PROCEDURE checkEnumField (result: status; tinfo: tInfo;
+ left, right: CARDINAL) : status ;
+VAR
+ typeRight: CARDINAL ;
+BEGIN
+ Assert (IsFieldEnumeration (left)) ;
+ IF isFalse (result)
+ THEN
+ RETURN result
+ ELSIF IsTyped (right)
+ THEN
+ typeRight := GetDType (right) ;
+ IF typeRight = NulSym
+ THEN
+ RETURN result
+ ELSE
+ RETURN doCheckPair (result, tinfo, GetDType (left), typeRight)
+ END
+ END ;
+ RETURN result
+END checkEnumField ;
+
+
+(*
+ checkEnumFieldEquivalence -
+*)
+
+PROCEDURE checkEnumFieldEquivalence (result: status; tinfo: tInfo;
+ left, right: CARDINAL) : status ;
+BEGIN
+ IF isFalse (result)
+ THEN
+ RETURN result
+ ELSIF (left = NulSym) OR (right = NulSym)
+ THEN
+ (* No option but to return true. *)
+ RETURN true
+ ELSIF IsFieldEnumeration (left)
+ THEN
+ RETURN checkEnumField (result, tinfo, left, right)
+ ELSIF IsFieldEnumeration (right)
+ THEN
+ RETURN checkEnumField (result, tinfo, right, left)
+ END ;
+ RETURN result
+END checkEnumFieldEquivalence ;
+
+
+(*
checkConstEquivalence - this check can be done first as it checks symbols which
may have no type. Ie constant strings. These constants
will likely have their type set during quadruple folding.
@@ -861,14 +1080,9 @@ BEGIN
IF IsSubrange (right)
THEN
RETURN doCheckPair (result, tinfo, left, GetDType (right))
- END ;
- IF left = right
- THEN
- RETURN true
- ELSE
- RETURN result
END
- END
+ END ;
+ RETURN result
END checkSubrangeTypeEquivalence ;
@@ -892,7 +1106,7 @@ PROCEDURE isZRC (zrc, sym: CARDINAL) : BOOLEAN ;
BEGIN
IF IsConst (sym)
THEN
- sym := SkipType (GetType (sym))
+ sym := SkipType (GetDType (sym))
END ;
IF (zrc = CType) AND (IsComplexN (sym) OR IsComplexType (sym))
THEN
@@ -911,11 +1125,11 @@ PROCEDURE isSameSizeConst (a, b: CARDINAL) : BOOLEAN ;
BEGIN
IF IsConst (a)
THEN
- a := SkipType (GetType (a)) ;
+ a := SkipType (GetDType (a)) ;
RETURN isZRC (a, b) OR (a = b) OR ((a # NulSym) AND isSameSize (a, b))
ELSIF IsConst (b)
THEN
- b := SkipType (GetType (b)) ;
+ b := SkipType (GetDType (b)) ;
RETURN isZRC (b, a) OR (a = b) OR ((b # NulSym) AND isSameSize (a, b))
END ;
RETURN FALSE
@@ -936,13 +1150,15 @@ END isSameSize ;
checkSystemEquivalence - check whether left and right are system types and whether they have the same size.
*)
-PROCEDURE checkSystemEquivalence (result: status; left, right: CARDINAL) : status ;
+PROCEDURE checkSystemEquivalence (result: status; tinfo: tInfo <* unused *>;
+ left, right: CARDINAL) : status ;
BEGIN
IF isFalse (result) OR (result = visited)
THEN
RETURN result
ELSE
IF (IsGenericSystemType (left) OR IsGenericSystemType (right)) AND
+ GccKnowsAbout (left) AND GccKnowsAbout (right) AND
isSameSize (left, right)
THEN
RETURN true
@@ -957,7 +1173,7 @@ END checkSystemEquivalence ;
a set, record or array.
*)
-PROCEDURE checkTypeKindViolation (result: status;
+PROCEDURE checkTypeKindViolation (result: status; tinfo: tInfo;
left, right: CARDINAL) : status ;
BEGIN
IF isFalse (result) OR (result = visited)
@@ -969,7 +1185,8 @@ BEGIN
(IsRecord (left) OR IsRecord (right)) OR
(IsArray (left) OR IsArray (right))
THEN
- RETURN false
+ RETURN falseReason2 ('a {%1ad} is incompatible with a {%2ad}',
+ tinfo, left, right)
END
END ;
RETURN result
@@ -977,7 +1194,7 @@ END checkTypeKindViolation ;
(*
- doCheckPair - invoke a series of ordered type checks checking compatibility
+ doCheckPair - invoke a series of type checks checking compatibility
between left and right modula2 symbols.
Pre-condition: left and right are modula-2 symbols.
tinfo is configured.
@@ -989,50 +1206,28 @@ END checkTypeKindViolation ;
PROCEDURE doCheckPair (result: status; tinfo: tInfo;
left, right: CARDINAL) : status ;
+VAR
+ i: CARDINAL ;
BEGIN
- IF isFalse (result) OR (result = visited)
+ IF (left = NulSym) OR (right = NulSym)
+ THEN
+ (* We cannot check NulSym. *)
+ RETURN true
+ ELSIF isKnown (result)
THEN
RETURN return (result, tinfo, left, right)
ELSIF left = right
THEN
RETURN return (true, tinfo, left, right)
ELSE
- result := checkConstEquivalence (unknown, tinfo, left, right) ;
- IF NOT isKnown (result)
- THEN
- result := checkVarEquivalence (unknown, tinfo, left, right) ;
- IF NOT isKnown (result)
+ i := 1 ;
+ WHILE i <= HighEquivalence DO
+ result := Equivalence[i] (result, tinfo, left, right) ;
+ IF isKnown (result)
THEN
- result := checkSystemEquivalence (unknown, left, right) ;
- IF NOT isKnown (result)
- THEN
- result := checkSubrangeTypeEquivalence (unknown, tinfo, left, right) ;
- IF NOT isKnown (result)
- THEN
- result := checkBaseTypeEquivalence (unknown, tinfo, left, right) ;
- IF NOT isKnown (result)
- THEN
- result := checkTypeEquivalence (unknown, left, right) ;
- IF NOT isKnown (result)
- THEN
- result := checkArrayTypeEquivalence (result, tinfo, left, right) ;
- IF NOT isKnown (result)
- THEN
- result := checkGenericTypeEquivalence (result, left, right) ;
- IF NOT isKnown (result)
- THEN
- result := checkTypeKindEquivalence (result, tinfo, left, right) ;
- IF NOT isKnown (result)
- THEN
- result := checkTypeKindViolation (result, left, right)
- END
- END
- END
- END
- END
- END
- END
- END
+ RETURN return (result, tinfo, left, right)
+ END ;
+ INC (i)
END
END ;
RETURN return (result, tinfo, left, right)
@@ -1040,6 +1235,45 @@ END doCheckPair ;
(*
+ InitEquivalenceArray - populate the Equivalence array with the
+ checking procedures.
+*)
+
+PROCEDURE InitEquivalenceArray ;
+BEGIN
+ HighEquivalence := 0 ;
+ addEquivalence (checkVarEquivalence) ;
+ addEquivalence (checkVarTypeEquivalence) ;
+ addEquivalence (checkCharStringTypeEquivalence) ;
+ addEquivalence (checkConstEquivalence);
+ addEquivalence (checkEnumFieldEquivalence) ;
+ addEquivalence (checkSystemEquivalence) ;
+ addEquivalence (checkSubrangeTypeEquivalence) ;
+ addEquivalence (checkBaseTypeEquivalence) ;
+ addEquivalence (checkTypeEquivalence) ;
+ addEquivalence (checkArrayTypeEquivalence) ;
+ addEquivalence (checkTypeKindEquivalence) ;
+ addEquivalence (checkTypeKindViolation)
+END InitEquivalenceArray ;
+
+
+(*
+ addEquivalence - places proc into Equivalence array.
+*)
+
+PROCEDURE addEquivalence (proc: EquivalenceProcedure) ;
+BEGIN
+ INC (HighEquivalence) ;
+ IF HighEquivalence <= MaxEquvalence
+ THEN
+ Equivalence[HighEquivalence] := proc
+ ELSE
+ InternalError ('increase MaxEquivalence constant in M2Check.mod')
+ END
+END addEquivalence ;
+
+
+(*
checkProcType -
*)
@@ -1090,6 +1324,12 @@ BEGIN
i := 1 ;
n := NoOfParamAny (left) ;
WHILE i <= n DO
+ IF isFalse (result) OR (result = visited)
+ THEN
+ (* Seen a mismatch therefore return. *)
+ RETURN return (result, tinfo, left, right)
+ END ;
+ result := unknown ; (* Each parameter must match. *)
IF IsVarParamAny (left, i) # IsVarParamAny (right, i)
THEN
IF IsVarParamAny (left, i)
@@ -1281,7 +1521,6 @@ BEGIN
END checkProcTypeEquivalence ;
-
(*
checkTypeKindEquivalence -
*)
@@ -1551,7 +1790,7 @@ BEGIN
THEN
RETURN Address
ELSE
- RETURN GetSType (sym)
+ RETURN GetDType (sym)
END
END getSType ;
@@ -1627,11 +1866,19 @@ BEGIN
printf ("doCheck (%d, %d)\n", left, right) ;
dumptInfo (tinfo)
END ;
- IF isInternal (left) OR isInternal (right)
+ IF (left = NulSym) OR (right = NulSym)
+ THEN
+ (* Cannot test if a type is NulSym, we assume true.
+ It maybe that later on a symbols type is set and later
+ on checking will be called and more accurately resolved.
+ For example constant strings can be concatenated during
+ the quadruple folding phase. *)
+ RETURN TRUE
+ ELSIF isInternal (left) OR isInternal (right)
THEN
(* Do not check constants which have been generated internally.
- Currently these are generated by the default BY constant value
- in a FOR loop. *)
+ Currently these are generated by the default BY constant
+ value in a FOR loop. *)
RETURN TRUE
END ;
(*
@@ -1650,9 +1897,9 @@ BEGIN
result := tinfo^.checkFunc (unknown, tinfo, left, right) ;
IF isKnown (result)
THEN
- (* remove this pair from the unresolved list. *)
+ (* Remove this pair from the unresolved list. *)
exclude (tinfo^.unresolved, left, right) ;
- (* add it to the resolved list. *)
+ (* Add it to the resolved list. *)
include (tinfo^.resolved, left, right, result) ;
IF result = false
THEN
@@ -1757,6 +2004,7 @@ END deconstructIndex ;
PROCEDURE deconstruct (tinfo: tInfo) ;
BEGIN
tinfo^.format := KillString (tinfo^.format) ;
+ tinfo^.reason := KillString (tinfo^.reason) ;
tinfo^.visited := deconstructIndex (tinfo^.visited) ;
tinfo^.resolved := deconstructIndex (tinfo^.resolved) ;
tinfo^.unresolved := deconstructIndex (tinfo^.unresolved)
@@ -1803,11 +2051,14 @@ END collapseString ;
*)
PROCEDURE AssignmentTypeCompatible (token: CARDINAL; format: ARRAY OF CHAR;
- des, expr: CARDINAL) : BOOLEAN ;
+ des, expr: CARDINAL;
+ enableReason: BOOLEAN) : BOOLEAN ;
VAR
tinfo: tInfo ;
BEGIN
tinfo := newtInfo () ;
+ tinfo^.reason := NIL ;
+ tinfo^.reasonEnable := enableReason AND StrictTypeReason ;
tinfo^.format := collapseString (format) ;
tinfo^.token := token ;
tinfo^.kind := assignment ;
@@ -1852,6 +2103,8 @@ BEGIN
tinfo := newtInfo () ;
formalT := getSType (formal) ;
actualT := getSType (actual) ;
+ tinfo^.reasonEnable := StrictTypeReason ;
+ tinfo^.reason := NIL ;
tinfo^.format := collapseString (format) ;
tinfo^.token := token ;
tinfo^.kind := parameter ;
@@ -1896,6 +2149,8 @@ VAR
tinfo: tInfo ;
BEGIN
tinfo := newtInfo () ;
+ tinfo^.reasonEnable := StrictTypeReason ;
+ tinfo^.reason := NIL ;
tinfo^.format := collapseString (format) ;
tinfo^.token := token ;
tinfo^.kind := expression ;
@@ -1960,7 +2215,8 @@ PROCEDURE init ;
BEGIN
pairFreeList := NIL ;
tinfoFreeList := NIL ;
- errors := InitIndex (1)
+ errors := InitIndex (1) ;
+ InitEquivalenceArray
END init ;
diff --git a/gcc/m2/gm2-compiler/M2GenGCC.mod b/gcc/m2/gm2-compiler/M2GenGCC.mod
index 2dfa566..4a9ced3 100644
--- a/gcc/m2/gm2-compiler/M2GenGCC.mod
+++ b/gcc/m2/gm2-compiler/M2GenGCC.mod
@@ -681,7 +681,7 @@ BEGIN
IfGreOp : CodeIfGre (q) |
IfInOp : CodeIfIn (q) |
IfNotInOp : CodeIfNotIn (q) |
- IndrXOp : CodeIndrX (q, op1, op2, op3) |
+ IndrXOp : CodeIndrX (q) |
XIndrOp : CodeXIndr (q) |
CallOp : CodeCall (CurrentQuadToken, op3) |
ParamOp : CodeParam (q) |
@@ -3004,7 +3004,7 @@ BEGIN
despos, op2pos, exprpos) ;
Assert (op2pos = UnknownTokenNo) ;
IF StrictTypeChecking AND
- (NOT AssignmentTypeCompatible (despos, "", des, expr))
+ (NOT AssignmentTypeCompatible (despos, "", des, expr, TRUE))
THEN
MetaErrorT2 (MakeVirtualTok (becomespos, despos, exprpos),
'assignment check caught mismatch between {%1Ead} and {%2ad}',
@@ -3233,7 +3233,7 @@ BEGIN
IF SkipType(GetTypeMode(op1))#SkipType(GetTypeMode(op3))
THEN
DescribeTypeError (tokenno, op1, op3) ;
- (* Assigning an errant op3 might ICE, therefore it is safer to return op1. *)
+ (* Assigning an errant op3 might ICE, therefore it is safer to return op1. *)
RETURN( Mod2Gcc (op1) )
END
END ;
@@ -3550,7 +3550,7 @@ BEGIN
location := TokenToLocation (virtpos) ;
IF StrictTypeChecking AND
- (NOT AssignmentTypeCompatible (virtpos, "", des, expr))
+ (NOT AssignmentTypeCompatible (virtpos, "", des, expr, TRUE))
THEN
ErrorMessageDecl (virtpos,
'assignment check caught mismatch between {%1Ead} and {%2ad}',
@@ -3918,8 +3918,6 @@ END NoWalkProcedure ;
PROCEDURE CheckBinaryExpressionTypes (quad: CARDINAL; p: WalkAction) : BOOLEAN ;
VAR
- lefttype,
- righttype,
des, left, right: CARDINAL ;
typeChecking,
constExpr,
@@ -3937,10 +3935,8 @@ BEGIN
IF typeChecking AND (op # LogicalRotateOp) AND (op # LogicalShiftOp)
THEN
subexprpos := MakeVirtualTok (operatorpos, leftpos, rightpos) ;
- lefttype := GetType (left) ;
- righttype := GetType (right) ;
IF StrictTypeChecking AND
- (NOT ExpressionTypeCompatible (subexprpos, "", lefttype, righttype,
+ (NOT ExpressionTypeCompatible (subexprpos, "", left, right,
StrictTypeChecking, FALSE))
THEN
MetaErrorT2 (subexprpos,
@@ -3950,19 +3946,6 @@ BEGIN
SubQuad (quad) ;
p (des) ;
RETURN FALSE
- END ;
- (* --fixme-- the ExpressionTypeCompatible above should be enough
- and the code below can be removed once ExpressionTypeCompatible
- is bug free. *)
- IF NOT IsExpressionCompatible (lefttype, righttype)
- THEN
- ErrorMessageDecl (subexprpos,
- 'expression mismatch between {%1Etad} and {%2tad}',
- left, right, TRUE) ;
- NoChange := FALSE ;
- SubQuad (quad) ;
- p (des) ;
- RETURN FALSE
END
END ;
RETURN TRUE
@@ -3978,7 +3961,6 @@ END CheckBinaryExpressionTypes ;
PROCEDURE CheckElementSetTypes (quad: CARDINAL) : BOOLEAN ;
VAR
- lefttype,
righttype,
ignore, left, right: CARDINAL ;
constExpr,
@@ -3995,13 +3977,9 @@ BEGIN
overflowChecking, constExpr,
leftpos, rightpos, ignorepos) ;
subexprpos := MakeVirtualTok (operatorpos, leftpos, rightpos) ;
- lefttype := GetType (left) ;
righttype := GetType (right) ;
- (* --fixme-- the ExpressionTypeCompatible below does not always catch
- type errors, it needs to be fixed and then some of the subsequent tests
- can be removed (and/or this procedure function rewritten). *)
IF StrictTypeChecking AND
- (NOT ExpressionTypeCompatible (subexprpos, "", lefttype, righttype,
+ (NOT ExpressionTypeCompatible (subexprpos, "", left, right,
StrictTypeChecking, TRUE))
THEN
MetaErrorT2 (subexprpos,
@@ -4020,17 +3998,6 @@ BEGIN
SubQuad (quad) ;
RETURN FALSE
END ;
- righttype := GetType (SkipType (righttype)) ;
- (* Now fall though and compare the set element left against the type of set righttype. *)
- IF NOT IsExpressionCompatible (lefttype, righttype)
- THEN
- ErrorMessageDecl (subexprpos,
- 'the types used in expression {%1Etad} {%kIN} {%2tad} are incompatible',
- left, right, TRUE) ;
- NoChange := FALSE ;
- SubQuad (quad) ;
- RETURN FALSE
- END ;
RETURN TRUE
END CheckElementSetTypes ;
@@ -8174,25 +8141,52 @@ END CodeIfNotIn ;
(op2 is the type of the data being indirectly copied)
*)
-PROCEDURE CodeIndrX (quad: CARDINAL; op1, op2, op3: CARDINAL) ;
+PROCEDURE CodeIndrX (quad: CARDINAL) ;
VAR
- location: location_t ;
+ constExpr,
+ overflowChecking: BOOLEAN ;
+ op : QuadOperator ;
+ tokenno,
+ left,
+ type,
+ right,
+ leftpos,
+ rightpos,
+ typepos,
+ indrxpos : CARDINAL ;
+ length,
+ newstr : tree ;
+ location : location_t ;
BEGIN
- location := TokenToLocation (CurrentQuadToken) ;
+ GetQuadOtok (quad, indrxpos, op, left, type, right,
+ overflowChecking, constExpr,
+ leftpos, typepos, rightpos) ;
+ tokenno := MakeVirtualTok (indrxpos, leftpos, rightpos) ;
+ location := TokenToLocation (tokenno) ;
(*
Follow the Quadruple rules:
*)
- DeclareConstant (CurrentQuadToken, op3) ; (* checks to see whether it is a constant and declares it *)
- DeclareConstructor (CurrentQuadToken, quad, op3) ;
- IF IsConstString (op3)
+ DeclareConstant (rightpos, right) ; (* Checks to see whether it is a constant
+ and if necessary declare it. *)
+ DeclareConstructor (rightpos, quad, right) ;
+ IF IsConstString (right)
THEN
InternalError ('not expecting to index through a constant string')
+ ELSIF StrictTypeChecking AND
+ (NOT AssignmentTypeCompatible (indrxpos, "", left, GetType (right), TRUE))
+ THEN
+ MetaErrorT2 (tokenno,
+ 'assignment check caught mismatch between {%1Ead} and {%2ad}',
+ left, right) ;
+ SubQuad (quad)
ELSE
+
(*
Mem[op1] := Mem[Mem[op3]]
*)
- BuildAssignmentStatement (location, Mod2Gcc (op1), BuildIndirect (location, Mod2Gcc (op3), Mod2Gcc (op2)))
+ BuildAssignmentStatement (location, Mod2Gcc (left),
+ BuildIndirect (location, Mod2Gcc (right), Mod2Gcc (type)))
END
END CodeIndrX ;
@@ -8230,7 +8224,7 @@ BEGIN
DeclareConstant (rightpos, right) ;
DeclareConstructor (rightpos, quad, right) ;
IF StrictTypeChecking AND
- (NOT AssignmentTypeCompatible (xindrpos, "", GetType (left), right))
+ (NOT AssignmentTypeCompatible (xindrpos, "", GetType (left), right, TRUE))
THEN
MetaErrorT2 (tokenno,
'assignment check caught mismatch between {%1Ead} and {%2ad}',
diff --git a/gcc/m2/gm2-compiler/M2MetaError.def b/gcc/m2/gm2-compiler/M2MetaError.def
index cfe9195..3dfe9fa 100644
--- a/gcc/m2/gm2-compiler/M2MetaError.def
+++ b/gcc/m2/gm2-compiler/M2MetaError.def
@@ -93,9 +93,9 @@ FROM NameKey IMPORT Name ;
%} }
the error messages may also embed optional strings such as:
- {%1a:this string is emitted if the symbol name is non null}
- {!%1a:this string is emitted if the symbol name is null}
- {!%1a:{%1d}}
+ {%1a:this string is emitted if the symbol name is null}
+ {!%1a:this string is emitted if the symbol name is non null}
+ {%1a:{%1d}}
if the symbol name does not exist then print a description
of the symbol.
{%1atd} was incompatible with the return type of the procedure
diff --git a/gcc/m2/gm2-compiler/M2Options.def b/gcc/m2/gm2-compiler/M2Options.def
index 2b78add..4cb7f8f 100644
--- a/gcc/m2/gm2-compiler/M2Options.def
+++ b/gcc/m2/gm2-compiler/M2Options.def
@@ -87,6 +87,8 @@ VAR
LineDirectives, (* Should compiler understand preprocessor *)
(* # linenumber "filename" markers? *)
StrictTypeChecking, (* -fm2-strict-type experimental checker. *)
+ StrictTypeAssignment, (* -fm2-strict-assignment. *)
+ StrictTypeReason, (* -fm2-strict-reason. *)
CPreProcessor, (* Must we run the cpp on the source? *)
Xcode, (* Should errors follow Xcode format? *)
ExtendedOpaque, (* Do we allow non pointer opaque types? *)
@@ -756,6 +758,20 @@ PROCEDURE SetStrictTypeChecking (value: BOOLEAN) ;
(*
+ SetStrictTypeAssignment - assigns the StrictTypeAssignment flag to value.
+*)
+
+PROCEDURE SetStrictTypeAssignment (value: BOOLEAN) ;
+
+
+(*
+ SetStrictTypeReason - assigns the StrictTypeReason flag to value.
+*)
+
+PROCEDURE SetStrictTypeReason (value: BOOLEAN) ;
+
+
+(*
setdefextension - set the source file definition module extension to arg.
This should include the . and by default it is set to .def.
*)
diff --git a/gcc/m2/gm2-compiler/M2Options.mod b/gcc/m2/gm2-compiler/M2Options.mod
index 39f0b2a..542b87b 100644
--- a/gcc/m2/gm2-compiler/M2Options.mod
+++ b/gcc/m2/gm2-compiler/M2Options.mod
@@ -657,6 +657,26 @@ END SetStrictTypeChecking ;
(*
+ SetStrictTypeAssignment - assigns the StrictTypeAssignment flag to value.
+*)
+
+PROCEDURE SetStrictTypeAssignment (value: BOOLEAN) ;
+BEGIN
+ StrictTypeAssignment := value
+END SetStrictTypeAssignment ;
+
+
+(*
+ SetStrictTypeReason - assigns the StrictTypeReason flag to value.
+*)
+
+PROCEDURE SetStrictTypeReason (value: BOOLEAN) ;
+BEGIN
+ StrictTypeReason := value
+END SetStrictTypeReason ;
+
+
+(*
SetVerboseUnbounded - sets the VerboseUnbounded flag to, value.
*)
@@ -2111,6 +2131,8 @@ BEGIN
UnusedVariableChecking := FALSE ;
UnusedParameterChecking := FALSE ;
StrictTypeChecking := TRUE ;
+ StrictTypeAssignment := TRUE ;
+ StrictTypeReason := TRUE ;
AutoInit := FALSE ;
SaveTemps := FALSE ;
ScaffoldDynamic := TRUE ;
diff --git a/gcc/m2/gm2-compiler/M2Quads.mod b/gcc/m2/gm2-compiler/M2Quads.mod
index 4022657..3c29fdd 100644
--- a/gcc/m2/gm2-compiler/M2Quads.mod
+++ b/gcc/m2/gm2-compiler/M2Quads.mod
@@ -226,6 +226,7 @@ FROM M2Options IMPORT NilChecking,
GenerateLineDebug, Exceptions,
Profiling, Coding, Optimizing,
UninitVariableChecking,
+ StrictTypeAssignment,
ScaffoldDynamic, ScaffoldStatic, cflag,
ScaffoldMain, SharedFlag, WholeProgram,
GetDumpDir, GetM2DumpFilter,
@@ -258,8 +259,10 @@ FROM M2Range IMPORT InitAssignmentRangeCheck,
InitRotateCheck,
InitShiftCheck,
InitTypesAssignmentCheck,
+ InitTypesIndrXCheck,
InitTypesExpressionCheck,
InitTypesParameterCheck,
+ InitTypesReturnTypeCheck,
InitForLoopBeginRangeCheck,
InitForLoopToRangeCheck,
InitForLoopEndRangeCheck,
@@ -284,7 +287,6 @@ IMPORT M2Error, FIO, SFIO, DynamicStrings, StdIO ;
CONST
DebugStackOn = TRUE ;
DebugVarients = FALSE ;
- BreakAtQuad = 758 ;
DebugTokPos = FALSE ;
TYPE
@@ -397,6 +399,7 @@ VAR
(* in order. *)
NoOfQuads : CARDINAL ; (* Number of used quadruples. *)
Head : CARDINAL ; (* Head of the list of quadruples. *)
+ BreakQuad : CARDINAL ; (* Stop when BreakQuad is created. *)
(*
@@ -1487,22 +1490,6 @@ BEGIN
END AddQuadInformation ;
-PROCEDURE stop ; BEGIN END stop ;
-
-
-(*
- CheckBreak - check whether QuadNo = BreakAtQuad and if so call stop.
-*)
-
-PROCEDURE CheckBreak (QuadNo: CARDINAL) ;
-BEGIN
- IF QuadNo = BreakAtQuad
- THEN
- stop
- END
-END CheckBreak ;
-
-
(*
PutQuadO - alters a quadruple QuadNo with Op, Oper1, Oper2, Oper3, and
sets a boolean to determinine whether overflow should be checked.
@@ -3888,6 +3875,10 @@ BEGIN
THEN
MetaErrorT1 (combinedtok, 'combined {%1Oad}', Des)
END ;
+ IF StrictTypeAssignment
+ THEN
+ BuildRange (InitTypesAssignmentCheck (combinedtok, Des, Exp))
+ END ;
IF (GetSType (Des) # NulSym) AND (NOT IsSet (GetDType (Des)))
THEN
(* Tell code generator to test runtime values of assignment so ensure we
@@ -5628,7 +5619,7 @@ VAR
proctok,
paramtok : CARDINAL ;
n1, n2 : Name ;
- ParamCheckId,
+ ParamCheckId,
Dim,
Actual,
FormalI,
@@ -5770,42 +5761,46 @@ VAR
CheckedProcedure: CARDINAL ;
e : Error ;
BEGIN
- n := NoOfParamAny (ProcType) ;
IF IsVar(call) OR IsTemporary(call) OR IsParameter(call)
THEN
CheckedProcedure := GetDType(call)
ELSE
CheckedProcedure := call
END ;
- IF n # NoOfParamAny (CheckedProcedure)
+ IF ProcType # CheckedProcedure
THEN
- e := NewError(GetDeclaredMod(ProcType)) ;
- n1 := GetSymName(call) ;
- n2 := GetSymName(ProcType) ;
- ErrorFormat2(e, 'procedure (%a) is a parameter being passed as variable (%a) but they are declared with different number of parameters',
- n1, n2) ;
- e := ChainError(GetDeclaredMod(call), e) ;
- t := NoOfParamAny (CheckedProcedure) ;
- IF n<2
+ n := NoOfParamAny (ProcType) ;
+ (* We need to check the formal parameters between the procedure and proc type. *)
+ IF n # NoOfParamAny (CheckedProcedure)
THEN
- ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameter, declared with (%d)',
- n1, n, t)
- ELSE
- ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameters, declared with (%d)',
- n1, n, t)
- END
- ELSE
- i := 1 ;
- WHILE i<=n DO
- IF IsVarParamAny (ProcType, i) # IsVarParamAny (CheckedProcedure, i)
+ e := NewError(GetDeclaredMod(ProcType)) ;
+ n1 := GetSymName(call) ;
+ n2 := GetSymName(ProcType) ;
+ ErrorFormat2(e, 'procedure (%a) is a parameter being passed as variable (%a) but they are declared with different number of parameters',
+ n1, n2) ;
+ e := ChainError(GetDeclaredMod(call), e) ;
+ t := NoOfParamAny (CheckedProcedure) ;
+ IF n<2
THEN
- MetaError3 ('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', ProcType, GetNth (ProcType, i), i) ;
- MetaError3 ('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', call, GetNth (call, i), i)
- END ;
- BuildRange (InitTypesParameterCheck (tokno, CheckedProcedure, i,
- GetNthParamAnyClosest (CheckedProcedure, i, GetCurrentModule ()),
- GetParam (ProcType, i), ParamCheckId)) ;
- INC(i)
+ ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameter, declared with (%d)',
+ n1, n, t)
+ ELSE
+ ErrorFormat3(e, 'procedure (%a) is being called incorrectly with (%d) parameters, declared with (%d)',
+ n1, n, t)
+ END
+ ELSE
+ i := 1 ;
+ WHILE i<=n DO
+ IF IsVarParamAny (ProcType, i) # IsVarParamAny (CheckedProcedure, i)
+ THEN
+ MetaError3 ('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', ProcType, GetNth (ProcType, i), i) ;
+ MetaError3 ('parameter {%3n} in {%1dD} causes a mismatch it was declared as a {%2d}', call, GetNth (call, i), i)
+ END ;
+ BuildRange (InitTypesParameterCheck (tokno, CheckedProcedure, i,
+ GetNthParamAnyClosest (CheckedProcedure, i, GetCurrentModule ()),
+ GetParam (ProcType, i), ParamCheckId)) ;
+ INC(i)
+ END
END
END
END CheckProcTypeAndProcedure ;
@@ -6272,21 +6267,24 @@ END ExpectVariable ;
doIndrX - perform des = *exp with a conversion if necessary.
*)
-PROCEDURE doIndrX (tok: CARDINAL;
- des, exp: CARDINAL) ;
+PROCEDURE doIndrX (tok: CARDINAL; des, exp: CARDINAL) ;
VAR
t: CARDINAL ;
BEGIN
- IF GetDType(des)=GetDType(exp)
+ IF GetDType (des) = GetDType (exp)
THEN
GenQuadOtok (tok, IndrXOp, des, GetSType (des), exp, TRUE,
tok, tok, tok)
ELSE
+ IF StrictTypeAssignment
+ THEN
+ BuildRange (InitTypesIndrXCheck (tok, des, exp))
+ END ;
t := MakeTemporary (tok, RightValue) ;
PutVar (t, GetSType (exp)) ;
GenQuadOtok (tok, IndrXOp, t, GetSType (exp), exp, TRUE,
tok, tok, tok) ;
- GenQuadOtok (tok, BecomesOp, des, NulSym, doVal (GetSType(des), t), TRUE,
+ GenQuadOtok (tok, BecomesOp, des, NulSym, doVal (GetSType (des), t), TRUE,
tok, UnknownTokenNo, tok)
END
END doIndrX ;
@@ -11295,7 +11293,7 @@ BEGIN
n1, n2)
ELSE
(* this checks the types are compatible, not the data contents. *)
- BuildRange (InitTypesAssignmentCheck (tokno, currentProc, actualVal))
+ BuildRange (InitTypesReturnTypeCheck (tokno, currentProc, actualVal))
END
END CheckReturnType ;
@@ -16061,12 +16059,55 @@ END StressStack ;
(*
+ gdbhook - a debugger convenience hook.
+*)
+
+PROCEDURE gdbhook ;
+END gdbhook ;
+
+
+(*
+ BreakWhenQuadCreated - to be called interactively by gdb.
+*)
+
+PROCEDURE BreakWhenQuadCreated (quad: CARDINAL) ;
+BEGIN
+ BreakQuad := quad
+END BreakWhenQuadCreated ;
+
+
+(*
+ CheckBreak - if quad = BreakQuad then call gdbhook.
+*)
+
+PROCEDURE CheckBreak (quad: CARDINAL) ;
+BEGIN
+ IF quad = BreakQuad
+ THEN
+ gdbhook
+ END
+END CheckBreak ;
+
+
+(*
Init - initialize the M2Quads module, all the stacks, all the lists
and the quads list.
*)
PROCEDURE Init ;
BEGIN
+ BreakWhenQuadCreated (0) ; (* Disable the intereactive quad watch. *)
+ (* To examine the quad table when a quad is created run cc1gm2 from gdb
+ and set a break point on gdbhook.
+ (gdb) break gdbhook
+ (gdb) run
+ Now below interactively call BreakWhenQuadCreated with the quad
+ under investigation. *)
+ gdbhook ;
+ (* Now is the time to interactively call gdb, for example:
+ (gdb) print BreakWhenQuadCreated (1234)
+ (gdb) cont
+ and you will arrive at gdbhook when this quad is created. *)
LogicalOrTok := MakeKey('_LOR') ;
LogicalAndTok := MakeKey('_LAND') ;
LogicalXorTok := MakeKey('_LXOR') ;
diff --git a/gcc/m2/gm2-compiler/M2Range.def b/gcc/m2/gm2-compiler/M2Range.def
index 42aa142..e825d94 100644
--- a/gcc/m2/gm2-compiler/M2Range.def
+++ b/gcc/m2/gm2-compiler/M2Range.def
@@ -291,6 +291,24 @@ PROCEDURE InitTypesExpressionCheck (tokno: CARDINAL; d, e: CARDINAL;
(*
+ InitTypesIndrXCheck - checks to see that the types of d and e
+ are assignment compatible. The type checking
+ will dereference *e during the type check.
+ d = *e.
+*)
+
+PROCEDURE InitTypesIndrXCheck (tokno: CARDINAL; d, e: CARDINAL) : CARDINAL ;
+
+
+(*
+ InitTypesReturnTypeCheck - checks to see that the type of val can
+ be returned from func.
+*)
+
+PROCEDURE InitTypesReturnTypeCheck (tokno: CARDINAL; func, val: CARDINAL) : CARDINAL ;
+
+
+(*
InitCaseBounds - creates a case bound range check.
*)
diff --git a/gcc/m2/gm2-compiler/M2Range.mod b/gcc/m2/gm2-compiler/M2Range.mod
index 8e3943a..dcac2ba 100644
--- a/gcc/m2/gm2-compiler/M2Range.mod
+++ b/gcc/m2/gm2-compiler/M2Range.mod
@@ -58,7 +58,7 @@ FROM M2Debug IMPORT Assert ;
FROM Indexing IMPORT Index, InitIndex, InBounds, PutIndice, GetIndice ;
FROM Storage IMPORT ALLOCATE ;
FROM M2ALU IMPORT PushIntegerTree, PushInt, ConvertToInt, Equ, Gre, Less, GreEqu ;
-FROM M2Options IMPORT VariantValueChecking, CaseEnumChecking, GetPIM ;
+FROM M2Options IMPORT VariantValueChecking, CaseEnumChecking, GetPIM, StrictTypeAssignment ;
FROM M2Error IMPORT Error, InternalError, ErrorFormat0, ErrorFormat1, ErrorFormat2, FlushErrors,
GetAnnounceScope ;
@@ -91,7 +91,6 @@ FROM M2Check IMPORT ParameterTypeCompatible, ExpressionTypeCompatible, Assignmen
FROM M2Base IMPORT Nil, IsRealType, GetBaseTypeMinMax,
Cardinal, Integer, ZType, IsComplexType,
- IsAssignmentCompatible,
IsExpressionCompatible,
IsParameterCompatible,
ExceptionAssign,
@@ -115,7 +114,9 @@ FROM M2CaseList IMPORT CaseBoundsResolved, OverlappingCaseBounds,
TYPE
TypeOfRange = (assignment, returnassignment, subrangeassignment,
inc, dec, incl, excl, shift, rotate,
- typeexpr, typeassign, typeparam, paramassign,
+ typeindrx, typeexpr, typeassign, typeparam,
+ typereturn,
+ paramassign,
staticarraysubscript,
dynamicarraysubscript,
forloopbegin, forloopto, forloopend,
@@ -289,9 +290,10 @@ BEGIN
excl : RETURN( ExceptionExcl ) |
shift : RETURN( ExceptionShift ) |
rotate : RETURN( ExceptionRotate ) |
- typeassign : InternalError ('not expecting this case value') |
- typeparam : InternalError ('not expecting this case value') |
- typeexpr : InternalError ('not expecting this case value') |
+ typeassign,
+ typeparam,
+ typeexpr,
+ typeindrx : InternalError ('not expecting this case value') |
paramassign : RETURN( ExceptionParameterBounds ) |
staticarraysubscript : RETURN( ExceptionStaticArray ) |
dynamicarraysubscript: RETURN( ExceptionDynamicArray ) |
@@ -822,7 +824,7 @@ END InitRotateCheck ;
(*
- InitTypesAssignmentCheck - checks to see that the types of, d, and, e,
+ InitTypesAssignmentCheck - checks to see that the types of d and e
are assignment compatible.
*)
@@ -837,6 +839,38 @@ END InitTypesAssignmentCheck ;
(*
+ InitTypesIndrXCheck - checks to see that the types of d and e
+ are assignment compatible. The type checking
+ will dereference *e during the type check.
+ d = *e.
+*)
+
+PROCEDURE InitTypesIndrXCheck (tokno: CARDINAL; d, e: CARDINAL) : CARDINAL ;
+VAR
+ r: CARDINAL ;
+BEGIN
+ r := InitRange () ;
+ Assert (PutRangeNoLow (tokno, GetIndice (RangeIndex, r), typeindrx, d, e) # NIL) ;
+ RETURN r
+END InitTypesIndrXCheck ;
+
+
+(*
+ InitTypesReturnTypeCheck - checks to see that the types of des and func
+ are assignment compatible.
+*)
+
+PROCEDURE InitTypesReturnTypeCheck (tokno: CARDINAL; func, val: CARDINAL) : CARDINAL ;
+VAR
+ r: CARDINAL ;
+BEGIN
+ r := InitRange () ;
+ Assert (PutRangeNoLow (tokno, GetIndice (RangeIndex, r), typereturn, func, val) # NIL) ;
+ RETURN r
+END InitTypesReturnTypeCheck ;
+
+
+(*
InitTypesParameterCheck - checks to see that the types of, d,
and, e, are parameter compatible.
*)
@@ -1219,9 +1253,11 @@ BEGIN
excl : RETURN( ExceptionExcl#NulSym ) |
shift : RETURN( ExceptionShift#NulSym ) |
rotate : RETURN( ExceptionRotate#NulSym ) |
- typeassign : RETURN( FALSE ) |
- typeparam : RETURN( FALSE ) |
- typeexpr : RETURN( FALSE ) |
+ typereturn,
+ typeassign,
+ typeparam,
+ typeexpr,
+ typeindrx : RETURN( FALSE ) |
paramassign : RETURN( ExceptionParameterBounds#NulSym ) |
staticarraysubscript : RETURN( ExceptionStaticArray#NulSym ) |
dynamicarraysubscript: RETURN( ExceptionDynamicArray#NulSym ) |
@@ -1246,7 +1282,9 @@ END HandlerExists ;
(*
- FoldAssignment -
+ FoldAssignment - attempts to fold the range violation checks.
+ It does not issue errors on type violations as that
+ is performed by FoldTypeAssign.
*)
PROCEDURE FoldAssignment (tokenno: CARDINAL; q: CARDINAL; r: CARDINAL) ;
@@ -1259,7 +1297,7 @@ BEGIN
TryDeclareConstant (exprtok, expr) ;
IF desLowestType # NulSym
THEN
- IF AssignmentTypeCompatible (tokenno, "", des, expr)
+ IF AssignmentTypeCompatible (tokenno, "", des, expr, FALSE)
THEN
IF GccKnowsAbout (expr) AND IsConst (expr) AND
GetMinMax (tokenno, desLowestType, min, max)
@@ -1275,6 +1313,8 @@ BEGIN
END
END
ELSE
+ (* We do not issue an error if these types are incompatible here
+ as this is done by FoldTypeAssign. *)
SubQuad (q)
END
END
@@ -1757,21 +1797,94 @@ END FoldRotate ;
(*
+ FoldTypeReturnFunc - checks to see that val can be returned from func.
+*)
+
+PROCEDURE FoldTypeReturnFunc (q: CARDINAL; tokenNo: CARDINAL; func, val: CARDINAL; r: CARDINAL) ;
+VAR
+ valType,
+ returnType: CARDINAL ;
+BEGIN
+ returnType := GetType (func) ;
+ IF returnType = NulSym
+ THEN
+ IF NOT reportedError (r)
+ THEN
+ MetaErrorsT2 (tokenNo,
+ 'procedure {%1Da} is not a procedure function',
+ '{%2ad} cannot be returned from {%1Da}',
+ func, val) ;
+ SubQuad(q)
+ END
+ ELSE
+ valType := val ;
+ IF IsVar (val) AND (GetMode (val) = LeftValue)
+ THEN
+ valType := GetType (val)
+ END ;
+ IF AssignmentTypeCompatible (tokenNo, "", returnType, valType, FALSE)
+ THEN
+ SubQuad (q)
+ ELSE
+ IF NOT reportedError (r)
+ THEN
+ MetaErrorsT2 (tokenNo,
+ 'the return type {%1Etad} used in procedure {%1Da}',
+ 'is incompatible with the returned expression {%1ad}}',
+ func, val) ;
+ setReported (r) ;
+ FlushErrors
+ END
+ END
+ END
+END FoldTypeReturnFunc ;
+
+
+(*
FoldTypeAssign -
*)
PROCEDURE FoldTypeAssign (q: CARDINAL; tokenNo: CARDINAL; des, expr: CARDINAL; r: CARDINAL) ;
+BEGIN
+ IF NOT reportedError (r)
+ THEN
+ IF AssignmentTypeCompatible (tokenNo,
+ 'assignment designator {%1Ea} {%1ta:of type {%1ta}}' +
+ ' cannot be assigned with' +
+ ' {%2ad: a {%2td} {%2ad}}{!%2ad: {%2ad} of type {%2tad}}',
+ des, expr, TRUE)
+ THEN
+ SubQuad (q)
+ ELSE
+ setReported (r) ;
+ FlushErrors
+ END
+ END
+END FoldTypeAssign ;
+
+
+(*
+ FoldTypeIndrX - check to see that des = *expr is type compatible.
+*)
+
+PROCEDURE FoldTypeIndrX (q: CARDINAL; tokenNo: CARDINAL; des, expr: CARDINAL; r: CARDINAL) ;
VAR
+ desType,
exprType: CARDINAL ;
BEGIN
- IF IsProcedure(expr)
+ (* Need to skip over a variable or temporary in des and expr so
+ long as expr is not a procedure. In the case of des = *expr,
+ both expr and des will be variables due to the property of
+ indirection. *)
+ desType := GetType (des) ;
+ IF IsProcedure (expr)
THEN
+ (* Must not GetType for a procedure as it gives the return type. *)
exprType := expr
ELSE
- exprType := GetType(expr)
+ exprType := GetType (expr)
END ;
-
- IF IsAssignmentCompatible (GetType(des), exprType)
+ IF AssignmentTypeCompatible (tokenNo, "", GetType (des), GetType (expr), FALSE)
THEN
SubQuad(q)
ELSE
@@ -1785,14 +1898,16 @@ BEGIN
des, expr) ;
ELSE
MetaErrorT3 (tokenNo,
- 'assignment designator {%1Ea} {%1ta:of type {%1ta}} {%1d:is a {%1d}} and expression {%2a} {%3ad:of type {%3ad}} are incompatible',
+ 'assignment designator {%1Ea} {%1ta:of type {%1ta}}' +
+ ' {%1d:is a {%1d}} and expression {%2a} {%3ad:of type' +
+ ' {%3ad}} are incompatible',
des, expr, exprType)
END ;
setReported (r) ;
FlushErrors
END
END
-END FoldTypeAssign ;
+END FoldTypeIndrX ;
(*
@@ -1859,35 +1974,90 @@ END FoldTypeExpr ;
*)
PROCEDURE CodeTypeAssign (tokenNo: CARDINAL; des, expr: CARDINAL; r: CARDINAL) ;
+BEGIN
+ IF NOT AssignmentTypeCompatible (tokenNo, "", des, expr, FALSE)
+ THEN
+ IF NOT reportedError (r)
+ THEN
+ MetaErrorT2 (tokenNo,
+ 'assignment designator {%1Ea} {%1ta:of type {%1ta}} {%1d:is a {%1d}} and expression {%2a} {%2tad:of type {%2tad}} are incompatible',
+ des, expr)
+ END ;
+ setReported (r)
+ END
+END CodeTypeAssign ;
+
+
+(*
+ CodeTypeReturnFunc -
+*)
+
+PROCEDURE CodeTypeReturnFunc (tokenNo: CARDINAL; func, val: CARDINAL; r: CARDINAL) ;
VAR
- exprType: CARDINAL ;
+ valType,
+ returnType: CARDINAL ;
BEGIN
- IF IsProcedure(expr)
+ returnType := GetType (func) ;
+ IF returnType = NulSym
THEN
- exprType := expr
+ IF NOT reportedError (r)
+ THEN
+ MetaErrorsT2 (tokenNo,
+ 'procedure {%1Da} is not a procedure function',
+ '{%2ad} cannot be returned from {%1Da}',
+ func, val) ;
+ END
ELSE
- exprType := GetType(expr)
- END ;
- IF NOT IsAssignmentCompatible(GetType(des), exprType)
+ valType := val ;
+ IF IsVar (val) AND (GetMode (val) = LeftValue)
+ THEN
+ valType := GetType (val)
+ END ;
+ IF NOT AssignmentTypeCompatible (tokenNo, "", returnType, valType, FALSE)
+ THEN
+ IF NOT reportedError (r)
+ THEN
+ MetaErrorsT2 (tokenNo,
+ 'the return type {%1Etad} used in procedure function {%1Da}',
+ 'is incompatible with the returned expression {%2EUa} {%2tad:of type {%2tad}}',
+ func, val)
+ END
+ END
+ END
+END CodeTypeReturnFunc ;
+
+
+(*
+ CodeTypeIndrX - checks that des = *expr is type compatible and generates an error if they
+ are not compatible. It skips over the LValue type so that to allow
+ the error messages to pick up the source variable name rather than
+ a temporary name or vague name 'expression'.
+*)
+
+PROCEDURE CodeTypeIndrX (tokenNo: CARDINAL; des, expr: CARDINAL; r: CARDINAL) ;
+BEGIN
+ IF NOT AssignmentTypeCompatible (tokenNo, "", GetType (des), GetType (expr), FALSE)
THEN
IF NOT reportedError (r)
THEN
- IF IsProcedure(des)
+ IF IsProcedure (des)
THEN
- MetaErrorsT2(tokenNo,
- 'the return type {%1Etad} declared in procedure {%1Da}',
- 'is incompatible with the returned expression {%2EUa} {%2tad:of type {%2tad}}',
- des, expr) ;
+ MetaErrorsT2 (tokenNo,
+ 'the return type {%1Etad} declared in procedure {%1Da}',
+ 'is incompatible with the returned expression {%2EUa} {%2tad:of type {%2tad}}',
+ des, expr) ;
ELSE
- MetaErrorT2(tokenNo,
- 'assignment designator {%1Ea} {%1ta:of type {%1ta}} {%1d:is a {%1d}} and expression {%2a} {%2tad:of type {%2tad}} are incompatible',
- des, expr)
+ MetaErrorT2 (tokenNo,
+ 'assignment designator {%1Ea} {%1ta:of type {%1ta}}' +
+ ' {%1d:is a {%1d}} and expression {%2a}' +
+ ' {%2tad:of type {%2tad}} are incompatible',
+ des, expr)
END ;
setReported (r)
END
(* FlushErrors *)
END
-END CodeTypeAssign ;
+END CodeTypeIndrX ;
(*
@@ -1941,9 +2111,11 @@ BEGIN
THEN
CASE type OF
- typeassign: FoldTypeAssign(q, tokenNo, des, expr, r) |
- typeparam: FoldTypeParam(q, tokenNo, des, expr, procedure, paramNo, r) |
- typeexpr: FoldTypeExpr(q, tokenNo, des, expr, strict, isin, r)
+ typeassign: FoldTypeAssign (q, tokenNo, des, expr, r) |
+ typeparam : FoldTypeParam (q, tokenNo, des, expr, procedure, paramNo, r) |
+ typeexpr : FoldTypeExpr (q, tokenNo, des, expr, strict, isin, r) |
+ typeindrx : FoldTypeIndrX (q, tokenNo, des, expr, r) |
+ typereturn: FoldTypeReturnFunc (q, tokenNo, des, expr, r)
ELSE
InternalError ('not expecting to reach this point')
@@ -1974,9 +2146,11 @@ BEGIN
THEN
CASE type OF
- typeassign: CodeTypeAssign(tokenNo, des, expr, r) |
- typeparam: CodeTypeParam(tokenNo, des, expr, procedure, paramNo) |
- typeexpr: CodeTypeExpr(tokenNo, des, expr, strict, isin, r)
+ typeassign: CodeTypeAssign (tokenNo, des, expr, r) |
+ typeparam : CodeTypeParam (tokenNo, des, expr, procedure, paramNo) |
+ typeexpr : CodeTypeExpr (tokenNo, des, expr, strict, isin, r) |
+ typeindrx : CodeTypeIndrX (tokenNo, des, expr, r) |
+ typereturn: CodeTypeReturnFunc (tokenNo, des, expr, r)
ELSE
InternalError ('not expecting to reach this point')
@@ -2005,7 +2179,7 @@ BEGIN
success := TRUE ;
WITH p^ DO
combinedtok := MakeVirtual2Tok (destok, exprtok) ;
- IF NOT AssignmentTypeCompatible (combinedtok, "", des, expr)
+ IF NOT AssignmentTypeCompatible (combinedtok, "", des, expr, TRUE)
THEN
MetaErrorT2 (combinedtok,
'type incompatibility between {%1Et} and {%2t} detected during the assignment of the designator {%1a} to the first expression {%2a} in the {%kFOR} loop',
@@ -2419,9 +2593,11 @@ BEGIN
excl : FoldExcl(tokenno, quad, range) |
shift : FoldShift(tokenno, quad, range) |
rotate : FoldRotate(tokenno, quad, range) |
- typeassign : FoldTypeCheck(tokenno, quad, range) |
- typeparam : FoldTypeCheck(tokenno, quad, range) |
- typeexpr : FoldTypeCheck(tokenno, quad, range) |
+ typereturn,
+ typeassign,
+ typeparam,
+ typeexpr,
+ typeindrx : FoldTypeCheck (tokenno, quad, range) |
paramassign : FoldParameterAssign(tokenno, quad, range) |
staticarraysubscript : FoldStaticArraySubscript(tokenno, quad, range) |
dynamicarraysubscript: FoldDynamicArraySubscript(tokenno, quad, range) |
@@ -3557,6 +3733,8 @@ BEGIN
typeassign : s := NIL |
typeparam : s := NIL |
typeexpr : s := NIL |
+ typeindrx : s := InitString ('assignment between designator {%1ad} and {%2ad} is incompatible') |
+ typereturn : s := InitString ('the value {%2ad} returned from procedure function {%1a} is type incompatible, expecting {%1tad} rather than a {%2tad}') |
paramassign : s := InitString('if this call is executed then the actual parameter {%2Wa} will be out of range of the {%3N} formal parameter {%1a}') |
staticarraysubscript : s := InitString('if this access to the static array {%1Wa:{%2a:{%1a}[{%2a}]}} is ever made then the index will be out of bounds in the {%3N} array subscript') |
dynamicarraysubscript: s := InitString('if this access to the dynamic array {%1Wa:{%2a:{%1a}[{%2a}]}} is ever made then the index will be out of bounds in the {%3N} array subscript') |
@@ -3605,9 +3783,11 @@ BEGIN
excl : CodeInclExcl (tokenNo, r, function, message) |
shift,
rotate : CodeShiftRotate (tokenNo, r, function, message) |
- typeassign : CodeTypeCheck (tokenNo, r) |
- typeparam : CodeTypeCheck (tokenNo, r) |
- typeexpr : CodeTypeCheck (tokenNo, r) |
+ typeassign,
+ typeparam,
+ typeexpr,
+ typeindrx,
+ typereturn : CodeTypeCheck (tokenNo, r) |
staticarraysubscript : CodeStaticArraySubscript (tokenNo, r, function, message) |
dynamicarraysubscript: CodeDynamicArraySubscript (tokenNo, r, function, message) |
forloopbegin : CodeForLoopBegin (tokenNo, r, function, message) |
@@ -3743,6 +3923,8 @@ BEGIN
rotate : WriteString('rotate(') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) |
typeexpr : WriteString('expr compatible (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) |
typeassign : WriteString('assignment compatible (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) |
+ typeindrx : WriteString('indrx compatible (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) |
+ typereturn : WriteString('return compatible (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) |
typeparam : WriteString('parameter compatible (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) |
paramassign : WriteString('parameter range (') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) |
staticarraysubscript : WriteString('staticarraysubscript(') ; WriteOperand(des) ; WriteString(', ') ; WriteOperand(expr) |
diff --git a/gcc/m2/gm2-gcc/m2options.h b/gcc/m2/gm2-gcc/m2options.h
index d60b510..041de26 100644
--- a/gcc/m2/gm2-gcc/m2options.h
+++ b/gcc/m2/gm2-gcc/m2options.h
@@ -168,6 +168,8 @@ EXTERN char *M2Options_GetM2DumpFilter (void);
EXTERN void M2Options_SetM2DebugTraceFilter (bool value, const char *arg);
EXTERN bool M2Options_SetM2Dump (bool value, const char *arg);
EXTERN bool M2Options_GetDumpGimple (void);
+EXTERN void M2Options_SetStrictTypeAssignment (bool value);
+EXTERN void M2Options_SetStrictTypeReason (bool value);
#undef EXTERN
#endif /* m2options_h. */
diff --git a/gcc/m2/gm2-lang.cc b/gcc/m2/gm2-lang.cc
index e8820da..31a2e46 100644
--- a/gcc/m2/gm2-lang.cc
+++ b/gcc/m2/gm2-lang.cc
@@ -525,6 +525,9 @@ gm2_langhook_handle_option (
case OPT_fm2_strict_type:
M2Options_SetStrictTypeChecking (value);
return 1;
+ case OPT_fm2_strict_type_reason:
+ M2Options_SetStrictTypeReason (value);
+ return 1;
case OPT_fm2_debug_trace_:
M2Options_SetM2DebugTraceFilter (value, arg);
return 1;
diff --git a/gcc/m2/gm2-libs-log/InOut.mod b/gcc/m2/gm2-libs-log/InOut.mod
index 79c706a..6b03034 100644
--- a/gcc/m2/gm2-libs-log/InOut.mod
+++ b/gcc/m2/gm2-libs-log/InOut.mod
@@ -257,16 +257,8 @@ END WriteString ;
PROCEDURE LocalWrite (ch: CHAR) ;
BEGIN
FIO.WriteChar(outFile, ch) ;
- Done := FIO.IsNoError(outFile)
-(*
- IF outUsed
- THEN
- FIO.WriteChar(outFile, ch) ;
- Done := FIO.IsNoError(outFile)
- ELSE
- Done := (write(stdout, ADR(ch), 1) = 1)
- END
-*)
+ Done := FIO.IsNoError(outFile) ;
+ FIO.FlushBuffer (outFile)
END LocalWrite ;
diff --git a/gcc/m2/lang.opt b/gcc/m2/lang.opt
index 1ea55f2..48c2380 100644
--- a/gcc/m2/lang.opt
+++ b/gcc/m2/lang.opt
@@ -190,6 +190,10 @@ fm2-strict-type
Modula-2
experimental flag to turn on the new strict type checker
+fm2-strict-type-reason
+Modula-2
+provides more detail why the types are incompatible
+
fm2-whole-program
Modula-2
compile all implementation modules and program module at once
diff --git a/gcc/passes.cc b/gcc/passes.cc
index e86aa1f..6c67ffe 100644
--- a/gcc/passes.cc
+++ b/gcc/passes.cc
@@ -64,6 +64,9 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
+/* Reserved TODOs */
+#define TODO_verify_il (1u << 31)
+
using namespace gcc;
/* This is used for debugging. It allows the current pass to printed
@@ -2059,7 +2062,6 @@ execute_function_todo (function *fn, void *data)
{
bool from_ipa_pass = (cfun == NULL);
unsigned int flags = (size_t)data;
- flags &= ~fn->last_verified;
if (!flags)
return;
@@ -2127,8 +2129,6 @@ execute_function_todo (function *fn, void *data)
gcc_assert (dom_info_state (fn, CDI_POST_DOMINATORS) == pre_verify_pstate);
}
- fn->last_verified = flags & TODO_verify_all;
-
pop_cfun ();
/* For IPA passes make sure to release dominator info, it can be
@@ -2193,14 +2193,6 @@ verify_interpass_invariants (void)
gcc_checking_assert (!fold_deferring_overflow_warnings_p ());
}
-/* Clear the last verified flag. */
-
-static void
-clear_last_verified (function *fn, void *data ATTRIBUTE_UNUSED)
-{
- fn->last_verified = 0;
-}
-
/* Helper function. Verify that the properties has been turn into the
properties expected by the pass. */
@@ -2339,13 +2331,15 @@ execute_one_ipa_transform_pass (struct cgraph_node *node,
if (pass->tv_id != TV_NONE)
timevar_push (pass->tv_id);
+ gcc_checking_assert (!(ipa_pass->function_transform_todo_flags_start & TODO_verify_il));
/* Run pre-pass verification. */
execute_todo (ipa_pass->function_transform_todo_flags_start);
/* Do it! */
todo_after = ipa_pass->function_transform (node);
- /* Run post-pass cleanup and verification. */
+ /* Run post-pass cleanup. */
+ gcc_checking_assert (!(todo_after & TODO_verify_il));
execute_todo (todo_after);
verify_interpass_invariants ();
@@ -2649,6 +2643,7 @@ execute_one_pass (opt_pass *pass)
/* Run pre-pass verification. */
+ gcc_checking_assert (!(pass->todo_flags_start & TODO_verify_il));
execute_todo (pass->todo_flags_start);
if (flag_checking)
@@ -2697,11 +2692,11 @@ execute_one_pass (opt_pass *pass)
return true;
}
- do_per_function (clear_last_verified, NULL);
-
do_per_function (update_properties_after_pass, pass);
/* Run post-pass cleanup and verification. */
+ gcc_checking_assert (!(todo_after & TODO_verify_il));
+ gcc_checking_assert (!(pass->todo_flags_finish & TODO_verify_il));
execute_todo (todo_after | pass->todo_flags_finish | TODO_verify_il);
if (profile_report)
{
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 7049ed7..8a74021 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -960,6 +960,14 @@ is_a_helper <rtx_call_insn *>::test (rtx_insn *insn)
template <>
template <>
inline bool
+is_a_helper <const rtx_call_insn *>::test (const rtx_insn *insn)
+{
+ return CALL_P (insn);
+}
+
+template <>
+template <>
+inline bool
is_a_helper <rtx_jump_table_data *>::test (rtx rt)
{
return JUMP_TABLE_DATA_P (rt);
@@ -3682,7 +3690,6 @@ extern bool nonzero_address_p (const_rtx);
extern bool rtx_unstable_p (const_rtx);
extern bool rtx_varies_p (const_rtx, bool);
extern bool rtx_addr_varies_p (const_rtx, bool);
-extern rtx get_call_rtx_from (const rtx_insn *);
extern tree get_call_fndecl (const rtx_insn *);
extern HOST_WIDE_INT get_integer_term (const_rtx);
extern rtx get_related_value (const_rtx);
@@ -4572,6 +4579,7 @@ extern void simplify_using_condition (rtx, rtx *, bitmap);
extern void compute_alignments (void);
extern void update_alignments (vec<rtx> &);
extern int asm_str_count (const char *templ);
+extern rtx get_call_rtx_from (const rtx_insn *);
struct rtl_hooks
{
diff --git a/gcc/rtlanal.cc b/gcc/rtlanal.cc
index 900f53e..239d669 100644
--- a/gcc/rtlanal.cc
+++ b/gcc/rtlanal.cc
@@ -813,21 +813,6 @@ rtx_addr_varies_p (const_rtx x, bool for_alias)
return false;
}
-/* Return the CALL in X if there is one. */
-
-rtx
-get_call_rtx_from (const rtx_insn *insn)
-{
- rtx x = PATTERN (insn);
- if (GET_CODE (x) == PARALLEL)
- x = XVECEXP (x, 0, 0);
- if (GET_CODE (x) == SET)
- x = SET_SRC (x);
- if (GET_CODE (x) == CALL && MEM_P (XEXP (x, 0)))
- return x;
- return NULL_RTX;
-}
-
/* Get the declaration of the function called by INSN. */
tree
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index f0d9128..ff68455 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,106 @@
+2025-06-02 Alexandre Oliva <oliva@adacore.com>
+
+ PR rtl-optimization/120424
+ PR middle-end/118939
+ * g++.target/arm/pr120424.C: New.
+ * gnat.dg/controlled9.adb: New.
+ * gnat.dg/controlled9_pkg.ads: New.
+
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/107600
+ * g++.dg/ext/is_destructible2.C: Add more cases.
+
+2025-06-02 Dongyan Chen <chendongyan@isrc.iscas.ac.cn>
+
+ * gcc.target/riscv/arch-59.c: New test.
+
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/120506
+ * g++.dg/cpp2a/constinit21.C: New test.
+
+2025-06-02 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR c++/118903
+ * g++.dg/coroutines/pr118903.C: New test.
+
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/107600
+ * g++.dg/ext/is_destructible2.C: New test.
+
+2025-06-02 Jason Merrill <jason@redhat.com>
+
+ PR c++/107600
+ * g++.dg/ext/has_trivial_destructor-3.C: New test.
+
+2025-06-02 Stafford Horne <shorne@gmail.com>
+
+ * gcc.target/or1k/return-2.c: Fix test.
+
+2025-06-02 Stafford Horne <shorne@gmail.com>
+
+ * gcc.target/or1k/call-1.c: New test.
+ * gcc.target/or1k/got-1.c: New test.
+
+2025-06-02 Christophe Lyon <christophe.lyon@linaro.org>
+
+ * lib/target-supports.exp (check_effective_target_tls_link): New.
+ * g++.dg/tls/pr102496-1.C: Require tls_link.
+ * g++.dg/tls/pr77285-1.C: Likewise.
+
+2025-06-02 Sandra Loosemore <sloosemore@baylibre.com>
+
+ * c-c++-common/gomp/declare-variant-2.c: Update expected output.
+ * c-c++-common/gomp/metadirective-condition-constexpr.c: New.
+ * c-c++-common/gomp/metadirective-condition.c: New.
+ * c-c++-common/gomp/metadirective-error-recovery.c: Update expected
+ output.
+ * g++.dg/gomp/metadirective-condition-class.C: New.
+ * g++.dg/gomp/metadirective-condition-template.C: New.
+
+2025-06-02 Liao Shihua <shihua@iscas.ac.cn>
+
+ * gcc.target/riscv/rvv/autovec/param-autovec-mode.c: Change
+ `autovec-mode` to `riscv-autovec-mode` in dg-options.
+
+2025-06-01 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR libfortran/119856
+ * gfortran.dg/pr119856.f90: New test.
+
+2025-06-01 Martin Uecker <uecker@tugraz.at>
+
+ PR c/120380
+ * gcc.dg/pr120380.c: New test.
+
+2025-06-01 Jason Merrill <jason@redhat.com>
+
+ PR c++/120123
+ * g++.dg/cpp23/explicit-obj-lambda18.C: Move to...
+ * g++.dg/cpp2a/concepts-lambda24.C: ...here.
+
+2025-06-01 Gaius Mulley <gaiusmod2@gmail.com>
+
+ PR modula2/120497
+ * gm2/pim/pass/ReturnType.mod: New test.
+ * gm2/pim/pass/ReturnType2.mod: New test.
+
+2025-05-31 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/120357
+ * gcc.dg/vect/vect-early-break_136-pr120357.c: New testcase.
+
+2025-05-31 Gaius Mulley <gaiusmod2@gmail.com>
+
+ PR modula2/120389
+ * gm2/pim/fail/testcharint.mod: New test.
+ * gm2/pim/fail/testindrx.mod: New test.
+ * gm2/pim/pass/testxindr.mod: New test.
+ * gm2/pim/pass/testxindr2.mod: New test.
+ * gm2/pim/pass/testxindr3.mod: New test.
+
2025-05-30 David Malcolm <dmalcolm@redhat.com>
PR other/116792
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c
index f8f5143..83e1bb1 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-2.c
@@ -38,7 +38,7 @@ void f18 (void);
void f19 (void);
#pragma omp declare variant (f1) match(user={condition()}) /* { dg-error "expected \[^\n\r]*expression before '\\)' token" } */
void f20 (void);
-#pragma omp declare variant (f1) match(user={condition(f1)}) /* { dg-error "property must be integer expression" } */
+#pragma omp declare variant (f1) match(user={condition(f1)})
void f21 (void);
#pragma omp declare variant (f1) match(user={condition(1, 2, 3)}) /* { dg-error "expected '\\)' before ',' token" } */
void f22 (void);
diff --git a/gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c b/gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c
new file mode 100644
index 0000000..3484478
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/metadirective-condition-constexpr.c
@@ -0,0 +1,13 @@
+/* { dg-do compile { target { c || c++11 } } } */
+/* { dg-additional-options "-std=c23" { target c } } */
+/* { dg-additional-options "-fdump-tree-original" } */
+
+constexpr int flag = 1;
+
+void f() {
+#pragma omp metadirective when(user={condition(flag)} : nothing) \
+ otherwise(error at(execution))
+}
+
+/* { dg-final { scan-tree-dump-not "__builtin_GOMP_error" "original" } } */
+
diff --git a/gcc/testsuite/c-c++-common/gomp/metadirective-condition.c b/gcc/testsuite/c-c++-common/gomp/metadirective-condition.c
new file mode 100644
index 0000000..099ad9d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/metadirective-condition.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-original" } */
+
+static int arr[10];
+static int g (int a) { return -a; }
+
+void f (int *ptr, float x) {
+
+ /* Implicit conversion float -> bool */
+ #pragma omp metadirective when(user={condition(x)} : nothing) otherwise(nothing)
+
+ /* Implicit conversion pointer -> bool */
+ #pragma omp metadirective when(user={condition(ptr)} : nothing) otherwise(nothing)
+
+ /* Array expression undergoes array->pointer conversion, OK but test is
+ always optimized away. */
+ #pragma omp metadirective when(user={condition(arr)} : nothing) otherwise(nothing)
+
+ /* Function reference has pointer-to-function type, OK but test is
+ always optimized away. */
+ #pragma omp metadirective when(user={condition(g)} : nothing) otherwise(nothing)
+}
+
+/* { dg-final { scan-tree-dump "x != 0.0" "original" } } */
+/* { dg-final { scan-tree-dump "ptr != 0B" "original" } } */
diff --git a/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c b/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c
index 3242281..92995a2 100644
--- a/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c
+++ b/gcc/testsuite/c-c++-common/gomp/metadirective-error-recovery.c
@@ -15,6 +15,11 @@ void f (int aa, int bb)
s2.b = bb + 1;
/* A struct is not a valid argument for the condition selector. */
- #pragma omp metadirective when(user={condition(s1)} : nothing) otherwise(nothing) /* { dg-error "property must be integer expression" } */
- #pragma omp metadirective when(user={condition(s2)} : nothing) otherwise(nothing) /* { dg-error "property must be integer expression" } */
+ #pragma omp metadirective when(user={condition(s1)} : nothing) otherwise(nothing)
+ /* { dg-error "used struct type value where scalar is required" "" { target c } .-1 } */
+ /* { dg-error "could not convert .s1. from .s. to .bool." "" { target c++ } .-2 } */
+ #pragma omp metadirective when(user={condition(s2)} : nothing) otherwise(nothing)
+ /* { dg-error "used struct type value where scalar is required" "" { target c } .-1 } */
+ /* { dg-error "could not convert .s2. from .s. to .bool." "" { target c++ } .-2 } */
+
}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr118903.C b/gcc/testsuite/g++.dg/coroutines/pr118903.C
new file mode 100644
index 0000000..a577a9a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/coroutines/pr118903.C
@@ -0,0 +1,40 @@
+// { dg-additional-options "-fsyntax-only" }
+
+#include <coroutine>
+
+struct awaitable {
+ constexpr bool await_ready() {
+ return true;
+ }
+ void await_suspend(std::coroutine_handle<void>) {
+
+ }
+ constexpr int await_resume() {
+ return 42;
+ }
+};
+
+struct super_simple_coroutine {
+ struct promise_type {
+ constexpr auto initial_suspend() {
+ return std::suspend_never();
+ }
+ constexpr auto final_suspend() const noexcept {
+ return std::suspend_never();
+ }
+ constexpr void unhandled_exception() {
+ // do nothing
+ }
+ constexpr auto get_return_object() {
+ return super_simple_coroutine{};
+ }
+ constexpr void return_void() {
+ }
+ };
+};
+
+auto fib (float f) -> super_simple_coroutine {
+ // if `co_await` is part of BodyStatement of a function
+ // it makes it coroutine
+ constexpr int x = co_await awaitable{}; // { dg-error {'co_await awaitable..' is not a constant expression} }
+}
diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda18.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda24.C
index 21bd2e9..28f56ca 100644
--- a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda18.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda24.C
@@ -1,5 +1,5 @@
// PR c++/120123
-// { dg-do compile { target c++23 } }
+// { dg-do compile { target c++20 } }
struct H {
void member(int) {}
diff --git a/gcc/testsuite/g++.dg/cpp2a/constinit21.C b/gcc/testsuite/g++.dg/cpp2a/constinit21.C
new file mode 100644
index 0000000..18bca90
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constinit21.C
@@ -0,0 +1,28 @@
+// PR c++/120506
+// { dg-do compile { target c++20 } }
+// Test that we give more information about why the init is non-constant
+
+struct A
+{
+ constexpr A(int c) : counter(c) { }
+
+ int counter;
+};
+
+
+struct B : A
+{
+ constexpr B(int c) : A(c) { }
+
+ int i; // OOPS, not initialized
+};
+
+struct C
+{
+ B sem;
+
+ constexpr C(int c) : sem(c) { }
+};
+
+constinit C s(0); // { dg-error "incompletely initialized" }
+// { dg-prune-output "constant" }
diff --git a/gcc/testsuite/g++.dg/ext/has_trivial_destructor-3.C b/gcc/testsuite/g++.dg/ext/has_trivial_destructor-3.C
new file mode 100644
index 0000000..a179be5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/has_trivial_destructor-3.C
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++11 } }
+
+struct X;
+
+template<class T>
+struct default_delete
+{
+ void operator()(T*) { static_assert(sizeof(T), "type is not incomplete"); }
+};
+
+template<class T, class D = default_delete<T>>
+struct unique_ptr
+{
+ ~unique_ptr() { del(ptr); }
+
+ T* ptr;
+ D del;
+};
+
+
+constexpr bool b = __has_trivial_destructor(unique_ptr<X>);
diff --git a/gcc/testsuite/g++.dg/ext/is_destructible2.C b/gcc/testsuite/g++.dg/ext/is_destructible2.C
new file mode 100644
index 0000000..2edf440
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_destructible2.C
@@ -0,0 +1,24 @@
+// PR c++/107600
+// { dg-additional-options -Wno-c++17-extensions }
+// { dg-do compile { target c++11 } }
+
+struct A
+{
+ A& operator= (const A&);
+ virtual ~A() = 0;
+};
+
+static_assert( __is_destructible(A) );
+static_assert( __is_assignable(A, A) );
+static_assert( not __is_destructible(int()) );
+static_assert( not __is_nothrow_destructible(int()) );
+static_assert( not __is_trivially_destructible(int()) );
+static_assert( __is_destructible(int&) );
+static_assert( __is_destructible(int&&) );
+static_assert( __is_destructible(int(&)[1]) );
+static_assert( __is_destructible(const int(&)[1]) );
+static_assert( __is_destructible(void(&)()) );
+static_assert( not __is_destructible(int[]) );
+static_assert( not __is_destructible(const int[]) );
+static_assert( not __is_destructible(int[][1]) );
+static_assert( not __is_destructible(const int[][1]) );
diff --git a/gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C b/gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C
new file mode 100644
index 0000000..6403611
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/metadirective-condition-class.C
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-original" } */
+
+class c
+{
+ public:
+ int x;
+ c (int xx) { x = xx; }
+ operator bool() { return x != 0; }
+};
+
+void f (c &objref)
+{
+ #pragma omp metadirective when(user={condition(objref)} : nothing) otherwise(nothing)
+}
+
+
+template <typename T> class d
+{
+ public:
+ T x;
+ d (T xx) { x = xx; }
+ operator bool() { return x != 0; }
+};
+
+template <typename T>
+void g (d<T> &objref)
+{
+ #pragma omp metadirective when(user={condition(objref)} : nothing) otherwise(nothing)
+}
+
+int main (void)
+{
+ c obj1 (42);
+ d<int> obj2 (69);
+
+ f (obj1);
+ g (obj2);
+}
+
+/* { dg-final { scan-tree-dump "c::operator bool \\(\\(struct c .\\) objref\\)" "original" } } */
+
+/* { dg-final { scan-tree-dump "d<int>::operator bool \\(\\(struct d .\\) objref\\)" "original" } } */
diff --git a/gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C b/gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C
new file mode 100644
index 0000000..30783d9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/metadirective-condition-template.C
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-fdump-tree-original" } */
+
+template<typename T, typename T2>
+void f (T x, T2 y)
+{
+ #pragma omp metadirective when(user={condition(x)}, \
+ target_device={device_num(y)} : flush)
+}
+
+class c
+{
+ public:
+ int x;
+ c (int xx) { x = xx; }
+ operator bool() { return x != 0; }
+};
+
+template <typename T> class d
+{
+ public:
+ T x;
+ d (T xx) { x = xx; }
+ operator bool() { return x != 0; }
+};
+
+int main (void)
+{
+ c obj1 (42);
+ d<int> obj2 (69);
+
+ f (42, 0);
+ f (&obj1, 0);
+ f (obj1, 0);
+ f (obj2, 0);
+}
+
+/* { dg-final { scan-tree-dump-times "if \\(x != 0 &&" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "if \\(x != 0B &&" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "if \\(<<cleanup_point c::operator bool \\(&x\\)>> &&" 1 "original" } } */
+/* { dg-final { scan-tree-dump-times "if \\(<<cleanup_point d<int>::operator bool \\(&x\\)>> &&" 1 "original" } } */
diff --git a/gcc/testsuite/g++.dg/modules/cpp-1.C b/gcc/testsuite/g++.dg/modules/cpp-1.C
index 2ad9637..56ef05fe 100644
--- a/gcc/testsuite/g++.dg/modules/cpp-1.C
+++ b/gcc/testsuite/g++.dg/modules/cpp-1.C
@@ -1,4 +1,5 @@
// { dg-do preprocess }
+// { dg-additional-options -fno-modules }
module bob;
#if 1
@@ -11,4 +12,4 @@ import gru;
EXPORT import mabel;
int i;
-// { dg-final { scan-file cpp-1.i "cpp-1.C\"\n\n\nmodule bob;\n\nexport import stuart;\n\n\n\nimport gru;\n\n import mabel;\n" } }
+// { dg-final { scan-file cpp-1.i "cpp-1.C\"\n\n\n\nmodule bob;\n\nexport import stuart;\n\n\n\nimport gru;\n\n import mabel;\n" } }
diff --git a/gcc/testsuite/g++.dg/modules/cpp-3.C b/gcc/testsuite/g++.dg/modules/cpp-3.C
index 3aa0c6e..cd776ae 100644
--- a/gcc/testsuite/g++.dg/modules/cpp-3.C
+++ b/gcc/testsuite/g++.dg/modules/cpp-3.C
@@ -1,4 +1,5 @@
// { dg-do preprocess }
+// { dg-additional-options -fno-modules }
#define NAME(X) X;
diff --git a/gcc/testsuite/g++.dg/modules/cpp-4.C b/gcc/testsuite/g++.dg/modules/cpp-4.C
index 6c19431..c423de2 100644
--- a/gcc/testsuite/g++.dg/modules/cpp-4.C
+++ b/gcc/testsuite/g++.dg/modules/cpp-4.C
@@ -1,3 +1,4 @@
+// { dg-additional-options -fno-modules }
// { dg-do preprocess }
#if 1
diff --git a/gcc/testsuite/g++.dg/tls/pr102496-1.C b/gcc/testsuite/g++.dg/tls/pr102496-1.C
index 8220e1e..e015ae9 100644
--- a/gcc/testsuite/g++.dg/tls/pr102496-1.C
+++ b/gcc/testsuite/g++.dg/tls/pr102496-1.C
@@ -1,6 +1,6 @@
// PR c++/102496
// { dg-do link { target c++11 } }
-// { dg-require-effective-target tls }
+// { dg-require-effective-target tls_link }
// { dg-add-options tls }
// { dg-additional-sources pr102496-2.C }
diff --git a/gcc/testsuite/g++.dg/tls/pr77285-1.C b/gcc/testsuite/g++.dg/tls/pr77285-1.C
index 7a93414..340c88b 100644
--- a/gcc/testsuite/g++.dg/tls/pr77285-1.C
+++ b/gcc/testsuite/g++.dg/tls/pr77285-1.C
@@ -1,5 +1,5 @@
// { dg-do link { target c++11 } }
-// { dg-require-effective-target tls }
+// { dg-require-effective-target tls_link }
// { dg-add-options tls }
// { dg-additional-sources pr77285-2.C }
diff --git a/gcc/testsuite/g++.target/arm/pr120424.C b/gcc/testsuite/g++.target/arm/pr120424.C
new file mode 100644
index 0000000..4d0e490
--- /dev/null
+++ b/gcc/testsuite/g++.target/arm/pr120424.C
@@ -0,0 +1,34 @@
+/* { dg-do compile } */
+/* { dg-options "-march=armv7 -O2 -fstack-clash-protection -fnon-call-exceptions" } */
+/* { dg-final { scan-assembler-not {#-8} } } */
+/* LRA register elimination gets confused when register spilling
+ causes arm_frame_pointer_required to switch from false to true, and
+ ends up using a stack slot below sp. */
+
+void f() {
+ int i = 0, j = 0;
+ asm ("" : : "m" (i), "m" (j));
+}
+
+void g(void (*fn[])(), int i)
+{
+ auto fn0 = fn[i+0];
+ auto fn1 = fn[i+1];
+ auto fn2 = fn[i+2];
+ auto fn3 = fn[i+3];
+ fn0();
+ fn1();
+ if (!fn2)
+ throw i+2;
+ fn2();
+ fn3();
+ fn0();
+ fn1();
+}
+
+int
+main()
+{
+ void (*fn[4])() = { f, f, f, f };
+ g (fn, 0);
+}
diff --git a/gcc/testsuite/g++.target/i386/pr103750.C b/gcc/testsuite/g++.target/i386/pr103750.C
new file mode 100644
index 0000000..c82c10a
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr103750.C
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=x86-64-v4 -std=c++17" } */
+/* Keep labels and directives ('.cfi_startproc', '.cfi_endproc'). */
+/* { dg-final { check-function-bodies "**" "" "" { target "*-*-*" } {^\t?\.} } } */
+
+#include <x86intrin.h>
+
+/*
+**_Z8qustrchrPDsS_Ds:
+**...
+**.L[0-9]+:
+** vpcmpeqw \(%[a-x]+\), %ymm0, %k1
+** vpcmpeqw 32\(%[a-x]+\), %ymm0, %k0
+** kortestw %k0, %k1
+** je .L[0-9]+
+**...
+*/
+
+const char16_t *
+qustrchr(char16_t *n, char16_t *e, char16_t c) noexcept
+{
+ __m256i mch256 = _mm256_set1_epi16(c);
+ for ( ; n < e; n += 32) {
+ __m256i data1 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(n));
+ __m256i data2 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(n) + 1);
+ __mmask16 mask1 = _mm256_cmpeq_epu16_mask(data1, mch256);
+ __mmask16 mask2 = _mm256_cmpeq_epu16_mask(data2, mch256);
+ if (_kortestz_mask16_u8(mask1, mask2))
+ continue;
+
+ unsigned idx = _tzcnt_u32(mask1);
+ if (mask1 == 0) {
+ idx = __tzcnt_u16(mask2);
+ n += 16;
+ }
+ return n + idx;
+ }
+ return e;
+}
diff --git a/gcc/testsuite/gcc.dg/Wjump-misses-init-3.c b/gcc/testsuite/gcc.dg/Wjump-misses-init-3.c
new file mode 100644
index 0000000..c3110c4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wjump-misses-init-3.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-Wc++-compat" } */
+
+void f()
+{
+ goto skip; /* { dg-warning "jump skips variable initialization" } */
+ int i = 1;
+skip: ;
+}
+
diff --git a/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c b/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c
index 2411b04..076c066 100644
--- a/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c
+++ b/gcc/testsuite/gcc.dg/gnu23-tag-composite-6.c
@@ -1,11 +1,31 @@
/* { dg-do compile } */
/* { dg-options "-std=gnu23" } */
+#define NEST(...) typeof(({ (__VA_ARGS__){ }; }))
+
int f()
{
typedef struct foo bar;
- struct foo { typeof(({ (struct foo { bar * x; }){ }; })) * x; } *q;
- typeof(q->x) p;
- 1 ? p : q;
+ struct foo { NEST(struct foo { bar *x; }) *x; } *q;
+ typeof(q->x) p0;
+ typeof(q->x) p1;
+ 1 ? p0 : q;
+ 1 ? p1 : q;
+ 1 ? p0 : p1;
+}
+
+int g()
+{
+ typedef struct fo2 bar;
+ struct fo2 { NEST(struct fo2 { NEST(struct fo2 { bar *x; }) * x; }) *x; } *q;
+ typeof(q->x) p0;
+ typeof(q->x->x) p1;
+ typeof(q->x->x->x) p2;
+ 1 ? p0 : q;
+ 1 ? p1 : q;
+ 1 ? p2 : q;
+ 1 ? p0 : p1;
+ 1 ? p2 : p1;
+ 1 ? p0 : p2;
}
diff --git a/gcc/testsuite/gcc.dg/pr116892.c b/gcc/testsuite/gcc.dg/pr116892.c
new file mode 100644
index 0000000..7eb431b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr116892.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-g -std=gnu23" } */
+
+enum fmt_type;
+
+void foo(const enum fmt_type a);
+
+enum [[gnu::packed]] fmt_type {
+ A
+} const a;
+
diff --git a/gcc/testsuite/gcc.dg/pr120380.c b/gcc/testsuite/gcc.dg/pr120380.c
new file mode 100644
index 0000000..10577a1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr120380.c
@@ -0,0 +1,24 @@
+/* PR c/120380 */
+/* { dg-do compile } */
+
+struct pair_t {
+ char c;
+ int i;
+};
+typedef struct foo_ { /* { dg-error "no member" } */
+ struct foo_ { /* { dg-error "nested redefinition" } */
+ /* { dg-error "no member" "" { target *-*-* } .-1 } */
+ struct foo_ { /* { dg-error "nested redefinition" } */
+ int value;
+ }
+ } /* { dg-error "does not declare anything" } */
+ /* { dg-error "no semicolon" "" { target *-*-* } .-1 } */
+} __attribute__((packed)) foo; /* { dg-error "does not declare anything" } */
+ /* { dg-error "no semicolon" "" { target *-*-* } .-1 } */
+struct pair_t p = {0, 1};
+foo *addr = (foo *)&p.i;
+int main() {
+ addr->value = 0; /* { dg-error "has no member" } */
+ return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c b/gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c
new file mode 100644
index 0000000..d765a03
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cswtch-6.c
@@ -0,0 +1,43 @@
+/* PR tree-optimization/120451 */
+/* { dg-do compile { target elf } } */
+/* { dg-options "-O2" } */
+
+void foo (int, int);
+
+__attribute__((noinline, noclone)) void
+f1 (int v, int w)
+{
+ int i, j;
+ if (w)
+ {
+ i = 129;
+ j = i - 1;
+ goto lab;
+ }
+ switch (v)
+ {
+ case 170:
+ j = 7;
+ i = 27;
+ break;
+ case 171:
+ i = 8;
+ j = 122;
+ break;
+ case 172:
+ i = 21;
+ j = -19;
+ break;
+ case 173:
+ i = 18;
+ j = 17;
+ break;
+ default:
+ __builtin_abort ();
+ }
+
+ lab:
+ foo (i, j);
+}
+
+/* { dg-final { scan-assembler ".rodata.cst16" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phiprop-2.c b/gcc/testsuite/gcc.dg/tree-ssa/phiprop-2.c
new file mode 100644
index 0000000..7181787
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phiprop-2.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -fdump-tree-phiopt2 -fdump-tree-phiprop1-details" } */
+
+/* PR tree-optimization/116824 */
+
+int g(int i, int *tt)
+{
+ const int t = 10;
+ const int *a;
+ {
+ if (t < i)
+ {
+ *tt = 1;
+ a = &t;
+ }
+ else
+ {
+ *tt = 1;
+ a = &i;
+ }
+ }
+ return *a;
+}
+
+/* Check that phiprop1 can do the insert of the loads. */
+/* { dg-final { scan-tree-dump-times "Inserting PHI for result of load" 1 "phiprop1"} } */
+/* Should be able to get MIN_EXPR in phiopt2 after cselim and phiprop. */
+/* { dg-final { scan-tree-dump-times "MIN_EXPR " 1 "phiopt2" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_136-pr120357.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_136-pr120357.c
new file mode 100644
index 0000000..8a51cfc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_136-pr120357.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-add-options vect_early_break } */
+/* { dg-additional-options "-O3" } */
+
+char a;
+unsigned long long t[2][22];
+int u[22];
+void f(void)
+{
+ for (int v = 0; v < 22; v++)
+ for (_Bool w = 0; w < (u[v] < 0) + 1; w = 1)
+ a *= 0 != t[w][v];
+}
diff --git a/gcc/testsuite/gcc.target/or1k/call-1.c b/gcc/testsuite/gcc.target/or1k/call-1.c
new file mode 100644
index 0000000..593e402
--- /dev/null
+++ b/gcc/testsuite/gcc.target/or1k/call-1.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcmodel=large" } */
+
+/* Generate local and global function calls. */
+
+extern int geti (void);
+
+__attribute__ ((noinline)) int
+calc (int a, int b)
+{
+ return a * b + 255;
+}
+
+int
+main (void)
+{
+ return geti () + calc (3, 4);
+}
+
+/* Ensure the 2 calls use register not immediate jumps. */
+/* { dg-final { scan-assembler-times "l.movhi\\s+" 2 } } */
+/* { dg-final { scan-assembler-times "l.jalr\\s+" 2 } } */
diff --git a/gcc/testsuite/gcc.target/or1k/got-1.c b/gcc/testsuite/gcc.target/or1k/got-1.c
new file mode 100644
index 0000000..5357096
--- /dev/null
+++ b/gcc/testsuite/gcc.target/or1k/got-1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fPIC -mcmodel=large" } */
+
+/* Generate references to the GOT. */
+
+extern int geti (void);
+extern int j;
+
+int
+calc (int a)
+{
+ return a * j + geti ();
+}
+
+/* Ensure the 2 references use gotha relocations and that the function call does
+ not use an immediate jump instruction. */
+/* { dg-final { scan-assembler-times "gotha" 2 } } */
+/* { dg-final { scan-assembler "l.jalr\\s+" } } */
diff --git a/gcc/testsuite/gcc.target/or1k/return-2.c b/gcc/testsuite/gcc.target/or1k/return-2.c
index add3720..c072ae2 100644
--- a/gcc/testsuite/gcc.target/or1k/return-2.c
+++ b/gcc/testsuite/gcc.target/or1k/return-2.c
@@ -16,4 +16,4 @@ struct a getstruct (long aa) {
/* Ensure our return value is returned on stack. */
/* { dg-final { scan-assembler-not "r12," } } */
/* { dg-final { scan-assembler "l.or\\s+r11, r3, r3" } } */
-/* { dg-final { scan-assembler-times "l.sw\\s+\\d+.r11.," 3 } } */
+/* { dg-final { scan-assembler-times "l.sw\\s+\\d+.r3.," 3 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/arch-59.c b/gcc/testsuite/gcc.target/riscv/arch-59.c
new file mode 100644
index 0000000..511cf22
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/arch-59.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64i_smcntrpmf -mabi=lp64" } */
+int foo()
+{
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv-nofm.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv-nofm.c
index 0750d8e..4685ed2 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv-nofm.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv-nofm.c
@@ -3,13 +3,13 @@
#include "vdiv-template.h"
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvdiv\.vx} 3 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 8 } } */
+/* { dg-final { scan-assembler-not {\tvdiv\.vx} } } */
/* { dg-final { scan-assembler-times {\tvdivu\.vv} 5 } } */
/* { dg-final { scan-assembler-times {\tvdivu\.vx} 3 } } */
-/* { dg-final { scan-assembler-times {\tvfdiv\.vv} 3 } } */
-/* { dg-final { scan-assembler-times {\tvfdiv\.vf} 3 } } */
+/* { dg-final { scan-assembler-times {\tvfdiv\.vv} 6 } } */
+/* { dg-final { scan-assembler-not {\tvfdiv\.vf} } } */
/* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 16 "optimized" } } */
/* { dg-final { scan-tree-dump-times "\.COND_LEN_RDIV" 6 "optimized" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
index 31b2284..59c48d2 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv32gcv.c
@@ -3,8 +3,8 @@
#include "vdiv-template.h"
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 5 } } */
-/* { dg-final { scan-assembler-times {\tvdiv\.vx} 3 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 8 } } */
+/* { dg-final { scan-assembler-not {\tvdiv\.vx} } } */
/* { dg-final { scan-assembler-times {\tvdivu\.vv} 5 } } */
/* { dg-final { scan-assembler-times {\tvdivu\.vx} 3 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv-nofm.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv-nofm.c
index 6015af9..b574dc4 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv-nofm.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv-nofm.c
@@ -3,13 +3,13 @@
#include "vdiv-template.h"
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdiv\.vx} 4 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 8 } } */
+/* { dg-final { scan-assembler-not {\tvdiv\.vx} } } */
/* { dg-final { scan-assembler-times {\tvdivu\.vv} 4 } } */
/* { dg-final { scan-assembler-times {\tvdivu\.vx} 4 } } */
-/* { dg-final { scan-assembler-times {\tvfdiv\.vv} 3 } } */
-/* { dg-final { scan-assembler-times {\tvfdiv\.vf} 3 } } */
+/* { dg-final { scan-assembler-times {\tvfdiv\.vv} 6 } } */
+/* { dg-final { scan-assembler-not {\tvfdiv\.vf} } } */
/* { dg-final { scan-tree-dump-times "\.COND_LEN_DIV" 16 "optimized" } } */
/* { dg-final { scan-tree-dump-times "\.COND_LEN_RDIV" 6 "optimized" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
index ccaa2f8..9b46c6b 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/binop/vdiv-rv64gcv.c
@@ -3,8 +3,8 @@
#include "vdiv-template.h"
-/* { dg-final { scan-assembler-times {\tvdiv\.vv} 4 } } */
-/* { dg-final { scan-assembler-times {\tvdiv\.vx} 4 } } */
+/* { dg-final { scan-assembler-times {\tvdiv\.vv} 8 } } */
+/* { dg-final { scan-assembler-not {\tvdiv\.vx} } } */
/* { dg-final { scan-assembler-times {\tvdivu\.vv} 4 } } */
/* { dg-final { scan-assembler-times {\tvdivu\.vx} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c
index b2ec8f9..1ee7eb3 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/param-autovec-mode.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d --param=autovec-mode=V4QI -fdump-tree-vect-details" } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d --param=riscv-autovec-mode=V4QI -fdump-tree-vect-details" } */
/* By default we will use RVVM1SI mode for vectorization because N is not
known. Check that we use V4QI and create an epilogue when the autovec-mode
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
new file mode 100644
index 0000000..821e5c5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f16.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64d --param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_0(_Float16, +, add)
+DEF_VF_MULOP_CASE_0(_Float16, -, sub)
+
+/* { dg-final { scan-assembler-times {vfmadd.vf} 1 } } */
+/* { dg-final { scan-assembler-times {vfmsub.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
new file mode 100644
index 0000000..49b4287
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f32.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_0(float, +, add)
+DEF_VF_MULOP_CASE_0(float, -, sub)
+
+/* { dg-final { scan-assembler-times {vfmadd.vf} 1 } } */
+/* { dg-final { scan-assembler-times {vfmsub.vf} 1 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c
new file mode 100644
index 0000000..2bb5d89
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-1-f64.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_0(double, +, add)
+DEF_VF_MULOP_CASE_0(double, -, sub)
+
+/* { dg-final { scan-assembler-times {vfmadd.vf} 1 } } */
+/* { dg-final { scan-assembler-times {vfmsub.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
new file mode 100644
index 0000000..cbb43ca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f16.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64d --param=fpr2vr-cost=1" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_0(_Float16, +, add)
+DEF_VF_MULOP_CASE_0(_Float16, -, sub)
+
+/* { dg-final { scan-assembler-not {vfmadd.vf} } } */
+/* { dg-final { scan-assembler-not {vfmsub.vf} } } */
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
new file mode 100644
index 0000000..66ff9b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f32.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=1" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_0(float, +, add)
+DEF_VF_MULOP_CASE_0(float, -, sub)
+
+/* { dg-final { scan-assembler-not {vfmadd.vf} } } */
+/* { dg-final { scan-assembler-not {vfmsub.vf} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c
new file mode 100644
index 0000000..66ff9b8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-2-f64.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=1" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_0(float, +, add)
+DEF_VF_MULOP_CASE_0(float, -, sub)
+
+/* { dg-final { scan-assembler-not {vfmadd.vf} } } */
+/* { dg-final { scan-assembler-not {vfmsub.vf} } } */
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
new file mode 100644
index 0000000..45980f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f16.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64d --param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_1(_Float16, +, add, VF_MULOP_BODY_X16)
+DEF_VF_MULOP_CASE_1(_Float16, -, sub, VF_MULOP_BODY_X16)
+
+/* { dg-final { scan-assembler {vfmadd.vf} } } */
+/* { dg-final { scan-assembler {vfmsub.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
new file mode 100644
index 0000000..c853620
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f32.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_1(float, +, add, VF_MULOP_BODY_X16)
+DEF_VF_MULOP_CASE_1(float, -, sub, VF_MULOP_BODY_X16)
+
+/* { dg-final { scan-assembler {vfmadd.vf} } } */
+/* { dg-final { scan-assembler {vfmsub.vf} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c
new file mode 100644
index 0000000..d38ae8b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-3-f64.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_1(double, +, add, VF_MULOP_BODY_X16)
+DEF_VF_MULOP_CASE_1(double, -, sub, VF_MULOP_BODY_X16)
+
+/* { dg-final { scan-assembler {vfmadd.vf} } } */
+/* { dg-final { scan-assembler {vfmsub.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
new file mode 100644
index 0000000..f1ca34e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f16.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv_zvfh -mabi=lp64d --param=fpr2vr-cost=4" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_1(_Float16, +, add, VF_MULOP_BODY_X16)
+DEF_VF_MULOP_CASE_1(_Float16, -, sub, VF_MULOP_BODY_X16)
+
+/* { dg-final { scan-assembler-not {vfmadd.vf} } } */
+/* { dg-final { scan-assembler-not {vfmsub.vf} } } */
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
new file mode 100644
index 0000000..6730d4b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f32.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=4" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_1(float, +, add, VF_MULOP_BODY_X16)
+DEF_VF_MULOP_CASE_1(float, -, sub, VF_MULOP_BODY_X16)
+
+/* { dg-final { scan-assembler-not {vfmadd.vf} } } */
+/* { dg-final { scan-assembler-not {vfmsub.vf} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c
new file mode 100644
index 0000000..bcb6a6e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf-4-f64.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=fpr2vr-cost=4" } */
+
+#include "vf_mulop.h"
+
+DEF_VF_MULOP_CASE_1(double, +, add, VF_MULOP_BODY_X16)
+DEF_VF_MULOP_CASE_1(double, -, sub, VF_MULOP_BODY_X16)
+
+/* { dg-final { scan-assembler-not {vfmadd.vf} } } */
+/* { dg-final { scan-assembler-not {vfmsub.vf} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h
new file mode 100644
index 0000000..5253978
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop.h
@@ -0,0 +1,61 @@
+#ifndef HAVE_DEFINED_VF_MULOP_H
+#define HAVE_DEFINED_VF_MULOP_H
+
+#include <stdint.h>
+
+#define DEF_VF_MULOP_CASE_0(T, OP, NAME) \
+ void test_vf_mulop_##NAME##_##T##_case_0(T *restrict out, T *restrict in, \
+ T x, unsigned n) { \
+ for (unsigned i = 0; i < n; i++) \
+ out[i] = in[i] OP out[i] * x; \
+ }
+#define DEF_VF_MULOP_CASE_0_WRAP(T, OP, NAME) DEF_VF_MULOP_CASE_0(T, OP, NAME)
+#define RUN_VF_MULOP_CASE_0(T, NAME, out, in, x, n) \
+ test_vf_mulop_##NAME##_##T##_case_0(out, in, x, n)
+#define RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n) \
+ RUN_VF_MULOP_CASE_0(T, NAME, out, in, x, n)
+
+#define VF_MULOP_BODY(op) \
+ out[k + 0] = in[k + 0] op tmp * out[k + 0]; \
+ out[k + 1] = in[k + 1] op tmp * out[k + 1]; \
+ k += 2;
+
+#define VF_MULOP_BODY_X4(op) \
+ VF_MULOP_BODY(op) \
+ VF_MULOP_BODY(op)
+
+#define VF_MULOP_BODY_X8(op) \
+ VF_MULOP_BODY_X4(op) \
+ VF_MULOP_BODY_X4(op)
+
+#define VF_MULOP_BODY_X16(op) \
+ VF_MULOP_BODY_X8(op) \
+ VF_MULOP_BODY_X8(op)
+
+#define VF_MULOP_BODY_X32(op) \
+ VF_MULOP_BODY_X16(op) \
+ VF_MULOP_BODY_X16(op)
+
+#define VF_MULOP_BODY_X64(op) \
+ VF_MULOP_BODY_X32(op) \
+ VF_MULOP_BODY_X32(op)
+
+#define VF_MULOP_BODY_X128(op) \
+ VF_MULOP_BODY_X64(op) \
+ VF_MULOP_BODY_X64(op)
+
+#define DEF_VF_MULOP_CASE_1(T, OP, NAME, BODY) \
+ void test_vf_mulop_##NAME##_##T##_case_1(T *restrict out, T *restrict in, \
+ T x, unsigned n) { \
+ unsigned k = 0; \
+ T tmp = x + 3; \
+ \
+ while (k < n) { \
+ tmp = tmp * 0x3f; \
+ BODY(OP) \
+ } \
+ }
+#define DEF_VF_MULOP_CASE_1_WRAP(T, OP, NAME, BODY) \
+ DEF_VF_MULOP_CASE_1(T, OP, NAME, BODY)
+
+#endif
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h
new file mode 100644
index 0000000..c16c1a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_data.h
@@ -0,0 +1,413 @@
+#ifndef HAVE_DEFINED_VF_MULOP_DATA_H
+#define HAVE_DEFINED_VF_MULOP_DATA_H
+
+#define N 16
+
+#define TEST_MULOP_DATA(T, NAME) test_##T##_##NAME##_data
+#define TEST_MULOP_DATA_WRAP(T, NAME) TEST_MULOP_DATA(T, NAME)
+
+
+_Float16 TEST_MULOP_DATA(_Float16, add)[][4][N] =
+{
+ {
+ { 0.30f16 },
+ {
+ 1.48f16, 1.48f16, 1.48f16, 1.48f16,
+ 0.80f16, 0.80f16, 0.80f16, 0.80f16,
+ 0.62f16, 0.62f16, 0.62f16, 0.62f16,
+ 1.18f16, 1.18f16, 1.18f16, 1.18f16,
+ },
+ {
+ 1.25f16, 1.25f16, 1.25f16, 1.25f16,
+ 1.89f16, 1.89f16, 1.89f16, 1.89f16,
+ 1.57f16, 1.57f16, 1.57f16, 1.57f16,
+ 1.21f16, 1.21f16, 1.21f16, 1.21f16,
+ },
+ {
+ 1.85f16, 1.85f16, 1.85f16, 1.85f16,
+ 1.37f16, 1.37f16, 1.37f16, 1.37f16,
+ 1.09f16, 1.09f16, 1.09f16, 1.09f16,
+ 1.54f16, 1.54f16, 1.54f16, 1.54f16,
+ }
+ },
+ {
+ { -0.505f16 },
+ {
+ -2.38f16, -2.38f16, -2.38f16, -2.38f16,
+ -2.06f16, -2.06f16, -2.06f16, -2.06f16,
+ -1.69f16, -1.69f16, -1.69f16, -1.69f16,
+ -1.1f16, -1.1f16, -1.1f16, -1.1f16,
+ },
+ {
+ -1.77f16, -1.77f16, -1.77f16, -1.77f16,
+ -1.6f16, -1.6f16, -1.6f16, -1.6f16,
+ -1.f16, -1.f16, -1.f16, -1.f16,
+ -1.23f16, -1.23f16, -1.23f16, -1.23f16,
+ },
+ {
+ -1.49f16, -1.49f16, -1.49f16, -1.49f16,
+ -1.25f16, -1.25f16, -1.25f16, -1.25f16,
+ -1.18f16, -1.18f16, -1.18f16, -1.18f16,
+ -0.479f16, -0.479f16, -0.479f16, -0.479f16,
+ }
+ },
+ {
+ { 4.95e-04f16 },
+ {
+ 1.4266e-05f16, 1.4266e-05f16, 1.4266e-05f16, 1.4266e-05f16,
+ 1.8129e-05f16, 1.8129e-05f16, 1.8129e-05f16, 1.8129e-05f16,
+ -8.4710e-06f16, -8.4710e-06f16, -8.4710e-06f16, -8.4710e-06f16,
+ 3.7876e-05f16, 3.7876e-05f16, 3.7876e-05f16, 3.7876e-05f16,
+ },
+ {
+ 2.2808e-02f16, 2.2808e-02f16, 2.2808e-02f16, 2.2808e-02f16,
+ 3.9633e-02f16, 3.9633e-02f16, 3.9633e-02f16, 3.9633e-02f16,
+ 9.9657e-02f16, 9.9657e-02f16, 9.9657e-02f16, 9.9657e-02f16,
+ 7.7189e-02f16, 7.7189e-02f16, 7.7189e-02f16, 7.7189e-02f16,
+ },
+ {
+ 2.5547e-05f16, 2.5547e-05f16, 2.5547e-05f16, 2.5547e-05f16,
+ 3.7732e-05f16, 3.7732e-05f16, 3.7732e-05f16, 3.7732e-05f16,
+ 4.0820e-05f16, 4.0820e-05f16, 4.0820e-05f16, 4.0820e-05f16,
+ 7.6054e-05f16, 7.6054e-05f16, 7.6054e-05f16, 7.6054e-05f16,
+ }
+ },
+};
+
+float TEST_MULOP_DATA(float, add)[][4][N] =
+{
+ {
+ { 43.71f },
+ {
+ -410.28f, -410.28f, -410.28f, -410.28f,
+ -276.91f, -276.91f, -276.91f, -276.91f,
+ -103.38f, -103.38f, -103.38f, -103.38f,
+ -378.24f, -378.24f, -378.24f, -378.24f,
+ },
+ {
+ 9.56f, 9.56f, 9.56f, 9.56f,
+ 6.39f, 6.39f, 6.39f, 6.39f,
+ 2.40f, 2.40f, 2.40f, 2.40f,
+ 8.80f, 8.80f, 8.80f, 8.80f,
+ },
+ {
+ 7.59f, 7.59f, 7.59f, 7.59f,
+ 2.40f, 2.40f, 2.40f, 2.40f,
+ 1.52f, 1.52f, 1.52f, 1.52f,
+ 6.41f, 6.41f, 6.41f, 6.41f,
+ }
+ },
+ {
+ { 2.04f },
+ {
+ -110.22f, -110.22f, -110.22f, -110.22f,
+ -25.13f, -25.13f, -25.13f, -25.13f,
+ -108.18f, -108.18f, -108.18f, -108.18f,
+ -107.14f, -107.14f, -107.14f, -107.14f,
+ },
+ {
+ 64.82f, 64.82f, 64.82f, 64.82f,
+ 31.65f, 31.65f, 31.65f, 31.65f,
+ 87.32f, 87.32f, 87.32f, 87.32f,
+ 58.70f, 58.70f, 58.70f, 58.70f,
+ },
+ {
+ 22.01f, 22.01f, 22.01f, 22.01f,
+ 39.44f, 39.44f, 39.44f, 39.44f,
+ 69.95f, 69.95f, 69.95f, 69.95f,
+ 12.61f, 12.61f, 12.61f, 12.61f,
+ }
+ },
+ {
+ { 20.35f },
+ {
+ 881.43f, 881.43f, 881.43f, 881.43f,
+ 3300.17f, 3300.17f, 3300.17f, 3300.17f,
+ 5217.85f, 5217.85f, 5217.85f, 5217.85f,
+ 66.57f, 66.57f, 66.57f, 66.57f,
+ },
+ {
+ 64.82f, 64.82f, 64.82f, 64.82f,
+ 31.65f, 31.65f, 31.65f, 31.65f,
+ 87.32f, 87.32f, 87.32f, 87.32f,
+ 58.70f, 58.70f, 58.70f, 58.70f,
+ },
+ {
+ 2200.52f, 2200.52f, 2200.52f, 2200.52f,
+ 3944.25f, 3944.25f, 3944.25f, 3944.25f,
+ 6994.81f, 6994.81f, 6994.81f, 6994.81f,
+ 1261.12f, 1261.12f, 1261.12f, 1261.12f,
+ }
+ },
+};
+
+double TEST_MULOP_DATA(double, add)[][4][N] =
+{
+ {
+ { 1.16e+12 },
+ {
+ 1.8757e+45, 1.8757e+45, 1.8757e+45, 1.8757e+45,
+ 7.5140e+45, 7.5140e+45, 7.5140e+45, 7.5140e+45,
+ 8.2069e+45, 8.2069e+45, 8.2069e+45, 8.2069e+45,
+ 4.9456e+45, 4.9456e+45, 4.9456e+45, 4.9456e+45,
+ },
+ {
+ 9.0242e+32, 9.0242e+32, 9.0242e+32, 9.0242e+32,
+ 3.6908e+32, 3.6908e+32, 3.6908e+32, 3.6908e+32,
+ 3.9202e+32, 3.9202e+32, 3.9202e+32, 3.9202e+32,
+ 5.0276e+32, 5.0276e+32, 5.0276e+32, 5.0276e+32,
+ },
+ {
+ 2.9201e+45, 2.9201e+45, 2.9201e+45, 2.9201e+45,
+ 7.9411e+45, 7.9411e+45, 7.9411e+45, 7.9411e+45,
+ 8.6606e+45, 8.6606e+45, 8.6606e+45, 8.6606e+45,
+ 5.5275e+45, 5.5275e+45, 5.5275e+45, 5.5275e+45,
+ }
+ },
+ {
+ { -7.29e+23 },
+ {
+ -6.4993e+65, -6.4993e+65, -6.4993e+65, -6.4993e+65,
+ -4.6760e+65, -4.6760e+65, -4.6760e+65, -4.6760e+65,
+ -8.1564e+65, -8.1564e+65, -8.1564e+65, -8.1564e+65,
+ -8.2899e+65, -8.2899e+65, -8.2899e+65, -8.2899e+65,
+ },
+ {
+ -7.7764e+41, -7.7764e+41, -7.7764e+41, -7.7764e+41,
+ -1.9756e+41, -1.9756e+41, -1.9756e+41, -1.9756e+41,
+ -4.8980e+41, -4.8980e+41, -4.8980e+41, -4.8980e+41,
+ -8.1062e+41, -8.1062e+41, -8.1062e+41, -8.1062e+41,
+ },
+ {
+ -8.2928e+64, -8.2928e+64, -8.2928e+64, -8.2928e+64,
+ -3.2356e+65, -3.2356e+65, -3.2356e+65, -3.2356e+65,
+ -4.5850e+65, -4.5850e+65, -4.5850e+65, -4.5850e+65,
+ -2.3794e+65, -2.3794e+65, -2.3794e+65, -2.3794e+65,
+ }
+ },
+ {
+ { 2.02e-03 },
+ {
+ -1.2191e-35, -1.2191e-35, -1.2191e-35, -1.2191e-35,
+ -1.0471e-36, -1.0471e-36, -1.0471e-36, -1.0471e-36,
+ -9.7582e-36, -9.7582e-36, -9.7582e-36, -9.7582e-36,
+ -2.2097e-36, -2.2097e-36, -2.2097e-36, -2.2097e-36,
+ },
+ {
+ 9.7703e-33, 9.7703e-33, 9.7703e-33, 9.7703e-33,
+ 4.1632e-33, 4.1632e-33, 4.1632e-33, 4.1632e-33,
+ 8.1964e-33, 8.1964e-33, 8.1964e-33, 8.1964e-33,
+ 4.7314e-33, 4.7314e-33, 4.7314e-33, 4.7314e-33,
+ },
+ {
+ 7.5586e-36, 7.5586e-36, 7.5586e-36, 7.5586e-36,
+ 7.3684e-36, 7.3684e-36, 7.3684e-36, 7.3684e-36,
+ 6.8101e-36, 6.8101e-36, 6.8101e-36, 6.8101e-36,
+ 7.3543e-36, 7.3543e-36, 7.3543e-36, 7.3543e-36,
+ }
+ },
+};
+
+_Float16 TEST_MULOP_DATA(_Float16, sub)[][4][N] =
+{
+ {
+ { 0.676f16 },
+ {
+ 1.39f16, 1.39f16, 1.39f16, 1.39f16,
+ 1.68f16, 1.68f16, 1.68f16, 1.68f16,
+ 1.63f16, 1.63f16, 1.63f16, 1.63f16,
+ 2.12f16, 2.12f16, 2.12f16, 2.12f16,
+ },
+ {
+ 1.04f16, 1.04f16, 1.04f16, 1.04f16,
+ 1.64f16, 1.64f16, 1.64f16, 1.64f16,
+ 1.95f16, 1.95f16, 1.95f16, 1.95f16,
+ 1.39f16, 1.39f16, 1.39f16, 1.39f16,
+ },
+ {
+ 0.687f16, 0.687f16, 0.687f16, 0.687f16,
+ 0.568f16, 0.568f16, 0.568f16, 0.568f16,
+ 0.315f16, 0.315f16, 0.315f16, 0.315f16,
+ 1.18f16, 1.18f16, 1.18f16, 1.18f16,
+ }
+},
+ {
+ { -0.324f16 },
+ {
+ -0.679f16, -0.679f16, -0.679f16, -0.679f16,
+ -0.992f16, -0.992f16, -0.992f16, -0.992f16,
+ -1.34f16, -1.34f16, -1.34f16, -1.34f16,
+ -0.297f16, -0.297f16, -0.297f16, -0.297f16,
+ },
+ {
+ -1.96f16, -1.96f16, -1.96f16, -1.96f16,
+ -1.36f16, -1.36f16, -1.36f16, -1.36f16,
+ -1.05f16, -1.05f16, -1.05f16, -1.05f16,
+ -1.61f16, -1.61f16, -1.61f16, -1.61f16,
+ },
+ {
+ -1.31f16, -1.31f16, -1.31f16, -1.31f16,
+ -1.43f16, -1.43f16, -1.43f16, -1.43f16,
+ -1.68f16, -1.68f16, -1.68f16, -1.68f16,
+ -0.82f16, -0.82f16, -0.82f16, -0.82f16,
+ }
+ },
+ {
+ { 7.08e+01f16 },
+ {
+ 4.49e+03f16, 4.49e+03f16, 4.49e+03f16, 4.49e+03f16,
+ 7.73e+03f16, 7.73e+03f16, 7.73e+03f16, 7.73e+03f16,
+ 8.42e+03f16, 8.42e+03f16, 8.42e+03f16, 8.42e+03f16,
+ 9.12e+03f16, 9.12e+03f16, 9.12e+03f16, 9.12e+03f16,
+ },
+ {
+ 1.40e+01f16, 1.40e+01f16, 1.40e+01f16, 1.40e+01f16,
+ 6.80e+01f16, 6.80e+01f16, 6.80e+01f16, 6.80e+01f16,
+ 9.54e+01f16, 9.54e+01f16, 9.54e+01f16, 9.54e+01f16,
+ 4.49e+01f16, 4.49e+01f16, 4.49e+01f16, 4.49e+01f16,
+ },
+ {
+ 3.50e+03f16, 3.50e+03f16, 3.50e+03f16, 3.50e+03f16,
+ 2.91e+03f16, 2.91e+03f16, 2.91e+03f16, 2.91e+03f16,
+ 1.66e+03f16, 1.66e+03f16, 1.66e+03f16, 1.66e+03f16,
+ 5.94e+03f16, 5.94e+03f16, 5.94e+03f16, 5.94e+03f16,
+ }
+ },
+};
+
+float TEST_MULOP_DATA(float, sub)[][4][N] =
+{
+ {
+ {8.51f },
+ {
+ 24.21f, 24.21f, 24.21f, 24.21f,
+ 40.31f, 40.31f, 40.31f, 40.31f,
+ 59.68f, 59.68f, 59.68f, 59.68f,
+ 45.42f, 45.42f, 45.42f, 45.42f,
+ },
+ {
+ 1.94f, 1.94f, 1.94f, 1.94f,
+ 4.24f, 4.24f, 4.24f, 4.24f,
+ 6.48f, 6.48f, 6.48f, 6.48f,
+ 4.68f, 4.68f, 4.68f, 4.68f,
+ },
+ {
+ 7.70f, 7.70f, 7.70f, 7.70f,
+ 4.23f, 4.23f, 4.23f, 4.23f,
+ 4.54f, 4.54f, 4.54f, 4.54f,
+ 5.59f, 5.59f, 5.59f, 5.59f,
+ },
+},
+ {
+ { 85.14f },
+ {
+ 1731.29f, 1731.29f, 1731.29f, 1731.29f,
+ 3656.53f, 3656.53f, 3656.53f, 3656.53f,
+ 5565.07f, 5565.07f, 5565.07f, 5565.07f,
+ 4042.14f, 4042.14f, 4042.14f, 4042.14f,
+ },
+ {
+ 19.43f, 19.43f, 19.43f, 19.43f,
+ 42.45f, 42.45f, 42.45f, 42.45f,
+ 64.83f, 64.83f, 64.83f, 64.83f,
+ 46.82f, 46.82f, 46.82f, 46.82f,
+ },
+ {
+ 77.02f, 77.02f, 77.02f, 77.02f,
+ 42.34f, 42.34f, 42.34f, 42.34f,
+ 45.44f, 45.44f, 45.44f, 45.44f,
+ 55.89f, 55.89f, 55.89f, 55.89f,
+ }
+ },
+ {
+ { 99.01f },
+ {
+ 6240.43f, 6240.43f, 6240.43f, 6240.43f,
+ 2179.23f, 2179.23f, 2179.23f, 2179.23f,
+ 5346.65f, 5346.65f, 5346.65f, 5346.65f,
+ 2649.91f, 2649.91f, 2649.91f, 2649.91f,
+ },
+ {
+ 59.46f, 59.46f, 59.46f, 59.46f,
+ 16.96f, 16.96f, 16.96f, 16.96f,
+ 52.55f, 52.55f, 52.55f, 52.55f,
+ 24.70f, 24.70f, 24.70f, 24.70f,
+ },
+ {
+ 353.30f, 353.30f, 353.30f, 353.30f,
+ 500.02f, 500.02f, 500.02f, 500.02f,
+ 143.67f, 143.67f, 143.67f, 143.67f,
+ 204.36f, 204.36f, 204.36f, 204.36f,
+ }
+ },
+};
+
+double TEST_MULOP_DATA(double, sub)[][4][N] =
+{
+ {
+ { 80.54 },
+ {
+ 5731.60, 5731.60, 5731.60, 5731.60,
+ 6682.41, 6682.41, 6682.41, 6682.41,
+ 7737.53, 7737.53, 7737.53, 7737.53,
+ 4922.68, 4922.68, 4922.68, 4922.68,
+ },
+ {
+ 67.14, 67.14, 67.14, 67.14,
+ 78.23, 78.23, 78.23, 78.23,
+ 94.35, 94.35, 94.35, 94.35,
+ 49.68, 49.68, 49.68, 49.68,
+ },
+ {
+ 324.14, 324.14, 324.14, 324.14,
+ 381.77, 381.77, 381.77, 381.77,
+ 138.58, 138.58, 138.58, 138.58,
+ 921.45, 921.45, 921.45, 921.45,
+ }
+ },
+ {
+ { 8.05e+01 },
+ {
+ 8.65e+27, 8.65e+27, 8.65e+27, 8.65e+27,
+ 1.01e+28, 1.01e+28, 1.01e+28, 1.01e+28,
+ 8.99e+27, 8.99e+27, 8.99e+27, 8.99e+27,
+ 1.32e+28, 1.32e+28, 1.32e+28, 1.32e+28,
+ },
+ {
+ 6.71e+25, 6.71e+25, 6.71e+25, 6.71e+25,
+ 7.82e+25, 7.82e+25, 7.82e+25, 7.82e+25,
+ 9.44e+25, 9.44e+25, 9.44e+25, 9.44e+25,
+ 4.97e+25, 4.97e+25, 4.97e+25, 4.97e+25,
+ },
+ {
+ 3.24e+27, 3.24e+27, 3.24e+27, 3.24e+27,
+ 3.82e+27, 3.82e+27, 3.82e+27, 3.82e+27,
+ 1.39e+27, 1.39e+27, 1.39e+27, 1.39e+27,
+ 9.21e+27, 9.21e+27, 9.21e+27, 9.21e+27,
+ }
+ },
+ {
+ { 2.02e-03 },
+ {
+ 2.7308e-35, 2.7308e-35, 2.7308e-35, 2.7308e-35,
+ 1.5784e-35, 1.5784e-35, 1.5784e-35, 1.5784e-35,
+ 2.3378e-35, 2.3378e-35, 2.3378e-35, 2.3378e-35,
+ 1.6918e-35, 1.6918e-35, 1.6918e-35, 1.6918e-35,
+ },
+ {
+ 9.7703e-33, 9.7703e-33, 9.7703e-33, 9.7703e-33,
+ 4.1632e-33, 4.1632e-33, 4.1632e-33, 4.1632e-33,
+ 8.1964e-33, 8.1964e-33, 8.1964e-33, 8.1964e-33,
+ 4.7314e-33, 4.7314e-33, 4.7314e-33, 4.7314e-33,
+ },
+ {
+ 7.5586e-36, 7.5586e-36, 7.5586e-36, 7.5586e-36,
+ 7.3684e-36, 7.3684e-36, 7.3684e-36, 7.3684e-36,
+ 6.8101e-36, 6.8101e-36, 6.8101e-36, 6.8101e-36,
+ 7.3543e-36, 7.3543e-36, 7.3543e-36, 7.3543e-36,
+ }
+ },
+};
+
+
+#endif
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h
new file mode 100644
index 0000000..bc6f483d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_mulop_run.h
@@ -0,0 +1,34 @@
+#ifndef HAVE_DEFINED_VF_MULOP_RUN_H
+#define HAVE_DEFINED_VF_MULOP_RUN_H
+
+#include <math.h>
+
+#define TYPE_FABS(x, T) \
+ (__builtin_types_compatible_p (T, double) ? fabs (x) : fabsf (x))
+
+int
+main ()
+{
+ unsigned i, k;
+
+ for (i = 0; i < sizeof (TEST_DATA) / sizeof (TEST_DATA[0]); i++)
+ {
+ T x = TEST_DATA[i][0][0];
+ T *in = TEST_DATA[i][1];
+ T *out = TEST_DATA[i][2];
+ T *expect = TEST_DATA[i][3];
+
+ TEST_RUN (T, NAME, out, in, x, N);
+
+ for (k = 0; k < N; k++)
+ {
+ T diff = expect[k] - out[k];
+ if (TYPE_FABS (diff, T) > .01 * TYPE_FABS (expect[k], T))
+ __builtin_abort ();
+ }
+ }
+
+ return 0;
+}
+
+#endif
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
new file mode 100644
index 0000000..1bcf9e0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f16.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+#include "vf_mulop_data.h"
+
+#define T _Float16
+#define NAME add
+
+DEF_VF_MULOP_CASE_0_WRAP(T, +, NAME)
+
+#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vf_mulop_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c
new file mode 100644
index 0000000..199b9ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f32.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+#include "vf_mulop_data.h"
+
+#define T float
+#define NAME add
+
+DEF_VF_MULOP_CASE_0_WRAP(T, +, NAME)
+
+#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vf_mulop_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c
new file mode 100644
index 0000000..3857f58
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmadd-run-1-f64.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+#include "vf_mulop_data.h"
+
+#define T double
+#define NAME add
+
+DEF_VF_MULOP_CASE_0_WRAP(T, +, NAME)
+
+#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vf_mulop_run.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
new file mode 100644
index 0000000..671c7d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f16.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+#include "vf_mulop_data.h"
+
+#define T _Float16
+#define NAME sub
+
+DEF_VF_MULOP_CASE_0_WRAP(T, -, NAME)
+
+#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vf_mulop_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c
new file mode 100644
index 0000000..f896963
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f32.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+#include "vf_mulop_data.h"
+
+#define T float
+#define NAME sub
+
+DEF_VF_MULOP_CASE_0_WRAP(T, -, NAME)
+
+#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vf_mulop_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c
new file mode 100644
index 0000000..b42ab1e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vf_vfmsub-run-1-f64.c
@@ -0,0 +1,15 @@
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "--param=fpr2vr-cost=0" } */
+
+#include "vf_mulop.h"
+#include "vf_mulop_data.h"
+
+#define T double
+#define NAME sub
+
+DEF_VF_MULOP_CASE_0_WRAP(T, -, NAME)
+
+#define TEST_DATA TEST_MULOP_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VF_MULOP_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vf_mulop_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 144d1ba..d88e76b 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
/* { dg-final { scan-assembler-times {vsub.vx} 1 } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-times {vor.vx} 1 } } */
/* { dg-final { scan-assembler-times {vxor.vx} 1 } } */
/* { dg-final { scan-assembler-times {vmul.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vdiv.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 74d35d1..53189c2 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
/* { dg-final { scan-assembler-times {vsub.vx} 1 } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-times {vor.vx} 1 } } */
/* { dg-final { scan-assembler-times {vxor.vx} 1 } } */
/* { dg-final { scan-assembler-times {vmul.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vdiv.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 ac512ff..5059beb 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
/* { dg-final { scan-assembler-times {vsub.vx} 1 } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-times {vor.vx} 1 } } */
/* { dg-final { scan-assembler-times {vxor.vx} 1 } } */
/* { dg-final { scan-assembler-times {vmul.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vdiv.vx} 1 } } */
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 4f7b675..4bbe5a4 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-times {vadd.vx} 1 } } */
/* { dg-final { scan-assembler-times {vsub.vx} 1 } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-times {vor.vx} 1 } } */
/* { dg-final { scan-assembler-times {vxor.vx} 1 } } */
/* { dg-final { scan-assembler-times {vmul.vx} 1 } } */
+/* { dg-final { scan-assembler-times {vdiv.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 075c8be..0437db4 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler-not {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-not {vor.vx} } } */
/* { dg-final { scan-assembler-not {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler-not {vdiv.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 595479c..95ed403 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler-not {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-not {vor.vx} } } */
/* { dg-final { scan-assembler-not {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler-not {vdiv.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 7b6fcbf..f8912a0 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler-not {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-not {vor.vx} } } */
/* { dg-final { scan-assembler-not {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler-not {vdiv.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 55fc717..3c8f915 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler-not {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-not {vor.vx} } } */
/* { dg-final { scan-assembler-not {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler-not {vdiv.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 bec6b3a..f49dae4 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler-not {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-not {vor.vx} } } */
/* { dg-final { scan-assembler-not {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler-not {vdiv.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 98fce52..8f502a3 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler-not {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-not {vor.vx} } } */
/* { dg-final { scan-assembler-not {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler-not {vdiv.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 48dd57a..3277bf2 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler-not {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-not {vor.vx} } } */
/* { dg-final { scan-assembler-not {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler-not {vdiv.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 9bdce82..25ed2ad 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
@@ -12,6 +12,7 @@ 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)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler-not {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_0_WRAP(T, *, mul)
/* { dg-final { scan-assembler-not {vor.vx} } } */
/* { dg-final { scan-assembler-not {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler-not {vdiv.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 a1b24f7..1e409de 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X16)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16)
/* { dg-final { scan-assembler {vor.vx} } } */
/* { dg-final { scan-assembler {vxor.vx} } } */
/* { dg-final { scan-assembler {vmul.vx} } } */
+/* { dg-final { scan-assembler {vdiv.vx} } } */
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 53bd744..2f242c7 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X4)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X4)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X4)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X4)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4)
/* { dg-final { scan-assembler {vor.vx} } } */
/* { dg-final { scan-assembler {vxor.vx} } } */
/* { dg-final { scan-assembler {vmul.vx} } } */
+/* { dg-final { scan-assembler {vdiv.vx} } } */
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 73cb89d..f027bd8 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY)
/* { dg-final { scan-assembler {vor.vx} } } */
/* { dg-final { scan-assembler {vxor.vx} } } */
/* { dg-final { scan-assembler {vmul.vx} } } */
+/* { dg-final { scan-assembler {vdiv.vx} } } */
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 ec20474..c4f55b0 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X8)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16)
/* { dg-final { scan-assembler {vor.vx} } } */
/* { dg-final { scan-assembler {vxor.vx} } } */
/* { dg-final { scan-assembler {vmul.vx} } } */
+/* { dg-final { scan-assembler {vdiv.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 902ba1e..d6b05bc 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X8)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X8)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X8)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X8)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X8)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X8)
/* { dg-final { scan-assembler {vor.vx} } } */
/* { dg-final { scan-assembler {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler {vdiv.vx} } } */
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 e57cee6..e1c043f 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X4)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X4)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X4)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X4)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4)
/* { dg-final { scan-assembler {vor.vx} } } */
/* { dg-final { scan-assembler {vxor.vx} } } */
/* { dg-final { scan-assembler {vmul.vx} } } */
+/* { dg-final { scan-assembler {vdiv.vx} } } */
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 3b4138d..1beb914 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY)
/* { dg-final { scan-assembler {vor.vx} } } */
/* { dg-final { scan-assembler {vxor.vx} } } */
/* { dg-final { scan-assembler {vmul.vx} } } */
+/* { dg-final { scan-assembler {vdiv.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 0ad52b2..0291517 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X8)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16)
/* { dg-final { scan-assembler {vor.vx} } } */
/* { dg-final { scan-assembler {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler {vdiv.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 5e04050..c22c82d 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X8)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X8)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X8)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X8)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X8)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X8)
/* { dg-final { scan-assembler {vor.vx} } } */
/* { dg-final { scan-assembler {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler {vdiv.vx} } } */
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 13a9fe2..dc35600 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X4)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X4)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X4)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X4)
/* { dg-final { scan-assembler {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X4)
/* { dg-final { scan-assembler {vor.vx} } } */
/* { dg-final { scan-assembler {vxor.vx} } } */
/* { dg-final { scan-assembler {vmul.vx} } } */
+/* { dg-final { scan-assembler {vdiv.vx} } } */
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 ca515b4..cee1e3a 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler-not {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY)
/* { dg-final { scan-assembler-not {vor.vx} } } */
/* { dg-final { scan-assembler-not {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler-not {vdiv.vx} } } */
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 70e1abc..74fd2fb 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
@@ -12,6 +12,7 @@ DEF_VX_BINARY_CASE_1_WRAP(T, &, and, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, |, or, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, ^, xor, VX_BINARY_BODY_X16)
DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16)
+DEF_VX_BINARY_CASE_1_WRAP(T, /, div, VX_BINARY_BODY_X8)
/* { dg-final { scan-assembler-not {vadd.vx} } } */
/* { dg-final { scan-assembler {vsub.vx} } } */
@@ -20,3 +21,4 @@ DEF_VX_BINARY_CASE_1_WRAP(T, *, mul, VX_BINARY_BODY_X16)
/* { dg-final { scan-assembler {vor.vx} } } */
/* { dg-final { scan-assembler {vxor.vx} } } */
/* { dg-final { scan-assembler-not {vmul.vx} } } */
+/* { dg-final { scan-assembler {vdiv.vx} } } */
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 c7289ac..ed8c562 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
@@ -2554,4 +2554,200 @@ int64_t TEST_BINARY_DATA(int64_t, mul)[][3][N] =
},
};
+int8_t TEST_BINARY_DATA(int8_t, div)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ },
+ {
+ { 127 },
+ {
+ 127, 127, 127, 127,
+ -1, -1, -1, -1,
+ -128, -128, -128, -128,
+ -2, -2, -2, -2,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ 0, 0, 0, 0,
+ },
+ },
+ {
+ { -128 },
+ {
+ -128, -128, -128, -128,
+ 1, 1, 1, 1,
+ 127, 127, 127, 127,
+ 2, 2, 2, 2,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ },
+ },
+};
+
+int16_t TEST_BINARY_DATA(int16_t, div)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ },
+ {
+ { 32767 },
+ {
+ 32767, 32767, 32767, 32767,
+ -1, -1, -1, -1,
+ -32768, -32768, -32768, -32768,
+ -2, -2, -2, -2,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ 0, 0, 0, 0,
+ },
+ },
+ {
+ { -32768 },
+ {
+ -32768, -32768, -32768, -32768,
+ 1, 1, 1, 1,
+ 32767, 32767, 32767, 32767,
+ 2, 2, 2, 2,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ },
+ },
+};
+
+int32_t TEST_BINARY_DATA(int32_t, div)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ },
+ {
+ { 2147483647 },
+ {
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ -1, -1, -1, -1,
+ -2147483648, -2147483648, -2147483648, -2147483648,
+ -2, -2, -2, -2,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ 0, 0, 0, 0,
+ },
+ },
+ {
+ { -2147483648 },
+ {
+ -2147483648, -2147483648, -2147483648, -2147483648,
+ 1, 1, 1, 1,
+ 2147483647, 2147483647, 2147483647, 2147483647,
+ 2, 2, 2, 2,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ },
+ },
+};
+
+int64_t TEST_BINARY_DATA(int64_t, div)[][3][N] =
+{
+ {
+ { 1 },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ {
+ 2, 2, 2, 2,
+ 1, 1, 1, 1,
+ -1, -1, -1, -1,
+ -2, -2, -2, -2,
+ },
+ },
+ {
+ { 9223372036854775807ll },
+ {
+ 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll,
+ -1, -1, -1, -1,
+ -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull,
+ -2, -2, -2, -2,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ -1, -1, -1, -1,
+ 0, 0, 0, 0,
+ },
+ },
+ {
+ { -9223372036854775808ull },
+ {
+ -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull, -9223372036854775808ull,
+ 1, 1, 1, 1,
+ 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll, 9223372036854775807ll,
+ 2, 2, 2, 2,
+ },
+ {
+ 1, 1, 1, 1,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ },
+ },
+};
+
#endif
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i16.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i16.c
new file mode 100644
index 0000000..64cf31c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i16.c
@@ -0,0 +1,15 @@
+/* { 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 div
+
+DEF_VX_BINARY_CASE_0_WRAP(T, /, NAME)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i32.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i32.c
new file mode 100644
index 0000000..2fe6623
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i32.c
@@ -0,0 +1,15 @@
+/* { 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 div
+
+DEF_VX_BINARY_CASE_0_WRAP(T, /, NAME)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i64.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i64.c
new file mode 100644
index 0000000..03dbe03
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i64.c
@@ -0,0 +1,15 @@
+/* { 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 int64_t
+#define NAME div
+
+DEF_VX_BINARY_CASE_0_WRAP(T, /, NAME)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i8.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i8.c
new file mode 100644
index 0000000..e54e5bc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vx_vf/vx_vdiv-run-1-i8.c
@@ -0,0 +1,15 @@
+/* { 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 div
+
+DEF_VX_BINARY_CASE_0_WRAP(T, /, NAME)
+
+#define TEST_DATA TEST_BINARY_DATA_WRAP(T, NAME)
+#define TEST_RUN(T, NAME, out, in, x, n) RUN_VX_BINARY_CASE_0_WRAP(T, NAME, out, in, x, n)
+
+#include "vx_binary_run.h"
diff --git a/gcc/testsuite/gfortran.dg/coarray_data_2.f90 b/gcc/testsuite/gfortran.dg/coarray_data_2.f90
new file mode 100644
index 0000000..bda57f3
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/coarray_data_2.f90
@@ -0,0 +1,14 @@
+! { dg-do compile }
+! { dg-additional-options "-fcoarray=lib -Warray-temporaries" }
+!
+! PR fortran/99838 - ICE due to missing locus with data statement for coarray
+!
+! Contributed by Gerhard Steinmetz
+
+program p
+ type t
+ integer :: a
+ end type
+ type(t) :: x(3)[*]
+ data x%a /1, 2, 3/ ! { dg-warning "Creating array temporary" }
+end
diff --git a/gcc/testsuite/gfortran.dg/pr119856.f90 b/gcc/testsuite/gfortran.dg/pr119856.f90
new file mode 100644
index 0000000..60ada0a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr119856.f90
@@ -0,0 +1,15 @@
+! { dg-do run }
+! PR119856, the error should occur in both write statements.
+program badfmt
+ implicit none
+
+ character(10):: fmt = "(AI5)" ! Not a PARAMETER so not examined
+ ! at compile time
+ integer :: ioerr
+ ioerr = 0
+ write (*, fmt, iostat=ioerr) 'value =', 42
+ if (ioerr /= 5006) stop 10
+!
+ write (*, fmt, iostat=ioerr) 'value =', 43
+ if (ioerr /= 5006) stop 13
+end program badfmt
diff --git a/gcc/testsuite/gm2/pim/fail/testcharint.mod b/gcc/testsuite/gm2/pim/fail/testcharint.mod
new file mode 100644
index 0000000..d403651
--- /dev/null
+++ b/gcc/testsuite/gm2/pim/fail/testcharint.mod
@@ -0,0 +1,8 @@
+MODULE testcharint ; (*!m2iso+gm2*)
+
+VAR
+ ch: CHAR ;
+ i : INTEGER ;
+BEGIN
+ ch := i
+END testcharint.
diff --git a/gcc/testsuite/gm2/pim/fail/testindrx.mod b/gcc/testsuite/gm2/pim/fail/testindrx.mod
new file mode 100644
index 0000000..2630ebd
--- /dev/null
+++ b/gcc/testsuite/gm2/pim/fail/testindrx.mod
@@ -0,0 +1,8 @@
+MODULE testindrx ; (*!m2iso+gm2*)
+
+VAR
+ x: ARRAY [1..5] OF INTEGER ;
+ ch: CHAR ;
+BEGIN
+ ch := x[1]
+END testindrx.
diff --git a/gcc/testsuite/gm2/pim/pass/ReturnType.mod b/gcc/testsuite/gm2/pim/pass/ReturnType.mod
new file mode 100644
index 0000000..149bc85
--- /dev/null
+++ b/gcc/testsuite/gm2/pim/pass/ReturnType.mod
@@ -0,0 +1,17 @@
+MODULE ReturnType ;
+
+TYPE
+ bar = POINTER TO CARDINAL ;
+
+
+PROCEDURE foo (VAR value: bar) : bar ;
+BEGIN
+ RETURN value
+END foo ;
+
+VAR
+ b: bar ;
+BEGIN
+ b := NIL ;
+ b := foo (b)
+END ReturnType.
diff --git a/gcc/testsuite/gm2/pim/pass/ReturnType2.mod b/gcc/testsuite/gm2/pim/pass/ReturnType2.mod
new file mode 100644
index 0000000..bab7f5b
--- /dev/null
+++ b/gcc/testsuite/gm2/pim/pass/ReturnType2.mod
@@ -0,0 +1,19 @@
+MODULE ReturnType2 ;
+
+TYPE
+ bar = POINTER TO RECORD
+ field: CARDINAL ;
+ END ;
+
+
+PROCEDURE foo (VAR value: bar) : bar ;
+BEGIN
+ RETURN value
+END foo ;
+
+VAR
+ b: bar ;
+BEGIN
+ b := NIL ;
+ b := foo (b)
+END ReturnType2.
diff --git a/gcc/testsuite/gm2/pim/pass/testxindr.mod b/gcc/testsuite/gm2/pim/pass/testxindr.mod
new file mode 100644
index 0000000..271f430
--- /dev/null
+++ b/gcc/testsuite/gm2/pim/pass/testxindr.mod
@@ -0,0 +1,17 @@
+MODULE testxindr ; (*!m2iso+gm2*)
+
+CONST
+ NulName = 0 ;
+
+TYPE
+ Name = CARDINAL ;
+
+ ptr = POINTER TO RECORD
+ n: Name ;
+ END ;
+
+VAR
+ p: ptr ;
+BEGIN
+ p^.n := NulName
+END testxindr.
diff --git a/gcc/testsuite/gm2/pim/pass/testxindr2.mod b/gcc/testsuite/gm2/pim/pass/testxindr2.mod
new file mode 100644
index 0000000..b0776dc
--- /dev/null
+++ b/gcc/testsuite/gm2/pim/pass/testxindr2.mod
@@ -0,0 +1,17 @@
+MODULE testxindr2 ; (*!m2iso+gm2*)
+
+CONST
+ NulName = 0 ;
+TYPE
+ Name = CARDINAL ;
+
+PROCEDURE set (VAR n: Name) ;
+BEGIN
+ n := NulName
+END set ;
+
+VAR
+ n: Name ;
+BEGIN
+ set (n)
+END testxindr2.
diff --git a/gcc/testsuite/gm2/pim/pass/testxindr3.mod b/gcc/testsuite/gm2/pim/pass/testxindr3.mod
new file mode 100644
index 0000000..5625c3e
--- /dev/null
+++ b/gcc/testsuite/gm2/pim/pass/testxindr3.mod
@@ -0,0 +1,15 @@
+MODULE testxindr3 ; (*!m2iso+gm2*)
+
+CONST
+ NulName = 0 ;
+
+PROCEDURE set (VAR n: CARDINAL) ;
+BEGIN
+ n := NulName
+END set ;
+
+VAR
+ n: CARDINAL ;
+BEGIN
+ set (n)
+END testxindr3.
diff --git a/gcc/testsuite/gnat.dg/controlled9.adb b/gcc/testsuite/gnat.dg/controlled9.adb
new file mode 100644
index 0000000..fb7acce
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/controlled9.adb
@@ -0,0 +1,10 @@
+-- { dg-do run }
+-- { dg-options "-O1 -fstack-check" }
+-- from PR middle-end/118939
+
+with Controlled9_Pkg;
+procedure Controlled9 is
+ S : constant Controlled9_Pkg.T_Access := new Controlled9_Pkg.T;
+begin
+ null;
+end Controlled9;
diff --git a/gcc/testsuite/gnat.dg/controlled9_pkg.ads b/gcc/testsuite/gnat.dg/controlled9_pkg.ads
new file mode 100644
index 0000000..d0e7c28
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/controlled9_pkg.ads
@@ -0,0 +1,5 @@
+with Ada.Finalization;
+package Controlled9_Pkg is
+ type T is new Ada.Finalization.Controlled with null record;
+ type T_Access is access all T;
+end Controlled9_Pkg;
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 75d723c..dfffe3a 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -1098,6 +1098,16 @@ proc check_effective_target_tls {} {
}]
}
+# Return 1 if we can link using TLS, 0 otherwise.
+
+proc check_effective_target_tls_link {} {
+ return [check_no_compiler_messages tls_link executable {
+ __thread int i;
+ int main (void) { return i; }
+ void g (int j) { i = j; }
+ }]
+}
+
# Return 1 if *native* thread local storage (TLS) is supported, 0 otherwise.
proc check_effective_target_tls_native {} {
diff --git a/gcc/tree-inline.cc b/gcc/tree-inline.cc
index 3289b4f..1a72e31 100644
--- a/gcc/tree-inline.cc
+++ b/gcc/tree-inline.cc
@@ -2866,7 +2866,6 @@ initialize_cfun (tree new_fndecl, tree callee_fndecl, profile_count count)
cfun->nonlocal_goto_save_area = src_cfun->nonlocal_goto_save_area;
cfun->function_end_locus = src_cfun->function_end_locus;
cfun->curr_properties = src_cfun->curr_properties;
- cfun->last_verified = src_cfun->last_verified;
cfun->va_list_gpr_size = src_cfun->va_list_gpr_size;
cfun->va_list_fpr_size = src_cfun->va_list_fpr_size;
cfun->has_nonlocal_label = src_cfun->has_nonlocal_label;
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 7cb5a12..4139f6d 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -236,9 +236,9 @@ protected:
(PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh | PROP_gimple_lomp)
/* To-do flags. */
+/* Note (1ul << 31) is reserved for TODO_verify_il. */
#define TODO_do_not_ggc_collect (1 << 1)
#define TODO_cleanup_cfg (1 << 5)
-#define TODO_verify_il (1 << 6)
#define TODO_dump_symtab (1 << 7)
#define TODO_remove_functions (1 << 8)
@@ -308,6 +308,8 @@ protected:
and stop pass manager. */
#define TODO_discard_function (1 << 23)
+/* (1ul << 31) is reserved for TODO_verify_il. */
+
/* Internally used in execute_function_todo(). */
#define TODO_update_ssa_any \
(TODO_update_ssa \
@@ -315,8 +317,6 @@ protected:
| TODO_update_ssa_full_phi \
| TODO_update_ssa_only_virtuals)
-#define TODO_verify_all TODO_verify_il
-
/* To-do flags for pending_TODOs. */
/* Tell the next scalar cleanup pass that there is
diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
index 81ea7d4..75901ec 100644
--- a/gcc/tree-ssa-forwprop.cc
+++ b/gcc/tree-ssa-forwprop.cc
@@ -205,7 +205,6 @@ struct _vec_perm_simplify_seq
typedef struct _vec_perm_simplify_seq *vec_perm_simplify_seq;
static bool forward_propagate_addr_expr (tree, tree, bool);
-static void optimize_vector_load (gimple_stmt_iterator *);
/* Set to true if we delete dead edges during the optimization. */
static bool cfg_changed;
@@ -3387,6 +3386,7 @@ optimize_vector_load (gimple_stmt_iterator *gsi)
gimple *stmt = gsi_stmt (*gsi);
tree lhs = gimple_assign_lhs (stmt);
tree rhs = gimple_assign_rhs1 (stmt);
+ tree vuse = gimple_vuse (stmt);
/* Gather BIT_FIELD_REFs to rewrite, looking through
VEC_UNPACK_{LO,HI}_EXPR. */
@@ -3495,6 +3495,7 @@ optimize_vector_load (gimple_stmt_iterator *gsi)
gimple *new_stmt = gimple_build_assign (tem, new_rhs);
location_t loc = gimple_location (use_stmt);
gimple_set_location (new_stmt, loc);
+ gimple_set_vuse (new_stmt, vuse);
gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
/* Perform scalar promotion. */
new_stmt = gimple_build_assign (gimple_assign_lhs (use_stmt),
@@ -3514,6 +3515,7 @@ optimize_vector_load (gimple_stmt_iterator *gsi)
new_rhs);
location_t loc = gimple_location (use_stmt);
gimple_set_location (new_stmt, loc);
+ gimple_set_vuse (new_stmt, vuse);
gsi_insert_before (gsi, new_stmt, GSI_SAME_STMT);
}
gimple_stmt_iterator gsi2 = gsi_for_stmt (use_stmt);
@@ -4167,7 +4169,7 @@ const pass_data pass_data_forwprop =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_update_ssa, /* todo_flags_finish */
+ 0, /* todo_flags_finish */
};
class pass_forwprop : public gimple_opt_pass
@@ -4404,6 +4406,7 @@ pass_forwprop::execute (function *fun)
component-wise loads. */
use_operand_p use_p;
imm_use_iterator iter;
+ tree vuse = gimple_vuse (stmt);
bool rewrite = true;
FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
{
@@ -4443,6 +4446,7 @@ pass_forwprop::execute (function *fun)
location_t loc = gimple_location (use_stmt);
gimple_set_location (new_stmt, loc);
+ gimple_set_vuse (new_stmt, vuse);
gimple_stmt_iterator gsi2 = gsi_for_stmt (use_stmt);
unlink_stmt_vdef (use_stmt);
gsi_remove (&gsi2, true);
diff --git a/gcc/tree-switch-conversion.cc b/gcc/tree-switch-conversion.cc
index bd4de96..d088287 100644
--- a/gcc/tree-switch-conversion.cc
+++ b/gcc/tree-switch-conversion.cc
@@ -1030,6 +1030,9 @@ switch_conversion::build_one_array (int num, tree arr_index_type,
TREE_CONSTANT (decl) = 1;
TREE_READONLY (decl) = 1;
DECL_IGNORED_P (decl) = 1;
+ /* The decl is mergable since we don't take the address ever and
+ just reading from it. */
+ DECL_MERGEABLE (decl) = 1;
if (offloading_function_p (cfun->decl))
DECL_ATTRIBUTES (decl)
= tree_cons (get_identifier ("omp declare target"), NULL_TREE,
diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc
index f2deb75..1792ee4 100644
--- a/gcc/tree-vect-data-refs.cc
+++ b/gcc/tree-vect-data-refs.cc
@@ -3685,7 +3685,7 @@ vect_analyze_data_ref_accesses (vec_info *vinfo,
/* For datarefs with big gap, it's better to split them into different
groups.
.i.e a[0], a[1], a[2], .. a[7], a[100], a[101],..., a[107] */
- if ((unsigned HOST_WIDE_INT)(init_b - init_prev) * tree_to_uhwi (szb)
+ if ((unsigned HOST_WIDE_INT)(init_b - init_prev)
> MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT)
break;
diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
index 2d1a688..8c5761d 100644
--- a/gcc/tree-vect-loop.cc
+++ b/gcc/tree-vect-loop.cc
@@ -6016,7 +6016,8 @@ vect_create_epilog_for_reduction (loop_vec_info loop_vinfo,
/* Create an induction variable. */
gimple_stmt_iterator incr_gsi;
bool insert_after;
- vect_iv_increment_position (loop_exit, &incr_gsi, &insert_after);
+ vect_iv_increment_position (LOOP_VINFO_IV_EXIT (loop_vinfo),
+ &incr_gsi, &insert_after);
create_iv (series_vect, PLUS_EXPR, vec_step, NULL_TREE, loop, &incr_gsi,
insert_after, &indx_before_incr, &indx_after_incr);
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index 5aeb1e0..cad1a24 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -1297,7 +1297,7 @@ const pass_data pass_data_early_vrp =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
+ ( TODO_cleanup_cfg | TODO_update_ssa ),
};
const pass_data pass_data_fast_vrp =
@@ -1310,7 +1310,7 @@ const pass_data pass_data_fast_vrp =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
+ ( TODO_cleanup_cfg | TODO_update_ssa ),
};
diff --git a/include/ChangeLog b/include/ChangeLog
index 5110716..886dab6 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,8 @@
+2025-06-02 Tobias Burnus <tburnus@baylibre.com>
+
+ PR libgomp/120444
+ * cuda/cuda.h (cuMemsetD8, cuMemsetD8Async): Declare.
+
2025-05-30 Julian Brown <julian@codesourcery.com>
Tobias Burnus <tburnus@baylibre.com>
diff --git a/include/cuda/cuda.h b/include/cuda/cuda.h
index 5e4b7f1..6be1ac0 100644
--- a/include/cuda/cuda.h
+++ b/include/cuda/cuda.h
@@ -279,6 +279,9 @@ CUresult cuMemcpy3D (const CUDA_MEMCPY3D *);
CUresult cuMemcpy3DAsync (const CUDA_MEMCPY3D *, CUstream);
CUresult cuMemcpy3DPeer (const CUDA_MEMCPY3D_PEER *);
CUresult cuMemcpy3DPeerAsync (const CUDA_MEMCPY3D_PEER *, CUstream);
+#define cuMemsetD8 cuMemsetD8_v2
+CUresult cuMemsetD8 (CUdeviceptr, unsigned char, size_t);
+CUresult cuMemsetD8Async (CUdeviceptr, unsigned char, size_t, CUstream);
#define cuMemFree cuMemFree_v2
CUresult cuMemFree (CUdeviceptr);
CUresult cuMemFreeHost (void *);
diff --git a/libgcobol/ChangeLog b/libgcobol/ChangeLog
index 83a826e..4293598 100644
--- a/libgcobol/ChangeLog
+++ b/libgcobol/ChangeLog
@@ -1,3 +1,8 @@
+2025-06-01 Robert Dubner <rdubner@symas.com>
+
+ PR cobol/119524
+ * libgcobol.cc (__gg__fprintf_stderr): New function.
+
2025-05-20 Robert Dubner <rdubner@symas.com>
James K. Lowden <jklowden@cobolworx.com>
diff --git a/libgcobol/libgcobol.cc b/libgcobol/libgcobol.cc
index 66405ba..3ab7463 100644
--- a/libgcobol/libgcobol.cc
+++ b/libgcobol/libgcobol.cc
@@ -49,6 +49,7 @@
#include <signal.h>
#include <syslog.h>
#include <unistd.h>
+#include <stdarg.h>
#if __has_include(<errno.h>)
# include <errno.h> // for program_invocation_short_name
#endif
@@ -13151,3 +13152,16 @@ __gg__set_env_value(cblc_field_t *value,
// And now, anticlimactically, set the variable:
setenv(trimmed_env, trimmed_val, 1);
}
+
+extern "C"
+void
+__gg__fprintf_stderr(const char *format_string, ...)
+ {
+ /* This routine allows the compiler to send stuff to stderr in a way
+ that is straightforward to use.. */
+ va_list ap;
+ va_start(ap, format_string);
+ vfprintf(stderr, format_string, ap);
+ va_end(ap);
+ }
+
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog
index 638c03e..1f658d5 100644
--- a/libgfortran/ChangeLog
+++ b/libgfortran/ChangeLog
@@ -1,3 +1,11 @@
+2025-06-01 Jerry DeLisle <jvdelisle@gcc.gnu.org>
+
+ PR libfortran/119856
+ * io/format.c (parse_format_list): Set the fmt->error
+ message for missing comma.
+ (parse_format): Do not cache the parsed format string
+ if a previous error ocurred.
+
2025-05-13 Jakub Jelinek <jakub@redhat.com>
PR libfortran/120196
diff --git a/libgfortran/io/format.c b/libgfortran/io/format.c
index eef1d34..87e21a9 100644
--- a/libgfortran/io/format.c
+++ b/libgfortran/io/format.c
@@ -1235,9 +1235,9 @@ parse_format_list (st_parameter_dt *dtp, bool *seen_dd)
default:
/* Assume a missing comma with -std=legacy, GNU extension. */
- if (compile_options.warn_std == 0)
- goto format_item_1;
- format_error (dtp, tail, comma_missing);
+ if (compile_options.warn_std != 0)
+ fmt->error = comma_missing;
+ goto format_item_1;
}
/* Optional comma is a weird between state where we've just finished
@@ -1252,7 +1252,7 @@ parse_format_list (st_parameter_dt *dtp, bool *seen_dd)
case FMT_RPAREN:
goto finished;
- default: /* Assume that we have another format item */
+ default: /* Assume that we have another format item */
fmt->saved_token = t;
break;
}
@@ -1419,7 +1419,7 @@ parse_format (st_parameter_dt *dtp)
else
fmt->error = "Missing initial left parenthesis in format";
- if (format_cache_ok)
+ if (format_cache_ok && !fmt->error)
save_parsed_format (dtp);
else
dtp->u.p.format_not_saved = 1;
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index 78bbf26..2c044a7 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,29 @@
+2025-06-02 Tobias Burnus <tburnus@baylibre.com>
+
+ PR libgomp/120444
+ * libgomp-plugin.h (GOMP_OFFLOAD_memset): Declare.
+ * libgomp.h (struct gomp_device_descr): Add memset_func.
+ * libgomp.map (GOMP_6.0.1): Add omp_target_memset{,_async}.
+ * libgomp.texi (Device Memory Routines): Document them.
+ * omp.h.in (omp_target_memset, omp_target_memset_async): Declare.
+ * omp_lib.f90.in (omp_target_memset, omp_target_memset_async):
+ Add interfaces.
+ * omp_lib.h.in (omp_target_memset, omp_target_memset_async): Likewise.
+ * plugin/cuda-lib.def: Add cuMemsetD8.
+ * plugin/plugin-gcn.c (struct hsa_runtime_fn_info): Add
+ hsa_amd_memory_fill_fn.
+ (init_hsa_runtime_functions): DLSYM_OPT_FN load it.
+ (GOMP_OFFLOAD_memset): New.
+ * plugin/plugin-nvptx.c (GOMP_OFFLOAD_memset): New.
+ * target.c (omp_target_memset_int, omp_target_memset,
+ omp_target_memset_async_helper, omp_target_memset_async): New.
+ (gomp_load_plugin_for_device): Add DLSYM (memset).
+ * testsuite/libgomp.c-c++-common/omp_target_memset.c: New test.
+ * testsuite/libgomp.c-c++-common/omp_target_memset-2.c: New test.
+ * testsuite/libgomp.c-c++-common/omp_target_memset-3.c: New test.
+ * testsuite/libgomp.fortran/omp_target_memset.f90: New test.
+ * testsuite/libgomp.fortran/omp_target_memset-2.f90: New test.
+
2025-05-30 Thomas Schwinge <tschwinge@baylibre.com>
* testsuite/libgomp.c++/target-std__valarray-1.C: New.
diff --git a/libgomp/libgomp-plugin.h b/libgomp/libgomp-plugin.h
index 50c89fe..191106b 100644
--- a/libgomp/libgomp-plugin.h
+++ b/libgomp/libgomp-plugin.h
@@ -177,6 +177,7 @@ extern int GOMP_OFFLOAD_memcpy3d (int, int, size_t, size_t, size_t, void *,
size_t, size_t, size_t, size_t, size_t,
const void *, size_t, size_t, size_t, size_t,
size_t);
+extern bool GOMP_OFFLOAD_memset (int, void *, int, size_t);
extern bool GOMP_OFFLOAD_can_run (void *);
extern void GOMP_OFFLOAD_run (int, void *, void *, void **);
extern void GOMP_OFFLOAD_async_run (int, void *, void *, void **, void *);
diff --git a/libgomp/libgomp.h b/libgomp/libgomp.h
index ed4e23a..a433983 100644
--- a/libgomp/libgomp.h
+++ b/libgomp/libgomp.h
@@ -1421,9 +1421,10 @@ struct gomp_device_descr
__typeof (GOMP_OFFLOAD_free) *free_func;
__typeof (GOMP_OFFLOAD_dev2host) *dev2host_func;
__typeof (GOMP_OFFLOAD_host2dev) *host2dev_func;
+ __typeof (GOMP_OFFLOAD_dev2dev) *dev2dev_func;
__typeof (GOMP_OFFLOAD_memcpy2d) *memcpy2d_func;
__typeof (GOMP_OFFLOAD_memcpy3d) *memcpy3d_func;
- __typeof (GOMP_OFFLOAD_dev2dev) *dev2dev_func;
+ __typeof (GOMP_OFFLOAD_memset) *memset_func;
__typeof (GOMP_OFFLOAD_can_run) *can_run_func;
__typeof (GOMP_OFFLOAD_run) *run_func;
__typeof (GOMP_OFFLOAD_async_run) *async_run_func;
diff --git a/libgomp/libgomp.map b/libgomp/libgomp.map
index ad9787c..f6aee7c 100644
--- a/libgomp/libgomp.map
+++ b/libgomp/libgomp.map
@@ -453,6 +453,12 @@ GOMP_6.0 {
omp_get_uid_from_device_8_;
} GOMP_5.1.3;
+GOMP_6.0.1 {
+ global:
+ omp_target_memset;
+ omp_target_memset_async;
+} GOMP_6.0;
+
OACC_2.0 {
global:
acc_get_num_devices;
diff --git a/libgomp/libgomp.texi b/libgomp/libgomp.texi
index e6ebe22..8e487bc 100644
--- a/libgomp/libgomp.texi
+++ b/libgomp/libgomp.texi
@@ -603,7 +603,7 @@ to address of matching mapped list item per 5.1, Sect. 2.21.7.2 @tab N @tab
@code{omp_get_device_teams_thread_limit}, and
@code{omp_set_device_teams_thread_limit} routines @tab N @tab
@item @code{omp_target_memset} and @code{omp_target_memset_async} routines
- @tab N @tab
+ @tab Y @tab
@item Fortran version of the interop runtime routines @tab Y @tab
@item Routines for obtaining memory spaces/allocators for shared/device memory
@tab N @tab
@@ -1984,8 +1984,8 @@ pointers on devices. They have C linkage and do not throw exceptions.
* omp_target_memcpy_async:: Copy data between devices asynchronously
* omp_target_memcpy_rect:: Copy a subvolume of data between devices
* omp_target_memcpy_rect_async:: Copy a subvolume of data between devices asynchronously
-@c * omp_target_memset:: <fixme>/TR12
-@c * omp_target_memset_async:: <fixme>/TR12
+* omp_target_memset:: Set bytes in device memory
+* omp_target_memset_async:: Set bytes in device memory asynchronously
* omp_target_associate_ptr:: Associate a device pointer with a host pointer
* omp_target_disassociate_ptr:: Remove device--host pointer association
* omp_get_mapped_ptr:: Return device pointer to a host pointer
@@ -2398,6 +2398,98 @@ the initial device.
@end table
+@node omp_target_memset
+@subsection @code{omp_target_memset} -- Set bytes in device memory
+@table @asis
+@item @emph{Description}:
+This routine fills memory on the device identified by device number
+@var{device_num}. Starting from the device address @var{ptr}, the first
+@var{count} bytes are set to the value @var{val}, converted to
+@code{unsigned char}. If @var{count} is zero, the routine has no effect;
+if @var{ptr} is @code{NULL}, the behavior is unspecified. The function
+returns @var{ptr}.
+
+The @var{device_num} must be a conforming device number and @var{ptr} must be
+a valid device pointer for that device. Running this routine in a
+@code{target} region except on the initial device is not supported.
+
+@item @emph{C/C++}
+@multitable @columnfractions .20 .80
+@item @emph{Prototype}: @tab @code{void *omp_target_memcpy(void *ptr,}
+@item @tab @code{ int val,}
+@item @tab @code{ size_t count,}
+@item @tab @code{ int device_num)}
+@end multitable
+
+@item @emph{Fortran}:
+@multitable @columnfractions .20 .80
+@item @emph{Interface}: @tab @code{type(c_ptr) function omp_target_memset( &}
+@item @tab @code{ ptr, val, count, device_num) bind(C)}
+@item @tab @code{use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t, c_int}
+@item @tab @code{type(c_ptr), value :: ptr}
+@item @tab @code{integer(c_size_t), value :: count}
+@item @tab @code{integer(c_int), value :: val, device_num}
+@end multitable
+
+@item @emph{See also}:
+@ref{omp_target_memset_async}
+
+@item @emph{Reference}:
+@uref{https://www.openmp.org, OpenMP specification v6.0}, Section 25.8.1
+@end table
+
+
+
+@node omp_target_memset_async
+@subsection @code{omp_target_memset} -- Set bytes in device memory asynchronously
+@table @asis
+@item @emph{Description}:
+This routine fills memory on the device identified by device number
+@var{device_num}. Starting from the device address @var{ptr}, the first
+@var{count} bytes are set to the value @var{val}, converted to
+@code{unsigned char}. If @var{count} is zero, the routine has no effect;
+if @var{ptr} is @code{NULL}, the behavior is unspecified. Task dependence
+is expressed by passing an array of depend objects to @var{depobj_list}, where
+the number of array elements is passed as @var{depobj_count}; if the count is
+zero, the @var{depobj_list} argument is ignored. In C++ and Fortran, the
+@var{depobj_list} argument can also be omitted in that case. The function
+returns @var{ptr}.
+
+The @var{device_num} must be a conforming device number and @var{ptr} must be
+a valid device pointer for that device. Running this routine in a
+@code{target} region except on the initial device is not supported.
+
+@item @emph{C/C++}
+@multitable @columnfractions .20 .80
+@item @emph{Prototype}: @tab @code{void *omp_target_memcpy_async(void *ptr,}
+@item @tab @code{ int val,}
+@item @tab @code{ size_t count,}
+@item @tab @code{ int device_num,}
+@item @tab @code{ int depobj_count,}
+@item @tab @code{ omp_depend_t *depobj_list)}
+@end multitable
+
+@item @emph{Fortran}:
+@multitable @columnfractions .20 .80
+@item @emph{Interface}: @tab @code{type(c_ptr) function omp_target_memset_async( &}
+@item @tab @code{ ptr, val, count, device_num, &}
+@item @tab @code{ depobj_count, depobj_list) bind(C)}
+@item @tab @code{use, intrinsic :: iso_c_binding, only: c_ptr, c_size_t, c_int}
+@item @tab @code{type(c_ptr), value :: ptr}
+@item @tab @code{integer(c_size_t), value :: count}
+@item @tab @code{integer(c_int), value :: val, device_num, depobj_count}
+@item @tab @code{integer(omp_depend_kind), optional :: depobj_list(*)}
+@end multitable
+
+
+@item @emph{See also}:
+@ref{omp_target_memset}
+
+@item @emph{Reference}:
+@uref{https://www.openmp.org, OpenMP specification v6.0}, Section 25.8.2
+@end table
+
+
@node omp_target_associate_ptr
@subsection @code{omp_target_associate_ptr} -- Associate a device pointer with a host pointer
diff --git a/libgomp/omp.h.in b/libgomp/omp.h.in
index 8d17db1..4f2bc46 100644
--- a/libgomp/omp.h.in
+++ b/libgomp/omp.h.in
@@ -347,6 +347,10 @@ extern int omp_target_memcpy_rect_async (void *, const void *, __SIZE_TYPE__,
const __SIZE_TYPE__ *, int, int, int,
omp_depend_t * __GOMP_DEFAULT_NULL)
__GOMP_NOTHROW;
+extern void *omp_target_memset (void *, int, __SIZE_TYPE__, int) __GOMP_NOTHROW;
+extern void *omp_target_memset_async (void *, int, __SIZE_TYPE__, int,
+ int, omp_depend_t * __GOMP_DEFAULT_NULL)
+ __GOMP_NOTHROW;
extern int omp_target_associate_ptr (const void *, const void *, __SIZE_TYPE__,
__SIZE_TYPE__, int) __GOMP_NOTHROW;
extern int omp_target_disassociate_ptr (const void *, int) __GOMP_NOTHROW;
diff --git a/libgomp/omp_lib.f90.in b/libgomp/omp_lib.f90.in
index cb6b95f..ce866c0 100644
--- a/libgomp/omp_lib.f90.in
+++ b/libgomp/omp_lib.f90.in
@@ -904,6 +904,29 @@
end interface
interface
+ function omp_target_memset (ptr, val, count, device_num) bind(c)
+ use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_size_t
+ type(c_ptr) :: omp_target_memset
+ type(c_ptr), value :: ptr
+ integer(c_size_t), value :: count
+ integer(c_int), value :: val, device_num
+ end function omp_target_memset
+ end interface
+
+ interface
+ function omp_target_memset_async (ptr, val, count, device_num, &
+ depobj_count, depobj_list) bind(c)
+ use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_size_t
+ import :: omp_depend_kind
+ type(c_ptr) :: omp_target_memset_async
+ type(c_ptr), value :: ptr
+ integer(c_size_t), value :: count
+ integer(c_int), value :: val, device_num, depobj_count
+ integer(omp_depend_kind), optional :: depobj_list(*)
+ end function omp_target_memset_async
+ end interface
+
+ interface
function omp_target_associate_ptr (host_ptr, device_ptr, size, &
device_offset, device_num) bind(c)
use, intrinsic :: iso_c_binding, only : c_ptr, c_size_t, c_int
diff --git a/libgomp/omp_lib.h.in b/libgomp/omp_lib.h.in
index f7af5ff..9047095 100644
--- a/libgomp/omp_lib.h.in
+++ b/libgomp/omp_lib.h.in
@@ -505,6 +505,31 @@
end interface
interface
+ function omp_target_memset (ptr, val, count, device_num) bind(c)
+ use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_size_t
+ type(c_ptr) omp_target_memset
+ type(c_ptr), value :: ptr
+ integer(c_size_t), value :: count
+ integer(c_int), value :: val, device_num
+ end function omp_target_memset
+ end interface
+
+ interface
+ function omp_target_memset_async (ptr, val, count, device_num, &
+ & depobj_count, depobj_list) &
+ & bind(c)
+ use, intrinsic :: iso_c_binding, only : c_ptr, c_int, c_size_t
+ import :: omp_depend_kind
+ type(c_ptr) :: omp_target_memset_async
+ type(c_ptr), value :: ptr
+ integer(c_size_t), value :: count
+ integer(c_int), value :: val, device_num, depobj_count
+ integer(omp_depend_kind), optional :: depobj_list(*)
+ end function omp_target_memset_async
+ end interface
+
+
+ interface
function omp_target_associate_ptr (host_ptr, device_ptr, size, &
& device_offset, device_num) &
& bind(c)
diff --git a/libgomp/plugin/cuda-lib.def b/libgomp/plugin/cuda-lib.def
index eb562ac..7f4ddcc 100644
--- a/libgomp/plugin/cuda-lib.def
+++ b/libgomp/plugin/cuda-lib.def
@@ -42,6 +42,7 @@ CUDA_ONE_CALL (cuMemcpyHtoDAsync)
CUDA_ONE_CALL (cuMemcpy2D)
CUDA_ONE_CALL (cuMemcpy2DUnaligned)
CUDA_ONE_CALL (cuMemcpy3D)
+CUDA_ONE_CALL (cuMemsetD8)
CUDA_ONE_CALL (cuMemFree)
CUDA_ONE_CALL (cuMemFreeHost)
CUDA_ONE_CALL (cuMemGetAddressRange)
diff --git a/libgomp/plugin/plugin-gcn.c b/libgomp/plugin/plugin-gcn.c
index 46203838..498b549 100644
--- a/libgomp/plugin/plugin-gcn.c
+++ b/libgomp/plugin/plugin-gcn.c
@@ -208,6 +208,8 @@ struct hsa_runtime_fn_info
hsa_status_t (*hsa_code_object_deserialize_fn)
(void *serialized_code_object, size_t serialized_code_object_size,
const char *options, hsa_code_object_t *code_object);
+ hsa_status_t (*hsa_amd_memory_fill_fn)(void *ptr, uint32_t value,
+ size_t count);
hsa_status_t (*hsa_amd_memory_lock_fn)
(void *host_ptr, size_t size, hsa_agent_t *agents, int num_agent,
void **agent_ptr);
@@ -1456,6 +1458,7 @@ init_hsa_runtime_functions (void)
DLSYM_FN (hsa_signal_load_acquire)
DLSYM_FN (hsa_queue_destroy)
DLSYM_FN (hsa_code_object_deserialize)
+ DLSYM_OPT_FN (hsa_amd_memory_fill)
DLSYM_OPT_FN (hsa_amd_memory_lock)
DLSYM_OPT_FN (hsa_amd_memory_unlock)
DLSYM_OPT_FN (hsa_amd_memory_async_copy_rect)
@@ -4435,6 +4438,83 @@ init_hip_runtime_functions (void)
return true;
}
+bool
+GOMP_OFFLOAD_memset (int ord, void *ptr, int val, size_t count)
+{
+ hsa_status_t status = HSA_STATUS_SUCCESS;
+
+ /* A memset feature is only provided via hsa_amd_memory_fill; while it
+ is fast, it is an HSA extension and it has two requirements: The memory
+ must be aligned to multiples of 4 bytes - and, by construction, only
+ multiples of 4 bytes can be filled (uint32_t value argument).
+
+ This means: Either not using that function or up to three function calls:
+ - copy 1 to 3 bytes to get alignment (hsa_memory_copy), if unaligned
+ - call hsa_amd_memory_fill
+ - copy remaining 1 to 3 bytes (hsa_memory_copy), if after alignment
+ count is not a multiple of 4 bytes.
+
+ Having more than one function call is only profitable if there is
+ enough data to process; see below for the used heuristic values. */
+
+ uint8_t v8 = (uint8_t) val;
+ size_t before = (4 - (uintptr_t) ptr % 4) % 4; /* 0 to 3 bytes. */
+ size_t tail = (count - before) % 4; /* 0 to 3 bytes. */
+
+ /* Heuristic */
+ enum {
+ /* Prefer alloca to malloc up to ... */
+ alloca_size = 256, /* bytes */
+ /* Call hsa_amd_memory_fill also when two copy calls are required. */
+ always_use_fill = 256*1024, /* bytes */
+ /* Call hsa_amd_memory_fill also when on copy call is required. */
+ use_fill_one_copy = (128+64)*1024 /* bytes */
+ };
+
+ /* Do not call hsa_amd_memory_fill when any of the following conditions
+ is true. Note that it is always preferred if available and
+ before == tail == 0. */
+ if (__builtin_expect (!hsa_fns.hsa_amd_memory_fill_fn, 0)
+ || (before && tail && count < always_use_fill)
+ || ((before || tail) && count < use_fill_one_copy))
+ before = count;
+
+ /* Copy call for alignment - or all data, if condition above is true. */
+ if (before)
+ {
+ void *data;
+ if (before > alloca_size)
+ data = malloc (before * sizeof (uint8_t));
+ else
+ data = alloca (before * sizeof (uint8_t));
+ memset (data, val, before);
+ status = hsa_fns.hsa_memory_copy_fn (ptr, data, before);
+ if (before > alloca_size)
+ free (data);
+ if (data == 0 || status != HSA_STATUS_SUCCESS)
+ goto fail;
+ count -= before;
+ }
+
+ if (count == 0)
+ return true;
+
+ ptr += before;
+
+ uint32_t values = v8 | (v8 << 8) | (v8 << 16) | (v8 << 24);
+ status = hsa_fns.hsa_amd_memory_fill_fn (ptr, values, count / 4);
+ if (tail && status == HSA_STATUS_SUCCESS)
+ {
+ ptr += count - tail;
+ status = hsa_fns.hsa_memory_copy_fn (ptr, &values, tail);
+ }
+ if (status == HSA_STATUS_SUCCESS)
+ return true;
+
+fail:
+ GOMP_PLUGIN_error ("memory set failed");
+ return false;
+}
void
GOMP_OFFLOAD_interop (struct interop_obj_t *obj, int ord,
diff --git a/libgomp/plugin/plugin-nvptx.c b/libgomp/plugin/plugin-nvptx.c
index a52d1ad..0ba445e 100644
--- a/libgomp/plugin/plugin-nvptx.c
+++ b/libgomp/plugin/plugin-nvptx.c
@@ -2298,6 +2298,15 @@ GOMP_OFFLOAD_memcpy3d (int dst_ord, int src_ord, size_t dim2_size,
}
bool
+GOMP_OFFLOAD_memset (int ord, void *ptr, int val, size_t count)
+{
+ if (!nvptx_attach_host_thread_to_device (ord))
+ return false;
+ CUDA_CALL (cuMemsetD8, (CUdeviceptr) ptr, (unsigned char) val, count);
+ return true;
+}
+
+bool
GOMP_OFFLOAD_openacc_async_host2dev (int ord, void *dst, const void *src,
size_t n, struct goacc_asyncqueue *aq)
{
diff --git a/libgomp/target.c b/libgomp/target.c
index fe94978..a2a4a72 100644
--- a/libgomp/target.c
+++ b/libgomp/target.c
@@ -5003,6 +5003,88 @@ omp_target_memcpy_rect_async (void *dst, const void *src, size_t element_size,
return 0;
}
+static void
+omp_target_memset_int (void *ptr, int val, size_t count,
+ struct gomp_device_descr *devicep)
+{
+ if (__builtin_expect (count == 0, 0))
+ return;
+ if (devicep == NULL)
+ {
+ memset (ptr, val, count);
+ return;
+ }
+
+ gomp_mutex_lock (&devicep->lock);
+ int ret = devicep->memset_func (devicep->target_id, ptr, val, count);
+ gomp_mutex_unlock (&devicep->lock);
+ if (!ret)
+ gomp_fatal ("omp_target_memset failed");
+}
+
+void*
+omp_target_memset (void *ptr, int val, size_t count, int device_num)
+{
+ struct gomp_device_descr *devicep;
+ if (device_num == omp_initial_device
+ || device_num == gomp_get_num_devices ()
+ || (devicep = resolve_device (device_num, false)) == NULL
+ || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)
+ || devicep->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
+ devicep = NULL;
+
+ omp_target_memset_int (ptr, val, count, devicep);
+ return ptr;
+}
+
+typedef struct
+{
+ void *ptr;
+ size_t count;
+ struct gomp_device_descr *devicep;
+ int val;
+} omp_target_memset_data;
+
+static void
+omp_target_memset_async_helper (void *args)
+{
+ omp_target_memset_data *a = args;
+ omp_target_memset_int (a->ptr, a->val, a->count, a->devicep);
+}
+
+void*
+omp_target_memset_async (void *ptr, int val, size_t count, int device_num,
+ int depobj_count, omp_depend_t *depobj_list)
+{
+ void *depend[depobj_count + 5];
+ struct gomp_device_descr *devicep;
+ unsigned flags = 0;
+ int i;
+
+ if (device_num == omp_initial_device
+ || device_num == gomp_get_num_devices ()
+ || (devicep = resolve_device (device_num, false)) == NULL
+ || !(devicep->capabilities & GOMP_OFFLOAD_CAP_OPENMP_400)
+ || devicep->capabilities & GOMP_OFFLOAD_CAP_SHARED_MEM)
+ devicep = NULL;
+
+ omp_target_memset_data s = {.ptr = ptr, .val = val, .count = count,
+ .devicep = devicep};
+ if (depobj_count > 0 && depobj_list != NULL)
+ {
+ flags |= GOMP_TASK_FLAG_DEPEND;
+ depend[0] = 0;
+ depend[1] = (void *) (uintptr_t) depobj_count;
+ depend[2] = depend[3] = depend[4] = 0;
+ for (i = 0; i < depobj_count; ++i)
+ depend[i + 5] = &depobj_list[i];
+ }
+
+ GOMP_task (omp_target_memset_async_helper, &s, NULL, sizeof (s),
+ __alignof__ (s), true, flags, depend, 0, NULL);
+ return ptr;
+}
+
int
omp_target_associate_ptr (const void *host_ptr, const void *device_ptr,
size_t size, size_t device_offset, int device_num)
@@ -5568,6 +5650,7 @@ gomp_load_plugin_for_device (struct gomp_device_descr *device,
DLSYM_OPT (async_run, async_run);
DLSYM_OPT (can_run, can_run);
DLSYM (dev2dev);
+ DLSYM (memset);
}
if (device->capabilities & GOMP_OFFLOAD_CAP_OPENACC_200)
{
diff --git a/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-2.c b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-2.c
new file mode 100644
index 0000000..b36d2f5
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-2.c
@@ -0,0 +1,62 @@
+// PR libgomp/120444
+// Async version
+
+#include <omp.h>
+
+int main()
+{
+ #pragma omp parallel for
+ for (int dev = omp_initial_device; dev <= omp_get_num_devices (); dev++)
+ {
+ char *ptr = (char *) omp_target_alloc (sizeof(int) * 1024, dev);
+
+ omp_depend_t dep;
+ #pragma omp depobj(dep) depend(inout: ptr)
+
+ /* Play also around with the alignment - as hsa_amd_memory_fill operates
+ on multiples of 4 bytes (uint32_t). */
+
+ for (int start = 0; start < 32; start++)
+ for (int tail = 0; tail < 32; tail++)
+ {
+ unsigned char val = '0' + start + tail;
+#if __cplusplus
+ void *ptr2 = omp_target_memset_async (ptr + start, val,
+ 1024 - start - tail, dev, 0);
+#else
+ void *ptr2 = omp_target_memset_async (ptr + start, val,
+ 1024 - start - tail, dev, 0, nullptr);
+#endif
+ if (ptr + start != ptr2)
+ __builtin_abort ();
+
+ #pragma omp taskwait
+
+ #pragma omp target device(dev) is_device_ptr(ptr) depend(depobj: dep) nowait
+ for (int i = start; i < 1024 - start - tail; i++)
+ {
+ if (ptr[i] != val)
+ __builtin_abort ();
+ ptr[i] += 2;
+ }
+
+ omp_target_memset_async (ptr + start, val + 3,
+ 1024 - start - tail, dev, 1, &dep);
+
+ #pragma omp target device(dev) is_device_ptr(ptr) depend(depobj: dep) nowait
+ for (int i = start; i < 1024 - start - tail; i++)
+ {
+ if (ptr[i] != val + 3)
+ __builtin_abort ();
+ ptr[i] += 1;
+ }
+
+ omp_target_memset_async (ptr + start, val - 3,
+ 1024 - start - tail, dev, 1, &dep);
+
+ #pragma omp taskwait depend (depobj: dep)
+ }
+ #pragma omp depobj(dep) destroy
+ omp_target_free (ptr, dev);
+ }
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-3.c b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-3.c
new file mode 100644
index 0000000..c0e4fa9
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset-3.c
@@ -0,0 +1,80 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <omp.h>
+
+#define MIN(x,y) ((x) < (y) ? x : y)
+
+enum { N = 524288 + 8 };
+
+static void
+init_val (int8_t *ptr, int val, size_t count)
+{
+ #pragma omp target is_device_ptr(ptr) firstprivate(val, count)
+ __builtin_memset (ptr, val, count);
+}
+
+static void
+check_val (int8_t *ptr, int val, size_t count)
+{
+ if (count == 0)
+ return;
+ #pragma omp target is_device_ptr(ptr) firstprivate(val, count)
+ for (size_t i = 0; i < count; i++)
+ if (ptr[i] != val) __builtin_abort ();
+}
+
+static void
+test_it (int8_t *ptr, int lshift, size_t count)
+{
+ if (N < count + lshift) __builtin_abort ();
+ if (lshift >= 4) __builtin_abort ();
+ ptr += lshift;
+
+ init_val (ptr, 'z', MIN (count + 32, N - lshift));
+
+ omp_target_memset (ptr, '1', count, omp_get_default_device());
+
+ check_val (ptr, '1', count);
+ check_val (ptr + count, 'z', MIN (32, N - lshift - count));
+}
+
+
+int main()
+{
+ size_t size;
+ int8_t *ptr = (int8_t *) omp_target_alloc (N + 3, omp_get_default_device());
+ ptr += (4 - (uintptr_t) ptr % 4) % 4;
+ if ((uintptr_t) ptr % 4 != 0) __builtin_abort ();
+
+ test_it (ptr, 0, 1);
+ test_it (ptr, 3, 1);
+ test_it (ptr, 0, 4);
+ test_it (ptr, 3, 4);
+ test_it (ptr, 0, 5);
+ test_it (ptr, 3, 5);
+ test_it (ptr, 0, 6);
+ test_it (ptr, 3, 6);
+
+ for (int i = 1; i <= 9; i++)
+ {
+ switch (i)
+ {
+ case 1: size = 16; break; // = 2^4 bytes
+ case 2: size = 32; break; // = 2^5 bytes
+ case 3: size = 64; break; // = 2^7 bytes
+ case 4: size = 128; break; // = 2^7 bytes
+ case 5: size = 256; break; // = 2^8 bytes
+ case 6: size = 512; break; // = 2^9 bytes
+ case 7: size = 65536; break; // = 2^16 bytes
+ case 8: size = 262144; break; // = 2^18 bytes
+ case 9: size = 524288; break; // = 2^20 bytes
+ default: __builtin_abort ();
+ }
+ test_it (ptr, 0, size);
+ test_it (ptr, 3, size);
+ test_it (ptr, 0, size + 1);
+ test_it (ptr, 3, size + 1);
+ test_it (ptr, 3, size + 2);
+ }
+ omp_target_free (ptr, omp_get_default_device());
+}
diff --git a/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset.c b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset.c
new file mode 100644
index 0000000..01909f8
--- /dev/null
+++ b/libgomp/testsuite/libgomp.c-c++-common/omp_target_memset.c
@@ -0,0 +1,62 @@
+// PR libgomp/120444
+
+#include <omp.h>
+
+int main()
+{
+ for (int dev = omp_initial_device; dev < omp_get_num_devices (); dev++)
+ {
+ char *ptr = (char *) omp_target_alloc (sizeof(int) * 1024, dev);
+
+ /* Play also around with the alignment - as hsa_amd_memory_fill operates
+ on multiples of 4 bytes (uint32_t). */
+
+ for (int start = 0; start < 32; start++)
+ for (int tail = 0; tail < 32; tail++)
+ {
+ unsigned char val = '0' + start + tail;
+ void *ptr2 = omp_target_memset (ptr + start, val,
+ 1024 - start - tail, dev);
+ if (ptr + start != ptr2)
+ __builtin_abort ();
+
+ #pragma omp target device(dev) is_device_ptr(ptr)
+ for (int i = start; i < 1024 - start - tail; i++)
+ if (ptr[i] != val)
+ __builtin_abort ();
+
+ }
+
+ /* Check 'small' values for correctness. */
+
+ for (int start = 0; start < 32; start++)
+ for (int size = 0; size <= 64 + 32; size++)
+ {
+ omp_target_memset (ptr, 'a' - 2, 1024, dev);
+
+ unsigned char val = '0' + start + size % 32;
+ void *ptr2 = omp_target_memset (ptr + start, val, size, dev);
+
+ if (ptr + start != ptr2)
+ __builtin_abort ();
+
+ if (size == 0)
+ continue;
+
+ #pragma omp target device(dev) is_device_ptr(ptr)
+ {
+ for (int i = 0; i < start; i++)
+ if (ptr[i] != 'a' - 2)
+ __builtin_abort ();
+ for (int i = start; i < start + size; i++)
+ if (ptr[i] != val)
+ __builtin_abort ();
+ for (int i = start + size + 1; i < 1024; i++)
+ if (ptr[i] != 'a' - 2)
+ __builtin_abort ();
+ }
+ }
+
+ omp_target_free (ptr, dev);
+ }
+}
diff --git a/libgomp/testsuite/libgomp.fortran/omp_target_memset-2.f90 b/libgomp/testsuite/libgomp.fortran/omp_target_memset-2.f90
new file mode 100644
index 0000000..2641086
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/omp_target_memset-2.f90
@@ -0,0 +1,67 @@
+! PR libgomp/120444
+! Async version
+
+use omp_lib
+use iso_c_binding
+implicit none (type, external)
+integer(c_int) :: dev
+
+!$omp parallel do
+do dev = omp_initial_device, omp_get_num_devices ()
+block
+ integer(c_int) :: i, val, start, tail
+ type(c_ptr) :: ptr, ptr2, tmpptr
+ integer(c_int8_t), pointer, contiguous :: fptr(:)
+ integer(c_intptr_t) :: intptr
+ integer(c_size_t), parameter :: count = 1024
+ integer(omp_depend_kind) :: dep(1)
+
+ ptr = omp_target_alloc (count, dev)
+
+ !$omp depobj(dep(1)) depend(inout: ptr)
+
+ ! Play also around with the alignment - as hsa_amd_memory_fill operates
+ ! on multiples of 4 bytes (c_int32_t)
+
+ do start = 0, 31
+ do tail = 0, 31
+ val = iachar('0') + start + tail
+
+ tmpptr = transfer (transfer (ptr, intptr) + start, tmpptr)
+ ptr2 = omp_target_memset_async (tmpptr, val, count - start - tail, dev, 0)
+
+ if (.not. c_associated (tmpptr, ptr2)) stop 1
+
+ !$omp taskwait
+
+ !$omp target device(dev) is_device_ptr(ptr) depend(depobj: dep(1)) nowait
+ do i = 1 + start, int(count, c_int) - start - tail
+ call c_f_pointer (ptr, fptr, [count])
+ if (fptr(i) /= int (val, c_int8_t)) stop 2
+ fptr(i) = fptr(i) + 2_c_int8_t
+ end do
+ !$omp end target
+
+ ptr2 = omp_target_memset_async (tmpptr, val + 3, &
+ count - start - tail, dev, 1, dep)
+
+ !$omp target device(dev) is_device_ptr(ptr) depend(depobj: dep(1)) nowait
+ do i = 1 + start, int(count, c_int) - start - tail
+ call c_f_pointer (ptr, fptr, [count])
+ if (fptr(i) /= int (val + 3, c_int8_t)) stop 3
+ fptr(i) = fptr(i) - 1_c_int8_t
+ end do
+ !$omp end target
+
+ ptr2 = omp_target_memset_async (tmpptr, val - 3, &
+ count - start - tail, dev, 1, dep)
+
+ !$omp taskwait depend (depobj: dep(1))
+ end do
+ end do
+
+ !$omp depobj(dep(1)) destroy
+ call omp_target_free (ptr, dev);
+end block
+end do
+end
diff --git a/libgomp/testsuite/libgomp.fortran/omp_target_memset.f90 b/libgomp/testsuite/libgomp.fortran/omp_target_memset.f90
new file mode 100644
index 0000000..1ee184a
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/omp_target_memset.f90
@@ -0,0 +1,39 @@
+! PR libgomp/120444
+
+use omp_lib
+use iso_c_binding
+implicit none (type, external)
+
+integer(c_int) :: dev, i, val, start, tail
+type(c_ptr) :: ptr, ptr2, tmpptr
+integer(c_int8_t), pointer, contiguous :: fptr(:)
+integer(c_intptr_t) :: intptr
+integer(c_size_t), parameter :: count = 1024
+
+do dev = omp_initial_device, omp_get_num_devices ()
+ ptr = omp_target_alloc (count, dev)
+
+ ! Play also around with the alignment - as hsa_amd_memory_fill operates
+ ! on multiples of 4 bytes (c_int32_t)
+
+ do start = 0, 31
+ do tail = 0, 31
+ val = iachar('0') + start + tail
+
+ tmpptr = transfer (transfer (ptr, intptr) + start, tmpptr)
+ ptr2 = omp_target_memset (tmpptr, val, count - start - tail, dev)
+
+ if (.not. c_associated (tmpptr, ptr2)) stop 1
+
+ !$omp target device(dev) is_device_ptr(ptr)
+ do i = 1 + start, int(count, c_int) - start - tail
+ call c_f_pointer (ptr, fptr, [count])
+ if (fptr(i) /= int (val, c_int8_t)) stop 2
+ end do
+ !$omp end target
+ end do
+ end do
+
+ call omp_target_free (ptr, dev);
+end do
+end
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 9df2d57..2a8963e 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,65 @@
+2025-06-02 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/bits/basic_string.h (basic_string::size): Remove space
+ before parameter list.
+ (basic_string::capacity): Likewise.
+ * include/bits/stl_deque.h (deque::size): Likewise.
+ * include/bits/stl_vector.h (vector::size, vector::capacity):
+ Likewise.
+ * include/bits/vector.tcc (vector::_M_realloc_insert): Likewise.
+ (vector::_M_realloc_append): Likewise.
+
+2025-06-02 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/120386
+ * include/bits/ranges_algo.h (__unique_copy_fn): Reorder
+ arguments for third case to match the first two cases.
+ * include/bits/stl_algo.h (__unique_copy): Replace three
+ overloads with two, depending only on the iterator category of
+ the input range. Dispatch to __unique_copy_1 for the
+ non-forward case.
+ (__unique_copy_1): New overloads for the case where the input
+ range uses non-forward iterators.
+ (unique_copy): Only pass the input range category to
+ __unique_copy.
+ * testsuite/25_algorithms/unique_copy/lwg2439.cc: New test.
+
+2025-06-02 Tomasz Kamiński <tkaminsk@redhat.com>
+
+ * include/bits/funcwrap.h (__polyfunc::__pass_by_rref): Define.
+ (__polyfunc::__param_t): Update to use __pass_by_rref.
+ * include/bits/cpyfunc_impl.h:: Assert that are parameters type
+ are complete.
+ * include/bits/funcref_impl.h: Likewise.
+ * include/bits/mofunc_impl.h: Likewise.
+ * testsuite/20_util/copyable_function/call.cc: New test.
+ * testsuite/20_util/function_ref/call.cc: New test.
+ * testsuite/20_util/move_only_function/call.cc: New test.
+ * testsuite/20_util/copyable_function/conv.cc: New test.
+ * testsuite/20_util/function_ref/conv.cc: New test.
+ * testsuite/20_util/move_only_function/conv.cc: New test.
+ * testsuite/20_util/copyable_function/incomplete_neg.cc: New test.
+ * testsuite/20_util/function_ref/incomplete_neg.cc: New test.
+ * testsuite/20_util/move_only_function/incomplete_neg.cc: New test.
+
+2025-06-02 Jonathan Wakely <jwakely@redhat.com>
+ Tomasz Kamiński <tkaminsk@redhat.com>
+
+ PR libstdc++/119152
+ * include/bits/indirect.h (std::polymorphic, pmr::polymorphic)
+ [__glibcxx_polymorphic]: Define.
+ * include/bits/version.def (polymorphic): Define.
+ * include/bits/version.h: Regenerate.
+ * include/std/memory: Define __cpp_lib_polymorphic.
+ * testsuite/std/memory/polymorphic/copy.cc: New test.
+ * testsuite/std/memory/polymorphic/copy_alloc.cc: New test.
+ * testsuite/std/memory/polymorphic/ctor.cc: New test.
+ * testsuite/std/memory/polymorphic/ctor_poly.cc: New test.
+ * testsuite/std/memory/polymorphic/incomplete.cc: New test.
+ * testsuite/std/memory/polymorphic/invalid_neg.cc: New test.
+ * testsuite/std/memory/polymorphic/move.cc: New test.
+ * testsuite/std/memory/polymorphic/move_alloc.cc: New test.
+
2025-05-30 Tomasz Kamiński <tkaminsk@redhat.com>
* testsuite/std/time/format/empty_spec.cc: New test.
diff --git a/libstdc++-v3/include/bits/atomic_timed_wait.h b/libstdc++-v3/include/bits/atomic_timed_wait.h
index 230afbc..bd2e6bf 100644
--- a/libstdc++-v3/include/bits/atomic_timed_wait.h
+++ b/libstdc++-v3/include/bits/atomic_timed_wait.h
@@ -87,7 +87,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__wait_until_impl(const void* __addr, __wait_args_base& __args,
const __wait_clock_t::duration& __atime);
- // Returns {true, val} if wait ended before a timeout.
template<typename _Clock, typename _Dur>
__wait_result_type
__wait_until(const void* __addr, __wait_args_base& __args,
@@ -158,8 +157,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
bool __bare_wait = false) noexcept
{
__detail::__wait_args __args{ __addr, __old, __order, __bare_wait };
- auto __res = __detail::__wait_until(__addr, &__args, __atime);
- return __res.first; // C++26 will also return last observed __val
+ auto __res = __detail::__wait_until(__addr, __args, __atime);
+ return !__res._M_timeout; // C++26 will also return last observed __val
}
template<typename _Tp, typename _ValFn,
@@ -203,7 +202,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__atomic_wait_address_for_v(const __detail::__platform_wait_t* __addr,
__detail::__platform_wait_t __old,
int __order,
- const chrono::time_point<_Rep, _Period>& __rtime,
+ const chrono::duration<_Rep, _Period>& __rtime,
bool __bare_wait = false) noexcept
{
__detail::__wait_args __args{ __addr, __old, __order, __bare_wait };
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
index a087e63..7081049 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -1164,7 +1164,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
{
size_type __sz = _M_string_length;
if (__sz > max_size ())
- __builtin_unreachable ();
+ __builtin_unreachable();
return __sz;
}
@@ -1279,7 +1279,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
size_t __sz = _M_is_local() ? size_type(_S_local_capacity)
: _M_allocated_capacity;
if (__sz < _S_local_capacity || __sz > max_size ())
- __builtin_unreachable ();
+ __builtin_unreachable();
return __sz;
}
diff --git a/libstdc++-v3/include/bits/cpyfunc_impl.h b/libstdc++-v3/include/bits/cpyfunc_impl.h
index bc44cd3e..f1918dd 100644
--- a/libstdc++-v3/include/bits/cpyfunc_impl.h
+++ b/libstdc++-v3/include/bits/cpyfunc_impl.h
@@ -64,6 +64,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_MOF_REF noexcept(_Noex)>
: __polyfunc::_Cpy_base
{
+ static_assert(
+ (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>()) && ...),
+ "each parameter type must be a complete class");
+
using _Base = __polyfunc::_Cpy_base;
using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>;
using _Signature = _Invoker::_Signature;
diff --git a/libstdc++-v3/include/bits/funcref_impl.h b/libstdc++-v3/include/bits/funcref_impl.h
index 1e19866..44c9922 100644
--- a/libstdc++-v3/include/bits/funcref_impl.h
+++ b/libstdc++-v3/include/bits/funcref_impl.h
@@ -68,6 +68,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
class function_ref<_Res(_ArgTypes...) _GLIBCXX_MOF_CV
noexcept(_Noex)>
{
+ static_assert(
+ (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>()) && ...),
+ "each parameter type must be a complete class");
+
using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>;
using _Signature = _Invoker::_Signature;
diff --git a/libstdc++-v3/include/bits/funcwrap.h b/libstdc++-v3/include/bits/funcwrap.h
index cf261bc..9db4ab7 100644
--- a/libstdc++-v3/include/bits/funcwrap.h
+++ b/libstdc++-v3/include/bits/funcwrap.h
@@ -199,7 +199,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
};
template<typename _Tp>
- using __param_t = __conditional_t<is_scalar_v<_Tp>, _Tp, _Tp&&>;
+ consteval bool
+ __pass_by_value()
+ {
+ // n.b. sizeof(Incomplete&) is ill-formed for incomplete types,
+ // so we check is_reference_v first.
+ if constexpr (is_reference_v<_Tp> || is_scalar_v<_Tp>)
+ return true;
+ else
+ // n.b. we already asserted that types are complete in wrappers,
+ // avoid triggering additional errors from this function.
+ if constexpr (std::__is_complete_or_unbounded(__type_identity<_Tp>()))
+ if constexpr (sizeof(_Tp) <= 2 * sizeof(void*))
+ return is_trivially_move_constructible_v<_Tp>
+ && is_trivially_destructible_v<_Tp>;
+ return false;
+ }
+
+ template<typename _Tp>
+ using __param_t = __conditional_t<__pass_by_value<_Tp>(), _Tp, _Tp&&>;
template<bool _Noex, typename _Ret, typename... _Args>
using _Invoker = _Base_invoker<_Noex, remove_cv_t<_Ret>, __param_t<_Args>...>;
diff --git a/libstdc++-v3/include/bits/indirect.h b/libstdc++-v3/include/bits/indirect.h
index 85908e2..e8000d7 100644
--- a/libstdc++-v3/include/bits/indirect.h
+++ b/libstdc++-v3/include/bits/indirect.h
@@ -452,7 +452,381 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ };
#endif // __glibcxx_indirect
- _GLIBCXX_END_NAMESPACE_VERSION
+#if __glibcxx_polymorphic // C++26 && HOSTED
+ template<typename _Tp, typename _Alloc = allocator<_Tp>>
+ class polymorphic;
+
+ namespace pmr
+ {
+ template<typename _Tp>
+ using polymorphic = polymorphic<_Tp, polymorphic_allocator<_Tp>>;
+ }
+
+ // [polymorphic], class template polymorphic
+ template<typename _Tp, typename _Alloc>
+ class polymorphic
+ {
+ static_assert(is_object_v<_Tp>);
+ static_assert(!is_array_v<_Tp>);
+ static_assert(!is_same_v<_Tp, in_place_t>);
+ static_assert(!__is_in_place_type_v<_Tp>);
+ static_assert(!is_const_v<_Tp> && !is_volatile_v<_Tp>);
+
+ using _ATraits = allocator_traits<_Alloc>;
+ static_assert(is_same_v<_Tp, typename _ATraits::value_type>);
+
+ // The owned object is embedded within a control block which knows the
+ // dynamic type and manages cloning and destroying the owned object.
+ struct _Obj
+ {
+ typename _ATraits::pointer _M_objp{}; // pointer to the owned object.
+
+ // A pointer to this type, e.g. _Obj*
+ using pointer
+ = typename _ATraits::template rebind_traits<_Obj>::pointer;
+
+ enum class _Op { _Dispose = 1, _Copy = 2, _Move = 3 };
+
+ constexpr virtual pointer
+ _M_manage(const _Alloc&, _Op, void* = nullptr) = 0;
+ };
+
+ template<typename _Up>
+ struct _Obj_impl : _Obj
+ {
+ using _MyTraits
+ = typename _ATraits::template rebind_traits<_Obj_impl>;
+
+ using _Op = _Obj::_Op;
+
+ union _Uninitialized {
+ constexpr _Uninitialized() { }
+ constexpr ~_Uninitialized() { }
+ _Up _M_objp;
+ };
+ _Uninitialized _M_u;
+
+ template<typename... _Args>
+ constexpr
+ _Obj_impl(typename _MyTraits::allocator_type& __a,
+ _Args&&... __args)
+ {
+ using _PtrTr = pointer_traits<typename _ATraits::pointer>;
+ _MyTraits::construct(__a, __builtin_addressof(_M_u._M_objp),
+ std::forward<_Args>(__args)...);
+ this->_M_objp = _PtrTr::pointer_to(_M_u._M_objp);
+ }
+
+ constexpr virtual typename _Obj::pointer
+ _M_manage(const _Alloc& __a, _Op __op, void*) override
+ {
+
+ switch (__op)
+ {
+ case _Op::_Move:
+ return _S_make_obj<_Up>(__a, std::move(_M_u._M_objp));
+ case _Op::_Copy:
+ return _S_make_obj<_Up>(__a,
+ const_cast<const _Up&>(_M_u._M_objp));
+ case _Op::_Dispose:
+ {
+ using _PtrTr = pointer_traits<typename _MyTraits::pointer>;
+ typename _MyTraits::allocator_type __a2(__a);
+ _MyTraits::destroy(__a2, std::__addressof(_M_u._M_objp));
+ _MyTraits::deallocate(__a2, _PtrTr::pointer_to(*this), 1);
+ return nullptr;
+ }
+ }
+ __builtin_unreachable();
+ }
+ };
+
+ // TODO: the standard permits a small-object optimization where the
+ // owned object is nested within the std::polymorphic not on the heap.
+
+ public:
+
+ using value_type = _Tp;
+ using allocator_type = _Alloc;
+ using pointer = typename allocator_traits<_Alloc>::pointer;
+ using const_pointer = typename allocator_traits<_Alloc>::const_pointer;
+
+ constexpr explicit
+ polymorphic() requires is_default_constructible_v<_Alloc>
+ : polymorphic(in_place_type<_Tp>)
+ { }
+
+ constexpr explicit
+ polymorphic(allocator_arg_t, const _Alloc& __a)
+ : polymorphic(allocator_arg, __a, in_place_type<_Tp>)
+ { }
+
+ constexpr
+ polymorphic(const polymorphic& __other)
+ : polymorphic(allocator_arg,
+ _ATraits::select_on_container_copy_construction(
+ __other._M_alloc),
+ __other)
+ { }
+
+ constexpr
+ polymorphic(allocator_arg_t, const _Alloc& __a,
+ const polymorphic& __other)
+ : _M_alloc(__a)
+ {
+ if (__other._M_objp)
+ _M_objp = __other._M_objp->_M_manage(__a, _Obj::_Op::_Copy);
+ else
+ _M_objp = nullptr;
+ }
+
+ constexpr
+ polymorphic(polymorphic&& __other) noexcept
+ : _M_alloc(std::move(__other._M_alloc)),
+ _M_objp(std::__exchange(__other._M_objp, nullptr))
+ { }
+
+ constexpr
+ polymorphic(allocator_arg_t, const _Alloc& __a, polymorphic&& __other)
+ noexcept(_ATraits::is_always_equal::value)
+ : _M_alloc(__a),
+ _M_objp(std::__exchange(__other._M_objp, nullptr))
+ {
+ if constexpr (!_ATraits::is_always_equal::value)
+ if (_M_objp && _M_alloc != __other._M_alloc)
+ {
+ // _M_alloc cannot free _M_objp, give it back to __other.
+ __other._M_objp = std::__exchange(_M_objp, nullptr);
+ // And create a new object that can be freed by _M_alloc.
+ _M_objp = __other._M_objp->_M_manage(__a, _Obj::_Op::_Move);
+ }
+ }
+
+ template<typename _Up = _Tp, typename _UUp = remove_cvref_t<_Up>>
+ requires (!is_same_v<_UUp, polymorphic>)
+ && (!__is_in_place_type_v<_UUp>)
+ && derived_from<_UUp, _Tp>
+ && is_constructible_v<_UUp, _Up>
+ && is_copy_constructible_v<_UUp>
+ && is_default_constructible_v<_Alloc>
+ constexpr explicit
+ polymorphic(_Up&& __u)
+ : _M_objp(_M_make_obj<_UUp>(std::forward<_Up>(__u)))
+ { }
+
+ template<typename _Up = _Tp, typename _UUp = remove_cvref_t<_Up>>
+ requires (!is_same_v<_UUp, polymorphic>)
+ && (!__is_in_place_type_v<_UUp>)
+ && derived_from<_UUp, _Tp>
+ && is_constructible_v<_UUp, _Up>
+ && is_copy_constructible_v<_UUp>
+ constexpr explicit
+ polymorphic(allocator_arg_t, const _Alloc& __a, _Up&& __u)
+ : _M_alloc(__a), _M_objp(_M_make_obj<_UUp>(std::forward<_Up>(__u)))
+ { }
+
+ template<typename _Up, typename... _Ts>
+ requires is_same_v<remove_cvref_t<_Up>, _Up>
+ && derived_from<_Up, _Tp>
+ && is_constructible_v<_Up, _Ts...>
+ && is_copy_constructible_v<_Up>
+ && is_default_constructible_v<_Alloc>
+ constexpr explicit
+ polymorphic(in_place_type_t<_Up> __t, _Ts&&... __ts)
+ : _M_objp(_M_make_obj<_Up>(std::forward<_Ts>(__ts)...))
+ { }
+
+ template<typename _Up, typename... _Ts>
+ requires is_same_v<remove_cvref_t<_Up>, _Up>
+ && derived_from<_Up, _Tp>
+ && is_constructible_v<_Up, _Ts...>
+ && is_copy_constructible_v<_Up>
+ constexpr explicit
+ polymorphic(allocator_arg_t, const _Alloc& __a,
+ in_place_type_t<_Up>, _Ts&&... __ts)
+ : _M_alloc(__a),
+ _M_objp(_M_make_obj<_Up>(std::forward<_Ts>(__ts)...))
+ { }
+
+ template<typename _Up, typename _Ip, typename... _Us>
+ requires is_same_v<remove_cvref_t<_Up>, _Up>
+ && derived_from<_Up, _Tp>
+ && is_constructible_v<_Up, initializer_list<_Ip>&, _Us...>
+ && is_copy_constructible_v<_Up>
+ && is_default_constructible_v<_Alloc>
+ constexpr explicit
+ polymorphic(in_place_type_t<_Up>, initializer_list<_Ip> __il,
+ _Us&&... __us)
+ : _M_objp(_M_make_obj<_Up>(__il, std::forward<_Us>(__us)...))
+ { }
+
+ template<typename _Up, typename _Ip, typename... _Us>
+ requires is_same_v<remove_cvref_t<_Up>, _Up>
+ && derived_from<_Up, _Tp>
+ && is_constructible_v<_Up, initializer_list<_Ip>&, _Us...>
+ && is_copy_constructible_v<_Up>
+ constexpr explicit
+ polymorphic(allocator_arg_t, const _Alloc& __a,
+ in_place_type_t<_Up>, initializer_list<_Ip> __il,
+ _Us&&... __us)
+ : _M_alloc(__a),
+ _M_objp(_M_make_obj<_Up>(__il, std::forward<_Us>(__us)...))
+ { }
+
+ constexpr ~polymorphic()
+ {
+ static_assert(sizeof(_Tp) != 0, "must be a complete type");
+ _M_reset(nullptr);
+ }
+
+ constexpr polymorphic&
+ operator=(const polymorphic& __other)
+ {
+ static_assert(sizeof(_Tp) != 0, "must be a complete type");
+
+ if (__builtin_addressof(__other) == this) [[unlikely]]
+ return *this;
+
+ constexpr bool __pocca
+ = _ATraits::propagate_on_container_copy_assignment::value;
+
+ typename _Obj::pointer __ptr = nullptr;
+ if (__other._M_objp)
+ {
+ auto& __a = __pocca ? __other._M_alloc : _M_alloc;
+ __ptr = __other._M_objp->_M_manage(__a, _Obj::_Op::_Copy);
+ }
+
+ _M_reset(__ptr);
+
+ if constexpr (__pocca)
+ _M_alloc = __other._M_alloc;
+
+ return *this;
+ }
+
+ constexpr polymorphic&
+ operator=(polymorphic&& __other)
+ noexcept(_ATraits::propagate_on_container_move_assignment::value
+ || _ATraits::is_always_equal::value)
+ {
+ if (__builtin_addressof(__other) == this) [[unlikely]]
+ return *this;
+
+ constexpr bool __pocma
+ = _ATraits::propagate_on_container_move_assignment::value;
+
+ typename _Obj::pointer __ptr = nullptr;
+
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4251. Move assignment for indirect unnecessarily requires copy construction
+ if constexpr (_ATraits::is_always_equal::value || __pocma)
+ __ptr = std::__exchange(__other._M_objp, nullptr);
+ else if (_M_alloc == __other._M_alloc)
+ __ptr = std::__exchange(__other._M_objp, nullptr);
+ else if (__other._M_objp)
+ {
+ static_assert(sizeof(_Tp) != 0, "must be a complete type");
+ __ptr = __other._M_objp->_M_manage(_M_alloc, _Obj::_Op::_Move);
+ }
+
+ _M_reset(__ptr);
+
+ if constexpr (__pocma)
+ _M_alloc = __other._M_alloc;
+
+ return *this;
+ }
+
+ constexpr const _Tp&
+ operator*() const noexcept
+ {
+ __glibcxx_assert(_M_objp != nullptr);
+ return *_M_objp->_M_objp;
+ }
+
+ constexpr _Tp&
+ operator*() noexcept
+ {
+ __glibcxx_assert(_M_objp != nullptr);
+ return *_M_objp->_M_objp;
+ }
+
+ constexpr const_pointer
+ operator->() const noexcept
+ {
+ __glibcxx_assert(_M_objp != nullptr);
+ return _M_objp ? _M_objp->_M_objp : const_pointer{};
+ }
+
+ constexpr pointer
+ operator->() noexcept
+ {
+ __glibcxx_assert(_M_objp != nullptr);
+ return _M_objp ? _M_objp->_M_objp : pointer{};
+ }
+
+ constexpr bool
+ valueless_after_move() const noexcept { return _M_objp == nullptr; }
+
+ constexpr allocator_type
+ get_allocator() const noexcept { return _M_alloc; }
+
+ constexpr void
+ swap(polymorphic& __other)
+ noexcept(_ATraits::propagate_on_container_swap::value
+ || _ATraits::is_always_equal::value)
+ {
+ using std::swap;
+ swap(_M_objp, __other._M_objp);
+ if constexpr (_ATraits::propagate_on_container_swap::value)
+ swap(_M_alloc, __other._M_alloc);
+ else if constexpr (!_ATraits::is_always_equal::value)
+ __glibcxx_assert(_M_alloc == __other._M_alloc);
+ }
+
+ friend constexpr void
+ swap(polymorphic& __lhs, polymorphic& __rhs)
+ noexcept(_ATraits::propagate_on_container_swap::value
+ || _ATraits::is_always_equal::value)
+ { __lhs.swap(__rhs); }
+
+ private:
+ template<typename _Up, typename... _Args>
+ static constexpr typename _Obj::pointer
+ _S_make_obj(const _Alloc& __a, _Args&&... __args)
+ {
+ __alloc_rebind<_Alloc, _Obj_impl<_Up>> __objalloc(__a);
+ _Scoped_allocation __sa(__objalloc, in_place, __objalloc,
+ std::forward<_Args>(__args)...);
+ auto __obj = __sa.release();
+ // FIXME: We need to downcast from _Obj_impl<U>* to _Obj* but the
+ // the pointer_traits usage breaks in constexpr. PR c++/110714
+ if constexpr (is_pointer_v<typename _Obj::pointer>)
+ return __obj;
+ else
+ return pointer_traits<typename _Obj::pointer>::pointer_to(*__obj);
+ }
+
+ template<typename _Up, typename... _Args>
+ constexpr typename _Obj::pointer
+ _M_make_obj(_Args&&... __args) const
+ { return _S_make_obj<_Up>(_M_alloc, std::forward<_Args>(__args)...); }
+
+ constexpr void
+ _M_reset(typename _Obj::pointer __ptr) noexcept
+ {
+ if (_M_objp)
+ _M_objp->_M_manage(_M_alloc, _Obj::_Op::_Dispose);
+ _M_objp = __ptr;
+ }
+
+ [[no_unique_address]] _Alloc _M_alloc = _Alloc();
+ typename _Obj::pointer _M_objp;
+ };
+#endif // __glibcxx_polymorphic
+
+_GLIBCXX_END_NAMESPACE_VERSION
} // namespace
#endif // C++26 __glibcxx_indirect || __glibcxx_polymorphic
diff --git a/libstdc++-v3/include/bits/mofunc_impl.h b/libstdc++-v3/include/bits/mofunc_impl.h
index 1ceb910..468e685 100644
--- a/libstdc++-v3/include/bits/mofunc_impl.h
+++ b/libstdc++-v3/include/bits/mofunc_impl.h
@@ -64,6 +64,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_MOF_REF noexcept(_Noex)>
: __polyfunc::_Mo_base
{
+ static_assert(
+ (std::__is_complete_or_unbounded(__type_identity<_ArgTypes>()) && ...),
+ "each parameter type must be a complete class");
+
using _Base = __polyfunc::_Mo_base;
using _Invoker = __polyfunc::_Invoker<_Noex, _Res, _ArgTypes...>;
using _Signature = _Invoker::_Signature;
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
index f36e7dd..7b14084 100644
--- a/libstdc++-v3/include/bits/ranges_algo.h
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -1218,6 +1218,9 @@ namespace ranges
if (__first == __last)
return {std::move(__first), std::move(__result)};
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4269. unique_copy passes arguments to its predicate backwards
+
// TODO: perform a closer comparison with reference implementations
if constexpr (forward_iterator<_Iter>)
{
@@ -1250,8 +1253,8 @@ namespace ranges
while (++__first != __last)
{
if (!(bool)std::__invoke(__comp,
- std::__invoke(__proj, *__first),
- std::__invoke(__proj, __value)))
+ std::__invoke(__proj, __value),
+ std::__invoke(__proj, *__first)))
{
__value = *__first;
*++__result = __value;
diff --git a/libstdc++-v3/include/bits/stl_algo.h b/libstdc++-v3/include/bits/stl_algo.h
index f5361ae..98c2249 100644
--- a/libstdc++-v3/include/bits/stl_algo.h
+++ b/libstdc++-v3/include/bits/stl_algo.h
@@ -918,52 +918,45 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__gnu_cxx::__ops::__iter_comp_iter(__binary_pred));
}
- /**
- * This is an uglified
- * unique_copy(_InputIterator, _InputIterator, _OutputIterator,
- * _BinaryPredicate)
- * overloaded for forward iterators and output iterator as result.
- */
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 4269. unique_copy passes arguments to its predicate backwards
+
+ // Implementation of std::unique_copy for forward iterators.
+ // This case is easy, just compare *i with *(i-1).
template<typename _ForwardIterator, typename _OutputIterator,
typename _BinaryPredicate>
_GLIBCXX20_CONSTEXPR
_OutputIterator
__unique_copy(_ForwardIterator __first, _ForwardIterator __last,
_OutputIterator __result, _BinaryPredicate __binary_pred,
- forward_iterator_tag, output_iterator_tag)
+ forward_iterator_tag)
{
- _ForwardIterator __next = __first;
+ _ForwardIterator __prev = __first;
*__result = *__first;
- while (++__next != __last)
- if (!__binary_pred(__first, __next))
+ while (++__first != __last)
+ if (!__binary_pred(__prev, __first))
{
- __first = __next;
*++__result = *__first;
+ __prev = __first;
}
return ++__result;
}
- /**
- * This is an uglified
- * unique_copy(_InputIterator, _InputIterator, _OutputIterator,
- * _BinaryPredicate)
- * overloaded for input iterators and output iterator as result.
- */
+ // Implementation of std::unique_copy for non-forward iterators,
+ // where we cannot compare with elements written to the output.
template<typename _InputIterator, typename _OutputIterator,
typename _BinaryPredicate>
_GLIBCXX20_CONSTEXPR
_OutputIterator
- __unique_copy(_InputIterator __first, _InputIterator __last,
- _OutputIterator __result, _BinaryPredicate __binary_pred,
- input_iterator_tag, output_iterator_tag)
+ __unique_copy_1(_InputIterator __first, _InputIterator __last,
+ _OutputIterator __result, _BinaryPredicate __binary_pred,
+ __false_type)
{
- typename iterator_traits<_InputIterator>::value_type __value = *__first;
- __decltype(__gnu_cxx::__ops::__iter_comp_val(__binary_pred))
- __rebound_pred
- = __gnu_cxx::__ops::__iter_comp_val(__binary_pred);
+ typedef typename iterator_traits<_InputIterator>::value_type _Val;
+ _Val __value = *__first;
*__result = __value;
while (++__first != __last)
- if (!__rebound_pred(__first, __value))
+ if (!__binary_pred(std::__addressof(__value), __first))
{
__value = *__first;
*++__result = __value;
@@ -971,19 +964,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return ++__result;
}
- /**
- * This is an uglified
- * unique_copy(_InputIterator, _InputIterator, _OutputIterator,
- * _BinaryPredicate)
- * overloaded for input iterators and forward iterator as result.
- */
+ // Implementation of std::unique_copy for non-forward iterators,
+ // where we can compare with the last element written to the output.
template<typename _InputIterator, typename _ForwardIterator,
typename _BinaryPredicate>
- _GLIBCXX20_CONSTEXPR
_ForwardIterator
- __unique_copy(_InputIterator __first, _InputIterator __last,
- _ForwardIterator __result, _BinaryPredicate __binary_pred,
- input_iterator_tag, forward_iterator_tag)
+ __unique_copy_1(_InputIterator __first, _InputIterator __last,
+ _ForwardIterator __result, _BinaryPredicate __binary_pred,
+ __true_type)
{
*__result = *__first;
while (++__first != __last)
@@ -992,6 +980,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return ++__result;
}
+ // Implementation of std::unique_copy for non-forward iterators.
+ // We cannot compare *i to *(i-1) so we need to either make a copy
+ // or compare with the last element written to the output range.
+ template<typename _InputIterator, typename _OutputIterator,
+ typename _BinaryPredicate>
+ _GLIBCXX20_CONSTEXPR
+ _OutputIterator
+ __unique_copy(_InputIterator __first, _InputIterator __last,
+ _OutputIterator __result, _BinaryPredicate __binary_pred,
+ input_iterator_tag)
+ {
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2439. unique_copy() sometimes can't fall back to reading its output
+ typedef iterator_traits<_InputIterator> _InItTraits;
+ typedef iterator_traits<_OutputIterator> _OutItTraits;
+ typedef typename _OutItTraits::iterator_category _Cat;
+ const bool __output_is_fwd = __is_base_of(forward_iterator_tag, _Cat);
+ const bool __same_type = __is_same(typename _OutItTraits::value_type,
+ typename _InItTraits::value_type);
+ typedef __truth_type<__output_is_fwd && __same_type> __cmp_with_output;
+ return std::__unique_copy_1(__first, __last, __result, __binary_pred,
+ typename __cmp_with_output::__type());
+ }
+
+
/**
* This is an uglified reverse(_BidirectionalIterator,
* _BidirectionalIterator)
@@ -4456,8 +4469,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
return __result;
return std::__unique_copy(__first, __last, __result,
__gnu_cxx::__ops::__iter_equal_to_iter(),
- std::__iterator_category(__first),
- std::__iterator_category(__result));
+ std::__iterator_category(__first));
}
/**
@@ -4499,8 +4511,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
return __result;
return std::__unique_copy(__first, __last, __result,
__gnu_cxx::__ops::__iter_comp_iter(__binary_pred),
- std::__iterator_category(__first),
- std::__iterator_category(__result));
+ std::__iterator_category(__first));
}
#if __cplusplus <= 201103L || _GLIBCXX_USE_DEPRECATED
diff --git a/libstdc++-v3/include/bits/stl_deque.h b/libstdc++-v3/include/bits/stl_deque.h
index 8d8ee57..7055641 100644
--- a/libstdc++-v3/include/bits/stl_deque.h
+++ b/libstdc++-v3/include/bits/stl_deque.h
@@ -1331,7 +1331,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{
size_type __sz = this->_M_impl._M_finish - this->_M_impl._M_start;
if (__sz > max_size ())
- __builtin_unreachable ();
+ __builtin_unreachable();
return __sz;
}
diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h
index 625c1c9..f2c1bce 100644
--- a/libstdc++-v3/include/bits/stl_vector.h
+++ b/libstdc++-v3/include/bits/stl_vector.h
@@ -372,8 +372,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_GLIBCXX20_CONSTEXPR
~_Vector_base() _GLIBCXX_NOEXCEPT
{
- _M_deallocate(_M_impl._M_start,
- _M_impl._M_end_of_storage - _M_impl._M_start);
+ ptrdiff_t __n = _M_impl._M_end_of_storage - _M_impl._M_start;
+ if (__n < 0)
+ __builtin_unreachable();
+ _M_deallocate(_M_impl._M_start, size_t(__n));
}
public:
@@ -1106,7 +1108,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{
ptrdiff_t __dif = this->_M_impl._M_finish - this->_M_impl._M_start;
if (__dif < 0)
- __builtin_unreachable ();
+ __builtin_unreachable();
return size_type(__dif);
}
@@ -1198,7 +1200,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
ptrdiff_t __dif = this->_M_impl._M_end_of_storage
- this->_M_impl._M_start;
if (__dif < 0)
- __builtin_unreachable ();
+ __builtin_unreachable();
return size_type(__dif);
}
diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc
index e18f01a..70ead1d 100644
--- a/libstdc++-v3/include/bits/vector.tcc
+++ b/libstdc++-v3/include/bits/vector.tcc
@@ -466,7 +466,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{
const size_type __len = _M_check_len(1u, "vector::_M_realloc_insert");
if (__len <= 0)
- __builtin_unreachable ();
+ __builtin_unreachable();
pointer __old_start = this->_M_impl._M_start;
pointer __old_finish = this->_M_impl._M_finish;
const size_type __elems_before = __position - begin();
@@ -573,10 +573,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{
const size_type __len = _M_check_len(1u, "vector::_M_realloc_append");
if (__len <= 0)
- __builtin_unreachable ();
+ __builtin_unreachable();
pointer __old_start = this->_M_impl._M_start;
pointer __old_finish = this->_M_impl._M_finish;
- const size_type __elems = end() - begin();
+ const size_type __elems = size();
pointer __new_start(this->_M_allocate(__len));
pointer __new_finish(__new_start);
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 9ab14a0..5efe4d1 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1978,6 +1978,15 @@ ftms = {
};
};
+ftms = {
+ name = polymorphic;
+ values = {
+ v = 202502;
+ cxxmin = 26;
+ hosted = yes;
+ };
+};
+
// Standard test specifications.
stds[97] = ">= 199711L";
stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index 3358e84..5e905da 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2213,4 +2213,14 @@
#endif /* !defined(__cpp_lib_indirect) && defined(__glibcxx_want_indirect) */
#undef __glibcxx_want_indirect
+#if !defined(__cpp_lib_polymorphic)
+# if (__cplusplus > 202302L) && _GLIBCXX_HOSTED
+# define __glibcxx_polymorphic 202502L
+# if defined(__glibcxx_want_all) || defined(__glibcxx_want_polymorphic)
+# define __cpp_lib_polymorphic 202502L
+# endif
+# endif
+#endif /* !defined(__cpp_lib_polymorphic) && defined(__glibcxx_want_polymorphic) */
+#undef __glibcxx_want_polymorphic
+
#undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit
index 5187c96..fd75edf 100644
--- a/libstdc++-v3/include/std/bit
+++ b/libstdc++-v3/include/std/bit
@@ -166,7 +166,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Variant for power of two _Nd which the compiler can
// easily pattern match.
constexpr unsigned __uNd = _Nd;
- const unsigned __r = __s;
+ const auto __r = static_cast<unsigned>(__s);
return (__x << (__r % __uNd)) | (__x >> ((-__r) % __uNd));
}
const int __r = __s % _Nd;
@@ -188,7 +188,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Variant for power of two _Nd which the compiler can
// easily pattern match.
constexpr unsigned __uNd = _Nd;
- const unsigned __r = __s;
+ const auto __r = static_cast<unsigned>(__s);
return (__x >> (__r % __uNd)) | (__x << ((-__r) % __uNd));
}
const int __r = __s % _Nd;
diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory
index d64e65c..1da03b3 100644
--- a/libstdc++-v3/include/std/memory
+++ b/libstdc++-v3/include/std/memory
@@ -113,6 +113,7 @@
#define __glibcxx_want_make_unique
#define __glibcxx_want_out_ptr
#define __glibcxx_want_parallel_algorithm
+#define __glibcxx_want_polymorphic
#define __glibcxx_want_ranges
#define __glibcxx_want_raw_memory_algorithms
#define __glibcxx_want_shared_ptr_arrays
diff --git a/libstdc++-v3/include/std/stop_token b/libstdc++-v3/include/std/stop_token
index 1225b3a..775ec6a 100644
--- a/libstdc++-v3/include/std/stop_token
+++ b/libstdc++-v3/include/std/stop_token
@@ -34,8 +34,7 @@
#define __glibcxx_want_jthread
#include <bits/version.h>
-#if __cplusplus > 201703L
-
+#ifdef __glibcxx_jthread // C++ >= 20
#include <atomic>
#include <bits/std_thread.h>
@@ -650,6 +649,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
stop_callback(stop_token, _Callback) -> stop_callback<_Callback>;
_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace
-#endif // __cplusplus > 201703L
+} // namespace std
+#endif // __glibcxx_jthread
#endif // _GLIBCXX_STOP_TOKEN
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index 6bf355d..c8907fe 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -1039,6 +1039,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Destructible and constructible type properties.
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible)
+ /// is_destructible
+ template<typename _Tp>
+ struct is_destructible
+ : public __bool_constant<__is_destructible(_Tp)>
+ { };
+#else
// In N3290 is_destructible does not say anything about function
// types and abstract types, see LWG 2049. This implementation
// describes function types as non-destructible and all complete
@@ -1090,7 +1097,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
"template argument must be a complete class or an unbounded array");
};
+#endif
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible)
+ /// is_nothrow_destructible
+ template<typename _Tp>
+ struct is_nothrow_destructible
+ : public __bool_constant<__is_nothrow_destructible(_Tp)>
+ { };
+#else
/// @cond undocumented
// is_nothrow_destructible requires that is_destructible is
@@ -1144,6 +1159,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
"template argument must be a complete class or an unbounded array");
};
+#endif
/// @cond undocumented
template<typename _Tp, typename... _Args>
@@ -1451,6 +1467,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"template argument must be a complete class or an unbounded array");
};
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible)
+ /// is_trivially_destructible
+ template<typename _Tp>
+ struct is_trivially_destructible
+ : public __bool_constant<__is_trivially_destructible(_Tp)>
+ { };
+#else
/// is_trivially_destructible
template<typename _Tp>
struct is_trivially_destructible
@@ -1460,7 +1483,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
"template argument must be a complete class or an unbounded array");
};
-
+#endif
/// has_virtual_destructor
template<typename _Tp>
@@ -3581,8 +3604,13 @@ template <typename _Tp>
inline constexpr bool is_move_assignable_v
= __is_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>);
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_destructible)
+template <typename _Tp>
+ inline constexpr bool is_destructible_v = __is_destructible(_Tp);
+#else
template <typename _Tp>
inline constexpr bool is_destructible_v = is_destructible<_Tp>::value;
+#endif
template <typename _Tp, typename... _Args>
inline constexpr bool is_trivially_constructible_v
@@ -3609,7 +3637,11 @@ template <typename _Tp>
= __is_trivially_assignable(__add_lval_ref_t<_Tp>,
__add_rval_ref_t<_Tp>);
-#if __cpp_concepts
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_trivially_destructible)
+template <typename _Tp>
+ inline constexpr bool is_trivially_destructible_v
+ = __is_trivially_destructible(_Tp);
+#elif __cpp_concepts
template <typename _Tp>
inline constexpr bool is_trivially_destructible_v = false;
@@ -3654,9 +3686,15 @@ template <typename _Tp>
inline constexpr bool is_nothrow_move_assignable_v
= __is_nothrow_assignable(__add_lval_ref_t<_Tp>, __add_rval_ref_t<_Tp>);
+#if _GLIBCXX_USE_BUILTIN_TRAIT(__is_nothrow_destructible)
+template <typename _Tp>
+ inline constexpr bool is_nothrow_destructible_v
+ = __is_nothrow_destructible(_Tp);
+#else
template <typename _Tp>
inline constexpr bool is_nothrow_destructible_v =
is_nothrow_destructible<_Tp>::value;
+#endif
template <typename _Tp>
inline constexpr bool has_virtual_destructor_v
diff --git a/libstdc++-v3/src/c++20/atomic.cc b/libstdc++-v3/src/c++20/atomic.cc
index a3ec92a..4120e1a 100644
--- a/libstdc++-v3/src/c++20/atomic.cc
+++ b/libstdc++-v3/src/c++20/atomic.cc
@@ -397,17 +397,18 @@ __cond_wait_until(__condvar& __cv, mutex& __mx,
}
#endif // ! HAVE_PLATFORM_TIMED_WAIT
-// Like __spin_impl, always returns _M_has_val == true.
+// Unlike __spin_impl, does not always return _M_has_val == true.
+// If the deadline has already passed then no fresh value is loaded.
__wait_result_type
__spin_until_impl(const __platform_wait_t* __addr,
const __wait_args_base& __args,
const __wait_clock_t::time_point& __deadline)
{
- auto __t0 = __wait_clock_t::now();
using namespace literals::chrono_literals;
- __platform_wait_t __val{};
- auto __now = __wait_clock_t::now();
+ __wait_result_type __res{};
+ auto __t0 = __wait_clock_t::now();
+ auto __now = __t0;
for (; __now < __deadline; __now = __wait_clock_t::now())
{
auto __elapsed = __now - __t0;
@@ -422,16 +423,21 @@ __spin_until_impl(const __platform_wait_t* __addr,
__thread_yield();
else
{
- auto __res = __detail::__spin_impl(__addr, __args);
+ __res = __detail::__spin_impl(__addr, __args);
if (!__res._M_timeout)
return __res;
}
- __atomic_load(__addr, &__val, __args._M_order);
- if (__val != __args._M_old)
- return { ._M_val = __val, ._M_has_val = true, ._M_timeout = false };
+ __atomic_load(__addr, &__res._M_val, __args._M_order);
+ __res._M_has_val = true;
+ if (__res._M_val != __args._M_old)
+ {
+ __res._M_timeout = false;
+ return __res;
+ }
}
- return { ._M_val = __val, ._M_has_val = true, ._M_timeout = true };
+ __res._M_timeout = true;
+ return __res;
}
} // namespace
diff --git a/libstdc++-v3/src/c++23/std.cc.in b/libstdc++-v3/src/c++23/std.cc.in
index ba46853..eddd3c8 100644
--- a/libstdc++-v3/src/c++23/std.cc.in
+++ b/libstdc++-v3/src/c++23/std.cc.in
@@ -511,7 +511,6 @@ export namespace std
}
// 22.7.2 <any>
-#if __cpp_lib_any
export namespace std
{
using std::any;
@@ -520,7 +519,6 @@ export namespace std
using std::make_any;
using std::swap;
}
-#endif
// 24.3.2 <array>
export namespace std
@@ -698,7 +696,6 @@ export namespace std
}
// 29.2 <chrono>
-#if __cpp_lib_chrono
export namespace std
{
namespace chrono
@@ -852,7 +849,6 @@ export namespace std::inline literals::inline chrono_literals
export namespace std::chrono {
using namespace literals::chrono_literals;
}
-#endif // __cpp_lib_chrono
// <codecvt>: deprecated C++17, removed C++26
export namespace std
@@ -864,7 +860,6 @@ export namespace std
}
// 17.11.1 <compare>
-#if __cpp_lib_three_way_comparison
export namespace std
{
using std::common_comparison_category;
@@ -890,7 +885,6 @@ export namespace std
using std::strong_order;
using std::weak_order;
}
-#endif // __cpp_lib_three_way_comparison
// 28.4 <complex>
export namespace std
@@ -944,7 +938,6 @@ export namespace std::inline literals::inline complex_literals
}
// 18 <concepts>
-#if __cpp_lib_concepts
export namespace std
{
using std::assignable_from;
@@ -983,7 +976,6 @@ export namespace std
using std::totally_ordered;
using std::totally_ordered_with;
}
-#endif
// 33.7 <condition_variable>
export namespace std
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/call.cc b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc
index cf99757..0ac5348 100644
--- a/libstdc++-v3/testsuite/20_util/copyable_function/call.cc
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/call.cc
@@ -204,13 +204,14 @@ test05()
}
struct Incomplete;
+enum CompleteEnum : int;
void
test_params()
{
- std::copyable_function<void(Incomplete)> f1;
- std::copyable_function<void(Incomplete&)> f2;
- std::copyable_function<void(Incomplete&&)> f3;
+ std::copyable_function<void(Incomplete&)> f1;
+ std::copyable_function<void(Incomplete&&)> f2;
+ std::copyable_function<void(CompleteEnum)> f4;
}
int main()
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc
index e678e16..11c839b 100644
--- a/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/conv.cc
@@ -2,6 +2,7 @@
// { dg-require-effective-target hosted }
#include <functional>
+#include <string_view>
#include <testsuite_hooks.h>
using std::copyable_function;
@@ -15,6 +16,21 @@ static_assert( !std::is_constructible_v<std::copyable_function<void()&>,
static_assert( !std::is_constructible_v<std::copyable_function<void() const>,
std::copyable_function<void()>> );
+using FuncType = int(int);
+
+// Top level const qualifiers are ignored and decay is performed in parameters
+// of function_types.
+static_assert( std::is_same_v<std::copyable_function<void(int const)>,
+ std::copyable_function<void(int)>> );
+static_assert( std::is_same_v<std::copyable_function<void(int[2])>,
+ std::copyable_function<void(int*)>>);
+static_assert( std::is_same_v<std::copyable_function<void(int[])>,
+ std::copyable_function<void(int*)>>);
+static_assert( std::is_same_v<std::copyable_function<void(int const[5])>,
+ std::copyable_function<void(int const*)>>);
+static_assert( std::is_same_v<std::copyable_function<void(FuncType)>,
+ std::copyable_function<void(FuncType*)>>);
+
// Non-trivial args, guarantess that type is not passed by copy
struct CountedArg
{
@@ -240,6 +256,24 @@ test06()
VERIFY( f2(c) == 2 );
}
+void
+test07()
+{
+ // Scalar types and small trivially move constructible types are passed
+ // by value to invoker. So int&& signature is not compatible for such types.
+ auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; };
+ std::copyable_function<int(CountedArg, int) const noexcept> ci1(fi);
+ VERIFY( ci1(c, 0) == 1 );
+ std::copyable_function<int(CountedArg, int&&) const noexcept> ci2(ci1);
+ VERIFY( ci2(c, 0) == 2 );
+
+ auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; };
+ std::copyable_function<int(CountedArg, std::string_view) const noexcept> cs1(fs);
+ VERIFY( cs1(c, "") == 1 );
+ std::copyable_function<int(CountedArg, std::string_view&&) const noexcept> cs2(cs1);
+ VERIFY( cs2(c, "") == 2 );
+}
+
int main()
{
test01();
@@ -248,4 +282,5 @@ int main()
test04();
test05();
test06();
+ test07();
}
diff --git a/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc
new file mode 100644
index 0000000..21ddde0
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/copyable_function/incomplete_neg.cc
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+
+struct IncompleteClass;
+
+using T1 = std::copyable_function<int(IncompleteClass)>::result_type; // { dg-error "here" }
+using T2 = std::copyable_function<int(int, IncompleteClass)>::result_type; // { dg-error "here" }
+
+enum Enum {
+ x = [] {
+ // Enum enumeration is incomplete here
+ using T3 = std::copyable_function<int(Enum)>::result_type; // { dg-error "here" }
+ return T3(1);
+ }()
+};
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/call.cc b/libstdc++-v3/testsuite/20_util/function_ref/call.cc
index a91c6b4..23253c3 100644
--- a/libstdc++-v3/testsuite/20_util/function_ref/call.cc
+++ b/libstdc++-v3/testsuite/20_util/function_ref/call.cc
@@ -164,16 +164,16 @@ test05()
}
struct Incomplete;
+enum CompleteEnum : int;
void
test_params()
{
auto f = [](auto&&) {};
- // There is discussion if this is supported.
- // std::function_ref<void(Incomplete)> f1(f);
- std::function_ref<void(Incomplete&)> f2(f);
- // See PR120259, this should be supported.
- // std::function_ref<void(Incomplete&&)> f3(f);
+ std::function_ref<void(Incomplete&)> f1(f);
+ // See PR libstdc++/120259, this should be supported.
+ // std::function_ref<void(Incomplete&&)> f2(f);
+ std::function_ref<void(CompleteEnum)> f3(f);
}
int main()
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/conv.cc b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc
index 7dc7b8c..7606d26 100644
--- a/libstdc++-v3/testsuite/20_util/function_ref/conv.cc
+++ b/libstdc++-v3/testsuite/20_util/function_ref/conv.cc
@@ -2,6 +2,7 @@
// { dg-require-effective-target hosted }
#include <functional>
+#include <string_view>
#include <testsuite_hooks.h>
using std::function_ref;
@@ -20,6 +21,21 @@ struct CountedArg
};
CountedArg const c;
+using FuncType = int(int);
+
+// Top level const qualifiers are ignored in function types, and decay
+// is performed.
+static_assert( std::is_same_v<std::function_ref<void(int const)>,
+ std::function_ref<void(int)>> );
+static_assert( std::is_same_v<std::function_ref<void(int[2])>,
+ std::function_ref<void(int*)>>);
+static_assert( std::is_same_v<std::function_ref<void(int[])>,
+ std::function_ref<void(int*)>>);
+static_assert( std::is_same_v<std::function_ref<void(int const[5])>,
+ std::function_ref<void(int const*)>>);
+static_assert( std::is_same_v<std::function_ref<void(FuncType)>,
+ std::function_ref<void(FuncType*)>>);
+
// The C++26 [func.wrap.general] p2 does not currently cover funciton_ref,
// so we make extra copies of arguments.
@@ -244,6 +260,23 @@ test08()
return true;
};
+void
+test09()
+{
+ // Scalar types and small trivially move constructible types are passed
+ // by value to invoker. So int&& signature is not compatible for such types.
+ auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; };
+ std::function_ref<int(CountedArg, int) const noexcept> ri1(fi);
+ VERIFY( ri1(c, 0) == 1 );
+ std::function_ref<int(CountedArg, int&&) const noexcept> ri2(ri1);
+ VERIFY( ri2(c, 0) == 2 );
+
+ auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; };
+ std::function_ref<int(CountedArg, std::string_view) const noexcept> rs1(fs);
+ VERIFY( rs1(c, "") == 1 );
+ std::function_ref<int(CountedArg, std::string_view&&) const noexcept> rs2(rs1);
+ VERIFY( rs2(c, "") == 2 );
+}
int main()
{
@@ -254,6 +287,7 @@ int main()
test05();
test06();
test07();
+ test09();
static_assert( test08() );
}
diff --git a/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc
new file mode 100644
index 0000000..c8db1ee
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function_ref/incomplete_neg.cc
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++26 } }
+
+#include <functional>
+
+struct IncompleteClass;
+
+int a1 = alignof(std::function_ref<int(IncompleteClass)>); // { dg-error "here" }
+int a2 = alignof(std::function_ref<int(int, IncompleteClass)>); // { dg-error "here" }
+
+enum Enum {
+ x = [] {
+ // Enum enumeration is incomplete here
+ int a3 = alignof(std::function_ref<int(Enum)>); // { dg-error "here" }
+ return 1;
+ }()
+};
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
index 217de37..72c8118 100644
--- a/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/call.cc
@@ -204,13 +204,14 @@ test05()
}
struct Incomplete;
+enum CompleteEnum : int;
void
test_params()
{
- std::move_only_function<void(Incomplete)> f1;
- std::move_only_function<void(Incomplete&)> f2;
- std::move_only_function<void(Incomplete&&)> f3;
+ std::move_only_function<void(Incomplete&)> f1;
+ std::move_only_function<void(Incomplete&&)> f2;
+ std::move_only_function<void(CompleteEnum)> f4;
}
int main()
diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc
index 3da5e9e..ef8bb37b 100644
--- a/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/conv.cc
@@ -2,6 +2,7 @@
// { dg-require-effective-target hosted }
#include <functional>
+#include <string_view>
#include <testsuite_hooks.h>
using std::move_only_function;
@@ -15,6 +16,21 @@ static_assert( !std::is_constructible_v<std::move_only_function<void()&>,
static_assert( !std::is_constructible_v<std::move_only_function<void() const>,
std::move_only_function<void()>> );
+using FuncType = int(int);
+
+// Top level const qualifiers are ignored in function types, and decay
+// is performed.
+static_assert( std::is_same_v<std::move_only_function<void(int const)>,
+ std::move_only_function<void(int)>> );
+static_assert( std::is_same_v<std::move_only_function<void(int[2])>,
+ std::move_only_function<void(int*)>>);
+static_assert( std::is_same_v<std::move_only_function<void(int[])>,
+ std::move_only_function<void(int*)>>);
+static_assert( std::is_same_v<std::move_only_function<void(int const[5])>,
+ std::move_only_function<void(int const*)>>);
+static_assert( std::is_same_v<std::move_only_function<void(FuncType)>,
+ std::move_only_function<void(FuncType*)>>);
+
// Non-trivial args, guarantess that type is not passed by copy
struct CountedArg
{
@@ -177,6 +193,24 @@ test06()
VERIFY( m1(c) == 2 );
}
+void
+test07()
+{
+ // Scalar types and small trivially move constructible types are passed
+ // by value to invoker. So int&& signature is not compatible for such types.
+ auto fi = [](CountedArg const& arg, int) noexcept { return arg.counter; };
+ std::move_only_function<int(CountedArg, int) const noexcept> mi1(fi);
+ VERIFY( mi1(c, 0) == 1 );
+ std::move_only_function<int(CountedArg, int&&) const noexcept> mi2(std::move(mi1));
+ VERIFY( mi2(c, 0) == 2 );
+
+ auto fs = [](CountedArg const& arg, std::string_view) noexcept { return arg.counter; };
+ std::move_only_function<int(CountedArg, std::string_view) const noexcept> ms1(fs);
+ VERIFY( ms1(c, "") == 1 );
+ std::move_only_function<int(CountedArg, std::string_view&&) const noexcept> ms2(std::move(ms1));
+ VERIFY( ms2(c, "") == 2 );
+}
+
int main()
{
test01();
@@ -185,4 +219,5 @@ int main()
test04();
test05();
test06();
+ test07();
}
diff --git a/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc b/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc
new file mode 100644
index 0000000..d025c47
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/move_only_function/incomplete_neg.cc
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++23 } }
+
+#include <functional>
+
+struct IncompleteClass;
+
+using T1 = std::move_only_function<int(IncompleteClass)>::result_type; // { dg-error "here" }
+using T2 = std::move_only_function<int(int, IncompleteClass)>::result_type; // { dg-error "here" }
+
+enum Enum {
+ x = [] {
+ // Enum enumeration is incomplete here
+ using T3 = std::move_only_function<int(Enum)>::result_type; // { dg-error "here" }
+ return T3(1);
+ }()
+};
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc b/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc
new file mode 100644
index 0000000..f2ec3e3
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/unique_copy/lwg2439.cc
@@ -0,0 +1,127 @@
+// { dg-do run }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+using namespace __gnu_test;
+
+int out[4];
+short out_shrt[4];
+short in[7] = { 1, 2, 2, 2, 3, 4, 4 };
+
+template<typename T>
+void
+check_and_reset(T* p)
+{
+ VERIFY( p[0] == 1 );
+ VERIFY( p[1] == 2 );
+ VERIFY( p[2] == 3 );
+ VERIFY( p[3] == 4 );
+ std::fill_n(p, 4, 0);
+}
+
+struct Eq
+{
+ bool operator()(short i, short j) const { return i == j; }
+ bool operator()(short, int) const { VERIFY(false); }
+ bool operator()(int, short) const { VERIFY(false); }
+};
+
+struct Eq2
+{
+ bool operator()(const short& i, const short& j) const
+ {
+ // Both arguments should be elements of the 'in' array.
+ VERIFY( in+0 <= &i && &i < in+7 );
+ VERIFY( in+0 <= &j && &j < in+7 );
+ VERIFY( &i < &j );
+ return i == j;
+ }
+ bool operator()(short, int) const { VERIFY(false); }
+ bool operator()(int, short) const { VERIFY(false); }
+};
+
+struct Eq3
+{
+ bool operator()(const short& i, const short& j) const
+ {
+ // First argument should be element of the 'out' array.
+ // Second argument should be element of the 'in' array.
+ VERIFY( out_shrt+0 <= &i && &i < out_shrt+4 );
+ VERIFY( in+0 <= &j && &j < in+7 );
+ return i == j;
+ }
+ bool operator()(short, int) const { VERIFY(false); }
+ bool operator()(int, short) const { VERIFY(false); }
+};
+
+void
+test_forward_source()
+{
+ // The input range uses forward iterators
+ test_container<short, forward_iterator_wrapper> inc(in);
+ test_container<int, output_iterator_wrapper> outc(out);
+ std::unique_copy(inc.begin(), inc.end(), outc.begin());
+ check_and_reset(out);
+
+ test_container<short, forward_iterator_wrapper> inc2(in);
+ test_container<int, output_iterator_wrapper> outc2(out);
+ std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq2());
+ check_and_reset(out);
+}
+
+void
+test_output_dest()
+{
+ // The input range uses input iterators.
+ // The output range uses output iterators.
+ test_container<short, input_iterator_wrapper> inc(in);
+ test_container<int, output_iterator_wrapper> outc(out);
+ std::unique_copy(inc.begin(), inc.end(), outc.begin());
+ check_and_reset(out);
+
+ test_container<short, input_iterator_wrapper> inc2(in);
+ test_container<int, output_iterator_wrapper> outc2(out);
+ std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq());
+ check_and_reset(out);
+}
+
+void
+test_forward_dest_diff_type()
+{
+ // The input range uses input iterators.
+ // The output range uses forward iterators, but with different value type.
+ test_container<short, input_iterator_wrapper> inc(in);
+ test_container<int, forward_iterator_wrapper> outc(out);
+ std::unique_copy(inc.begin(), inc.end(), outc.begin());
+ check_and_reset(out);
+
+ test_container<short, input_iterator_wrapper> inc2(in);
+ test_container<int, forward_iterator_wrapper> outc2(out);
+ std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq());
+ check_and_reset(out);
+}
+
+void
+test_forward_dest_same_type()
+{
+ // The input range uses input iterators.
+ // The output range uses forward iterators, with same value type.
+ test_container<short, input_iterator_wrapper> inc(in);
+ test_container<short, forward_iterator_wrapper> outc(out_shrt);
+ std::unique_copy(inc.begin(), inc.end(), outc.begin());
+ check_and_reset(out_shrt);
+
+ test_container<short, input_iterator_wrapper> inc2(in);
+ test_container<short, forward_iterator_wrapper> outc2(out_shrt);
+ std::unique_copy(inc2.begin(), inc2.end(), outc2.begin(), Eq3());
+ check_and_reset(out_shrt);
+}
+
+int main()
+{
+ test_forward_source();
+ test_output_dest();
+ test_forward_dest_diff_type();
+ test_forward_dest_same_type();
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc
new file mode 100644
index 0000000..bea05ac
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy.cc
@@ -0,0 +1,157 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+struct Derived : Base
+{
+ constexpr Derived()
+ : x(0), y(0), z(0)
+ { }
+
+ constexpr Derived(int a, int b, int c)
+ : x(a), y(b), z(c)
+ { }
+
+private:
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const Derived*>(&other))
+ return this->x == op->x && this->y == op->y && this->z == op->z;
+ return false;
+ }
+
+ int x;
+ int y;
+ int z;
+};
+
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+using Polymorhic = std::polymorphic<Base, tracker_allocator<Base>>;
+const Polymorhic src(std::in_place_type<Derived>, 1, 2, 3);
+
+constexpr void
+test_ctor()
+{
+ Counter::reset();
+ Polymorhic i1(src);
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Counter::reset();
+ Polymorhic i2(std::allocator_arg, {}, src);
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_assign()
+{
+ Counter::reset();
+ Polymorhic i1(std::in_place_type<Derived>);
+ const size_t holderSize = Counter::get_allocation_count();
+ VERIFY( holderSize >= sizeof(Derived) );
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ auto(std::move(i1));
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_valueless()
+{
+ Polymorhic e(std::in_place_type<Derived>);
+ auto(std::move(e));
+ VERIFY( e.valueless_after_move() );
+
+ Counter::reset();
+ Polymorhic i1(e);
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorhic i2(std::allocator_arg, {}, e);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorhic i3(src);
+ Counter::reset();
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Counter::reset();
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_all()
+{
+ test_ctor();
+ test_assign();
+ test_valueless();
+}
+
+int main()
+{
+ test_all();
+
+ static_assert([] {
+ test_all();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc
new file mode 100644
index 0000000..f41c32e
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/copy_alloc.cc
@@ -0,0 +1,270 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+ virtual constexpr int
+ get_alloc_personality() const
+ { return -1; }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+template<typename T, typename Allocator>
+struct VecDerived : Base, std::vector<T, Allocator>
+{
+ using VecBase = std::vector<T, Allocator>;
+
+ using VecBase::VecBase;
+
+ constexpr int
+ get_alloc_personality() const override
+ { return this->get_allocator().get_personality(); }
+
+private:
+
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const VecDerived*>(&other))
+ return *static_cast<const VecBase*>(this)
+ == *static_cast<const VecBase*>(op);
+ return false;
+ }
+};
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+
+template<bool Propagate>
+constexpr void
+test_ctor()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic src(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>, {1, 2, 3});
+
+ Counter::reset();
+ Polymorphic i1(src);
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i1->get_alloc_personality() == 0 );
+ VERIFY( i1.get_allocator().get_personality() == 0 );
+ }
+ VERIFY( Counter::get_allocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+
+ Counter::reset();
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, src);
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_assign()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic src(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>, {1, 2, 3});
+
+ Counter::reset();
+ Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ const size_t holderSize = Counter::get_allocation_count();
+ VERIFY( holderSize >= sizeof(Vector) );
+ Counter::reset();
+
+ i1 = src;
+ VERIFY( *i1 == *src );
+ VERIFY( &*i1 != &*src );
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44});
+ Counter::reset();
+
+ i2 = src;
+ VERIFY( *i2 == *src );
+ VERIFY( &*i2 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i2->get_alloc_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ }
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{11, 22});
+ auto(std::move(i3));
+ Counter::reset();
+
+ i3 = src;
+ VERIFY( *i3 == *src );
+ VERIFY( &*i3 != &*src );
+ VERIFY( i3->get_alloc_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44});
+ auto(std::move(i4));
+ Counter::reset();
+
+ i4 = src;
+ VERIFY( *i4 == *src );
+ VERIFY( &*i4 != &*src );
+ if (Propagate)
+ {
+ VERIFY( i4->get_alloc_personality() == 22 );
+ VERIFY( i4.get_allocator().get_personality() == 11 );
+ }
+ else
+ {
+ VERIFY( i4->get_alloc_personality() == 44 );
+ VERIFY( i4.get_allocator().get_personality() == 33 );
+ }
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_valueless()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ Polymorphic e(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ auto(std::move(e));
+ VERIFY( e.valueless_after_move() );
+
+ Counter::reset();
+ Polymorphic i1(e);
+ VERIFY( i1.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i1.get_allocator().get_personality() == 0 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Counter::reset();
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, e);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44});
+ Counter::reset();
+
+ i3 = e;
+ VERIFY( i3.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Counter::reset();
+ i2 = e;
+ VERIFY( i2.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_all()
+{
+ test_ctor<Propagate>();
+ test_assign<Propagate>();
+ test_valueless<Propagate>();
+}
+
+int main()
+{
+ test_all<true>();
+ test_all<false>();
+
+ static_assert([] {
+ test_all<true>();
+ test_all<false>();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc
new file mode 100644
index 0000000..bb4c947
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor.cc
@@ -0,0 +1,190 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#ifndef __cpp_lib_polymorphic
+# error __cpp_lib_polymorphic feature test macro missing in <memory>
+#elif __cpp_lib_polymorphic != 202502
+# error __cpp_lib_polymorphic feature test macro has wrong value in <memory>
+#endif
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+using __gnu_test::uneq_allocator;
+using UneqAlloc = uneq_allocator<int>;
+using ScopedAlloc = std::scoped_allocator_adaptor<
+ uneq_allocator<std::vector<int, UneqAlloc>>,
+ UneqAlloc>;
+
+struct Obj
+{
+ int i;
+ char c[2];
+};
+
+constexpr void
+test_default_ctor()
+{
+ using __gnu_test::default_init_allocator;
+
+ std::polymorphic<Obj, default_init_allocator<Obj>> i1;
+ default_init_allocator<int> a{};
+
+ // The contained object and the allocator should be value-initialized.
+ VERIFY( i1->i == 0 );
+ VERIFY( i1->c[0] == 0 );
+ VERIFY( i1->c[1] == 0 );
+ VERIFY( i1.get_allocator() == a );
+
+ a.state = 5;
+ // Allocator-extended default constructor:
+ std::polymorphic<Obj, default_init_allocator<Obj>> i2(std::allocator_arg, a);
+ VERIFY( i2.get_allocator() == a );
+
+ // Object is constructed using allocator-aware constructor.
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i3(std::allocator_arg, ScopedAlloc(11, 22));
+ VERIFY( i3->empty() );
+ VERIFY( i3->get_allocator().get_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+}
+
+constexpr void
+test_forwarding_ctor()
+{
+ Obj obj{1, {'2', '3'}};
+ auto verify = [](std::polymorphic<Obj> const& i)
+ {
+ VERIFY( i->i == 1 );
+ VERIFY( i->c[0] == '2' );
+ VERIFY( i->c[1] == '3' );
+ };
+
+ std::polymorphic<Obj> i1(std::as_const(obj));
+ verify(i1);
+ std::polymorphic<Obj> i2(std::move(std::as_const(obj)));
+ verify(i2);
+ std::polymorphic<Obj> i3(obj);
+ verify(i3);
+ std::polymorphic<Obj> i4(std::move(obj));
+ verify(i4);
+
+ std::polymorphic<Obj> i5({1, {'2', '3'}});
+ verify(i5);
+
+ std::vector<int, UneqAlloc> v{1, 2, 3, 4, 5};
+ // Object is constructed using allocator-aware constructor.
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i7(std::allocator_arg, ScopedAlloc(11, 22), v);
+ VERIFY( i7->size() == 5 );
+ VERIFY( v.size() == 5 );
+ VERIFY( i7->get_allocator().get_personality() == 22 );
+ VERIFY( i7.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i8(std::allocator_arg, ScopedAlloc(11, 22), std::move(v));
+ VERIFY( i8->size() == 5 );
+ VERIFY( v.size() == 0 );
+ VERIFY( i8->get_allocator().get_personality() == 22 );
+ VERIFY( i8.get_allocator().get_personality() == 11 );
+}
+
+constexpr void
+test_inplace_ctor()
+{
+ std::polymorphic<Obj> i1(std::in_place_type<Obj>);
+ VERIFY( i1->i == 0 );
+ VERIFY( i1->c[0] == 0 );
+ VERIFY( i1->c[1] == 0 );
+
+ std::polymorphic<Obj> i2(std::in_place_type<Obj>, 10);
+ VERIFY( i2->i == 10 );
+ VERIFY( i2->c[0] == 0 );
+ VERIFY( i2->c[1] == 0 );
+
+ std::polymorphic<Obj, uneq_allocator<Obj>>
+ i3(std::allocator_arg, 42, std::in_place_type<Obj>);
+ VERIFY( i3->i == 0 );
+ VERIFY( i3->c[0] == 0 );
+ VERIFY( i3->c[1] == 0 );
+ VERIFY( i3.get_allocator().get_personality() == 42 );
+
+ std::polymorphic<Obj, uneq_allocator<Obj>>
+ i4(std::allocator_arg, 42, std::in_place_type<Obj>, 10);
+ VERIFY( i4->i == 10 );
+ VERIFY( i4->c[0] == 0 );
+ VERIFY( i4->c[1] == 0 );
+ VERIFY( i4.get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int>>
+ i5(std::in_place_type<std::vector<int>>);
+ VERIFY( i5->size() == 0 );
+
+ std::polymorphic<std::vector<int>>
+ i6(std::in_place_type<std::vector<int>>, 5, 13);
+ VERIFY( i6->size() == 5 );
+ VERIFY( i6->at(0) == 13 );
+
+ std::polymorphic<std::vector<int>>
+ i7(std::in_place_type<std::vector<int>>, {1, 2, 3, 4});
+ VERIFY( i7->size() == 4 );
+ VERIFY( i7->at(2) == 3 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>>
+ i8(std::in_place_type<std::vector<int, UneqAlloc>>, UneqAlloc{42});
+ VERIFY( i8->size() == 0 );
+ VERIFY( i8->get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>>
+ i9(std::in_place_type<std::vector<int, UneqAlloc>>, 5, 13, UneqAlloc{42});
+ VERIFY( i9->size() == 5 );
+ VERIFY( i9->at(0) == 13 );
+ VERIFY( i9->get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>>
+ i10(std::in_place_type<std::vector<int, UneqAlloc>>, {1, 2, 3, 4}, UneqAlloc{42});
+ VERIFY( i10->size() == 4 );
+ VERIFY( i10->at(2) == 3 );
+ VERIFY( i10->get_allocator().get_personality() == 42 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i14(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<std::vector<int, UneqAlloc>>);
+ VERIFY( i14->size() == 0 );
+ VERIFY( i14->get_allocator().get_personality() == 22 );
+ VERIFY( i14.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i15(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<std::vector<int, UneqAlloc>>, 5, 13);
+ VERIFY( i15->size() == 5 );
+ VERIFY( i15->at(0) == 13 );
+ VERIFY( i15->get_allocator().get_personality() == 22 );
+ VERIFY( i15.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<std::vector<int, UneqAlloc>, ScopedAlloc>
+ i16(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<std::vector<int, UneqAlloc>>, {1, 2, 3, 4});
+ VERIFY( i16->size() == 4 );
+ VERIFY( i16->at(2) == 3 );
+ VERIFY( i16->get_allocator().get_personality() == 22 );
+ VERIFY( i16.get_allocator().get_personality() == 11 );
+}
+
+int main()
+{
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+
+ static_assert([] {
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc
new file mode 100644
index 0000000..03519a1
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/ctor_poly.cc
@@ -0,0 +1,220 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+
+#ifndef __cpp_lib_polymorphic
+# error __cpp_lib_polymorphic feature test macro missing in <memory>
+#elif __cpp_lib_polymorphic != 202502
+# error __cpp_lib_polymorphic feature test macro has wrong value in <memory>
+#endif
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+ virtual constexpr int
+ get_personality() const
+ { return -1; }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const
+ { return true; }
+};
+
+struct ObjDerived : Base
+{
+ constexpr ObjDerived()
+ : x(0), y(0), z(0)
+ { }
+
+ constexpr ObjDerived(int a, int b, int c)
+ : x(a), y(b), z(c)
+ { }
+
+ virtual constexpr int
+ get_personality() const
+ { return -2; }
+
+private:
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const ObjDerived*>(&other))
+ return this->x == op->x && this->y == op->y && this->z == op->z;
+ return false;
+ }
+
+ int x;
+ int y;
+ int z;
+};
+
+template<typename T, typename Allocator>
+struct VecDerived : Base, std::vector<T, Allocator>
+{
+ using VecBase = std::vector<T, Allocator>;
+
+ using VecBase::VecBase;
+
+ constexpr int
+ get_personality() const override
+ { return this->get_allocator().get_personality(); }
+
+private:
+
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const VecDerived*>(&other))
+ return *static_cast<const VecBase*>(this)
+ == *static_cast<const VecBase*>(op);
+ return false;
+ }
+};
+
+using __gnu_test::uneq_allocator;
+using UneqAlloc = uneq_allocator<int>;
+using ScopedAlloc = std::scoped_allocator_adaptor<
+ uneq_allocator<Base>,
+ UneqAlloc>;
+
+constexpr void
+test_default_ctor()
+{
+ using __gnu_test::default_init_allocator;
+
+ std::polymorphic<Base, default_init_allocator<Base>> i1;
+ default_init_allocator<int> a{};
+
+ // The contained object and the allocator should be value-initialized.
+ VERIFY( *i1 == Base() );
+ VERIFY( i1->get_personality() == -1 );
+ VERIFY( i1.get_allocator() == a );
+
+ a.state = 5;
+ // Allocator-extended default constructor:
+ std::polymorphic<Base, default_init_allocator<Base>> i2(std::allocator_arg, a);
+ VERIFY( *i1 == Base() );
+ VERIFY( i1->get_personality() == -1 );
+}
+
+constexpr void
+test_forwarding_ctor()
+{
+ const ObjDerived src(1, 2, 3);
+
+ std::polymorphic<Base> i1(src);
+ VERIFY( *i1 == src );
+ VERIFY( i1->get_personality() == -2 );
+ std::polymorphic<Base> i2(std::move(src));
+ VERIFY( *i2 == src );
+ VERIFY( i2->get_personality() == -2 );
+
+ ObjDerived obj = src;
+ std::polymorphic<Base> i3(obj);
+ VERIFY( *i3 == src );
+ VERIFY( i3->get_personality() == -2 );
+ std::polymorphic<Base> i4(std::move(obj));
+ VERIFY( *i4 == src );
+ VERIFY( i4->get_personality() == -2 );
+
+ const VecDerived<int, UneqAlloc> v{1, 2, 3, 4, 5};
+ // Object is constructed using allocator-aware constructor.
+ std::polymorphic<Base, ScopedAlloc>
+ i5(std::allocator_arg, ScopedAlloc(11, 22), v);
+ VERIFY( *i5 == v );
+ VERIFY( i5->get_personality() == 22 );
+ VERIFY( i5.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i6(std::allocator_arg, ScopedAlloc(11, 22), auto(v));
+ VERIFY( *i6 == v );
+ VERIFY( i6->get_personality() == 22 );
+ VERIFY( i6.get_allocator().get_personality() == 11 );
+}
+
+constexpr void
+test_inplace_ctor()
+{
+ std::polymorphic<Base> i1(std::in_place_type<ObjDerived>);
+ VERIFY( *i1 == ObjDerived() );
+ VERIFY( i1->get_personality() == -2 );
+
+ std::polymorphic<Base> i2(std::in_place_type<ObjDerived>, 10, 20, 30);
+ VERIFY( *i2 == ObjDerived(10, 20, 30) );
+ VERIFY( i2->get_personality() == -2 );
+
+ std::polymorphic<Base, uneq_allocator<Base>>
+ i3(std::allocator_arg, 42, std::in_place_type<ObjDerived>);
+ VERIFY( *i3 == ObjDerived() );
+ VERIFY( i3->get_personality() == -2 );
+ VERIFY( i3.get_allocator().get_personality() == 42 );
+
+ std::polymorphic<Base, uneq_allocator<Base>>
+ i4(std::allocator_arg, 42, std::in_place_type<ObjDerived>, 10, 20, 30);
+ VERIFY( *i4 == ObjDerived(10, 20, 30) );
+ VERIFY( i4->get_personality() == -2 );
+ VERIFY( i4.get_allocator().get_personality() == 42 );
+
+ const VecDerived<int, UneqAlloc> ze;
+ const VecDerived<int, UneqAlloc> fe(5, 13);
+ const VecDerived<int, UneqAlloc> il{1, 2, 3 ,4};
+
+ std::polymorphic<Base>
+ i5(std::in_place_type<VecDerived<int, UneqAlloc>>, UneqAlloc{42});
+ VERIFY( *i5 == ze );
+ VERIFY( i5->get_personality() == 42 );
+
+ std::polymorphic<Base>
+ i6(std::in_place_type<VecDerived<int, UneqAlloc>>, 5, 13, UneqAlloc{42});
+ VERIFY( *i6 == fe );
+ VERIFY( i6->get_personality() == 42 );
+
+ std::polymorphic<Base>
+ i7(std::in_place_type<VecDerived<int, UneqAlloc>>, {1, 2, 3, 4}, UneqAlloc{42});
+ VERIFY( *i7 == il );
+ VERIFY( i7->get_personality() == 42 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i8(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<VecDerived<int, UneqAlloc>>);
+ VERIFY( *i8 == ze );
+ VERIFY( i8->get_personality() == 22 );
+ VERIFY( i8.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i9(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<VecDerived<int, UneqAlloc>>, 5, 13);
+ VERIFY( *i9 == fe );
+ VERIFY( i9->get_personality() == 22 );
+ VERIFY( i9.get_allocator().get_personality() == 11 );
+
+ std::polymorphic<Base, ScopedAlloc>
+ i10(std::allocator_arg, ScopedAlloc(11, 22),
+ std::in_place_type<VecDerived<int, UneqAlloc>>, {1, 2, 3, 4});
+ VERIFY( *i10 == il );
+ VERIFY( i10->get_personality() == 22 );
+ VERIFY( i10.get_allocator().get_personality() == 11 );
+}
+
+int main()
+{
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+
+ static_assert([] {
+ test_default_ctor();
+ test_forwarding_ctor();
+ test_inplace_ctor();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc
new file mode 100644
index 0000000..e5dd78f
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/incomplete.cc
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++26 } }
+
+#include <memory>
+
+struct Incomplete;
+
+std::polymorphic<Incomplete>*
+test_move(std::polymorphic<Incomplete>& i1, std::polymorphic<Incomplete>& i2)
+{
+ i1 = std::move(i2);
+ swap(i1, i2);
+ return new std::polymorphic<Incomplete>(std::move(i1));
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc
new file mode 100644
index 0000000..a01af3f
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/invalid_neg.cc
@@ -0,0 +1,28 @@
+// { dg-do compile { target c++26 } }
+
+#include <memory>
+
+// In every specialization polymorphic<T, Allocator>, if the type
+// allocator_traits<Allocator>::value_type is not the same type as T,
+// the program is ill-formed.
+using T1 = std::polymorphic<int, std::allocator<long>>::value_type; // { dg-error "here" }
+
+// A program that instantiates the definition of the template
+// polymorphic<T, Allocator> with a type for the T parameter that is
+// a non-object type, an array type, in_place_t,
+// a specialization of in_place_type_t, or a cv-qualified type is ill-formed.
+
+using T2 = std::polymorphic<int&>::value_type; // { dg-error "here" }
+
+using T3 = std::polymorphic<int[1]>::value_type; // { dg-error "here" }
+
+using T4 = std::polymorphic<std::in_place_t>::value_type; // { dg-error "here" }
+
+using T5 = std::polymorphic<std::in_place_type_t<int>>::value_type; // { dg-error "here" }
+
+using T6 = std::polymorphic<const int>::value_type; // { dg-error "here" }
+
+using T7 = std::polymorphic<volatile int>::value_type; // { dg-error "here" }
+
+// { dg-error "static assertion failed" "" { target *-*-* } 0 }
+// { dg-prune-output "forming pointer to reference" }
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc
new file mode 100644
index 0000000..c802159
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move.cc
@@ -0,0 +1,177 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+#include <optional>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+struct Derived : Base
+{
+ constexpr Derived()
+ : x(0), y(0), z(0)
+ { }
+
+ constexpr Derived(int a, int b, int c)
+ : x(a), y(b), z(c)
+ { }
+
+private:
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const Derived*>(&other))
+ return this->x == op->x && this->y == op->y && this->z == op->z;
+ return false;
+ }
+
+ int x;
+ int y;
+ int z;
+};
+
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+using Polymorphic = std::polymorphic<Base, tracker_allocator<Base>>;
+const Polymorphic val(std::in_place_type<Derived>, 1, 2, 3);
+
+constexpr void
+verifyNoAllocations()
+{
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+constexpr void
+test_ctor()
+{
+ std::optional<Polymorphic> src;
+ auto make = [&src] -> Polymorphic&& {
+ src.emplace(val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Polymorphic i1(make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, {}, make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i2 == *val );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_assign()
+{
+ std::optional<Polymorphic> src;
+ auto make = [&src] -> Polymorphic&& {
+ src.emplace(val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Polymorphic i1(std::in_place_type<Derived>);
+
+ i1 = make();
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ auto(std::move(i1));
+ i1 = make();
+ VERIFY( *i1 == *val );
+ VERIFY( src->valueless_after_move() );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_swap()
+{
+ const Polymorphic val1(std::in_place_type<Derived>, 1, 2, 3);
+ const Polymorphic val2(std::in_place_type<Derived>, 2, 4, 6);
+
+ Polymorphic i1(val1);
+ Polymorphic i2(val2);
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i2 == *val1 );
+ VERIFY( *i1 == *val2 );
+ verifyNoAllocations();
+
+ auto(std::move(i1));
+
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i1 == *val1 );
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+}
+
+constexpr void
+test_valueless()
+{
+ auto e = [] {
+ Polymorphic res(std::in_place_type<Derived>);
+ auto(std::move(res));
+ Counter::reset();
+ return res;
+ };
+
+ Polymorphic i1(e());
+ VERIFY( i1.valueless_after_move() );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, {}, e());
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+
+ Polymorphic i3(val);
+ i3 = e();
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Derived) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ i3 = e();
+ verifyNoAllocations();
+}
+
+constexpr void
+test_all()
+{
+ test_ctor();
+ test_assign();
+ test_swap();
+ test_valueless();
+}
+
+int main()
+{
+ test_all();
+
+ static_assert([] {
+ test_all();
+ return true;
+ });
+}
diff --git a/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc
new file mode 100644
index 0000000..09afedb
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/memory/polymorphic/move_alloc.cc
@@ -0,0 +1,339 @@
+// { dg-do run { target c++26 } }
+
+#include <memory>
+#include <scoped_allocator>
+#include <utility>
+#include <vector>
+#include <optional>
+
+#include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
+
+struct Base {
+ friend constexpr
+ bool operator==(const Base& lhs, const Base& rhs)
+ { return lhs.eq(rhs); }
+
+ virtual constexpr int
+ get_alloc_personality() const
+ { return -1; }
+
+private:
+ constexpr virtual bool
+ eq(const Base& other) const = 0;
+};
+
+template<typename T, typename Allocator>
+struct VecDerived : Base, std::vector<T, Allocator>
+{
+ using VecBase = std::vector<T, Allocator>;
+
+ using VecBase::VecBase;
+
+ constexpr int
+ get_alloc_personality() const override
+ { return this->get_allocator().get_personality(); }
+
+private:
+
+ constexpr bool
+ eq(const Base& other) const override
+ {
+ if (auto op = dynamic_cast<const VecDerived*>(&other))
+ return *static_cast<const VecBase*>(this)
+ == *static_cast<const VecBase*>(op);
+ return false;
+ }
+};
+
+using __gnu_test::propagating_allocator;
+using __gnu_test::tracker_allocator;
+using Counter = __gnu_test::tracker_allocator_counter;
+
+constexpr void
+verifyNoAllocations()
+{
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_ctor()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic val(std::in_place_type<Vector>, {1, 2, 3});
+ std::optional<Polymorphic> src;
+ auto make = [&val, &src] -> Polymorphic&& {
+ src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Polymorphic i1(make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{11, 22}, make());
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i2 == *val );
+ VERIFY( i2->get_alloc_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}, make());
+ // We move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( *i3 == *val );
+ VERIFY( i3->get_alloc_personality() == 44 );
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 2 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_assign()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic val(std::in_place_type<Vector>, {1, 2, 3});
+ std::optional<Polymorphic> src;
+ auto make = [&val, &src] -> Polymorphic&& {
+ src.emplace(std::allocator_arg, ScopedAlloc{11, 22}, val);
+ Counter::reset();
+ return std::move(*src);
+ };
+
+ Counter::reset();
+ Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22});
+ const std::size_t holderSize = Counter::get_allocation_count();
+ VERIFY( holderSize >= sizeof(Vector) );
+
+ i1 = make();
+ VERIFY( src->valueless_after_move() );
+ VERIFY( *i1 == *val );
+ VERIFY( i1->get_alloc_personality() == 22 );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44});
+
+ i2 = make();
+ VERIFY( *i2 == *val );
+ if (Propagate)
+ {
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i2->get_alloc_personality() == 22 );
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ }
+ else
+ {
+ // We allocate new holder and move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ }
+ VERIFY( Counter::get_deallocation_count() == holderSize );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ auto(std::move(i3));
+
+ i3 = make();
+ VERIFY( *i3 == *val );
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i3->get_alloc_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44},
+ std::in_place_type<Vector>);
+ auto(std::move(i4));
+
+ i4 = make();
+ VERIFY( *i4 == *val );
+ if (Propagate)
+ {
+ VERIFY( src->valueless_after_move() );
+ VERIFY( i4->get_alloc_personality() == 22 );
+ VERIFY( i4.get_allocator().get_personality() == 11 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_construct_count() == 0 );
+ }
+ else
+ {
+ // We allocate new holder and move-from contained object
+ VERIFY( !src->valueless_after_move() );
+ VERIFY( i4->get_alloc_personality() == 44 );
+ VERIFY( i4.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == holderSize );
+ VERIFY( Counter::get_construct_count() == 2 );
+ }
+ VERIFY( Counter::get_deallocation_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 0 );
+}
+
+template<bool Propagate>
+constexpr void
+test_swap()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ const Polymorphic val1(std::in_place_type<Vector>, {1, 2, 3});
+ const Polymorphic val2(std::in_place_type<Vector>, {2, 4, 6});
+
+ Polymorphic i1(std::allocator_arg, ScopedAlloc{11, 22}, val1);
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{11, 22}, val2);
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i2 == *val1 );
+ VERIFY( *i1 == *val2 );
+ verifyNoAllocations();
+
+ auto(std::move(i1));
+
+ Counter::reset();
+ i1.swap(i2);
+ VERIFY( *i1 == *val1 );
+ VERIFY( i2.valueless_after_move() );
+ verifyNoAllocations();
+
+ if (!Propagate)
+ return;
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44}, val2);
+ Counter::reset();
+ i1.swap(i3);
+ VERIFY( *i1 == *val2 );
+ VERIFY( i1->get_alloc_personality() == 44 );
+ VERIFY( i1.get_allocator().get_personality() == 33 );
+ VERIFY( *i3 == *val1 );
+ VERIFY( i3->get_alloc_personality() == 22 );
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ i1.swap(i2);
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ VERIFY( *i2 == *val2 );
+ VERIFY( i2->get_alloc_personality() == 44 );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+}
+
+template<bool Propagate>
+constexpr void
+test_valueless()
+{
+ using PropAlloc = propagating_allocator<int, Propagate>;
+ using Vector = VecDerived<int, PropAlloc>;
+ using ScopedAlloc = std::scoped_allocator_adaptor<
+ propagating_allocator<Vector, Propagate, tracker_allocator<Vector>>,
+ PropAlloc>;
+ using Polymorphic = std::polymorphic<Vector, ScopedAlloc>;
+
+ auto e = [] {
+ Polymorphic res(std::allocator_arg, ScopedAlloc{11, 22},
+ std::in_place_type<Vector>);
+ auto(std::move(res));
+ Counter::reset();
+ return res;
+ };
+
+ Polymorphic i1(e());
+ VERIFY( i1.valueless_after_move() );
+ VERIFY( i1.get_allocator().get_personality() == 11 );
+ verifyNoAllocations();
+
+ Polymorphic i2(std::allocator_arg, ScopedAlloc{33, 44}, e());
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+
+ Polymorphic i3(std::allocator_arg, ScopedAlloc{33, 44});
+
+ i3 = e();
+ VERIFY( i3.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i3.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i3.get_allocator().get_personality() == 33 );
+ VERIFY( Counter::get_allocation_count() == 0 );
+ VERIFY( Counter::get_deallocation_count() >= sizeof(Vector) );
+ VERIFY( Counter::get_construct_count() == 0 );
+ VERIFY( Counter::get_destruct_count() == 1 );
+
+ i2 = e();
+ VERIFY( i2.valueless_after_move() );
+ if (Propagate)
+ VERIFY( i2.get_allocator().get_personality() == 11 );
+ else
+ VERIFY( i2.get_allocator().get_personality() == 33 );
+ verifyNoAllocations();
+
+ i3.swap(i2);
+ VERIFY( i2.valueless_after_move() );
+ VERIFY( i1.valueless_after_move() );
+ verifyNoAllocations();
+
+ if (!Propagate)
+ return;
+
+ Polymorphic i4(std::allocator_arg, ScopedAlloc{33, 44}, e());
+ i4.swap(i1);
+ verifyNoAllocations();
+}
+
+template<bool Propagate>
+constexpr void
+test_all()
+{
+ test_ctor<Propagate>();
+ test_assign<Propagate>();
+ test_swap<Propagate>();
+ test_valueless<Propagate>();
+}
+
+int main()
+{
+ test_all<true>();
+ test_all<false>();
+
+ static_assert([] {
+ test_all<true>();
+ test_all<false>();
+ return true;
+ });
+}